]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Add use of asprintf()
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is a utility for dumping out a postgres database
5  *        into a script file.
6  *
7  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32
33 #include "postgres_fe.h"
34
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef ENABLE_NLS
38 #include <locale.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h>
42 #endif
43
44 #include "getopt_long.h"
45
46 #include "access/attnum.h"
47 #include "access/sysattr.h"
48 #include "access/transam.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_event_trigger.h"
53 #include "catalog/pg_largeobject.h"
54 #include "catalog/pg_largeobject_metadata.h"
55 #include "catalog/pg_proc.h"
56 #include "catalog/pg_trigger.h"
57 #include "catalog/pg_type.h"
58 #include "libpq/libpq-fs.h"
59
60 #include "pg_backup_archiver.h"
61 #include "pg_backup_db.h"
62 #include "pg_backup_utils.h"
63 #include "dumputils.h"
64 #include "parallel.h"
65
66 extern char *optarg;
67 extern int      optind,
68                         opterr;
69
70
71 typedef struct
72 {
73         const char *descr;                      /* comment for an object */
74         Oid                     classoid;               /* object class (catalog OID) */
75         Oid                     objoid;                 /* object OID */
76         int                     objsubid;               /* subobject (table column #) */
77 } CommentItem;
78
79 typedef struct
80 {
81         const char *provider;           /* label provider of this security label */
82         const char *label;                      /* security label for an object */
83         Oid                     classoid;               /* object class (catalog OID) */
84         Oid                     objoid;                 /* object OID */
85         int                     objsubid;               /* subobject (table column #) */
86 } SecLabelItem;
87
88 /* global decls */
89 bool            g_verbose;                      /* User wants verbose narration of our
90                                                                  * activities. */
91
92 /* various user-settable parameters */
93 bool            schemaOnly;
94 bool            dataOnly;
95 int                     dumpSections;           /* bitmask of chosen sections */
96 bool            aclsSkip;
97 const char *lockWaitTimeout;
98
99 /* subquery used to convert user ID (eg, datdba) to user name */
100 static const char *username_subquery;
101
102 /* obsolete as of 7.3: */
103 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
104
105 /*
106  * Object inclusion/exclusion lists
107  *
108  * The string lists record the patterns given by command-line switches,
109  * which we then convert to lists of OIDs of matching objects.
110  */
111 static SimpleStringList schema_include_patterns = {NULL, NULL};
112 static SimpleOidList schema_include_oids = {NULL, NULL};
113 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
114 static SimpleOidList schema_exclude_oids = {NULL, NULL};
115
116 static SimpleStringList table_include_patterns = {NULL, NULL};
117 static SimpleOidList table_include_oids = {NULL, NULL};
118 static SimpleStringList table_exclude_patterns = {NULL, NULL};
119 static SimpleOidList table_exclude_oids = {NULL, NULL};
120 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
121 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
122
123 /* default, if no "inclusion" switches appear, is to dump everything */
124 static bool include_everything = true;
125
126 char            g_opaque_type[10];      /* name for the opaque type */
127
128 /* placeholders for the delimiters for comments */
129 char            g_comment_start[10];
130 char            g_comment_end[10];
131
132 static const CatalogId nilCatalogId = {0, 0};
133
134 /* flags for various command-line long options */
135 static int      binary_upgrade = 0;
136 static int      disable_dollar_quoting = 0;
137 static int      dump_inserts = 0;
138 static int      column_inserts = 0;
139 static int      no_security_labels = 0;
140 static int      no_synchronized_snapshots = 0;
141 static int      no_unlogged_table_data = 0;
142 static int      serializable_deferrable = 0;
143
144
145 static void help(const char *progname);
146 static void setup_connection(Archive *AH, const char *dumpencoding,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids);
152 static void expand_table_name_patterns(Archive *fout,
153                                                    SimpleStringList *patterns,
154                                                    SimpleOidList *oids);
155 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
156 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
157 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
158 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
159 static void dumpComment(Archive *fout, const char *target,
160                         const char *namespace, const char *owner,
161                         CatalogId catalogId, int subid, DumpId dumpId);
162 static int findComments(Archive *fout, Oid classoid, Oid objoid,
163                          CommentItem **items);
164 static int      collectComments(Archive *fout, CommentItem **items);
165 static void dumpSecLabel(Archive *fout, const char *target,
166                          const char *namespace, const char *owner,
167                          CatalogId catalogId, int subid, DumpId dumpId);
168 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
169                           SecLabelItem **items);
170 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
171 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
172 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
173 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
174 static void dumpType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
179 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
181 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
182 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
183 static void dumpFunc(Archive *fout, FuncInfo *finfo);
184 static void dumpCast(Archive *fout, CastInfo *cast);
185 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
186 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
187 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
188 static void dumpCollation(Archive *fout, CollInfo *convinfo);
189 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
190 static void dumpRule(Archive *fout, RuleInfo *rinfo);
191 static void dumpAgg(Archive *fout, AggInfo *agginfo);
192 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
193 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
194 static void dumpTable(Archive *fout, TableInfo *tbinfo);
195 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
196 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
197 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
198 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
199 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
200 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
201 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
202 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
203 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
204 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
205 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
206 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
207 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
208 static void dumpUserMappings(Archive *fout,
209                                  const char *servername, const char *namespace,
210                                  const char *owner, CatalogId catalogId, DumpId dumpId);
211 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
212
213 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
214                 const char *type, const char *name, const char *subname,
215                 const char *tag, const char *nspname, const char *owner,
216                 const char *acls);
217
218 static void getDependencies(Archive *fout);
219 static void BuildArchiveDependencies(Archive *fout);
220 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
221                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
222
223 static DumpableObject *createBoundaryObjects(void);
224 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
225                                                 DumpableObject *boundaryObjs);
226
227 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
228 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
229 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
230 static void buildMatViewRefreshDependencies(Archive *fout);
231 static void getTableDataFKConstraints(void);
232 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
233                                                                            bool is_agg);
234 static char *format_function_arguments_old(Archive *fout,
235                                                           FuncInfo *finfo, int nallargs,
236                                                           char **allargtypes,
237                                                           char **argmodes,
238                                                           char **argnames);
239 static char *format_function_signature(Archive *fout,
240                                                   FuncInfo *finfo, bool honor_quotes);
241 static const char *convertRegProcReference(Archive *fout,
242                                                 const char *proc);
243 static const char *convertOperatorReference(Archive *fout, const char *opr);
244 static const char *convertTSFunction(Archive *fout, Oid funcOid);
245 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
246 static Oid      findLastBuiltinOid_V70(Archive *fout);
247 static void selectSourceSchema(Archive *fout, const char *schemaName);
248 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
249 static char *myFormatType(const char *typname, int32 typmod);
250 static void getBlobs(Archive *fout);
251 static void dumpBlob(Archive *fout, BlobInfo *binfo);
252 static int      dumpBlobs(Archive *fout, void *arg);
253 static void dumpDatabase(Archive *AH);
254 static void dumpEncoding(Archive *AH);
255 static void dumpStdStrings(Archive *AH);
256 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
257                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
258 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
259                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
260 static void binary_upgrade_set_pg_class_oids(Archive *fout,
261                                                                  PQExpBuffer upgrade_buffer,
262                                                                  Oid pg_class_oid, bool is_index);
263 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
264                                                                 DumpableObject *dobj,
265                                                                 const char *objlabel);
266 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
267 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
268 static char *get_synchronized_snapshot(Archive *fout);
269 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
270 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
271
272
273 int
274 main(int argc, char **argv)
275 {
276         int                     c;
277         const char *filename = NULL;
278         const char *format = "p";
279         const char *dbname = NULL;
280         const char *pghost = NULL;
281         const char *pgport = NULL;
282         const char *username = NULL;
283         const char *dumpencoding = NULL;
284         bool            oids = false;
285         TableInfo  *tblinfo;
286         int                     numTables;
287         DumpableObject **dobjs;
288         int                     numObjs;
289         DumpableObject *boundaryObjs;
290         int                     i;
291         int                     numWorkers = 1;
292         enum trivalue prompt_password = TRI_DEFAULT;
293         int                     compressLevel = -1;
294         int                     plainText = 0;
295         int                     outputClean = 0;
296         int                     outputCreateDB = 0;
297         bool            outputBlobs = false;
298         int                     outputNoOwner = 0;
299         char       *outputSuperuser = NULL;
300         char       *use_role = NULL;
301         int                     optindex;
302         RestoreOptions *ropt;
303         ArchiveFormat archiveFormat = archUnknown;
304         ArchiveMode archiveMode;
305         Archive    *fout;                       /* the script file */
306
307         static int      disable_triggers = 0;
308         static int      outputNoTablespaces = 0;
309         static int      use_setsessauth = 0;
310
311         static struct option long_options[] = {
312                 {"data-only", no_argument, NULL, 'a'},
313                 {"blobs", no_argument, NULL, 'b'},
314                 {"clean", no_argument, NULL, 'c'},
315                 {"create", no_argument, NULL, 'C'},
316                 {"dbname", required_argument, NULL, 'd'},
317                 {"file", required_argument, NULL, 'f'},
318                 {"format", required_argument, NULL, 'F'},
319                 {"host", required_argument, NULL, 'h'},
320                 {"ignore-version", no_argument, NULL, 'i'},
321                 {"jobs", 1, NULL, 'j'},
322                 {"no-reconnect", no_argument, NULL, 'R'},
323                 {"oids", no_argument, NULL, 'o'},
324                 {"no-owner", no_argument, NULL, 'O'},
325                 {"port", required_argument, NULL, 'p'},
326                 {"schema", required_argument, NULL, 'n'},
327                 {"exclude-schema", required_argument, NULL, 'N'},
328                 {"schema-only", no_argument, NULL, 's'},
329                 {"superuser", required_argument, NULL, 'S'},
330                 {"table", required_argument, NULL, 't'},
331                 {"exclude-table", required_argument, NULL, 'T'},
332                 {"no-password", no_argument, NULL, 'w'},
333                 {"password", no_argument, NULL, 'W'},
334                 {"username", required_argument, NULL, 'U'},
335                 {"verbose", no_argument, NULL, 'v'},
336                 {"no-privileges", no_argument, NULL, 'x'},
337                 {"no-acl", no_argument, NULL, 'x'},
338                 {"compress", required_argument, NULL, 'Z'},
339                 {"encoding", required_argument, NULL, 'E'},
340                 {"help", no_argument, NULL, '?'},
341                 {"version", no_argument, NULL, 'V'},
342
343                 /*
344                  * the following options don't have an equivalent short option letter
345                  */
346                 {"attribute-inserts", no_argument, &column_inserts, 1},
347                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
348                 {"column-inserts", no_argument, &column_inserts, 1},
349                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
350                 {"disable-triggers", no_argument, &disable_triggers, 1},
351                 {"exclude-table-data", required_argument, NULL, 4},
352                 {"inserts", no_argument, &dump_inserts, 1},
353                 {"lock-wait-timeout", required_argument, NULL, 2},
354                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
355                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
356                 {"role", required_argument, NULL, 3},
357                 {"section", required_argument, NULL, 5},
358                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
359                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
360                 {"no-security-labels", no_argument, &no_security_labels, 1},
361                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
362                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
363
364                 {NULL, 0, NULL, 0}
365         };
366
367         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
368
369         /*
370          * Initialize what we need for parallel execution, especially for thread
371          * support on Windows.
372          */
373         init_parallel_dump_utils();
374
375         g_verbose = false;
376
377         strcpy(g_comment_start, "-- ");
378         g_comment_end[0] = '\0';
379         strcpy(g_opaque_type, "opaque");
380
381         dataOnly = schemaOnly = false;
382         dumpSections = DUMP_UNSECTIONED;
383         lockWaitTimeout = NULL;
384
385         progname = get_progname(argv[0]);
386
387         /* Set default options based on progname */
388         if (strcmp(progname, "pg_backup") == 0)
389                 format = "c";
390
391         if (argc > 1)
392         {
393                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
394                 {
395                         help(progname);
396                         exit_nicely(0);
397                 }
398                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
399                 {
400                         puts("pg_dump (PostgreSQL) " PG_VERSION);
401                         exit_nicely(0);
402                 }
403         }
404
405         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
406                                                         long_options, &optindex)) != -1)
407         {
408                 switch (c)
409                 {
410                         case 'a':                       /* Dump data only */
411                                 dataOnly = true;
412                                 break;
413
414                         case 'b':                       /* Dump blobs */
415                                 outputBlobs = true;
416                                 break;
417
418                         case 'c':                       /* clean (i.e., drop) schema prior to create */
419                                 outputClean = 1;
420                                 break;
421
422                         case 'C':                       /* Create DB */
423                                 outputCreateDB = 1;
424                                 break;
425
426                         case 'd':                       /* database name */
427                                 dbname = pg_strdup(optarg);
428                                 break;
429
430                         case 'E':                       /* Dump encoding */
431                                 dumpencoding = pg_strdup(optarg);
432                                 break;
433
434                         case 'f':
435                                 filename = pg_strdup(optarg);
436                                 break;
437
438                         case 'F':
439                                 format = pg_strdup(optarg);
440                                 break;
441
442                         case 'h':                       /* server host */
443                                 pghost = pg_strdup(optarg);
444                                 break;
445
446                         case 'i':
447                                 /* ignored, deprecated option */
448                                 break;
449
450                         case 'j':                       /* number of dump jobs */
451                                 numWorkers = atoi(optarg);
452                                 break;
453
454                         case 'n':                       /* include schema(s) */
455                                 simple_string_list_append(&schema_include_patterns, optarg);
456                                 include_everything = false;
457                                 break;
458
459                         case 'N':                       /* exclude schema(s) */
460                                 simple_string_list_append(&schema_exclude_patterns, optarg);
461                                 break;
462
463                         case 'o':                       /* Dump oids */
464                                 oids = true;
465                                 break;
466
467                         case 'O':                       /* Don't reconnect to match owner */
468                                 outputNoOwner = 1;
469                                 break;
470
471                         case 'p':                       /* server port */
472                                 pgport = pg_strdup(optarg);
473                                 break;
474
475                         case 'R':
476                                 /* no-op, still accepted for backwards compatibility */
477                                 break;
478
479                         case 's':                       /* dump schema only */
480                                 schemaOnly = true;
481                                 break;
482
483                         case 'S':                       /* Username for superuser in plain text output */
484                                 outputSuperuser = pg_strdup(optarg);
485                                 break;
486
487                         case 't':                       /* include table(s) */
488                                 simple_string_list_append(&table_include_patterns, optarg);
489                                 include_everything = false;
490                                 break;
491
492                         case 'T':                       /* exclude table(s) */
493                                 simple_string_list_append(&table_exclude_patterns, optarg);
494                                 break;
495
496                         case 'U':
497                                 username = pg_strdup(optarg);
498                                 break;
499
500                         case 'v':                       /* verbose */
501                                 g_verbose = true;
502                                 break;
503
504                         case 'w':
505                                 prompt_password = TRI_NO;
506                                 break;
507
508                         case 'W':
509                                 prompt_password = TRI_YES;
510                                 break;
511
512                         case 'x':                       /* skip ACL dump */
513                                 aclsSkip = true;
514                                 break;
515
516                         case 'Z':                       /* Compression Level */
517                                 compressLevel = atoi(optarg);
518                                 break;
519
520                         case 0:
521                                 /* This covers the long options. */
522                                 break;
523
524                         case 2:                         /* lock-wait-timeout */
525                                 lockWaitTimeout = pg_strdup(optarg);
526                                 break;
527
528                         case 3:                         /* SET ROLE */
529                                 use_role = pg_strdup(optarg);
530                                 break;
531
532                         case 4:                         /* exclude table(s) data */
533                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
534                                 break;
535
536                         case 5:                         /* section */
537                                 set_dump_section(optarg, &dumpSections);
538                                 break;
539
540                         default:
541                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
542                                 exit_nicely(1);
543                 }
544         }
545
546         /*
547          * Non-option argument specifies database name as long as it wasn't
548          * already specified with -d / --dbname
549          */
550         if (optind < argc && dbname == NULL)
551                 dbname = argv[optind++];
552
553         /* Complain if any arguments remain */
554         if (optind < argc)
555         {
556                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
557                                 progname, argv[optind]);
558                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
559                                 progname);
560                 exit_nicely(1);
561         }
562
563         /* --column-inserts implies --inserts */
564         if (column_inserts)
565                 dump_inserts = 1;
566
567         if (dataOnly && schemaOnly)
568                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
569
570         if (dataOnly && outputClean)
571                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
572
573         if (dump_inserts && oids)
574         {
575                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
576                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
577                 exit_nicely(1);
578         }
579
580         /* Identify archive format to emit */
581         archiveFormat = parseArchiveFormat(format, &archiveMode);
582
583         /* archiveFormat specific setup */
584         if (archiveFormat == archNull)
585                 plainText = 1;
586
587         /* Custom and directory formats are compressed by default, others not */
588         if (compressLevel == -1)
589         {
590                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
591                         compressLevel = Z_DEFAULT_COMPRESSION;
592                 else
593                         compressLevel = 0;
594         }
595
596         /*
597          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
598          * parallel jobs because that's the maximum limit for the
599          * WaitForMultipleObjects() call.
600          */
601         if (numWorkers <= 0
602 #ifdef WIN32
603                 || numWorkers > MAXIMUM_WAIT_OBJECTS
604 #endif
605                 )
606                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
607
608         /* Parallel backup only in the directory archive format so far */
609         if (archiveFormat != archDirectory && numWorkers > 1)
610                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
611
612         /* Open the output file */
613         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
614                                                  setupDumpWorker);
615
616         /* Register the cleanup hook */
617         on_exit_close_archive(fout);
618
619         if (fout == NULL)
620                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
621
622         /* Let the archiver know how noisy to be */
623         fout->verbose = g_verbose;
624
625         /*
626          * We allow the server to be back to 7.0, and up to any minor release of
627          * our own major version.  (See also version check in pg_dumpall.c.)
628          */
629         fout->minRemoteVersion = 70000;
630         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
631
632         fout->numWorkers = numWorkers;
633
634         /*
635          * Open the database using the Archiver, so it knows about it. Errors mean
636          * death.
637          */
638         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
639         setup_connection(fout, dumpencoding, use_role);
640
641         /*
642          * Disable security label support if server version < v9.1.x (prevents
643          * access to nonexistent pg_seclabel catalog)
644          */
645         if (fout->remoteVersion < 90100)
646                 no_security_labels = 1;
647
648         /*
649          * When running against 9.0 or later, check if we are in recovery mode,
650          * which means we are on a hot standby.
651          */
652         if (fout->remoteVersion >= 90000)
653         {
654                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
655
656                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
657                 {
658                         /*
659                          * On hot standby slaves, never try to dump unlogged table data,
660                          * since it will just throw an error.
661                          */
662                         no_unlogged_table_data = true;
663                 }
664                 PQclear(res);
665         }
666
667         /* Select the appropriate subquery to convert user IDs to names */
668         if (fout->remoteVersion >= 80100)
669                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
670         else if (fout->remoteVersion >= 70300)
671                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
672         else
673                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
674
675         /* check the version for the synchronized snapshots feature */
676         if (numWorkers > 1 && fout->remoteVersion < 90200
677                 && !no_synchronized_snapshots)
678                 exit_horribly(NULL,
679                  "Synchronized snapshots are not supported by this server version.\n"
680                   "Run with --no-synchronized-snapshots instead if you do not need\n"
681                                           "synchronized snapshots.\n");
682
683         /* Find the last built-in OID, if needed */
684         if (fout->remoteVersion < 70300)
685         {
686                 if (fout->remoteVersion >= 70100)
687                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
688                                                                                                   PQdb(GetConnection(fout)));
689                 else
690                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
691                 if (g_verbose)
692                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
693         }
694
695         /* Expand schema selection patterns into OID lists */
696         if (schema_include_patterns.head != NULL)
697         {
698                 expand_schema_name_patterns(fout, &schema_include_patterns,
699                                                                         &schema_include_oids);
700                 if (schema_include_oids.head == NULL)
701                         exit_horribly(NULL, "No matching schemas were found\n");
702         }
703         expand_schema_name_patterns(fout, &schema_exclude_patterns,
704                                                                 &schema_exclude_oids);
705         /* non-matching exclusion patterns aren't an error */
706
707         /* Expand table selection patterns into OID lists */
708         if (table_include_patterns.head != NULL)
709         {
710                 expand_table_name_patterns(fout, &table_include_patterns,
711                                                                    &table_include_oids);
712                 if (table_include_oids.head == NULL)
713                         exit_horribly(NULL, "No matching tables were found\n");
714         }
715         expand_table_name_patterns(fout, &table_exclude_patterns,
716                                                            &table_exclude_oids);
717
718         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
719                                                            &tabledata_exclude_oids);
720
721         /* non-matching exclusion patterns aren't an error */
722
723         /*
724          * Dumping blobs is now default unless we saw an inclusion switch or -s
725          * ... but even if we did see one of these, -b turns it back on.
726          */
727         if (include_everything && !schemaOnly)
728                 outputBlobs = true;
729
730         /*
731          * Now scan the database and create DumpableObject structs for all the
732          * objects we intend to dump.
733          */
734         tblinfo = getSchemaData(fout, &numTables);
735
736         if (fout->remoteVersion < 80400)
737                 guessConstraintInheritance(tblinfo, numTables);
738
739         if (!schemaOnly)
740         {
741                 getTableData(tblinfo, numTables, oids);
742                 buildMatViewRefreshDependencies(fout);
743                 if (dataOnly)
744                         getTableDataFKConstraints();
745         }
746
747         if (outputBlobs)
748                 getBlobs(fout);
749
750         /*
751          * Collect dependency data to assist in ordering the objects.
752          */
753         getDependencies(fout);
754
755         /* Lastly, create dummy objects to represent the section boundaries */
756         boundaryObjs = createBoundaryObjects();
757
758         /* Get pointers to all the known DumpableObjects */
759         getDumpableObjects(&dobjs, &numObjs);
760
761         /*
762          * Add dummy dependencies to enforce the dump section ordering.
763          */
764         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
765
766         /*
767          * Sort the objects into a safe dump order (no forward references).
768          *
769          * In 7.3 or later, we can rely on dependency information to help us
770          * determine a safe order, so the initial sort is mostly for cosmetic
771          * purposes: we sort by name to ensure that logically identical schemas
772          * will dump identically.  Before 7.3 we don't have dependencies and we
773          * use OID ordering as an (unreliable) guide to creation order.
774          */
775         if (fout->remoteVersion >= 70300)
776                 sortDumpableObjectsByTypeName(dobjs, numObjs);
777         else
778                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
779
780         /* If we do a parallel dump, we want the largest tables to go first */
781         if (archiveFormat == archDirectory && numWorkers > 1)
782                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
783
784         sortDumpableObjects(dobjs, numObjs,
785                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
786
787         /*
788          * Create archive TOC entries for all the objects to be dumped, in a safe
789          * order.
790          */
791
792         /* First the special ENCODING and STDSTRINGS entries. */
793         dumpEncoding(fout);
794         dumpStdStrings(fout);
795
796         /* The database item is always next, unless we don't want it at all */
797         if (include_everything && !dataOnly)
798                 dumpDatabase(fout);
799
800         /* Now the rearrangeable objects. */
801         for (i = 0; i < numObjs; i++)
802                 dumpDumpableObject(fout, dobjs[i]);
803
804         /*
805          * Set up options info to ensure we dump what we want.
806          */
807         ropt = NewRestoreOptions();
808         ropt->filename = filename;
809         ropt->dropSchema = outputClean;
810         ropt->dataOnly = dataOnly;
811         ropt->schemaOnly = schemaOnly;
812         ropt->dumpSections = dumpSections;
813         ropt->aclsSkip = aclsSkip;
814         ropt->superuser = outputSuperuser;
815         ropt->createDB = outputCreateDB;
816         ropt->noOwner = outputNoOwner;
817         ropt->noTablespace = outputNoTablespaces;
818         ropt->disable_triggers = disable_triggers;
819         ropt->use_setsessauth = use_setsessauth;
820
821         if (compressLevel == -1)
822                 ropt->compression = 0;
823         else
824                 ropt->compression = compressLevel;
825
826         ropt->suppressDumpWarnings = true;      /* We've already shown them */
827
828         SetArchiveRestoreOptions(fout, ropt);
829
830         /*
831          * The archive's TOC entries are now marked as to which ones will actually
832          * be output, so we can set up their dependency lists properly. This isn't
833          * necessary for plain-text output, though.
834          */
835         if (!plainText)
836                 BuildArchiveDependencies(fout);
837
838         /*
839          * And finally we can do the actual output.
840          *
841          * Note: for non-plain-text output formats, the output file is written
842          * inside CloseArchive().  This is, um, bizarre; but not worth changing
843          * right now.
844          */
845         if (plainText)
846                 RestoreArchive(fout);
847
848         CloseArchive(fout);
849
850         exit_nicely(0);
851 }
852
853
854 static void
855 help(const char *progname)
856 {
857         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
858         printf(_("Usage:\n"));
859         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
860
861         printf(_("\nGeneral options:\n"));
862         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
863         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
864                          "                               plain text (default))\n"));
865         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
866         printf(_("  -v, --verbose                verbose mode\n"));
867         printf(_("  -V, --version                output version information, then exit\n"));
868         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
869         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
870         printf(_("  -?, --help                   show this help, then exit\n"));
871
872         printf(_("\nOptions controlling the output content:\n"));
873         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
874         printf(_("  -b, --blobs                  include large objects in dump\n"));
875         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
876         printf(_("  -C, --create                 include commands to create database in dump\n"));
877         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
878         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
879         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
880         printf(_("  -o, --oids                   include OIDs in dump\n"));
881         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
882                          "                               plain-text format\n"));
883         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
884         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
885         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
886         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
887         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
888         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
889         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
890         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
891         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
892         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
893         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
894         printf(_("  --no-security-labels         do not dump security label assignments\n"));
895         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
896         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
897         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
898         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
899         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
900         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
901         printf(_("  --use-set-session-authorization\n"
902                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
903                          "                               ALTER OWNER commands to set ownership\n"));
904
905         printf(_("\nConnection options:\n"));
906         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
907         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
908         printf(_("  -p, --port=PORT          database server port number\n"));
909         printf(_("  -U, --username=NAME      connect as specified database user\n"));
910         printf(_("  -w, --no-password        never prompt for password\n"));
911         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
912         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
913
914         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
915                          "variable value is used.\n\n"));
916         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
917 }
918
919 static void
920 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
921 {
922         PGconn     *conn = GetConnection(AH);
923         const char *std_strings;
924
925         /*
926          * Set the client encoding if requested. If dumpencoding == NULL then
927          * either it hasn't been requested or we're a cloned connection and then
928          * this has already been set in CloneArchive according to the original
929          * connection encoding.
930          */
931         if (dumpencoding)
932         {
933                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
934                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
935                                                   dumpencoding);
936         }
937
938         /*
939          * Get the active encoding and the standard_conforming_strings setting, so
940          * we know how to escape strings.
941          */
942         AH->encoding = PQclientEncoding(conn);
943
944         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
945         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
946
947         /* Set the role if requested */
948         if (!use_role && AH->use_role)
949                 use_role = AH->use_role;
950
951         /* Set the role if requested */
952         if (use_role && AH->remoteVersion >= 80100)
953         {
954                 PQExpBuffer query = createPQExpBuffer();
955
956                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
957                 ExecuteSqlStatement(AH, query->data);
958                 destroyPQExpBuffer(query);
959
960                 /* save this for later use on parallel connections */
961                 if (!AH->use_role)
962                         AH->use_role = strdup(use_role);
963         }
964
965         /* Set the datestyle to ISO to ensure the dump's portability */
966         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
967
968         /* Likewise, avoid using sql_standard intervalstyle */
969         if (AH->remoteVersion >= 80400)
970                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
971
972         /*
973          * If supported, set extra_float_digits so that we can dump float data
974          * exactly (given correctly implemented float I/O code, anyway)
975          */
976         if (AH->remoteVersion >= 90000)
977                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
978         else if (AH->remoteVersion >= 70400)
979                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
980
981         /*
982          * If synchronized scanning is supported, disable it, to prevent
983          * unpredictable changes in row ordering across a dump and reload.
984          */
985         if (AH->remoteVersion >= 80300)
986                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
987
988         /*
989          * Disable timeouts if supported.
990          */
991         if (AH->remoteVersion >= 70300)
992                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
993         if (AH->remoteVersion >= 90300)
994                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
995
996         /*
997          * Quote all identifiers, if requested.
998          */
999         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1000                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1001
1002         /*
1003          * Start transaction-snapshot mode transaction to dump consistent data.
1004          */
1005         ExecuteSqlStatement(AH, "BEGIN");
1006         if (AH->remoteVersion >= 90100)
1007         {
1008                 if (serializable_deferrable)
1009                         ExecuteSqlStatement(AH,
1010                                                                 "SET TRANSACTION ISOLATION LEVEL "
1011                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1012                 else
1013                         ExecuteSqlStatement(AH,
1014                                                                 "SET TRANSACTION ISOLATION LEVEL "
1015                                                                 "REPEATABLE READ, READ ONLY");
1016         }
1017         else if (AH->remoteVersion >= 70400)
1018         {
1019                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1020                 ExecuteSqlStatement(AH,
1021                                                         "SET TRANSACTION ISOLATION LEVEL "
1022                                                         "SERIALIZABLE READ ONLY");
1023         }
1024         else
1025                 ExecuteSqlStatement(AH,
1026                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1027
1028
1029
1030         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1031         {
1032                 if (AH->sync_snapshot_id)
1033                 {
1034                         PQExpBuffer query = createPQExpBuffer();
1035
1036                         appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1037                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1038                         ExecuteSqlStatement(AH, query->data);
1039                         destroyPQExpBuffer(query);
1040                 }
1041                 else
1042                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1043         }
1044 }
1045
1046 static void
1047 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1048 {
1049         setup_connection(AHX, NULL, NULL);
1050 }
1051
1052 static char *
1053 get_synchronized_snapshot(Archive *fout)
1054 {
1055         char       *query = "SELECT pg_export_snapshot()";
1056         char       *result;
1057         PGresult   *res;
1058
1059         res = ExecuteSqlQueryForSingleRow(fout, query);
1060         result = strdup(PQgetvalue(res, 0, 0));
1061         PQclear(res);
1062
1063         return result;
1064 }
1065
1066 static ArchiveFormat
1067 parseArchiveFormat(const char *format, ArchiveMode *mode)
1068 {
1069         ArchiveFormat archiveFormat;
1070
1071         *mode = archModeWrite;
1072
1073         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1074         {
1075                 /* This is used by pg_dumpall, and is not documented */
1076                 archiveFormat = archNull;
1077                 *mode = archModeAppend;
1078         }
1079         else if (pg_strcasecmp(format, "c") == 0)
1080                 archiveFormat = archCustom;
1081         else if (pg_strcasecmp(format, "custom") == 0)
1082                 archiveFormat = archCustom;
1083         else if (pg_strcasecmp(format, "d") == 0)
1084                 archiveFormat = archDirectory;
1085         else if (pg_strcasecmp(format, "directory") == 0)
1086                 archiveFormat = archDirectory;
1087         else if (pg_strcasecmp(format, "p") == 0)
1088                 archiveFormat = archNull;
1089         else if (pg_strcasecmp(format, "plain") == 0)
1090                 archiveFormat = archNull;
1091         else if (pg_strcasecmp(format, "t") == 0)
1092                 archiveFormat = archTar;
1093         else if (pg_strcasecmp(format, "tar") == 0)
1094                 archiveFormat = archTar;
1095         else
1096                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1097         return archiveFormat;
1098 }
1099
1100 /*
1101  * Find the OIDs of all schemas matching the given list of patterns,
1102  * and append them to the given OID list.
1103  */
1104 static void
1105 expand_schema_name_patterns(Archive *fout,
1106                                                         SimpleStringList *patterns,
1107                                                         SimpleOidList *oids)
1108 {
1109         PQExpBuffer query;
1110         PGresult   *res;
1111         SimpleStringListCell *cell;
1112         int                     i;
1113
1114         if (patterns->head == NULL)
1115                 return;                                 /* nothing to do */
1116
1117         if (fout->remoteVersion < 70300)
1118                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1119
1120         query = createPQExpBuffer();
1121
1122         /*
1123          * We use UNION ALL rather than UNION; this might sometimes result in
1124          * duplicate entries in the OID list, but we don't care.
1125          */
1126
1127         for (cell = patterns->head; cell; cell = cell->next)
1128         {
1129                 if (cell != patterns->head)
1130                         appendPQExpBuffer(query, "UNION ALL\n");
1131                 appendPQExpBuffer(query,
1132                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1133                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1134                                                           false, NULL, "n.nspname", NULL, NULL);
1135         }
1136
1137         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1138
1139         for (i = 0; i < PQntuples(res); i++)
1140         {
1141                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1142         }
1143
1144         PQclear(res);
1145         destroyPQExpBuffer(query);
1146 }
1147
1148 /*
1149  * Find the OIDs of all tables matching the given list of patterns,
1150  * and append them to the given OID list.
1151  */
1152 static void
1153 expand_table_name_patterns(Archive *fout,
1154                                                    SimpleStringList *patterns, SimpleOidList *oids)
1155 {
1156         PQExpBuffer query;
1157         PGresult   *res;
1158         SimpleStringListCell *cell;
1159         int                     i;
1160
1161         if (patterns->head == NULL)
1162                 return;                                 /* nothing to do */
1163
1164         query = createPQExpBuffer();
1165
1166         /*
1167          * We use UNION ALL rather than UNION; this might sometimes result in
1168          * duplicate entries in the OID list, but we don't care.
1169          */
1170
1171         for (cell = patterns->head; cell; cell = cell->next)
1172         {
1173                 if (cell != patterns->head)
1174                         appendPQExpBuffer(query, "UNION ALL\n");
1175                 appendPQExpBuffer(query,
1176                                                   "SELECT c.oid"
1177                                                   "\nFROM pg_catalog.pg_class c"
1178                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1179                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1180                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1181                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1182                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1183                                                           false, "n.nspname", "c.relname", NULL,
1184                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1185         }
1186
1187         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1188
1189         for (i = 0; i < PQntuples(res); i++)
1190         {
1191                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1192         }
1193
1194         PQclear(res);
1195         destroyPQExpBuffer(query);
1196 }
1197
1198 /*
1199  * selectDumpableNamespace: policy-setting subroutine
1200  *              Mark a namespace as to be dumped or not
1201  */
1202 static void
1203 selectDumpableNamespace(NamespaceInfo *nsinfo)
1204 {
1205         /*
1206          * If specific tables are being dumped, do not dump any complete
1207          * namespaces. If specific namespaces are being dumped, dump just those
1208          * namespaces. Otherwise, dump all non-system namespaces.
1209          */
1210         if (table_include_oids.head != NULL)
1211                 nsinfo->dobj.dump = false;
1212         else if (schema_include_oids.head != NULL)
1213                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1214                                                                                                    nsinfo->dobj.catId.oid);
1215         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1216                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1217                 nsinfo->dobj.dump = false;
1218         else
1219                 nsinfo->dobj.dump = true;
1220
1221         /*
1222          * In any case, a namespace can be excluded by an exclusion switch
1223          */
1224         if (nsinfo->dobj.dump &&
1225                 simple_oid_list_member(&schema_exclude_oids,
1226                                                            nsinfo->dobj.catId.oid))
1227                 nsinfo->dobj.dump = false;
1228 }
1229
1230 /*
1231  * selectDumpableTable: policy-setting subroutine
1232  *              Mark a table as to be dumped or not
1233  */
1234 static void
1235 selectDumpableTable(TableInfo *tbinfo)
1236 {
1237         /*
1238          * If specific tables are being dumped, dump just those tables; else, dump
1239          * according to the parent namespace's dump flag.
1240          */
1241         if (table_include_oids.head != NULL)
1242                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1243                                                                                                    tbinfo->dobj.catId.oid);
1244         else
1245                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1246
1247         /*
1248          * In any case, a table can be excluded by an exclusion switch
1249          */
1250         if (tbinfo->dobj.dump &&
1251                 simple_oid_list_member(&table_exclude_oids,
1252                                                            tbinfo->dobj.catId.oid))
1253                 tbinfo->dobj.dump = false;
1254 }
1255
1256 /*
1257  * selectDumpableType: policy-setting subroutine
1258  *              Mark a type as to be dumped or not
1259  *
1260  * If it's a table's rowtype or an autogenerated array type, we also apply a
1261  * special type code to facilitate sorting into the desired order.      (We don't
1262  * want to consider those to be ordinary types because that would bring tables
1263  * up into the datatype part of the dump order.)  We still set the object's
1264  * dump flag; that's not going to cause the dummy type to be dumped, but we
1265  * need it so that casts involving such types will be dumped correctly -- see
1266  * dumpCast.  This means the flag should be set the same as for the underlying
1267  * object (the table or base type).
1268  */
1269 static void
1270 selectDumpableType(TypeInfo *tyinfo)
1271 {
1272         /* skip complex types, except for standalone composite types */
1273         if (OidIsValid(tyinfo->typrelid) &&
1274                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1275         {
1276                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1277
1278                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1279                 if (tytable != NULL)
1280                         tyinfo->dobj.dump = tytable->dobj.dump;
1281                 else
1282                         tyinfo->dobj.dump = false;
1283                 return;
1284         }
1285
1286         /* skip auto-generated array types */
1287         if (tyinfo->isArray)
1288         {
1289                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1290
1291                 /*
1292                  * Fall through to set the dump flag; we assume that the subsequent
1293                  * rules will do the same thing as they would for the array's base
1294                  * type.  (We cannot reliably look up the base type here, since
1295                  * getTypes may not have processed it yet.)
1296                  */
1297         }
1298
1299         /* dump only types in dumpable namespaces */
1300         if (!tyinfo->dobj.namespace->dobj.dump)
1301                 tyinfo->dobj.dump = false;
1302
1303         /* skip undefined placeholder types */
1304         else if (!tyinfo->isDefined)
1305                 tyinfo->dobj.dump = false;
1306
1307         else
1308                 tyinfo->dobj.dump = true;
1309 }
1310
1311 /*
1312  * selectDumpableDefaultACL: policy-setting subroutine
1313  *              Mark a default ACL as to be dumped or not
1314  *
1315  * For per-schema default ACLs, dump if the schema is to be dumped.
1316  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1317  * and aclsSkip are checked separately.
1318  */
1319 static void
1320 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1321 {
1322         if (dinfo->dobj.namespace)
1323                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1324         else
1325                 dinfo->dobj.dump = include_everything;
1326 }
1327
1328 /*
1329  * selectDumpableExtension: policy-setting subroutine
1330  *              Mark an extension as to be dumped or not
1331  *
1332  * Normally, we dump all extensions, or none of them if include_everything
1333  * is false (i.e., a --schema or --table switch was given).  However, in
1334  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1335  * assume those will already be installed in the target database.  We identify
1336  * such extensions by their having OIDs in the range reserved for initdb.
1337  */
1338 static void
1339 selectDumpableExtension(ExtensionInfo *extinfo)
1340 {
1341         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1342                 extinfo->dobj.dump = false;
1343         else
1344                 extinfo->dobj.dump = include_everything;
1345 }
1346
1347 /*
1348  * selectDumpableObject: policy-setting subroutine
1349  *              Mark a generic dumpable object as to be dumped or not
1350  *
1351  * Use this only for object types without a special-case routine above.
1352  */
1353 static void
1354 selectDumpableObject(DumpableObject *dobj)
1355 {
1356         /*
1357          * Default policy is to dump if parent namespace is dumpable, or always
1358          * for non-namespace-associated items.
1359          */
1360         if (dobj->namespace)
1361                 dobj->dump = dobj->namespace->dobj.dump;
1362         else
1363                 dobj->dump = true;
1364 }
1365
1366 /*
1367  *      Dump a table's contents for loading using the COPY command
1368  *      - this routine is called by the Archiver when it wants the table
1369  *        to be dumped.
1370  */
1371
1372 static int
1373 dumpTableData_copy(Archive *fout, void *dcontext)
1374 {
1375         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1376         TableInfo  *tbinfo = tdinfo->tdtable;
1377         const char *classname = tbinfo->dobj.name;
1378         const bool      hasoids = tbinfo->hasoids;
1379         const bool      oids = tdinfo->oids;
1380         PQExpBuffer q = createPQExpBuffer();
1381
1382         /*
1383          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1384          * which uses it already.
1385          */
1386         PQExpBuffer clistBuf = createPQExpBuffer();
1387         PGconn     *conn = GetConnection(fout);
1388         PGresult   *res;
1389         int                     ret;
1390         char       *copybuf;
1391         const char *column_list;
1392
1393         if (g_verbose)
1394                 write_msg(NULL, "dumping contents of table %s\n", classname);
1395
1396         /*
1397          * Make sure we are in proper schema.  We will qualify the table name
1398          * below anyway (in case its name conflicts with a pg_catalog table); but
1399          * this ensures reproducible results in case the table contains regproc,
1400          * regclass, etc columns.
1401          */
1402         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1403
1404         /*
1405          * If possible, specify the column list explicitly so that we have no
1406          * possibility of retrieving data in the wrong column order.  (The default
1407          * column ordering of COPY will not be what we want in certain corner
1408          * cases involving ADD COLUMN and inheritance.)
1409          */
1410         if (fout->remoteVersion >= 70300)
1411                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1412         else
1413                 column_list = "";               /* can't select columns in COPY */
1414
1415         if (oids && hasoids)
1416         {
1417                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1418                                                   fmtQualifiedId(fout->remoteVersion,
1419                                                                                  tbinfo->dobj.namespace->dobj.name,
1420                                                                                  classname),
1421                                                   column_list);
1422         }
1423         else if (tdinfo->filtercond)
1424         {
1425                 /* Note: this syntax is only supported in 8.2 and up */
1426                 appendPQExpBufferStr(q, "COPY (SELECT ");
1427                 /* klugery to get rid of parens in column list */
1428                 if (strlen(column_list) > 2)
1429                 {
1430                         appendPQExpBufferStr(q, column_list + 1);
1431                         q->data[q->len - 1] = ' ';
1432                 }
1433                 else
1434                         appendPQExpBufferStr(q, "* ");
1435                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1436                                                   fmtQualifiedId(fout->remoteVersion,
1437                                                                                  tbinfo->dobj.namespace->dobj.name,
1438                                                                                  classname),
1439                                                   tdinfo->filtercond);
1440         }
1441         else
1442         {
1443                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1444                                                   fmtQualifiedId(fout->remoteVersion,
1445                                                                                  tbinfo->dobj.namespace->dobj.name,
1446                                                                                  classname),
1447                                                   column_list);
1448         }
1449         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1450         PQclear(res);
1451         destroyPQExpBuffer(clistBuf);
1452
1453         for (;;)
1454         {
1455                 ret = PQgetCopyData(conn, &copybuf, 0);
1456
1457                 if (ret < 0)
1458                         break;                          /* done or error */
1459
1460                 if (copybuf)
1461                 {
1462                         WriteData(fout, copybuf, ret);
1463                         PQfreemem(copybuf);
1464                 }
1465
1466                 /* ----------
1467                  * THROTTLE:
1468                  *
1469                  * There was considerable discussion in late July, 2000 regarding
1470                  * slowing down pg_dump when backing up large tables. Users with both
1471                  * slow & fast (multi-processor) machines experienced performance
1472                  * degradation when doing a backup.
1473                  *
1474                  * Initial attempts based on sleeping for a number of ms for each ms
1475                  * of work were deemed too complex, then a simple 'sleep in each loop'
1476                  * implementation was suggested. The latter failed because the loop
1477                  * was too tight. Finally, the following was implemented:
1478                  *
1479                  * If throttle is non-zero, then
1480                  *              See how long since the last sleep.
1481                  *              Work out how long to sleep (based on ratio).
1482                  *              If sleep is more than 100ms, then
1483                  *                      sleep
1484                  *                      reset timer
1485                  *              EndIf
1486                  * EndIf
1487                  *
1488                  * where the throttle value was the number of ms to sleep per ms of
1489                  * work. The calculation was done in each loop.
1490                  *
1491                  * Most of the hard work is done in the backend, and this solution
1492                  * still did not work particularly well: on slow machines, the ratio
1493                  * was 50:1, and on medium paced machines, 1:1, and on fast
1494                  * multi-processor machines, it had little or no effect, for reasons
1495                  * that were unclear.
1496                  *
1497                  * Further discussion ensued, and the proposal was dropped.
1498                  *
1499                  * For those people who want this feature, it can be implemented using
1500                  * gettimeofday in each loop, calculating the time since last sleep,
1501                  * multiplying that by the sleep ratio, then if the result is more
1502                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1503                  * function to sleep for a subsecond period ie.
1504                  *
1505                  * select(0, NULL, NULL, NULL, &tvi);
1506                  *
1507                  * This will return after the interval specified in the structure tvi.
1508                  * Finally, call gettimeofday again to save the 'last sleep time'.
1509                  * ----------
1510                  */
1511         }
1512         archprintf(fout, "\\.\n\n\n");
1513
1514         if (ret == -2)
1515         {
1516                 /* copy data transfer failed */
1517                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1518                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1519                 write_msg(NULL, "The command was: %s\n", q->data);
1520                 exit_nicely(1);
1521         }
1522
1523         /* Check command status and return to normal libpq state */
1524         res = PQgetResult(conn);
1525         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1526         {
1527                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1528                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1529                 write_msg(NULL, "The command was: %s\n", q->data);
1530                 exit_nicely(1);
1531         }
1532         PQclear(res);
1533
1534         destroyPQExpBuffer(q);
1535         return 1;
1536 }
1537
1538 /*
1539  * Dump table data using INSERT commands.
1540  *
1541  * Caution: when we restore from an archive file direct to database, the
1542  * INSERT commands emitted by this function have to be parsed by
1543  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1544  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1545  */
1546 static int
1547 dumpTableData_insert(Archive *fout, void *dcontext)
1548 {
1549         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1550         TableInfo  *tbinfo = tdinfo->tdtable;
1551         const char *classname = tbinfo->dobj.name;
1552         PQExpBuffer q = createPQExpBuffer();
1553         PGresult   *res;
1554         int                     tuple;
1555         int                     nfields;
1556         int                     field;
1557
1558         /*
1559          * Make sure we are in proper schema.  We will qualify the table name
1560          * below anyway (in case its name conflicts with a pg_catalog table); but
1561          * this ensures reproducible results in case the table contains regproc,
1562          * regclass, etc columns.
1563          */
1564         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1565
1566         if (fout->remoteVersion >= 70100)
1567         {
1568                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1569                                                   "SELECT * FROM ONLY %s",
1570                                                   fmtQualifiedId(fout->remoteVersion,
1571                                                                                  tbinfo->dobj.namespace->dobj.name,
1572                                                                                  classname));
1573         }
1574         else
1575         {
1576                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1577                                                   "SELECT * FROM %s",
1578                                                   fmtQualifiedId(fout->remoteVersion,
1579                                                                                  tbinfo->dobj.namespace->dobj.name,
1580                                                                                  classname));
1581         }
1582         if (tdinfo->filtercond)
1583                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1584
1585         ExecuteSqlStatement(fout, q->data);
1586
1587         while (1)
1588         {
1589                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1590                                                           PGRES_TUPLES_OK);
1591                 nfields = PQnfields(res);
1592                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1593                 {
1594                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1595                         if (nfields == 0)
1596                         {
1597                                 /* corner case for zero-column table */
1598                                 archprintf(fout, "DEFAULT VALUES;\n");
1599                                 continue;
1600                         }
1601                         if (column_inserts)
1602                         {
1603                                 resetPQExpBuffer(q);
1604                                 appendPQExpBuffer(q, "(");
1605                                 for (field = 0; field < nfields; field++)
1606                                 {
1607                                         if (field > 0)
1608                                                 appendPQExpBuffer(q, ", ");
1609                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1610                                 }
1611                                 appendPQExpBuffer(q, ") ");
1612                                 archputs(q->data, fout);
1613                         }
1614                         archprintf(fout, "VALUES (");
1615                         for (field = 0; field < nfields; field++)
1616                         {
1617                                 if (field > 0)
1618                                         archprintf(fout, ", ");
1619                                 if (PQgetisnull(res, tuple, field))
1620                                 {
1621                                         archprintf(fout, "NULL");
1622                                         continue;
1623                                 }
1624
1625                                 /* XXX This code is partially duplicated in ruleutils.c */
1626                                 switch (PQftype(res, field))
1627                                 {
1628                                         case INT2OID:
1629                                         case INT4OID:
1630                                         case INT8OID:
1631                                         case OIDOID:
1632                                         case FLOAT4OID:
1633                                         case FLOAT8OID:
1634                                         case NUMERICOID:
1635                                                 {
1636                                                         /*
1637                                                          * These types are printed without quotes unless
1638                                                          * they contain values that aren't accepted by the
1639                                                          * scanner unquoted (e.g., 'NaN').      Note that
1640                                                          * strtod() and friends might accept NaN, so we
1641                                                          * can't use that to test.
1642                                                          *
1643                                                          * In reality we only need to defend against
1644                                                          * infinity and NaN, so we need not get too crazy
1645                                                          * about pattern matching here.
1646                                                          */
1647                                                         const char *s = PQgetvalue(res, tuple, field);
1648
1649                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1650                                                                 archprintf(fout, "%s", s);
1651                                                         else
1652                                                                 archprintf(fout, "'%s'", s);
1653                                                 }
1654                                                 break;
1655
1656                                         case BITOID:
1657                                         case VARBITOID:
1658                                                 archprintf(fout, "B'%s'",
1659                                                                    PQgetvalue(res, tuple, field));
1660                                                 break;
1661
1662                                         case BOOLOID:
1663                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1664                                                         archprintf(fout, "true");
1665                                                 else
1666                                                         archprintf(fout, "false");
1667                                                 break;
1668
1669                                         default:
1670                                                 /* All other types are printed as string literals. */
1671                                                 resetPQExpBuffer(q);
1672                                                 appendStringLiteralAH(q,
1673                                                                                           PQgetvalue(res, tuple, field),
1674                                                                                           fout);
1675                                                 archputs(q->data, fout);
1676                                                 break;
1677                                 }
1678                         }
1679                         archprintf(fout, ");\n");
1680                 }
1681
1682                 if (PQntuples(res) <= 0)
1683                 {
1684                         PQclear(res);
1685                         break;
1686                 }
1687                 PQclear(res);
1688         }
1689
1690         archprintf(fout, "\n\n");
1691
1692         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1693
1694         destroyPQExpBuffer(q);
1695         return 1;
1696 }
1697
1698
1699 /*
1700  * dumpTableData -
1701  *        dump the contents of a single table
1702  *
1703  * Actually, this just makes an ArchiveEntry for the table contents.
1704  */
1705 static void
1706 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1707 {
1708         TableInfo  *tbinfo = tdinfo->tdtable;
1709         PQExpBuffer copyBuf = createPQExpBuffer();
1710         PQExpBuffer clistBuf = createPQExpBuffer();
1711         DataDumperPtr dumpFn;
1712         char       *copyStmt;
1713
1714         if (!dump_inserts)
1715         {
1716                 /* Dump/restore using COPY */
1717                 dumpFn = dumpTableData_copy;
1718                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1719                 appendPQExpBuffer(copyBuf, "COPY %s ",
1720                                                   fmtId(tbinfo->dobj.name));
1721                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1722                                                   fmtCopyColumnList(tbinfo, clistBuf),
1723                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1724                 copyStmt = copyBuf->data;
1725         }
1726         else
1727         {
1728                 /* Restore using INSERT */
1729                 dumpFn = dumpTableData_insert;
1730                 copyStmt = NULL;
1731         }
1732
1733         /*
1734          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1735          * dependency on its table as "special" and pass it to ArchiveEntry now.
1736          * See comments for BuildArchiveDependencies.
1737          */
1738         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1739                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1740                                  NULL, tbinfo->rolname,
1741                                  false, "TABLE DATA", SECTION_DATA,
1742                                  "", "", copyStmt,
1743                                  &(tbinfo->dobj.dumpId), 1,
1744                                  dumpFn, tdinfo);
1745
1746         destroyPQExpBuffer(copyBuf);
1747         destroyPQExpBuffer(clistBuf);
1748 }
1749
1750 /*
1751  * refreshMatViewData -
1752  *        load or refresh the contents of a single materialized view
1753  *
1754  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1755  * statement.
1756  */
1757 static void
1758 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1759 {
1760         TableInfo  *tbinfo = tdinfo->tdtable;
1761         PQExpBuffer q;
1762
1763         /* If the materialized view is not flagged as populated, skip this. */
1764         if (!tbinfo->relispopulated)
1765                 return;
1766
1767         q = createPQExpBuffer();
1768
1769         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1770                                           fmtId(tbinfo->dobj.name));
1771
1772         ArchiveEntry(fout,
1773                                  tdinfo->dobj.catId,    /* catalog ID */
1774                                  tdinfo->dobj.dumpId,   /* dump ID */
1775                                  tbinfo->dobj.name,             /* Name */
1776                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1777                                  NULL,                  /* Tablespace */
1778                                  tbinfo->rolname,               /* Owner */
1779                                  false,                 /* with oids */
1780                                  "MATERIALIZED VIEW DATA",              /* Desc */
1781                                  SECTION_POST_DATA,             /* Section */
1782                                  q->data,               /* Create */
1783                                  "",                    /* Del */
1784                                  NULL,                  /* Copy */
1785                                  tdinfo->dobj.dependencies,             /* Deps */
1786                                  tdinfo->dobj.nDeps,    /* # Deps */
1787                                  NULL,                  /* Dumper */
1788                                  NULL);                 /* Dumper Arg */
1789
1790         destroyPQExpBuffer(q);
1791 }
1792
1793 /*
1794  * getTableData -
1795  *        set up dumpable objects representing the contents of tables
1796  */
1797 static void
1798 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1799 {
1800         int                     i;
1801
1802         for (i = 0; i < numTables; i++)
1803         {
1804                 if (tblinfo[i].dobj.dump)
1805                         makeTableDataInfo(&(tblinfo[i]), oids);
1806         }
1807 }
1808
1809 /*
1810  * Make a dumpable object for the data of this specific table
1811  *
1812  * Note: we make a TableDataInfo if and only if we are going to dump the
1813  * table data; the "dump" flag in such objects isn't used.
1814  */
1815 static void
1816 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1817 {
1818         TableDataInfo *tdinfo;
1819
1820         /*
1821          * Nothing to do if we already decided to dump the table.  This will
1822          * happen for "config" tables.
1823          */
1824         if (tbinfo->dataObj != NULL)
1825                 return;
1826
1827         /* Skip VIEWs (no data to dump) */
1828         if (tbinfo->relkind == RELKIND_VIEW)
1829                 return;
1830         /* Skip FOREIGN TABLEs (no data to dump) */
1831         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1832                 return;
1833
1834         /* Don't dump data in unlogged tables, if so requested */
1835         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1836                 no_unlogged_table_data)
1837                 return;
1838
1839         /* Check that the data is not explicitly excluded */
1840         if (simple_oid_list_member(&tabledata_exclude_oids,
1841                                                            tbinfo->dobj.catId.oid))
1842                 return;
1843
1844         /* OK, let's dump it */
1845         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1846
1847         if (tbinfo->relkind == RELKIND_MATVIEW)
1848                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1849         else
1850                 tdinfo->dobj.objType = DO_TABLE_DATA;
1851
1852         /*
1853          * Note: use tableoid 0 so that this object won't be mistaken for
1854          * something that pg_depend entries apply to.
1855          */
1856         tdinfo->dobj.catId.tableoid = 0;
1857         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1858         AssignDumpId(&tdinfo->dobj);
1859         tdinfo->dobj.name = tbinfo->dobj.name;
1860         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1861         tdinfo->tdtable = tbinfo;
1862         tdinfo->oids = oids;
1863         tdinfo->filtercond = NULL;      /* might get set later */
1864         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1865
1866         tbinfo->dataObj = tdinfo;
1867 }
1868
1869 /*
1870  * The refresh for a materialized view must be dependent on the refresh for
1871  * any materialized view that this one is dependent on.
1872  *
1873  * This must be called after all the objects are created, but before they are
1874  * sorted.
1875  */
1876 static void
1877 buildMatViewRefreshDependencies(Archive *fout)
1878 {
1879         PQExpBuffer query;
1880         PGresult   *res;
1881         int                     ntups,
1882                                 i;
1883         int                     i_classid,
1884                                 i_objid,
1885                                 i_refobjid;
1886
1887         /* No Mat Views before 9.3. */
1888         if (fout->remoteVersion < 90300)
1889                 return;
1890
1891         /* Make sure we are in proper schema */
1892         selectSourceSchema(fout, "pg_catalog");
1893
1894         query = createPQExpBuffer();
1895
1896         appendPQExpBuffer(query, "with recursive w as "
1897                                           "( "
1898                                         "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
1899                                           "from pg_depend d1 "
1900                                           "join pg_class c1 on c1.oid = d1.objid "
1901                                           "and c1.relkind = 'm' "
1902                                           "join pg_rewrite r1 on r1.ev_class = d1.objid "
1903                                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
1904                                           "and d2.objid = r1.oid "
1905                                           "and d2.refobjid <> d1.objid "
1906                                           "join pg_class c2 on c2.oid = d2.refobjid "
1907                                           "and c2.relkind in ('m','v') "
1908                                           "where d1.classid = 'pg_class'::regclass "
1909                                           "union "
1910                                           "select w.objid, d3.refobjid, c3.relkind "
1911                                           "from w "
1912                                           "join pg_rewrite r3 on r3.ev_class = w.refobjid "
1913                                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
1914                                           "and d3.objid = r3.oid "
1915                                           "and d3.refobjid <> w.refobjid "
1916                                           "join pg_class c3 on c3.oid = d3.refobjid "
1917                                           "and c3.relkind in ('m','v') "
1918                                           ") "
1919                           "select 'pg_class'::regclass::oid as classid, objid, refobjid "
1920                                           "from w "
1921                                           "where refrelkind = 'm'");
1922
1923         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1924
1925         ntups = PQntuples(res);
1926
1927         i_classid = PQfnumber(res, "classid");
1928         i_objid = PQfnumber(res, "objid");
1929         i_refobjid = PQfnumber(res, "refobjid");
1930
1931         for (i = 0; i < ntups; i++)
1932         {
1933                 CatalogId       objId;
1934                 CatalogId       refobjId;
1935                 DumpableObject *dobj;
1936                 DumpableObject *refdobj;
1937                 TableInfo  *tbinfo;
1938                 TableInfo  *reftbinfo;
1939
1940                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1941                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1942                 refobjId.tableoid = objId.tableoid;
1943                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1944
1945                 dobj = findObjectByCatalogId(objId);
1946                 if (dobj == NULL)
1947                         continue;
1948
1949                 Assert(dobj->objType == DO_TABLE);
1950                 tbinfo = (TableInfo *) dobj;
1951                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1952                 dobj = (DumpableObject *) tbinfo->dataObj;
1953                 if (dobj == NULL)
1954                         continue;
1955                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1956
1957                 refdobj = findObjectByCatalogId(refobjId);
1958                 if (refdobj == NULL)
1959                         continue;
1960
1961                 Assert(refdobj->objType == DO_TABLE);
1962                 reftbinfo = (TableInfo *) refdobj;
1963                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
1964                 refdobj = (DumpableObject *) reftbinfo->dataObj;
1965                 if (refdobj == NULL)
1966                         continue;
1967                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
1968
1969                 addObjectDependency(dobj, refdobj->dumpId);
1970
1971                 if (!reftbinfo->relispopulated)
1972                         tbinfo->relispopulated = false;
1973         }
1974
1975         PQclear(res);
1976
1977         destroyPQExpBuffer(query);
1978 }
1979
1980 /*
1981  * getTableDataFKConstraints -
1982  *        add dump-order dependencies reflecting foreign key constraints
1983  *
1984  * This code is executed only in a data-only dump --- in schema+data dumps
1985  * we handle foreign key issues by not creating the FK constraints until
1986  * after the data is loaded.  In a data-only dump, however, we want to
1987  * order the table data objects in such a way that a table's referenced
1988  * tables are restored first.  (In the presence of circular references or
1989  * self-references this may be impossible; we'll detect and complain about
1990  * that during the dependency sorting step.)
1991  */
1992 static void
1993 getTableDataFKConstraints(void)
1994 {
1995         DumpableObject **dobjs;
1996         int                     numObjs;
1997         int                     i;
1998
1999         /* Search through all the dumpable objects for FK constraints */
2000         getDumpableObjects(&dobjs, &numObjs);
2001         for (i = 0; i < numObjs; i++)
2002         {
2003                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2004                 {
2005                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2006                         TableInfo  *ftable;
2007
2008                         /* Not interesting unless both tables are to be dumped */
2009                         if (cinfo->contable == NULL ||
2010                                 cinfo->contable->dataObj == NULL)
2011                                 continue;
2012                         ftable = findTableByOid(cinfo->confrelid);
2013                         if (ftable == NULL ||
2014                                 ftable->dataObj == NULL)
2015                                 continue;
2016
2017                         /*
2018                          * Okay, make referencing table's TABLE_DATA object depend on the
2019                          * referenced table's TABLE_DATA object.
2020                          */
2021                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2022                                                                 ftable->dataObj->dobj.dumpId);
2023                 }
2024         }
2025         free(dobjs);
2026 }
2027
2028
2029 /*
2030  * guessConstraintInheritance:
2031  *      In pre-8.4 databases, we can't tell for certain which constraints
2032  *      are inherited.  We assume a CHECK constraint is inherited if its name
2033  *      matches the name of any constraint in the parent.  Originally this code
2034  *      tried to compare the expression texts, but that can fail for various
2035  *      reasons --- for example, if the parent and child tables are in different
2036  *      schemas, reverse-listing of function calls may produce different text
2037  *      (schema-qualified or not) depending on search path.
2038  *
2039  *      In 8.4 and up we can rely on the conislocal field to decide which
2040  *      constraints must be dumped; much safer.
2041  *
2042  *      This function assumes all conislocal flags were initialized to TRUE.
2043  *      It clears the flag on anything that seems to be inherited.
2044  */
2045 static void
2046 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2047 {
2048         int                     i,
2049                                 j,
2050                                 k;
2051
2052         for (i = 0; i < numTables; i++)
2053         {
2054                 TableInfo  *tbinfo = &(tblinfo[i]);
2055                 int                     numParents;
2056                 TableInfo **parents;
2057                 TableInfo  *parent;
2058
2059                 /* Sequences and views never have parents */
2060                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2061                         tbinfo->relkind == RELKIND_VIEW)
2062                         continue;
2063
2064                 /* Don't bother computing anything for non-target tables, either */
2065                 if (!tbinfo->dobj.dump)
2066                         continue;
2067
2068                 numParents = tbinfo->numParents;
2069                 parents = tbinfo->parents;
2070
2071                 if (numParents == 0)
2072                         continue;                       /* nothing to see here, move along */
2073
2074                 /* scan for inherited CHECK constraints */
2075                 for (j = 0; j < tbinfo->ncheck; j++)
2076                 {
2077                         ConstraintInfo *constr;
2078
2079                         constr = &(tbinfo->checkexprs[j]);
2080
2081                         for (k = 0; k < numParents; k++)
2082                         {
2083                                 int                     l;
2084
2085                                 parent = parents[k];
2086                                 for (l = 0; l < parent->ncheck; l++)
2087                                 {
2088                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2089
2090                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2091                                         {
2092                                                 constr->conislocal = false;
2093                                                 break;
2094                                         }
2095                                 }
2096                                 if (!constr->conislocal)
2097                                         break;
2098                         }
2099                 }
2100         }
2101 }
2102
2103
2104 /*
2105  * dumpDatabase:
2106  *      dump the database definition
2107  */
2108 static void
2109 dumpDatabase(Archive *fout)
2110 {
2111         PQExpBuffer dbQry = createPQExpBuffer();
2112         PQExpBuffer delQry = createPQExpBuffer();
2113         PQExpBuffer creaQry = createPQExpBuffer();
2114         PGconn     *conn = GetConnection(fout);
2115         PGresult   *res;
2116         int                     i_tableoid,
2117                                 i_oid,
2118                                 i_dba,
2119                                 i_encoding,
2120                                 i_collate,
2121                                 i_ctype,
2122                                 i_frozenxid,
2123                                 i_tablespace;
2124         CatalogId       dbCatId;
2125         DumpId          dbDumpId;
2126         const char *datname,
2127                            *dba,
2128                            *encoding,
2129                            *collate,
2130                            *ctype,
2131                            *tablespace;
2132         uint32          frozenxid;
2133
2134         datname = PQdb(conn);
2135
2136         if (g_verbose)
2137                 write_msg(NULL, "saving database definition\n");
2138
2139         /* Make sure we are in proper schema */
2140         selectSourceSchema(fout, "pg_catalog");
2141
2142         /* Get the database owner and parameters from pg_database */
2143         if (fout->remoteVersion >= 80400)
2144         {
2145                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2146                                                   "(%s datdba) AS dba, "
2147                                                   "pg_encoding_to_char(encoding) AS encoding, "
2148                                                   "datcollate, datctype, datfrozenxid, "
2149                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2150                                           "shobj_description(oid, 'pg_database') AS description "
2151
2152                                                   "FROM pg_database "
2153                                                   "WHERE datname = ",
2154                                                   username_subquery);
2155                 appendStringLiteralAH(dbQry, datname, fout);
2156         }
2157         else if (fout->remoteVersion >= 80200)
2158         {
2159                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2160                                                   "(%s datdba) AS dba, "
2161                                                   "pg_encoding_to_char(encoding) AS encoding, "
2162                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2163                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2164                                           "shobj_description(oid, 'pg_database') AS description "
2165
2166                                                   "FROM pg_database "
2167                                                   "WHERE datname = ",
2168                                                   username_subquery);
2169                 appendStringLiteralAH(dbQry, datname, fout);
2170         }
2171         else if (fout->remoteVersion >= 80000)
2172         {
2173                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2174                                                   "(%s datdba) AS dba, "
2175                                                   "pg_encoding_to_char(encoding) AS encoding, "
2176                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2177                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2178                                                   "FROM pg_database "
2179                                                   "WHERE datname = ",
2180                                                   username_subquery);
2181                 appendStringLiteralAH(dbQry, datname, fout);
2182         }
2183         else if (fout->remoteVersion >= 70100)
2184         {
2185                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2186                                                   "(%s datdba) AS dba, "
2187                                                   "pg_encoding_to_char(encoding) AS encoding, "
2188                                                   "NULL AS datcollate, NULL AS datctype, "
2189                                                   "0 AS datfrozenxid, "
2190                                                   "NULL AS tablespace "
2191                                                   "FROM pg_database "
2192                                                   "WHERE datname = ",
2193                                                   username_subquery);
2194                 appendStringLiteralAH(dbQry, datname, fout);
2195         }
2196         else
2197         {
2198                 appendPQExpBuffer(dbQry, "SELECT "
2199                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2200                                                   "oid, "
2201                                                   "(%s datdba) AS dba, "
2202                                                   "pg_encoding_to_char(encoding) AS encoding, "
2203                                                   "NULL AS datcollate, NULL AS datctype, "
2204                                                   "0 AS datfrozenxid, "
2205                                                   "NULL AS tablespace "
2206                                                   "FROM pg_database "
2207                                                   "WHERE datname = ",
2208                                                   username_subquery);
2209                 appendStringLiteralAH(dbQry, datname, fout);
2210         }
2211
2212         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2213
2214         i_tableoid = PQfnumber(res, "tableoid");
2215         i_oid = PQfnumber(res, "oid");
2216         i_dba = PQfnumber(res, "dba");
2217         i_encoding = PQfnumber(res, "encoding");
2218         i_collate = PQfnumber(res, "datcollate");
2219         i_ctype = PQfnumber(res, "datctype");
2220         i_frozenxid = PQfnumber(res, "datfrozenxid");
2221         i_tablespace = PQfnumber(res, "tablespace");
2222
2223         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2224         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2225         dba = PQgetvalue(res, 0, i_dba);
2226         encoding = PQgetvalue(res, 0, i_encoding);
2227         collate = PQgetvalue(res, 0, i_collate);
2228         ctype = PQgetvalue(res, 0, i_ctype);
2229         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2230         tablespace = PQgetvalue(res, 0, i_tablespace);
2231
2232         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2233                                           fmtId(datname));
2234         if (strlen(encoding) > 0)
2235         {
2236                 appendPQExpBuffer(creaQry, " ENCODING = ");
2237                 appendStringLiteralAH(creaQry, encoding, fout);
2238         }
2239         if (strlen(collate) > 0)
2240         {
2241                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
2242                 appendStringLiteralAH(creaQry, collate, fout);
2243         }
2244         if (strlen(ctype) > 0)
2245         {
2246                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
2247                 appendStringLiteralAH(creaQry, ctype, fout);
2248         }
2249         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2250                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2251                                                   fmtId(tablespace));
2252         appendPQExpBuffer(creaQry, ";\n");
2253
2254         if (binary_upgrade)
2255         {
2256                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2257                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2258                                                   "SET datfrozenxid = '%u'\n"
2259                                                   "WHERE        datname = ",
2260                                                   frozenxid);
2261                 appendStringLiteralAH(creaQry, datname, fout);
2262                 appendPQExpBuffer(creaQry, ";\n");
2263
2264         }
2265
2266         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2267                                           fmtId(datname));
2268
2269         dbDumpId = createDumpId();
2270
2271         ArchiveEntry(fout,
2272                                  dbCatId,               /* catalog ID */
2273                                  dbDumpId,              /* dump ID */
2274                                  datname,               /* Name */
2275                                  NULL,                  /* Namespace */
2276                                  NULL,                  /* Tablespace */
2277                                  dba,                   /* Owner */
2278                                  false,                 /* with oids */
2279                                  "DATABASE",    /* Desc */
2280                                  SECTION_PRE_DATA,              /* Section */
2281                                  creaQry->data, /* Create */
2282                                  delQry->data,  /* Del */
2283                                  NULL,                  /* Copy */
2284                                  NULL,                  /* Deps */
2285                                  0,                             /* # Deps */
2286                                  NULL,                  /* Dumper */
2287                                  NULL);                 /* Dumper Arg */
2288
2289         /*
2290          * pg_largeobject and pg_largeobject_metadata come from the old system
2291          * intact, so set their relfrozenxids.
2292          */
2293         if (binary_upgrade)
2294         {
2295                 PGresult   *lo_res;
2296                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2297                 PQExpBuffer loOutQry = createPQExpBuffer();
2298                 int                     i_relfrozenxid;
2299
2300                 /*
2301                  * pg_largeobject
2302                  */
2303                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2304                                                   "FROM pg_catalog.pg_class\n"
2305                                                   "WHERE oid = %u;\n",
2306                                                   LargeObjectRelationId);
2307
2308                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2309
2310                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2311
2312                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2313                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2314                                                   "SET relfrozenxid = '%u'\n"
2315                                                   "WHERE oid = %u;\n",
2316                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2317                                                   LargeObjectRelationId);
2318                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2319                                          "pg_largeobject", NULL, NULL, "",
2320                                          false, "pg_largeobject", SECTION_PRE_DATA,
2321                                          loOutQry->data, "", NULL,
2322                                          NULL, 0,
2323                                          NULL, NULL);
2324
2325                 PQclear(lo_res);
2326
2327                 /*
2328                  * pg_largeobject_metadata
2329                  */
2330                 if (fout->remoteVersion >= 90000)
2331                 {
2332                         resetPQExpBuffer(loFrozenQry);
2333                         resetPQExpBuffer(loOutQry);
2334
2335                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2336                                                           "FROM pg_catalog.pg_class\n"
2337                                                           "WHERE oid = %u;\n",
2338                                                           LargeObjectMetadataRelationId);
2339
2340                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2341
2342                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2343
2344                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2345                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2346                                                           "SET relfrozenxid = '%u'\n"
2347                                                           "WHERE oid = %u;\n",
2348                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2349                                                           LargeObjectMetadataRelationId);
2350                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2351                                                  "pg_largeobject_metadata", NULL, NULL, "",
2352                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2353                                                  loOutQry->data, "", NULL,
2354                                                  NULL, 0,
2355                                                  NULL, NULL);
2356
2357                         PQclear(lo_res);
2358                 }
2359
2360                 destroyPQExpBuffer(loFrozenQry);
2361                 destroyPQExpBuffer(loOutQry);
2362         }
2363
2364         /* Dump DB comment if any */
2365         if (fout->remoteVersion >= 80200)
2366         {
2367                 /*
2368                  * 8.2 keeps comments on shared objects in a shared table, so we
2369                  * cannot use the dumpComment used for other database objects.
2370                  */
2371                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2372
2373                 if (comment && strlen(comment))
2374                 {
2375                         resetPQExpBuffer(dbQry);
2376
2377                         /*
2378                          * Generates warning when loaded into a differently-named
2379                          * database.
2380                          */
2381                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2382                         appendStringLiteralAH(dbQry, comment, fout);
2383                         appendPQExpBuffer(dbQry, ";\n");
2384
2385                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2386                                                  dba, false, "COMMENT", SECTION_NONE,
2387                                                  dbQry->data, "", NULL,
2388                                                  &dbDumpId, 1, NULL, NULL);
2389                 }
2390         }
2391         else
2392         {
2393                 resetPQExpBuffer(dbQry);
2394                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2395                 dumpComment(fout, dbQry->data, NULL, "",
2396                                         dbCatId, 0, dbDumpId);
2397         }
2398
2399         PQclear(res);
2400
2401         /* Dump shared security label. */
2402         if (!no_security_labels && fout->remoteVersion >= 90200)
2403         {
2404                 PQExpBuffer seclabelQry = createPQExpBuffer();
2405
2406                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2407                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2408                 resetPQExpBuffer(seclabelQry);
2409                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2410                 if (strlen(seclabelQry->data))
2411                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2412                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2413                                                  seclabelQry->data, "", NULL,
2414                                                  &dbDumpId, 1, NULL, NULL);
2415                 destroyPQExpBuffer(seclabelQry);
2416         }
2417
2418         destroyPQExpBuffer(dbQry);
2419         destroyPQExpBuffer(delQry);
2420         destroyPQExpBuffer(creaQry);
2421 }
2422
2423
2424 /*
2425  * dumpEncoding: put the correct encoding into the archive
2426  */
2427 static void
2428 dumpEncoding(Archive *AH)
2429 {
2430         const char *encname = pg_encoding_to_char(AH->encoding);
2431         PQExpBuffer qry = createPQExpBuffer();
2432
2433         if (g_verbose)
2434                 write_msg(NULL, "saving encoding = %s\n", encname);
2435
2436         appendPQExpBuffer(qry, "SET client_encoding = ");
2437         appendStringLiteralAH(qry, encname, AH);
2438         appendPQExpBuffer(qry, ";\n");
2439
2440         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2441                                  "ENCODING", NULL, NULL, "",
2442                                  false, "ENCODING", SECTION_PRE_DATA,
2443                                  qry->data, "", NULL,
2444                                  NULL, 0,
2445                                  NULL, NULL);
2446
2447         destroyPQExpBuffer(qry);
2448 }
2449
2450
2451 /*
2452  * dumpStdStrings: put the correct escape string behavior into the archive
2453  */
2454 static void
2455 dumpStdStrings(Archive *AH)
2456 {
2457         const char *stdstrings = AH->std_strings ? "on" : "off";
2458         PQExpBuffer qry = createPQExpBuffer();
2459
2460         if (g_verbose)
2461                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2462                                   stdstrings);
2463
2464         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2465                                           stdstrings);
2466
2467         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2468                                  "STDSTRINGS", NULL, NULL, "",
2469                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2470                                  qry->data, "", NULL,
2471                                  NULL, 0,
2472                                  NULL, NULL);
2473
2474         destroyPQExpBuffer(qry);
2475 }
2476
2477
2478 /*
2479  * getBlobs:
2480  *      Collect schema-level data about large objects
2481  */
2482 static void
2483 getBlobs(Archive *fout)
2484 {
2485         PQExpBuffer blobQry = createPQExpBuffer();
2486         BlobInfo   *binfo;
2487         DumpableObject *bdata;
2488         PGresult   *res;
2489         int                     ntups;
2490         int                     i;
2491
2492         /* Verbose message */
2493         if (g_verbose)
2494                 write_msg(NULL, "reading large objects\n");
2495
2496         /* Make sure we are in proper schema */
2497         selectSourceSchema(fout, "pg_catalog");
2498
2499         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2500         if (fout->remoteVersion >= 90000)
2501                 appendPQExpBuffer(blobQry,
2502                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2503                                                   " FROM pg_largeobject_metadata",
2504                                                   username_subquery);
2505         else if (fout->remoteVersion >= 70100)
2506                 appendPQExpBuffer(blobQry,
2507                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2508                                                   " FROM pg_largeobject");
2509         else
2510                 appendPQExpBuffer(blobQry,
2511                                                   "SELECT oid, NULL::oid, NULL::oid"
2512                                                   " FROM pg_class WHERE relkind = 'l'");
2513
2514         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2515
2516         ntups = PQntuples(res);
2517         if (ntups > 0)
2518         {
2519                 /*
2520                  * Each large object has its own BLOB archive entry.
2521                  */
2522                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2523
2524                 for (i = 0; i < ntups; i++)
2525                 {
2526                         binfo[i].dobj.objType = DO_BLOB;
2527                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2528                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2529                         AssignDumpId(&binfo[i].dobj);
2530
2531                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2532                         if (!PQgetisnull(res, i, 1))
2533                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2534                         else
2535                                 binfo[i].rolname = "";
2536                         if (!PQgetisnull(res, i, 2))
2537                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2538                         else
2539                                 binfo[i].blobacl = NULL;
2540                 }
2541
2542                 /*
2543                  * If we have any large objects, a "BLOBS" archive entry is needed.
2544                  * This is just a placeholder for sorting; it carries no data now.
2545                  */
2546                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2547                 bdata->objType = DO_BLOB_DATA;
2548                 bdata->catId = nilCatalogId;
2549                 AssignDumpId(bdata);
2550                 bdata->name = pg_strdup("BLOBS");
2551         }
2552
2553         PQclear(res);
2554         destroyPQExpBuffer(blobQry);
2555 }
2556
2557 /*
2558  * dumpBlob
2559  *
2560  * dump the definition (metadata) of the given large object
2561  */
2562 static void
2563 dumpBlob(Archive *fout, BlobInfo *binfo)
2564 {
2565         PQExpBuffer cquery = createPQExpBuffer();
2566         PQExpBuffer dquery = createPQExpBuffer();
2567
2568         appendPQExpBuffer(cquery,
2569                                           "SELECT pg_catalog.lo_create('%s');\n",
2570                                           binfo->dobj.name);
2571
2572         appendPQExpBuffer(dquery,
2573                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2574                                           binfo->dobj.name);
2575
2576         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2577                                  binfo->dobj.name,
2578                                  NULL, NULL,
2579                                  binfo->rolname, false,
2580                                  "BLOB", SECTION_PRE_DATA,
2581                                  cquery->data, dquery->data, NULL,
2582                                  NULL, 0,
2583                                  NULL, NULL);
2584
2585         /* set up tag for comment and/or ACL */
2586         resetPQExpBuffer(cquery);
2587         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2588
2589         /* Dump comment if any */
2590         dumpComment(fout, cquery->data,
2591                                 NULL, binfo->rolname,
2592                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2593
2594         /* Dump security label if any */
2595         dumpSecLabel(fout, cquery->data,
2596                                  NULL, binfo->rolname,
2597                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2598
2599         /* Dump ACL if any */
2600         if (binfo->blobacl)
2601                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2602                                 binfo->dobj.name, NULL, cquery->data,
2603                                 NULL, binfo->rolname, binfo->blobacl);
2604
2605         destroyPQExpBuffer(cquery);
2606         destroyPQExpBuffer(dquery);
2607 }
2608
2609 /*
2610  * dumpBlobs:
2611  *      dump the data contents of all large objects
2612  */
2613 static int
2614 dumpBlobs(Archive *fout, void *arg)
2615 {
2616         const char *blobQry;
2617         const char *blobFetchQry;
2618         PGconn     *conn = GetConnection(fout);
2619         PGresult   *res;
2620         char            buf[LOBBUFSIZE];
2621         int                     ntups;
2622         int                     i;
2623         int                     cnt;
2624
2625         if (g_verbose)
2626                 write_msg(NULL, "saving large objects\n");
2627
2628         /* Make sure we are in proper schema */
2629         selectSourceSchema(fout, "pg_catalog");
2630
2631         /*
2632          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2633          * the already-in-memory dumpable objects instead...
2634          */
2635         if (fout->remoteVersion >= 90000)
2636                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2637         else if (fout->remoteVersion >= 70100)
2638                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2639         else
2640                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2641
2642         ExecuteSqlStatement(fout, blobQry);
2643
2644         /* Command to fetch from cursor */
2645         blobFetchQry = "FETCH 1000 IN bloboid";
2646
2647         do
2648         {
2649                 /* Do a fetch */
2650                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2651
2652                 /* Process the tuples, if any */
2653                 ntups = PQntuples(res);
2654                 for (i = 0; i < ntups; i++)
2655                 {
2656                         Oid                     blobOid;
2657                         int                     loFd;
2658
2659                         blobOid = atooid(PQgetvalue(res, i, 0));
2660                         /* Open the BLOB */
2661                         loFd = lo_open(conn, blobOid, INV_READ);
2662                         if (loFd == -1)
2663                                 exit_horribly(NULL, "could not open large object %u: %s",
2664                                                           blobOid, PQerrorMessage(conn));
2665
2666                         StartBlob(fout, blobOid);
2667
2668                         /* Now read it in chunks, sending data to archive */
2669                         do
2670                         {
2671                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2672                                 if (cnt < 0)
2673                                         exit_horribly(NULL, "error reading large object %u: %s",
2674                                                                   blobOid, PQerrorMessage(conn));
2675
2676                                 WriteData(fout, buf, cnt);
2677                         } while (cnt > 0);
2678
2679                         lo_close(conn, loFd);
2680
2681                         EndBlob(fout, blobOid);
2682                 }
2683
2684                 PQclear(res);
2685         } while (ntups > 0);
2686
2687         return 1;
2688 }
2689
2690 static void
2691 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2692                                                                                  PQExpBuffer upgrade_buffer,
2693                                                                                  Oid pg_type_oid)
2694 {
2695         PQExpBuffer upgrade_query = createPQExpBuffer();
2696         PGresult   *upgrade_res;
2697         Oid                     pg_type_array_oid;
2698
2699         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2700         appendPQExpBuffer(upgrade_buffer,
2701          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2702                                           pg_type_oid);
2703
2704         /* we only support old >= 8.3 for binary upgrades */
2705         appendPQExpBuffer(upgrade_query,
2706                                           "SELECT typarray "
2707                                           "FROM pg_catalog.pg_type "
2708                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2709                                           pg_type_oid);
2710
2711         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2712
2713         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2714
2715         if (OidIsValid(pg_type_array_oid))
2716         {
2717                 appendPQExpBuffer(upgrade_buffer,
2718                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2719                 appendPQExpBuffer(upgrade_buffer,
2720                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2721                                                   pg_type_array_oid);
2722         }
2723
2724         PQclear(upgrade_res);
2725         destroyPQExpBuffer(upgrade_query);
2726 }
2727
2728 static bool
2729 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2730                                                                                 PQExpBuffer upgrade_buffer,
2731                                                                                 Oid pg_rel_oid)
2732 {
2733         PQExpBuffer upgrade_query = createPQExpBuffer();
2734         PGresult   *upgrade_res;
2735         Oid                     pg_type_oid;
2736         bool            toast_set = false;
2737
2738         /* we only support old >= 8.3 for binary upgrades */
2739         appendPQExpBuffer(upgrade_query,
2740                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2741                                           "FROM pg_catalog.pg_class c "
2742                                           "LEFT JOIN pg_catalog.pg_class t ON "
2743                                           "  (c.reltoastrelid = t.oid) "
2744                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2745                                           pg_rel_oid);
2746
2747         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2748
2749         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2750
2751         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2752                                                                                          pg_type_oid);
2753
2754         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2755         {
2756                 /* Toast tables do not have pg_type array rows */
2757                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2758                                                                                         PQfnumber(upgrade_res, "trel")));
2759
2760                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2761                 appendPQExpBuffer(upgrade_buffer,
2762                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2763                                                   pg_type_toast_oid);
2764
2765                 toast_set = true;
2766         }
2767
2768         PQclear(upgrade_res);
2769         destroyPQExpBuffer(upgrade_query);
2770
2771         return toast_set;
2772 }
2773
2774 static void
2775 binary_upgrade_set_pg_class_oids(Archive *fout,
2776                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2777                                                                  bool is_index)
2778 {
2779         PQExpBuffer upgrade_query = createPQExpBuffer();
2780         PGresult   *upgrade_res;
2781         Oid                     pg_class_reltoastrelid;
2782         Oid                     pg_index_indexrelid;
2783
2784         appendPQExpBuffer(upgrade_query,
2785                                           "SELECT c.reltoastrelid, i.indexrelid "
2786                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2787                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
2788                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2789                                           pg_class_oid);
2790
2791         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2792
2793         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2794         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
2795
2796         appendPQExpBuffer(upgrade_buffer,
2797                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2798
2799         if (!is_index)
2800         {
2801                 appendPQExpBuffer(upgrade_buffer,
2802                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2803                                                   pg_class_oid);
2804                 /* only tables have toast tables, not indexes */
2805                 if (OidIsValid(pg_class_reltoastrelid))
2806                 {
2807                         /*
2808                          * One complexity is that the table definition might not require
2809                          * the creation of a TOAST table, and the TOAST table might have
2810                          * been created long after table creation, when the table was
2811                          * loaded with wide data.  By setting the TOAST oid we force
2812                          * creation of the TOAST heap and TOAST index by the backend so we
2813                          * can cleanly copy the files during binary upgrade.
2814                          */
2815
2816                         appendPQExpBuffer(upgrade_buffer,
2817                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2818                                                           pg_class_reltoastrelid);
2819
2820                         /* every toast table has an index */
2821                         appendPQExpBuffer(upgrade_buffer,
2822                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2823                                                           pg_index_indexrelid);
2824                 }
2825         }
2826         else
2827                 appendPQExpBuffer(upgrade_buffer,
2828                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2829                                                   pg_class_oid);
2830
2831         appendPQExpBuffer(upgrade_buffer, "\n");
2832
2833         PQclear(upgrade_res);
2834         destroyPQExpBuffer(upgrade_query);
2835 }
2836
2837 /*
2838  * If the DumpableObject is a member of an extension, add a suitable
2839  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2840  */
2841 static void
2842 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2843                                                                 DumpableObject *dobj,
2844                                                                 const char *objlabel)
2845 {
2846         DumpableObject *extobj = NULL;
2847         int                     i;
2848
2849         if (!dobj->ext_member)
2850                 return;
2851
2852         /*
2853          * Find the parent extension.  We could avoid this search if we wanted to
2854          * add a link field to DumpableObject, but the space costs of that would
2855          * be considerable.  We assume that member objects could only have a
2856          * direct dependency on their own extension, not any others.
2857          */
2858         for (i = 0; i < dobj->nDeps; i++)
2859         {
2860                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2861                 if (extobj && extobj->objType == DO_EXTENSION)
2862                         break;
2863                 extobj = NULL;
2864         }
2865         if (extobj == NULL)
2866                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2867
2868         appendPQExpBuffer(upgrade_buffer,
2869           "\n-- For binary upgrade, handle extension membership the hard way\n");
2870         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2871                                           fmtId(extobj->name),
2872                                           objlabel);
2873 }
2874
2875 /*
2876  * getNamespaces:
2877  *        read all namespaces in the system catalogs and return them in the
2878  * NamespaceInfo* structure
2879  *
2880  *      numNamespaces is set to the number of namespaces read in
2881  */
2882 NamespaceInfo *
2883 getNamespaces(Archive *fout, int *numNamespaces)
2884 {
2885         PGresult   *res;
2886         int                     ntups;
2887         int                     i;
2888         PQExpBuffer query;
2889         NamespaceInfo *nsinfo;
2890         int                     i_tableoid;
2891         int                     i_oid;
2892         int                     i_nspname;
2893         int                     i_rolname;
2894         int                     i_nspacl;
2895
2896         /*
2897          * Before 7.3, there are no real namespaces; create two dummy entries, one
2898          * for user stuff and one for system stuff.
2899          */
2900         if (fout->remoteVersion < 70300)
2901         {
2902                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2903
2904                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2905                 nsinfo[0].dobj.catId.tableoid = 0;
2906                 nsinfo[0].dobj.catId.oid = 0;
2907                 AssignDumpId(&nsinfo[0].dobj);
2908                 nsinfo[0].dobj.name = pg_strdup("public");
2909                 nsinfo[0].rolname = pg_strdup("");
2910                 nsinfo[0].nspacl = pg_strdup("");
2911
2912                 selectDumpableNamespace(&nsinfo[0]);
2913
2914                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2915                 nsinfo[1].dobj.catId.tableoid = 0;
2916                 nsinfo[1].dobj.catId.oid = 1;
2917                 AssignDumpId(&nsinfo[1].dobj);
2918                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2919                 nsinfo[1].rolname = pg_strdup("");
2920                 nsinfo[1].nspacl = pg_strdup("");
2921
2922                 selectDumpableNamespace(&nsinfo[1]);
2923
2924                 *numNamespaces = 2;
2925
2926                 return nsinfo;
2927         }
2928
2929         query = createPQExpBuffer();
2930
2931         /* Make sure we are in proper schema */
2932         selectSourceSchema(fout, "pg_catalog");
2933
2934         /*
2935          * we fetch all namespaces including system ones, so that every object we
2936          * read in can be linked to a containing namespace.
2937          */
2938         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2939                                           "(%s nspowner) AS rolname, "
2940                                           "nspacl FROM pg_namespace",
2941                                           username_subquery);
2942
2943         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2944
2945         ntups = PQntuples(res);
2946
2947         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2948
2949         i_tableoid = PQfnumber(res, "tableoid");
2950         i_oid = PQfnumber(res, "oid");
2951         i_nspname = PQfnumber(res, "nspname");
2952         i_rolname = PQfnumber(res, "rolname");
2953         i_nspacl = PQfnumber(res, "nspacl");
2954
2955         for (i = 0; i < ntups; i++)
2956         {
2957                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2958                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2959                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2960                 AssignDumpId(&nsinfo[i].dobj);
2961                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2962                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2963                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2964
2965                 /* Decide whether to dump this namespace */
2966                 selectDumpableNamespace(&nsinfo[i]);
2967
2968                 if (strlen(nsinfo[i].rolname) == 0)
2969                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2970                                           nsinfo[i].dobj.name);
2971         }
2972
2973         PQclear(res);
2974         destroyPQExpBuffer(query);
2975
2976         *numNamespaces = ntups;
2977
2978         return nsinfo;
2979 }
2980
2981 /*
2982  * findNamespace:
2983  *              given a namespace OID and an object OID, look up the info read by
2984  *              getNamespaces
2985  *
2986  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2987  * a system object or not.      In 7.3 and later there is no guessing, and we
2988  * don't use objoid at all.
2989  */
2990 static NamespaceInfo *
2991 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2992 {
2993         NamespaceInfo *nsinfo;
2994
2995         if (fout->remoteVersion >= 70300)
2996         {
2997                 nsinfo = findNamespaceByOid(nsoid);
2998         }
2999         else
3000         {
3001                 /* This code depends on the dummy objects set up by getNamespaces. */
3002                 Oid                     i;
3003
3004                 if (objoid > g_last_builtin_oid)
3005                         i = 0;                          /* user object */
3006                 else
3007                         i = 1;                          /* system object */
3008                 nsinfo = findNamespaceByOid(i);
3009         }
3010
3011         if (nsinfo == NULL)
3012                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3013
3014         return nsinfo;
3015 }
3016
3017 /*
3018  * getExtensions:
3019  *        read all extensions in the system catalogs and return them in the
3020  * ExtensionInfo* structure
3021  *
3022  *      numExtensions is set to the number of extensions read in
3023  */
3024 ExtensionInfo *
3025 getExtensions(Archive *fout, int *numExtensions)
3026 {
3027         PGresult   *res;
3028         int                     ntups;
3029         int                     i;
3030         PQExpBuffer query;
3031         ExtensionInfo *extinfo;
3032         int                     i_tableoid;
3033         int                     i_oid;
3034         int                     i_extname;
3035         int                     i_nspname;
3036         int                     i_extrelocatable;
3037         int                     i_extversion;
3038         int                     i_extconfig;
3039         int                     i_extcondition;
3040
3041         /*
3042          * Before 9.1, there are no extensions.
3043          */
3044         if (fout->remoteVersion < 90100)
3045         {
3046                 *numExtensions = 0;
3047                 return NULL;
3048         }
3049
3050         query = createPQExpBuffer();
3051
3052         /* Make sure we are in proper schema */
3053         selectSourceSchema(fout, "pg_catalog");
3054
3055         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
3056                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3057                                           "FROM pg_extension x "
3058                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
3059
3060         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3061
3062         ntups = PQntuples(res);
3063
3064         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3065
3066         i_tableoid = PQfnumber(res, "tableoid");
3067         i_oid = PQfnumber(res, "oid");
3068         i_extname = PQfnumber(res, "extname");
3069         i_nspname = PQfnumber(res, "nspname");
3070         i_extrelocatable = PQfnumber(res, "extrelocatable");
3071         i_extversion = PQfnumber(res, "extversion");
3072         i_extconfig = PQfnumber(res, "extconfig");
3073         i_extcondition = PQfnumber(res, "extcondition");
3074
3075         for (i = 0; i < ntups; i++)
3076         {
3077                 extinfo[i].dobj.objType = DO_EXTENSION;
3078                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3079                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3080                 AssignDumpId(&extinfo[i].dobj);
3081                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3082                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3083                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3084                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3085                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3086                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3087
3088                 /* Decide whether we want to dump it */
3089                 selectDumpableExtension(&(extinfo[i]));
3090         }
3091
3092         PQclear(res);
3093         destroyPQExpBuffer(query);
3094
3095         *numExtensions = ntups;
3096
3097         return extinfo;
3098 }
3099
3100 /*
3101  * getTypes:
3102  *        read all types in the system catalogs and return them in the
3103  * TypeInfo* structure
3104  *
3105  *      numTypes is set to the number of types read in
3106  *
3107  * NB: this must run after getFuncs() because we assume we can do
3108  * findFuncByOid().
3109  */
3110 TypeInfo *
3111 getTypes(Archive *fout, int *numTypes)
3112 {
3113         PGresult   *res;
3114         int                     ntups;
3115         int                     i;
3116         PQExpBuffer query = createPQExpBuffer();
3117         TypeInfo   *tyinfo;
3118         ShellTypeInfo *stinfo;
3119         int                     i_tableoid;
3120         int                     i_oid;
3121         int                     i_typname;
3122         int                     i_typnamespace;
3123         int                     i_typacl;
3124         int                     i_rolname;
3125         int                     i_typinput;
3126         int                     i_typoutput;
3127         int                     i_typelem;
3128         int                     i_typrelid;
3129         int                     i_typrelkind;
3130         int                     i_typtype;
3131         int                     i_typisdefined;
3132         int                     i_isarray;
3133
3134         /*
3135          * we include even the built-in types because those may be used as array
3136          * elements by user-defined types
3137          *
3138          * we filter out the built-in types when we dump out the types
3139          *
3140          * same approach for undefined (shell) types and array types
3141          *
3142          * Note: as of 8.3 we can reliably detect whether a type is an
3143          * auto-generated array type by checking the element type's typarray.
3144          * (Before that the test is capable of generating false positives.) We
3145          * still check for name beginning with '_', though, so as to avoid the
3146          * cost of the subselect probe for all standard types.  This would have to
3147          * be revisited if the backend ever allows renaming of array types.
3148          */
3149
3150         /* Make sure we are in proper schema */
3151         selectSourceSchema(fout, "pg_catalog");
3152
3153         if (fout->remoteVersion >= 90200)
3154         {
3155                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3156                                                   "typnamespace, typacl, "
3157                                                   "(%s typowner) AS rolname, "
3158                                                   "typinput::oid AS typinput, "
3159                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3160                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3161                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3162                                                   "typtype, typisdefined, "
3163                                                   "typname[0] = '_' AND typelem != 0 AND "
3164                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3165                                                   "FROM pg_type",
3166                                                   username_subquery);
3167         }
3168         else if (fout->remoteVersion >= 80300)
3169         {
3170                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3171                                                   "typnamespace, '{=U}' AS typacl, "
3172                                                   "(%s typowner) AS rolname, "
3173                                                   "typinput::oid AS typinput, "
3174                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3175                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3176                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3177                                                   "typtype, typisdefined, "
3178                                                   "typname[0] = '_' AND typelem != 0 AND "
3179                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3180                                                   "FROM pg_type",
3181                                                   username_subquery);
3182         }
3183         else if (fout->remoteVersion >= 70300)
3184         {
3185                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3186                                                   "typnamespace, '{=U}' AS typacl, "
3187                                                   "(%s typowner) AS rolname, "
3188                                                   "typinput::oid AS typinput, "
3189                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3190                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3191                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3192                                                   "typtype, typisdefined, "
3193                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3194                                                   "FROM pg_type",
3195                                                   username_subquery);
3196         }
3197         else if (fout->remoteVersion >= 70100)
3198         {
3199                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3200                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3201                                                   "(%s typowner) AS rolname, "
3202                                                   "typinput::oid AS typinput, "
3203                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3204                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3205                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3206                                                   "typtype, typisdefined, "
3207                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3208                                                   "FROM pg_type",
3209                                                   username_subquery);
3210         }
3211         else
3212         {
3213                 appendPQExpBuffer(query, "SELECT "
3214                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3215                                                   "oid, typname, "
3216                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3217                                                   "(%s typowner) AS rolname, "
3218                                                   "typinput::oid AS typinput, "
3219                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3220                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3221                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3222                                                   "typtype, typisdefined, "
3223                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3224                                                   "FROM pg_type",
3225                                                   username_subquery);
3226         }
3227
3228         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3229
3230         ntups = PQntuples(res);
3231
3232         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3233
3234         i_tableoid = PQfnumber(res, "tableoid");
3235         i_oid = PQfnumber(res, "oid");
3236         i_typname = PQfnumber(res, "typname");
3237         i_typnamespace = PQfnumber(res, "typnamespace");
3238         i_typacl = PQfnumber(res, "typacl");
3239         i_rolname = PQfnumber(res, "rolname");
3240         i_typinput = PQfnumber(res, "typinput");
3241         i_typoutput = PQfnumber(res, "typoutput");
3242         i_typelem = PQfnumber(res, "typelem");
3243         i_typrelid = PQfnumber(res, "typrelid");
3244         i_typrelkind = PQfnumber(res, "typrelkind");
3245         i_typtype = PQfnumber(res, "typtype");
3246         i_typisdefined = PQfnumber(res, "typisdefined");
3247         i_isarray = PQfnumber(res, "isarray");
3248
3249         for (i = 0; i < ntups; i++)
3250         {
3251                 tyinfo[i].dobj.objType = DO_TYPE;
3252                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3253                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3254                 AssignDumpId(&tyinfo[i].dobj);
3255                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3256                 tyinfo[i].dobj.namespace =
3257                         findNamespace(fout,
3258                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3259                                                   tyinfo[i].dobj.catId.oid);
3260                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3261                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3262                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3263                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3264                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3265                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3266                 tyinfo[i].shellType = NULL;
3267
3268                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3269                         tyinfo[i].isDefined = true;
3270                 else
3271                         tyinfo[i].isDefined = false;
3272
3273                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3274                         tyinfo[i].isArray = true;
3275                 else
3276                         tyinfo[i].isArray = false;
3277
3278                 /* Decide whether we want to dump it */
3279                 selectDumpableType(&tyinfo[i]);
3280
3281                 /*
3282                  * If it's a domain, fetch info about its constraints, if any
3283                  */
3284                 tyinfo[i].nDomChecks = 0;
3285                 tyinfo[i].domChecks = NULL;
3286                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3287                         getDomainConstraints(fout, &(tyinfo[i]));
3288
3289                 /*
3290                  * If it's a base type, make a DumpableObject representing a shell
3291                  * definition of the type.      We will need to dump that ahead of the I/O
3292                  * functions for the type.      Similarly, range types need a shell
3293                  * definition in case they have a canonicalize function.
3294                  *
3295                  * Note: the shell type doesn't have a catId.  You might think it
3296                  * should copy the base type's catId, but then it might capture the
3297                  * pg_depend entries for the type, which we don't want.
3298                  */
3299                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3300                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3301                 {
3302                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3303                         stinfo->dobj.objType = DO_SHELL_TYPE;
3304                         stinfo->dobj.catId = nilCatalogId;
3305                         AssignDumpId(&stinfo->dobj);
3306                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3307                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3308                         stinfo->baseType = &(tyinfo[i]);
3309                         tyinfo[i].shellType = stinfo;
3310
3311                         /*
3312                          * Initially mark the shell type as not to be dumped.  We'll only
3313                          * dump it if the I/O or canonicalize functions need to be dumped;
3314                          * this is taken care of while sorting dependencies.
3315                          */
3316                         stinfo->dobj.dump = false;
3317
3318                         /*
3319                          * However, if dumping from pre-7.3, there will be no dependency
3320                          * info so we have to fake it here.  We only need to worry about
3321                          * typinput and typoutput since the other functions only exist
3322                          * post-7.3.
3323                          */
3324                         if (fout->remoteVersion < 70300)
3325                         {
3326                                 Oid                     typinput;
3327                                 Oid                     typoutput;
3328                                 FuncInfo   *funcInfo;
3329
3330                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3331                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3332
3333                                 funcInfo = findFuncByOid(typinput);
3334                                 if (funcInfo && funcInfo->dobj.dump)
3335                                 {
3336                                         /* base type depends on function */
3337                                         addObjectDependency(&tyinfo[i].dobj,
3338                                                                                 funcInfo->dobj.dumpId);
3339                                         /* function depends on shell type */
3340                                         addObjectDependency(&funcInfo->dobj,
3341                                                                                 stinfo->dobj.dumpId);
3342                                         /* mark shell type as to be dumped */
3343                                         stinfo->dobj.dump = true;
3344                                 }
3345
3346                                 funcInfo = findFuncByOid(typoutput);
3347                                 if (funcInfo && funcInfo->dobj.dump)
3348                                 {
3349                                         /* base type depends on function */
3350                                         addObjectDependency(&tyinfo[i].dobj,
3351                                                                                 funcInfo->dobj.dumpId);
3352                                         /* function depends on shell type */
3353                                         addObjectDependency(&funcInfo->dobj,
3354                                                                                 stinfo->dobj.dumpId);
3355                                         /* mark shell type as to be dumped */
3356                                         stinfo->dobj.dump = true;
3357                                 }
3358                         }
3359                 }
3360
3361                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3362                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3363                                           tyinfo[i].dobj.name);
3364         }
3365
3366         *numTypes = ntups;
3367
3368         PQclear(res);
3369
3370         destroyPQExpBuffer(query);
3371
3372         return tyinfo;
3373 }
3374
3375 /*
3376  * getOperators:
3377  *        read all operators in the system catalogs and return them in the
3378  * OprInfo* structure
3379  *
3380  *      numOprs is set to the number of operators read in
3381  */
3382 OprInfo *
3383 getOperators(Archive *fout, int *numOprs)
3384 {
3385         PGresult   *res;
3386         int                     ntups;
3387         int                     i;
3388         PQExpBuffer query = createPQExpBuffer();
3389         OprInfo    *oprinfo;
3390         int                     i_tableoid;
3391         int                     i_oid;
3392         int                     i_oprname;
3393         int                     i_oprnamespace;
3394         int                     i_rolname;
3395         int                     i_oprkind;
3396         int                     i_oprcode;
3397
3398         /*
3399          * find all operators, including builtin operators; we filter out
3400          * system-defined operators at dump-out time.
3401          */
3402
3403         /* Make sure we are in proper schema */
3404         selectSourceSchema(fout, "pg_catalog");
3405
3406         if (fout->remoteVersion >= 70300)
3407         {
3408                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3409                                                   "oprnamespace, "
3410                                                   "(%s oprowner) AS rolname, "
3411                                                   "oprkind, "
3412                                                   "oprcode::oid AS oprcode "
3413                                                   "FROM pg_operator",
3414                                                   username_subquery);
3415         }
3416         else if (fout->remoteVersion >= 70100)
3417         {
3418                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3419                                                   "0::oid AS oprnamespace, "
3420                                                   "(%s oprowner) AS rolname, "
3421                                                   "oprkind, "
3422                                                   "oprcode::oid AS oprcode "
3423                                                   "FROM pg_operator",
3424                                                   username_subquery);
3425         }
3426         else
3427         {
3428                 appendPQExpBuffer(query, "SELECT "
3429                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3430                                                   "oid, oprname, "
3431                                                   "0::oid AS oprnamespace, "
3432                                                   "(%s oprowner) AS rolname, "
3433                                                   "oprkind, "
3434                                                   "oprcode::oid AS oprcode "
3435                                                   "FROM pg_operator",
3436                                                   username_subquery);
3437         }
3438
3439         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3440
3441         ntups = PQntuples(res);
3442         *numOprs = ntups;
3443
3444         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3445
3446         i_tableoid = PQfnumber(res, "tableoid");
3447         i_oid = PQfnumber(res, "oid");
3448         i_oprname = PQfnumber(res, "oprname");
3449         i_oprnamespace = PQfnumber(res, "oprnamespace");
3450         i_rolname = PQfnumber(res, "rolname");
3451         i_oprkind = PQfnumber(res, "oprkind");
3452         i_oprcode = PQfnumber(res, "oprcode");
3453
3454         for (i = 0; i < ntups; i++)
3455         {
3456                 oprinfo[i].dobj.objType = DO_OPERATOR;
3457                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3458                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3459                 AssignDumpId(&oprinfo[i].dobj);
3460                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3461                 oprinfo[i].dobj.namespace =
3462                         findNamespace(fout,
3463                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3464                                                   oprinfo[i].dobj.catId.oid);
3465                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3466                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3467                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3468
3469                 /* Decide whether we want to dump it */
3470                 selectDumpableObject(&(oprinfo[i].dobj));
3471
3472                 if (strlen(oprinfo[i].rolname) == 0)
3473                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3474                                           oprinfo[i].dobj.name);
3475         }
3476
3477         PQclear(res);
3478
3479         destroyPQExpBuffer(query);
3480
3481         return oprinfo;
3482 }
3483
3484 /*
3485  * getCollations:
3486  *        read all collations in the system catalogs and return them in the
3487  * CollInfo* structure
3488  *
3489  *      numCollations is set to the number of collations read in
3490  */
3491 CollInfo *
3492 getCollations(Archive *fout, int *numCollations)
3493 {
3494         PGresult   *res;
3495         int                     ntups;
3496         int                     i;
3497         PQExpBuffer query;
3498         CollInfo   *collinfo;
3499         int                     i_tableoid;
3500         int                     i_oid;
3501         int                     i_collname;
3502         int                     i_collnamespace;
3503         int                     i_rolname;
3504
3505         /* Collations didn't exist pre-9.1 */
3506         if (fout->remoteVersion < 90100)
3507         {
3508                 *numCollations = 0;
3509                 return NULL;
3510         }
3511
3512         query = createPQExpBuffer();
3513
3514         /*
3515          * find all collations, including builtin collations; we filter out
3516          * system-defined collations at dump-out time.
3517          */
3518
3519         /* Make sure we are in proper schema */
3520         selectSourceSchema(fout, "pg_catalog");
3521
3522         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3523                                           "collnamespace, "
3524                                           "(%s collowner) AS rolname "
3525                                           "FROM pg_collation",
3526                                           username_subquery);
3527
3528         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3529
3530         ntups = PQntuples(res);
3531         *numCollations = ntups;
3532
3533         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3534
3535         i_tableoid = PQfnumber(res, "tableoid");
3536         i_oid = PQfnumber(res, "oid");
3537         i_collname = PQfnumber(res, "collname");
3538         i_collnamespace = PQfnumber(res, "collnamespace");
3539         i_rolname = PQfnumber(res, "rolname");
3540
3541         for (i = 0; i < ntups; i++)
3542         {
3543                 collinfo[i].dobj.objType = DO_COLLATION;
3544                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3545                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3546                 AssignDumpId(&collinfo[i].dobj);
3547                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3548                 collinfo[i].dobj.namespace =
3549                         findNamespace(fout,
3550                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3551                                                   collinfo[i].dobj.catId.oid);
3552                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3553
3554                 /* Decide whether we want to dump it */
3555                 selectDumpableObject(&(collinfo[i].dobj));
3556         }
3557
3558         PQclear(res);
3559
3560         destroyPQExpBuffer(query);
3561
3562         return collinfo;
3563 }
3564
3565 /*
3566  * getConversions:
3567  *        read all conversions in the system catalogs and return them in the
3568  * ConvInfo* structure
3569  *
3570  *      numConversions is set to the number of conversions read in
3571  */
3572 ConvInfo *
3573 getConversions(Archive *fout, int *numConversions)
3574 {
3575         PGresult   *res;
3576         int                     ntups;
3577         int                     i;
3578         PQExpBuffer query = createPQExpBuffer();
3579         ConvInfo   *convinfo;
3580         int                     i_tableoid;
3581         int                     i_oid;
3582         int                     i_conname;
3583         int                     i_connamespace;
3584         int                     i_rolname;
3585
3586         /* Conversions didn't exist pre-7.3 */
3587         if (fout->remoteVersion < 70300)
3588         {
3589                 *numConversions = 0;
3590                 return NULL;
3591         }
3592
3593         /*
3594          * find all conversions, including builtin conversions; we filter out
3595          * system-defined conversions at dump-out time.
3596          */
3597
3598         /* Make sure we are in proper schema */
3599         selectSourceSchema(fout, "pg_catalog");
3600
3601         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3602                                           "connamespace, "
3603                                           "(%s conowner) AS rolname "
3604                                           "FROM pg_conversion",
3605                                           username_subquery);
3606
3607         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3608
3609         ntups = PQntuples(res);
3610         *numConversions = ntups;
3611
3612         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3613
3614         i_tableoid = PQfnumber(res, "tableoid");
3615         i_oid = PQfnumber(res, "oid");
3616         i_conname = PQfnumber(res, "conname");
3617         i_connamespace = PQfnumber(res, "connamespace");
3618         i_rolname = PQfnumber(res, "rolname");
3619
3620         for (i = 0; i < ntups; i++)
3621         {
3622                 convinfo[i].dobj.objType = DO_CONVERSION;
3623                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3624                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3625                 AssignDumpId(&convinfo[i].dobj);
3626                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3627                 convinfo[i].dobj.namespace =
3628                         findNamespace(fout,
3629                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3630                                                   convinfo[i].dobj.catId.oid);
3631                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3632
3633                 /* Decide whether we want to dump it */
3634                 selectDumpableObject(&(convinfo[i].dobj));
3635         }
3636
3637         PQclear(res);
3638
3639         destroyPQExpBuffer(query);
3640
3641         return convinfo;
3642 }
3643
3644 /*
3645  * getOpclasses:
3646  *        read all opclasses in the system catalogs and return them in the
3647  * OpclassInfo* structure
3648  *
3649  *      numOpclasses is set to the number of opclasses read in
3650  */
3651 OpclassInfo *
3652 getOpclasses(Archive *fout, int *numOpclasses)
3653 {
3654         PGresult   *res;
3655         int                     ntups;
3656         int                     i;
3657         PQExpBuffer query = createPQExpBuffer();
3658         OpclassInfo *opcinfo;
3659         int                     i_tableoid;
3660         int                     i_oid;
3661         int                     i_opcname;
3662         int                     i_opcnamespace;
3663         int                     i_rolname;
3664
3665         /*
3666          * find all opclasses, including builtin opclasses; we filter out
3667          * system-defined opclasses at dump-out time.
3668          */
3669
3670         /* Make sure we are in proper schema */
3671         selectSourceSchema(fout, "pg_catalog");
3672
3673         if (fout->remoteVersion >= 70300)
3674         {
3675                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3676                                                   "opcnamespace, "
3677                                                   "(%s opcowner) AS rolname "
3678                                                   "FROM pg_opclass",
3679                                                   username_subquery);
3680         }
3681         else if (fout->remoteVersion >= 70100)
3682         {
3683                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3684                                                   "0::oid AS opcnamespace, "
3685                                                   "''::name AS rolname "
3686                                                   "FROM pg_opclass");
3687         }
3688         else
3689         {
3690                 appendPQExpBuffer(query, "SELECT "
3691                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3692                                                   "oid, opcname, "
3693                                                   "0::oid AS opcnamespace, "
3694                                                   "''::name AS rolname "
3695                                                   "FROM pg_opclass");
3696         }
3697
3698         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3699
3700         ntups = PQntuples(res);
3701         *numOpclasses = ntups;
3702
3703         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3704
3705         i_tableoid = PQfnumber(res, "tableoid");
3706         i_oid = PQfnumber(res, "oid");
3707         i_opcname = PQfnumber(res, "opcname");
3708         i_opcnamespace = PQfnumber(res, "opcnamespace");
3709         i_rolname = PQfnumber(res, "rolname");
3710
3711         for (i = 0; i < ntups; i++)
3712         {
3713                 opcinfo[i].dobj.objType = DO_OPCLASS;
3714                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3715                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3716                 AssignDumpId(&opcinfo[i].dobj);
3717                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3718                 opcinfo[i].dobj.namespace =
3719                         findNamespace(fout,
3720                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3721                                                   opcinfo[i].dobj.catId.oid);
3722                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3723
3724                 /* Decide whether we want to dump it */
3725                 selectDumpableObject(&(opcinfo[i].dobj));
3726
3727                 if (fout->remoteVersion >= 70300)
3728                 {
3729                         if (strlen(opcinfo[i].rolname) == 0)
3730                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3731                                                   opcinfo[i].dobj.name);
3732                 }
3733         }
3734
3735         PQclear(res);
3736
3737         destroyPQExpBuffer(query);
3738
3739         return opcinfo;
3740 }
3741
3742 /*
3743  * getOpfamilies:
3744  *        read all opfamilies in the system catalogs and return them in the
3745  * OpfamilyInfo* structure
3746  *
3747  *      numOpfamilies is set to the number of opfamilies read in
3748  */
3749 OpfamilyInfo *
3750 getOpfamilies(Archive *fout, int *numOpfamilies)
3751 {
3752         PGresult   *res;
3753         int                     ntups;
3754         int                     i;
3755         PQExpBuffer query;
3756         OpfamilyInfo *opfinfo;
3757         int                     i_tableoid;
3758         int                     i_oid;
3759         int                     i_opfname;
3760         int                     i_opfnamespace;
3761         int                     i_rolname;
3762
3763         /* Before 8.3, there is no separate concept of opfamilies */
3764         if (fout->remoteVersion < 80300)
3765         {
3766                 *numOpfamilies = 0;
3767                 return NULL;
3768         }
3769
3770         query = createPQExpBuffer();
3771
3772         /*
3773          * find all opfamilies, including builtin opfamilies; we filter out
3774          * system-defined opfamilies at dump-out time.
3775          */
3776
3777         /* Make sure we are in proper schema */
3778         selectSourceSchema(fout, "pg_catalog");
3779
3780         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3781                                           "opfnamespace, "
3782                                           "(%s opfowner) AS rolname "
3783                                           "FROM pg_opfamily",
3784                                           username_subquery);
3785
3786         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3787
3788         ntups = PQntuples(res);
3789         *numOpfamilies = ntups;
3790
3791         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3792
3793         i_tableoid = PQfnumber(res, "tableoid");
3794         i_oid = PQfnumber(res, "oid");
3795         i_opfname = PQfnumber(res, "opfname");
3796         i_opfnamespace = PQfnumber(res, "opfnamespace");
3797         i_rolname = PQfnumber(res, "rolname");
3798
3799         for (i = 0; i < ntups; i++)
3800         {
3801                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3802                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3803                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3804                 AssignDumpId(&opfinfo[i].dobj);
3805                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3806                 opfinfo[i].dobj.namespace =
3807                         findNamespace(fout,
3808                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3809                                                   opfinfo[i].dobj.catId.oid);
3810                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3811
3812                 /* Decide whether we want to dump it */
3813                 selectDumpableObject(&(opfinfo[i].dobj));
3814
3815                 if (fout->remoteVersion >= 70300)
3816                 {
3817                         if (strlen(opfinfo[i].rolname) == 0)
3818                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3819                                                   opfinfo[i].dobj.name);
3820                 }
3821         }
3822
3823         PQclear(res);
3824
3825         destroyPQExpBuffer(query);
3826
3827         return opfinfo;
3828 }
3829
3830 /*
3831  * getAggregates:
3832  *        read all the user-defined aggregates in the system catalogs and
3833  * return them in the AggInfo* structure
3834  *
3835  * numAggs is set to the number of aggregates read in
3836  */
3837 AggInfo *
3838 getAggregates(Archive *fout, int *numAggs)
3839 {
3840         PGresult   *res;
3841         int                     ntups;
3842         int                     i;
3843         PQExpBuffer query = createPQExpBuffer();
3844         AggInfo    *agginfo;
3845         int                     i_tableoid;
3846         int                     i_oid;
3847         int                     i_aggname;
3848         int                     i_aggnamespace;
3849         int                     i_pronargs;
3850         int                     i_proargtypes;
3851         int                     i_rolname;
3852         int                     i_aggacl;
3853         int                     i_proiargs;
3854
3855         /* Make sure we are in proper schema */
3856         selectSourceSchema(fout, "pg_catalog");
3857
3858         /*
3859          * Find all user-defined aggregates.  See comment in getFuncs() for the
3860          * rationale behind the filtering logic.
3861          */
3862
3863         if (fout->remoteVersion >= 80400)
3864         {
3865                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3866                                                   "pronamespace AS aggnamespace, "
3867                                                   "pronargs, proargtypes, "
3868                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3869                                                   "(%s proowner) AS rolname, "
3870                                                   "proacl AS aggacl "
3871                                                   "FROM pg_proc p "
3872                                                   "WHERE proisagg AND ("
3873                                                   "pronamespace != "
3874                                                   "(SELECT oid FROM pg_namespace "
3875                                                   "WHERE nspname = 'pg_catalog')",
3876                                                   username_subquery);
3877                 if (binary_upgrade && fout->remoteVersion >= 90100)
3878                         appendPQExpBuffer(query,
3879                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3880                                                           "classid = 'pg_proc'::regclass AND "
3881                                                           "objid = p.oid AND "
3882                                                           "refclassid = 'pg_extension'::regclass AND "
3883                                                           "deptype = 'e')");
3884                 appendPQExpBuffer(query, ")");
3885         }
3886         else if (fout->remoteVersion >= 80200)
3887         {
3888                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3889                                                   "pronamespace AS aggnamespace, "
3890                                                   "pronargs, proargtypes, "
3891                                                   "NULL::text AS proiargs,"
3892                                                   "(%s proowner) AS rolname, "
3893                                                   "proacl AS aggacl "
3894                                                   "FROM pg_proc p "
3895                                                   "WHERE proisagg AND ("
3896                                                   "pronamespace != "
3897                                                   "(SELECT oid FROM pg_namespace "
3898                                                   "WHERE nspname = 'pg_catalog'))",
3899                                                   username_subquery);
3900         }
3901         else if (fout->remoteVersion >= 70300)
3902         {
3903                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3904                                                   "pronamespace AS aggnamespace, "
3905                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3906                                                   "proargtypes, "
3907                                                   "NULL::text AS proiargs, "
3908                                                   "(%s proowner) AS rolname, "
3909                                                   "proacl AS aggacl "
3910                                                   "FROM pg_proc "
3911                                                   "WHERE proisagg "
3912                                                   "AND pronamespace != "
3913                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3914                                                   username_subquery);
3915         }
3916         else if (fout->remoteVersion >= 70100)
3917         {
3918                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3919                                                   "0::oid AS aggnamespace, "
3920                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3921                                                   "aggbasetype AS proargtypes, "
3922                                                   "NULL::text AS proiargs, "
3923                                                   "(%s aggowner) AS rolname, "
3924                                                   "'{=X}' AS aggacl "
3925                                                   "FROM pg_aggregate "
3926                                                   "where oid > '%u'::oid",
3927                                                   username_subquery,
3928                                                   g_last_builtin_oid);
3929         }
3930         else
3931         {
3932                 appendPQExpBuffer(query, "SELECT "
3933                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3934                                                   "oid, aggname, "
3935                                                   "0::oid AS aggnamespace, "
3936                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3937                                                   "aggbasetype AS proargtypes, "
3938                                                   "NULL::text AS proiargs, "
3939                                                   "(%s aggowner) AS rolname, "
3940                                                   "'{=X}' AS aggacl "
3941                                                   "FROM pg_aggregate "
3942                                                   "where oid > '%u'::oid",
3943                                                   username_subquery,
3944                                                   g_last_builtin_oid);
3945         }
3946
3947         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3948
3949         ntups = PQntuples(res);
3950         *numAggs = ntups;
3951
3952         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3953
3954         i_tableoid = PQfnumber(res, "tableoid");
3955         i_oid = PQfnumber(res, "oid");
3956         i_aggname = PQfnumber(res, "aggname");
3957         i_aggnamespace = PQfnumber(res, "aggnamespace");
3958         i_pronargs = PQfnumber(res, "pronargs");
3959         i_proargtypes = PQfnumber(res, "proargtypes");
3960         i_rolname = PQfnumber(res, "rolname");
3961         i_aggacl = PQfnumber(res, "aggacl");
3962         i_proiargs = PQfnumber(res, "proiargs");
3963
3964         for (i = 0; i < ntups; i++)
3965         {
3966                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3967                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3968                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3969                 AssignDumpId(&agginfo[i].aggfn.dobj);
3970                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3971                 agginfo[i].aggfn.dobj.namespace =
3972                         findNamespace(fout,
3973                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3974                                                   agginfo[i].aggfn.dobj.catId.oid);
3975                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3976                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3977                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3978                                           agginfo[i].aggfn.dobj.name);
3979                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3980                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3981                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3982                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
3983                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3984                 if (agginfo[i].aggfn.nargs == 0)
3985                         agginfo[i].aggfn.argtypes = NULL;
3986                 else
3987                 {
3988                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3989                         if (fout->remoteVersion >= 70300)
3990                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3991                                                           agginfo[i].aggfn.argtypes,
3992                                                           agginfo[i].aggfn.nargs);
3993                         else
3994                                 /* it's just aggbasetype */
3995                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3996                 }
3997
3998                 /* Decide whether we want to dump it */
3999                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
4000         }
4001
4002         PQclear(res);
4003
4004         destroyPQExpBuffer(query);
4005
4006         return agginfo;
4007 }
4008
4009 /*
4010  * getFuncs:
4011  *        read all the user-defined functions in the system catalogs and
4012  * return them in the FuncInfo* structure
4013  *
4014  * numFuncs is set to the number of functions read in
4015  */
4016 FuncInfo *
4017 getFuncs(Archive *fout, int *numFuncs)
4018 {
4019         PGresult   *res;
4020         int                     ntups;
4021         int                     i;
4022         PQExpBuffer query = createPQExpBuffer();
4023         FuncInfo   *finfo;
4024         int                     i_tableoid;
4025         int                     i_oid;
4026         int                     i_proname;
4027         int                     i_pronamespace;
4028         int                     i_rolname;
4029         int                     i_prolang;
4030         int                     i_pronargs;
4031         int                     i_proargtypes;
4032         int                     i_prorettype;
4033         int                     i_proacl;
4034         int                     i_proiargs;
4035
4036         /* Make sure we are in proper schema */
4037         selectSourceSchema(fout, "pg_catalog");
4038
4039         /*
4040          * Find all user-defined functions.  Normally we can exclude functions in
4041          * pg_catalog, which is worth doing since there are several thousand of
4042          * 'em.  However, there are some extensions that create functions in
4043          * pg_catalog.  In normal dumps we can still ignore those --- but in
4044          * binary-upgrade mode, we must dump the member objects of the extension,
4045          * so be sure to fetch any such functions.
4046          *
4047          * Also, in 9.2 and up, exclude functions that are internally dependent on
4048          * something else, since presumably those will be created as a result of
4049          * creating the something else.  This currently only acts to suppress
4050          * constructor functions for range types.  Note that this is OK only
4051          * because the constructors don't have any dependencies the range type
4052          * doesn't have; otherwise we might not get creation ordering correct.
4053          */
4054
4055         if (fout->remoteVersion >= 80400)
4056         {
4057                 appendPQExpBuffer(query,
4058                                                   "SELECT tableoid, oid, proname, prolang, "
4059                                                   "pronargs, proargtypes, prorettype, proacl, "
4060                                                   "pronamespace, "
4061                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4062                                                   "(%s proowner) AS rolname "
4063                                                   "FROM pg_proc p "
4064                                                   "WHERE NOT proisagg AND ("
4065                                                   "pronamespace != "
4066                                                   "(SELECT oid FROM pg_namespace "
4067                                                   "WHERE nspname = 'pg_catalog')",
4068                                                   username_subquery);
4069                 if (fout->remoteVersion >= 90200)
4070                         appendPQExpBuffer(query,
4071                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4072                                                           "WHERE classid = 'pg_proc'::regclass AND "
4073                                                           "objid = p.oid AND deptype = 'i')");
4074                 if (binary_upgrade && fout->remoteVersion >= 90100)
4075                         appendPQExpBuffer(query,
4076                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4077                                                           "classid = 'pg_proc'::regclass AND "
4078                                                           "objid = p.oid AND "
4079                                                           "refclassid = 'pg_extension'::regclass AND "
4080                                                           "deptype = 'e')");
4081                 appendPQExpBuffer(query, ")");
4082         }
4083         else if (fout->remoteVersion >= 70300)
4084         {
4085                 appendPQExpBuffer(query,
4086                                                   "SELECT tableoid, oid, proname, prolang, "
4087                                                   "pronargs, proargtypes, prorettype, proacl, "
4088                                                   "pronamespace, "
4089                                                   "NULL::text AS proiargs,"
4090                                                   "(%s proowner) AS rolname "
4091                                                   "FROM pg_proc p "
4092                                                   "WHERE NOT proisagg AND ("
4093                                                   "pronamespace != "
4094                                                   "(SELECT oid FROM pg_namespace "
4095                                                   "WHERE nspname = 'pg_catalog'))",
4096                                                   username_subquery);
4097         }
4098         else if (fout->remoteVersion >= 70100)
4099         {
4100                 appendPQExpBuffer(query,
4101                                                   "SELECT tableoid, oid, proname, prolang, "
4102                                                   "pronargs, proargtypes, prorettype, "
4103                                                   "'{=X}' AS proacl, "
4104                                                   "0::oid AS pronamespace, "
4105                                                   "NULL::text AS proiargs,"
4106                                                   "(%s proowner) AS rolname "
4107                                                   "FROM pg_proc "
4108                                                   "WHERE pg_proc.oid > '%u'::oid",
4109                                                   username_subquery,
4110                                                   g_last_builtin_oid);
4111         }
4112         else
4113         {
4114                 appendPQExpBuffer(query,
4115                                                   "SELECT "
4116                                                   "(SELECT oid FROM pg_class "
4117                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4118                                                   "oid, proname, prolang, "
4119                                                   "pronargs, proargtypes, prorettype, "
4120                                                   "'{=X}' AS proacl, "
4121                                                   "0::oid AS pronamespace, "
4122                                                   "NULL::text AS proiargs,"
4123                                                   "(%s proowner) AS rolname "
4124                                                   "FROM pg_proc "
4125                                                   "where pg_proc.oid > '%u'::oid",
4126                                                   username_subquery,
4127                                                   g_last_builtin_oid);
4128         }
4129
4130         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4131
4132         ntups = PQntuples(res);
4133
4134         *numFuncs = ntups;
4135
4136         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4137
4138         i_tableoid = PQfnumber(res, "tableoid");
4139         i_oid = PQfnumber(res, "oid");
4140         i_proname = PQfnumber(res, "proname");
4141         i_pronamespace = PQfnumber(res, "pronamespace");
4142         i_rolname = PQfnumber(res, "rolname");
4143         i_prolang = PQfnumber(res, "prolang");
4144         i_pronargs = PQfnumber(res, "pronargs");
4145         i_proargtypes = PQfnumber(res, "proargtypes");
4146         i_prorettype = PQfnumber(res, "prorettype");
4147         i_proacl = PQfnumber(res, "proacl");
4148         i_proiargs = PQfnumber(res, "proiargs");
4149
4150         for (i = 0; i < ntups; i++)
4151         {
4152                 finfo[i].dobj.objType = DO_FUNC;
4153                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4154                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4155                 AssignDumpId(&finfo[i].dobj);
4156                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4157                 finfo[i].dobj.namespace =
4158                         findNamespace(fout,
4159                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4160                                                   finfo[i].dobj.catId.oid);
4161                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4162                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4163                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4164                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4165                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4166                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4167                 if (finfo[i].nargs == 0)
4168                         finfo[i].argtypes = NULL;
4169                 else
4170                 {
4171                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4172                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4173                                                   finfo[i].argtypes, finfo[i].nargs);
4174                 }
4175
4176                 /* Decide whether we want to dump it */
4177                 selectDumpableObject(&(finfo[i].dobj));
4178
4179                 if (strlen(finfo[i].rolname) == 0)
4180                         write_msg(NULL,
4181                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4182                                           finfo[i].dobj.name);
4183         }
4184
4185         PQclear(res);
4186
4187         destroyPQExpBuffer(query);
4188
4189         return finfo;
4190 }
4191
4192 /*
4193  * getTables
4194  *        read all the user-defined tables (no indexes, no catalogs)
4195  * in the system catalogs return them in the TableInfo* structure
4196  *
4197  * numTables is set to the number of tables read in
4198  */
4199 TableInfo *
4200 getTables(Archive *fout, int *numTables)
4201 {
4202         PGresult   *res;
4203         int                     ntups;
4204         int                     i;
4205         PQExpBuffer query = createPQExpBuffer();
4206         TableInfo  *tblinfo;
4207         int                     i_reltableoid;
4208         int                     i_reloid;
4209         int                     i_relname;
4210         int                     i_relnamespace;
4211         int                     i_relkind;
4212         int                     i_relacl;
4213         int                     i_rolname;
4214         int                     i_relchecks;
4215         int                     i_relhastriggers;
4216         int                     i_relhasindex;
4217         int                     i_relhasrules;
4218         int                     i_relhasoids;
4219         int                     i_relfrozenxid;
4220         int                     i_toastoid;
4221         int                     i_toastfrozenxid;
4222         int                     i_relpersistence;
4223         int                     i_relispopulated;
4224         int                     i_owning_tab;
4225         int                     i_owning_col;
4226         int                     i_reltablespace;
4227         int                     i_reloptions;
4228         int                     i_checkoption;
4229         int                     i_toastreloptions;
4230         int                     i_reloftype;
4231         int                     i_relpages;
4232
4233         /* Make sure we are in proper schema */
4234         selectSourceSchema(fout, "pg_catalog");
4235
4236         /*
4237          * Find all the tables and table-like objects.
4238          *
4239          * We include system catalogs, so that we can work if a user table is
4240          * defined to inherit from a system catalog (pretty weird, but...)
4241          *
4242          * We ignore relations that are not ordinary tables, sequences, views,
4243          * materialized views, composite types, or foreign tables.
4244          *
4245          * Composite-type table entries won't be dumped as such, but we have to
4246          * make a DumpableObject for them so that we can track dependencies of the
4247          * composite type (pg_depend entries for columns of the composite type
4248          * link to the pg_class entry not the pg_type entry).
4249          *
4250          * Note: in this phase we should collect only a minimal amount of
4251          * information about each table, basically just enough to decide if it is
4252          * interesting. We must fetch all tables in this phase because otherwise
4253          * we cannot correctly identify inherited columns, owned sequences, etc.
4254          */
4255
4256         if (fout->remoteVersion >= 90300)
4257         {
4258                 /*
4259                  * Left join to pick up dependency info linking sequences to their
4260                  * owning column, if any (note this dependency is AUTO as of 8.2)
4261                  */
4262                 appendPQExpBuffer(query,
4263                                                   "SELECT c.tableoid, c.oid, c.relname, "
4264                                                   "c.relacl, c.relkind, c.relnamespace, "
4265                                                   "(%s c.relowner) AS rolname, "
4266                                                   "c.relchecks, c.relhastriggers, "
4267                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4268                                                   "c.relfrozenxid, tc.oid AS toid, "
4269                                                   "tc.relfrozenxid AS tfrozenxid, "
4270                                                   "c.relpersistence, c.relispopulated, "
4271                                                   "c.relpages, "
4272                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4273                                                   "d.refobjid AS owning_tab, "
4274                                                   "d.refobjsubid AS owning_col, "
4275                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4276                                                 "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4277                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4278                                                            "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4279                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4280                                                   "FROM pg_class c "
4281                                                   "LEFT JOIN pg_depend d ON "
4282                                                   "(c.relkind = '%c' AND "
4283                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4284                                                   "d.objsubid = 0 AND "
4285                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4286                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4287                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4288                                                   "ORDER BY c.oid",
4289                                                   username_subquery,
4290                                                   RELKIND_SEQUENCE,
4291                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4292                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4293                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4294         }
4295         else if (fout->remoteVersion >= 90100)
4296         {
4297                 /*
4298                  * Left join to pick up dependency info linking sequences to their
4299                  * owning column, if any (note this dependency is AUTO as of 8.2)
4300                  */
4301                 appendPQExpBuffer(query,
4302                                                   "SELECT c.tableoid, c.oid, c.relname, "
4303                                                   "c.relacl, c.relkind, c.relnamespace, "
4304                                                   "(%s c.relowner) AS rolname, "
4305                                                   "c.relchecks, c.relhastriggers, "
4306                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4307                                                   "c.relfrozenxid, tc.oid AS toid, "
4308                                                   "tc.relfrozenxid AS tfrozenxid, "
4309                                                   "c.relpersistence, 't' as relispopulated, "
4310                                                   "c.relpages, "
4311                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4312                                                   "d.refobjid AS owning_tab, "
4313                                                   "d.refobjsubid AS owning_col, "
4314                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4315                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4316                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4317                                                   "FROM pg_class c "
4318                                                   "LEFT JOIN pg_depend d ON "
4319                                                   "(c.relkind = '%c' AND "
4320                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4321                                                   "d.objsubid = 0 AND "
4322                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4323                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4324                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4325                                                   "ORDER BY c.oid",
4326                                                   username_subquery,
4327                                                   RELKIND_SEQUENCE,
4328                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4329                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4330                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4331         }
4332         else if (fout->remoteVersion >= 90000)
4333         {
4334                 /*
4335                  * Left join to pick up dependency info linking sequences to their
4336                  * owning column, if any (note this dependency is AUTO as of 8.2)
4337                  */
4338                 appendPQExpBuffer(query,
4339                                                   "SELECT c.tableoid, c.oid, c.relname, "
4340                                                   "c.relacl, c.relkind, c.relnamespace, "
4341                                                   "(%s c.relowner) AS rolname, "
4342                                                   "c.relchecks, c.relhastriggers, "
4343                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4344                                                   "c.relfrozenxid, tc.oid AS toid, "
4345                                                   "tc.relfrozenxid AS tfrozenxid, "
4346                                                   "'p' AS relpersistence, 't' as relispopulated, "
4347                                                   "c.relpages, "
4348                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4349                                                   "d.refobjid AS owning_tab, "
4350                                                   "d.refobjsubid AS owning_col, "
4351                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4352                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4353                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4354                                                   "FROM pg_class c "
4355                                                   "LEFT JOIN pg_depend d ON "
4356                                                   "(c.relkind = '%c' AND "
4357                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4358                                                   "d.objsubid = 0 AND "
4359                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4360                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4361                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4362                                                   "ORDER BY c.oid",
4363                                                   username_subquery,
4364                                                   RELKIND_SEQUENCE,
4365                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4366                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4367         }
4368         else if (fout->remoteVersion >= 80400)
4369         {
4370                 /*
4371                  * Left join to pick up dependency info linking sequences to their
4372                  * owning column, if any (note this dependency is AUTO as of 8.2)
4373                  */
4374                 appendPQExpBuffer(query,
4375                                                   "SELECT c.tableoid, c.oid, c.relname, "
4376                                                   "c.relacl, c.relkind, c.relnamespace, "
4377                                                   "(%s c.relowner) AS rolname, "
4378                                                   "c.relchecks, c.relhastriggers, "
4379                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4380                                                   "c.relfrozenxid, tc.oid AS toid, "
4381                                                   "tc.relfrozenxid AS tfrozenxid, "
4382                                                   "'p' AS relpersistence, 't' as relispopulated, "
4383                                                   "c.relpages, "
4384                                                   "NULL AS reloftype, "
4385                                                   "d.refobjid AS owning_tab, "
4386                                                   "d.refobjsubid AS owning_col, "
4387                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4388                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4389                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4390                                                   "FROM pg_class c "
4391                                                   "LEFT JOIN pg_depend d ON "
4392                                                   "(c.relkind = '%c' AND "
4393                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4394                                                   "d.objsubid = 0 AND "
4395                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4396                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4397                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4398                                                   "ORDER BY c.oid",
4399                                                   username_subquery,
4400                                                   RELKIND_SEQUENCE,
4401                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4402                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4403         }
4404         else if (fout->remoteVersion >= 80200)
4405         {
4406                 /*
4407                  * Left join to pick up dependency info linking sequences to their
4408                  * owning column, if any (note this dependency is AUTO as of 8.2)
4409                  */
4410                 appendPQExpBuffer(query,
4411                                                   "SELECT c.tableoid, c.oid, c.relname, "
4412                                                   "c.relacl, c.relkind, c.relnamespace, "
4413                                                   "(%s c.relowner) AS rolname, "
4414                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4415                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4416                                                   "c.relfrozenxid, tc.oid AS toid, "
4417                                                   "tc.relfrozenxid AS tfrozenxid, "
4418                                                   "'p' AS relpersistence, 't' as relispopulated, "
4419                                                   "c.relpages, "
4420                                                   "NULL AS reloftype, "
4421                                                   "d.refobjid AS owning_tab, "
4422                                                   "d.refobjsubid AS owning_col, "
4423                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4424                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4425                                                   "NULL AS toast_reloptions "
4426                                                   "FROM pg_class c "
4427                                                   "LEFT JOIN pg_depend d ON "
4428                                                   "(c.relkind = '%c' AND "
4429                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4430                                                   "d.objsubid = 0 AND "
4431                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4432                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4433                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4434                                                   "ORDER BY c.oid",
4435                                                   username_subquery,
4436                                                   RELKIND_SEQUENCE,
4437                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4438                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4439         }
4440         else if (fout->remoteVersion >= 80000)
4441         {
4442                 /*
4443                  * Left join to pick up dependency info linking sequences to their
4444                  * owning column, if any
4445                  */
4446                 appendPQExpBuffer(query,
4447                                                   "SELECT c.tableoid, c.oid, relname, "
4448                                                   "relacl, relkind, relnamespace, "
4449                                                   "(%s relowner) AS rolname, "
4450                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4451                                                   "relhasindex, relhasrules, relhasoids, "
4452                                                   "0 AS relfrozenxid, "
4453                                                   "0 AS toid, "
4454                                                   "0 AS tfrozenxid, "
4455                                                   "'p' AS relpersistence, 't' as relispopulated, "
4456                                                   "relpages, "
4457                                                   "NULL AS reloftype, "
4458                                                   "d.refobjid AS owning_tab, "
4459                                                   "d.refobjsubid AS owning_col, "
4460                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4461                                                   "NULL AS reloptions, "
4462                                                   "NULL AS toast_reloptions "
4463                                                   "FROM pg_class c "
4464                                                   "LEFT JOIN pg_depend d ON "
4465                                                   "(c.relkind = '%c' AND "
4466                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4467                                                   "d.objsubid = 0 AND "
4468                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4469                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4470                                                   "ORDER BY c.oid",
4471                                                   username_subquery,
4472                                                   RELKIND_SEQUENCE,
4473                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4474                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4475         }
4476         else if (fout->remoteVersion >= 70300)
4477         {
4478                 /*
4479                  * Left join to pick up dependency info linking sequences to their
4480                  * owning column, if any
4481                  */
4482                 appendPQExpBuffer(query,
4483                                                   "SELECT c.tableoid, c.oid, relname, "
4484                                                   "relacl, relkind, relnamespace, "
4485                                                   "(%s relowner) AS rolname, "
4486                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4487                                                   "relhasindex, relhasrules, relhasoids, "
4488                                                   "0 AS relfrozenxid, "
4489                                                   "0 AS toid, "
4490                                                   "0 AS tfrozenxid, "
4491                                                   "'p' AS relpersistence, 't' as relispopulated, "
4492                                                   "relpages, "
4493                                                   "NULL AS reloftype, "
4494                                                   "d.refobjid AS owning_tab, "
4495                                                   "d.refobjsubid AS owning_col, "
4496                                                   "NULL AS reltablespace, "
4497                                                   "NULL AS reloptions, "
4498                                                   "NULL AS toast_reloptions "
4499                                                   "FROM pg_class c "
4500                                                   "LEFT JOIN pg_depend d ON "
4501                                                   "(c.relkind = '%c' AND "
4502                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4503                                                   "d.objsubid = 0 AND "
4504                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4505                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4506                                                   "ORDER BY c.oid",
4507                                                   username_subquery,
4508                                                   RELKIND_SEQUENCE,
4509                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4510                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4511         }
4512         else if (fout->remoteVersion >= 70200)
4513         {
4514                 appendPQExpBuffer(query,
4515                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4516                                                   "0::oid AS relnamespace, "
4517                                                   "(%s relowner) AS rolname, "
4518                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4519                                                   "relhasindex, relhasrules, relhasoids, "
4520                                                   "0 AS relfrozenxid, "
4521                                                   "0 AS toid, "
4522                                                   "0 AS tfrozenxid, "
4523                                                   "'p' AS relpersistence, 't' as relispopulated, "
4524                                                   "relpages, "
4525                                                   "NULL AS reloftype, "
4526                                                   "NULL::oid AS owning_tab, "
4527                                                   "NULL::int4 AS owning_col, "
4528                                                   "NULL AS reltablespace, "
4529                                                   "NULL AS reloptions, "
4530                                                   "NULL AS toast_reloptions "
4531                                                   "FROM pg_class "
4532                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4533                                                   "ORDER BY oid",
4534                                                   username_subquery,
4535                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4536         }
4537         else if (fout->remoteVersion >= 70100)
4538         {
4539                 /* all tables have oids in 7.1 */
4540                 appendPQExpBuffer(query,
4541                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4542                                                   "0::oid AS relnamespace, "
4543                                                   "(%s relowner) AS rolname, "
4544                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4545                                                   "relhasindex, relhasrules, "
4546                                                   "'t'::bool AS relhasoids, "
4547                                                   "0 AS relfrozenxid, "
4548                                                   "0 AS toid, "
4549                                                   "0 AS tfrozenxid, "
4550                                                   "'p' AS relpersistence, 't' as relispopulated, "
4551                                                   "relpages, "
4552                                                   "NULL AS reloftype, "
4553                                                   "NULL::oid AS owning_tab, "
4554                                                   "NULL::int4 AS owning_col, "
4555                                                   "NULL AS reltablespace, "
4556                                                   "NULL AS reloptions, "
4557                                                   "NULL AS toast_reloptions "
4558                                                   "FROM pg_class "
4559                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4560                                                   "ORDER BY oid",
4561                                                   username_subquery,
4562                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4563         }
4564         else
4565         {
4566                 /*
4567                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4568                  * have a view by looking for a rule in pg_rewrite.
4569                  */
4570                 appendPQExpBuffer(query,
4571                                                   "SELECT "
4572                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4573                                                   "oid, relname, relacl, "
4574                                                   "CASE WHEN relhasrules and relkind = 'r' "
4575                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4576                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4577                                                   "THEN '%c'::\"char\" "
4578                                                   "ELSE relkind END AS relkind,"
4579                                                   "0::oid AS relnamespace, "
4580                                                   "(%s relowner) AS rolname, "
4581                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4582                                                   "relhasindex, relhasrules, "
4583                                                   "'t'::bool AS relhasoids, "
4584                                                   "0 as relfrozenxid, "
4585                                                   "0 AS toid, "
4586                                                   "0 AS tfrozenxid, "
4587                                                   "'p' AS relpersistence, 't' as relispopulated, "
4588                                                   "0 AS relpages, "
4589                                                   "NULL AS reloftype, "
4590                                                   "NULL::oid AS owning_tab, "
4591                                                   "NULL::int4 AS owning_col, "
4592                                                   "NULL AS reltablespace, "
4593                                                   "NULL AS reloptions, "
4594                                                   "NULL AS toast_reloptions "
4595                                                   "FROM pg_class c "
4596                                                   "WHERE relkind IN ('%c', '%c') "
4597                                                   "ORDER BY oid",
4598                                                   RELKIND_VIEW,
4599                                                   username_subquery,
4600                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4601         }
4602
4603         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4604
4605         ntups = PQntuples(res);
4606
4607         *numTables = ntups;
4608
4609         /*
4610          * Extract data from result and lock dumpable tables.  We do the locking
4611          * before anything else, to minimize the window wherein a table could
4612          * disappear under us.
4613          *
4614          * Note that we have to save info about all tables here, even when dumping
4615          * only one, because we don't yet know which tables might be inheritance
4616          * ancestors of the target table.
4617          */
4618         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4619
4620         i_reltableoid = PQfnumber(res, "tableoid");
4621         i_reloid = PQfnumber(res, "oid");
4622         i_relname = PQfnumber(res, "relname");
4623         i_relnamespace = PQfnumber(res, "relnamespace");
4624         i_relacl = PQfnumber(res, "relacl");
4625         i_relkind = PQfnumber(res, "relkind");
4626         i_rolname = PQfnumber(res, "rolname");
4627         i_relchecks = PQfnumber(res, "relchecks");
4628         i_relhastriggers = PQfnumber(res, "relhastriggers");
4629         i_relhasindex = PQfnumber(res, "relhasindex");
4630         i_relhasrules = PQfnumber(res, "relhasrules");
4631         i_relhasoids = PQfnumber(res, "relhasoids");
4632         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4633         i_toastoid = PQfnumber(res, "toid");
4634         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4635         i_relpersistence = PQfnumber(res, "relpersistence");
4636         i_relispopulated = PQfnumber(res, "relispopulated");
4637         i_relpages = PQfnumber(res, "relpages");
4638         i_owning_tab = PQfnumber(res, "owning_tab");
4639         i_owning_col = PQfnumber(res, "owning_col");
4640         i_reltablespace = PQfnumber(res, "reltablespace");
4641         i_reloptions = PQfnumber(res, "reloptions");
4642         i_checkoption = PQfnumber(res, "checkoption");
4643         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4644         i_reloftype = PQfnumber(res, "reloftype");
4645
4646         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4647         {
4648                 /*
4649                  * Arrange to fail instead of waiting forever for a table lock.
4650                  *
4651                  * NB: this coding assumes that the only queries issued within the
4652                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4653                  * applied to other things too.
4654                  */
4655                 resetPQExpBuffer(query);
4656                 appendPQExpBuffer(query, "SET statement_timeout = ");
4657                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4658                 ExecuteSqlStatement(fout, query->data);
4659         }
4660
4661         for (i = 0; i < ntups; i++)
4662         {
4663                 tblinfo[i].dobj.objType = DO_TABLE;
4664                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4665                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4666                 AssignDumpId(&tblinfo[i].dobj);
4667                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4668                 tblinfo[i].dobj.namespace =
4669                         findNamespace(fout,
4670                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4671                                                   tblinfo[i].dobj.catId.oid);
4672                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4673                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4674                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4675                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4676                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4677                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4678                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4679                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4680                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
4681                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4682                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4683                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4684                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4685                 if (PQgetisnull(res, i, i_reloftype))
4686                         tblinfo[i].reloftype = NULL;
4687                 else
4688                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4689                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4690                 if (PQgetisnull(res, i, i_owning_tab))
4691                 {
4692                         tblinfo[i].owning_tab = InvalidOid;
4693                         tblinfo[i].owning_col = 0;
4694                 }
4695                 else
4696                 {
4697                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4698                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4699                 }
4700                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4701                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4702                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
4703                         tblinfo[i].checkoption = NULL;
4704                 else
4705                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
4706                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4707
4708                 /* other fields were zeroed above */
4709
4710                 /*
4711                  * Decide whether we want to dump this table.
4712                  */
4713                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4714                         tblinfo[i].dobj.dump = false;
4715                 else
4716                         selectDumpableTable(&tblinfo[i]);
4717                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4718
4719                 /*
4720                  * Read-lock target tables to make sure they aren't DROPPED or altered
4721                  * in schema before we get around to dumping them.
4722                  *
4723                  * Note that we don't explicitly lock parents of the target tables; we
4724                  * assume our lock on the child is enough to prevent schema
4725                  * alterations to parent tables.
4726                  *
4727                  * NOTE: it'd be kinda nice to lock other relations too, not only
4728                  * plain tables, but the backend doesn't presently allow that.
4729                  */
4730                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4731                 {
4732                         resetPQExpBuffer(query);
4733                         appendPQExpBuffer(query,
4734                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4735                                                           fmtQualifiedId(fout->remoteVersion,
4736                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4737                                                                                          tblinfo[i].dobj.name));
4738                         ExecuteSqlStatement(fout, query->data);
4739                 }
4740
4741                 /* Emit notice if join for owner failed */
4742                 if (strlen(tblinfo[i].rolname) == 0)
4743                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4744                                           tblinfo[i].dobj.name);
4745         }
4746
4747         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4748         {
4749                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4750         }
4751
4752         PQclear(res);
4753
4754         destroyPQExpBuffer(query);
4755
4756         return tblinfo;
4757 }
4758
4759 /*
4760  * getOwnedSeqs
4761  *        identify owned sequences and mark them as dumpable if owning table is
4762  *
4763  * We used to do this in getTables(), but it's better to do it after the
4764  * index used by findTableByOid() has been set up.
4765  */
4766 void
4767 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4768 {
4769         int                     i;
4770
4771         /*
4772          * Force sequences that are "owned" by table columns to be dumped whenever
4773          * their owning table is being dumped.
4774          */
4775         for (i = 0; i < numTables; i++)
4776         {
4777                 TableInfo  *seqinfo = &tblinfo[i];
4778                 TableInfo  *owning_tab;
4779
4780                 if (!OidIsValid(seqinfo->owning_tab))
4781                         continue;                       /* not an owned sequence */
4782                 if (seqinfo->dobj.dump)
4783                         continue;                       /* no need to search */
4784                 owning_tab = findTableByOid(seqinfo->owning_tab);
4785                 if (owning_tab && owning_tab->dobj.dump)
4786                 {
4787                         seqinfo->interesting = true;
4788                         seqinfo->dobj.dump = true;
4789                 }
4790         }
4791 }
4792
4793 /*
4794  * getInherits
4795  *        read all the inheritance information
4796  * from the system catalogs return them in the InhInfo* structure
4797  *
4798  * numInherits is set to the number of pairs read in
4799  */
4800 InhInfo *
4801 getInherits(Archive *fout, int *numInherits)
4802 {
4803         PGresult   *res;
4804         int                     ntups;
4805         int                     i;
4806         PQExpBuffer query = createPQExpBuffer();
4807         InhInfo    *inhinfo;
4808
4809         int                     i_inhrelid;
4810         int                     i_inhparent;
4811
4812         /* Make sure we are in proper schema */
4813         selectSourceSchema(fout, "pg_catalog");
4814
4815         /* find all the inheritance information */
4816
4817         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4818
4819         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4820
4821         ntups = PQntuples(res);
4822
4823         *numInherits = ntups;
4824
4825         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4826
4827         i_inhrelid = PQfnumber(res, "inhrelid");
4828         i_inhparent = PQfnumber(res, "inhparent");
4829
4830         for (i = 0; i < ntups; i++)
4831         {
4832                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4833                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4834         }
4835
4836         PQclear(res);
4837
4838         destroyPQExpBuffer(query);
4839
4840         return inhinfo;
4841 }
4842
4843 /*
4844  * getIndexes
4845  *        get information about every index on a dumpable table
4846  *
4847  * Note: index data is not returned directly to the caller, but it
4848  * does get entered into the DumpableObject tables.
4849  */
4850 void
4851 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4852 {
4853         int                     i,
4854                                 j;
4855         PQExpBuffer query = createPQExpBuffer();
4856         PGresult   *res;
4857         IndxInfo   *indxinfo;
4858         ConstraintInfo *constrinfo;
4859         int                     i_tableoid,
4860                                 i_oid,
4861                                 i_indexname,
4862                                 i_indexdef,
4863                                 i_indnkeys,
4864                                 i_indkey,
4865                                 i_indisclustered,
4866                                 i_contype,
4867                                 i_conname,
4868                                 i_condeferrable,
4869                                 i_condeferred,
4870                                 i_contableoid,
4871                                 i_conoid,
4872                                 i_condef,
4873                                 i_tablespace,
4874                                 i_options,
4875                                 i_relpages;
4876         int                     ntups;
4877
4878         for (i = 0; i < numTables; i++)
4879         {
4880                 TableInfo  *tbinfo = &tblinfo[i];
4881
4882                 /* Only plain tables and materialized views have indexes. */
4883                 if (tbinfo->relkind != RELKIND_RELATION &&
4884                         tbinfo->relkind != RELKIND_MATVIEW)
4885                         continue;
4886                 if (!tbinfo->hasindex)
4887                         continue;
4888
4889                 /* Ignore indexes of tables not to be dumped */
4890                 if (!tbinfo->dobj.dump)
4891                         continue;
4892
4893                 if (g_verbose)
4894                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4895                                           tbinfo->dobj.name);
4896
4897                 /* Make sure we are in proper schema so indexdef is right */
4898                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4899
4900                 /*
4901                  * The point of the messy-looking outer join is to find a constraint
4902                  * that is related by an internal dependency link to the index. If we
4903                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4904                  * assume an index won't have more than one internal dependency.
4905                  *
4906                  * As of 9.0 we don't need to look at pg_depend but can check for a
4907                  * match to pg_constraint.conindid.  The check on conrelid is
4908                  * redundant but useful because that column is indexed while conindid
4909                  * is not.
4910                  */
4911                 resetPQExpBuffer(query);
4912                 if (fout->remoteVersion >= 90000)
4913                 {
4914                         /*
4915                          * the test on indisready is necessary in 9.2, and harmless in
4916                          * earlier/later versions
4917                          */
4918                         appendPQExpBuffer(query,
4919                                                           "SELECT t.tableoid, t.oid, "
4920                                                           "t.relname AS indexname, "
4921                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4922                                                           "t.relnatts AS indnkeys, "
4923                                                           "i.indkey, i.indisclustered, "
4924                                                           "t.relpages, "
4925                                                           "c.contype, c.conname, "
4926                                                           "c.condeferrable, c.condeferred, "
4927                                                           "c.tableoid AS contableoid, "
4928                                                           "c.oid AS conoid, "
4929                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4930                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4931                                                         "array_to_string(t.reloptions, ', ') AS options "
4932                                                           "FROM pg_catalog.pg_index i "
4933                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4934                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4935                                                           "ON (i.indrelid = c.conrelid AND "
4936                                                           "i.indexrelid = c.conindid AND "
4937                                                           "c.contype IN ('p','u','x')) "
4938                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4939                                                           "AND i.indisvalid AND i.indisready "
4940                                                           "ORDER BY indexname",
4941                                                           tbinfo->dobj.catId.oid);
4942                 }
4943                 else if (fout->remoteVersion >= 80200)
4944                 {
4945                         appendPQExpBuffer(query,
4946                                                           "SELECT t.tableoid, t.oid, "
4947                                                           "t.relname AS indexname, "
4948                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4949                                                           "t.relnatts AS indnkeys, "
4950                                                           "i.indkey, i.indisclustered, "
4951                                                           "t.relpages, "
4952                                                           "c.contype, c.conname, "
4953                                                           "c.condeferrable, c.condeferred, "
4954                                                           "c.tableoid AS contableoid, "
4955                                                           "c.oid AS conoid, "
4956                                                           "null AS condef, "
4957                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4958                                                         "array_to_string(t.reloptions, ', ') AS options "
4959                                                           "FROM pg_catalog.pg_index i "
4960                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4961                                                           "LEFT JOIN pg_catalog.pg_depend d "
4962                                                           "ON (d.classid = t.tableoid "
4963                                                           "AND d.objid = t.oid "
4964                                                           "AND d.deptype = 'i') "
4965                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4966                                                           "ON (d.refclassid = c.tableoid "
4967                                                           "AND d.refobjid = c.oid) "
4968                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4969                                                           "AND i.indisvalid "
4970                                                           "ORDER BY indexname",
4971                                                           tbinfo->dobj.catId.oid);
4972                 }
4973                 else if (fout->remoteVersion >= 80000)
4974                 {
4975                         appendPQExpBuffer(query,
4976                                                           "SELECT t.tableoid, t.oid, "
4977                                                           "t.relname AS indexname, "
4978                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4979                                                           "t.relnatts AS indnkeys, "
4980                                                           "i.indkey, i.indisclustered, "
4981                                                           "t.relpages, "
4982                                                           "c.contype, c.conname, "
4983                                                           "c.condeferrable, c.condeferred, "
4984                                                           "c.tableoid AS contableoid, "
4985                                                           "c.oid AS conoid, "
4986                                                           "null AS condef, "
4987                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4988                                                           "null AS options "
4989                                                           "FROM pg_catalog.pg_index i "
4990                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4991                                                           "LEFT JOIN pg_catalog.pg_depend d "
4992                                                           "ON (d.classid = t.tableoid "
4993                                                           "AND d.objid = t.oid "
4994                                                           "AND d.deptype = 'i') "
4995                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4996                                                           "ON (d.refclassid = c.tableoid "
4997                                                           "AND d.refobjid = c.oid) "
4998                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4999                                                           "ORDER BY indexname",
5000                                                           tbinfo->dobj.catId.oid);
5001                 }
5002                 else if (fout->remoteVersion >= 70300)
5003                 {
5004                         appendPQExpBuffer(query,
5005                                                           "SELECT t.tableoid, t.oid, "
5006                                                           "t.relname AS indexname, "
5007                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5008                                                           "t.relnatts AS indnkeys, "
5009                                                           "i.indkey, i.indisclustered, "
5010                                                           "t.relpages, "
5011                                                           "c.contype, c.conname, "
5012                                                           "c.condeferrable, c.condeferred, "
5013                                                           "c.tableoid AS contableoid, "
5014                                                           "c.oid AS conoid, "
5015                                                           "null AS condef, "
5016                                                           "NULL AS tablespace, "
5017                                                           "null AS options "
5018                                                           "FROM pg_catalog.pg_index i "
5019                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5020                                                           "LEFT JOIN pg_catalog.pg_depend d "
5021                                                           "ON (d.classid = t.tableoid "
5022                                                           "AND d.objid = t.oid "
5023                                                           "AND d.deptype = 'i') "
5024                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5025                                                           "ON (d.refclassid = c.tableoid "
5026                                                           "AND d.refobjid = c.oid) "
5027                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5028                                                           "ORDER BY indexname",
5029                                                           tbinfo->dobj.catId.oid);
5030                 }
5031                 else if (fout->remoteVersion >= 70100)
5032                 {
5033                         appendPQExpBuffer(query,
5034                                                           "SELECT t.tableoid, t.oid, "
5035                                                           "t.relname AS indexname, "
5036                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5037                                                           "t.relnatts AS indnkeys, "
5038                                                           "i.indkey, false AS indisclustered, "
5039                                                           "t.relpages, "
5040                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5041                                                           "ELSE '0'::char END AS contype, "
5042                                                           "t.relname AS conname, "
5043                                                           "false AS condeferrable, "
5044                                                           "false AS condeferred, "
5045                                                           "0::oid AS contableoid, "
5046                                                           "t.oid AS conoid, "
5047                                                           "null AS condef, "
5048                                                           "NULL AS tablespace, "
5049                                                           "null AS options "
5050                                                           "FROM pg_index i, pg_class t "
5051                                                           "WHERE t.oid = i.indexrelid "
5052                                                           "AND i.indrelid = '%u'::oid "
5053                                                           "ORDER BY indexname",
5054                                                           tbinfo->dobj.catId.oid);
5055                 }
5056                 else
5057                 {
5058                         appendPQExpBuffer(query,
5059                                                           "SELECT "
5060                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5061                                                           "t.oid, "
5062                                                           "t.relname AS indexname, "
5063                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5064                                                           "t.relnatts AS indnkeys, "
5065                                                           "i.indkey, false AS indisclustered, "
5066                                                           "t.relpages, "
5067                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5068                                                           "ELSE '0'::char END AS contype, "
5069                                                           "t.relname AS conname, "
5070                                                           "false AS condeferrable, "
5071                                                           "false AS condeferred, "
5072                                                           "0::oid AS contableoid, "
5073                                                           "t.oid AS conoid, "
5074                                                           "null AS condef, "
5075                                                           "NULL AS tablespace, "
5076                                                           "null AS options "
5077                                                           "FROM pg_index i, pg_class t "
5078                                                           "WHERE t.oid = i.indexrelid "
5079                                                           "AND i.indrelid = '%u'::oid "
5080                                                           "ORDER BY indexname",
5081                                                           tbinfo->dobj.catId.oid);
5082                 }
5083
5084                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5085
5086                 ntups = PQntuples(res);
5087
5088                 i_tableoid = PQfnumber(res, "tableoid");
5089                 i_oid = PQfnumber(res, "oid");
5090                 i_indexname = PQfnumber(res, "indexname");
5091                 i_indexdef = PQfnumber(res, "indexdef");
5092                 i_indnkeys = PQfnumber(res, "indnkeys");
5093                 i_indkey = PQfnumber(res, "indkey");
5094                 i_indisclustered = PQfnumber(res, "indisclustered");
5095                 i_relpages = PQfnumber(res, "relpages");
5096                 i_contype = PQfnumber(res, "contype");
5097                 i_conname = PQfnumber(res, "conname");
5098                 i_condeferrable = PQfnumber(res, "condeferrable");
5099                 i_condeferred = PQfnumber(res, "condeferred");
5100                 i_contableoid = PQfnumber(res, "contableoid");
5101                 i_conoid = PQfnumber(res, "conoid");
5102                 i_condef = PQfnumber(res, "condef");
5103                 i_tablespace = PQfnumber(res, "tablespace");
5104                 i_options = PQfnumber(res, "options");
5105
5106                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5107                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5108
5109                 for (j = 0; j < ntups; j++)
5110                 {
5111                         char            contype;
5112
5113                         indxinfo[j].dobj.objType = DO_INDEX;
5114                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5115                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5116                         AssignDumpId(&indxinfo[j].dobj);
5117                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5118                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5119                         indxinfo[j].indextable = tbinfo;
5120                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5121                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5122                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5123                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5124
5125                         /*
5126                          * In pre-7.4 releases, indkeys may contain more entries than
5127                          * indnkeys says (since indnkeys will be 1 for a functional
5128                          * index).      We don't actually care about this case since we don't
5129                          * examine indkeys except for indexes associated with PRIMARY and
5130                          * UNIQUE constraints, which are never functional indexes. But we
5131                          * have to allocate enough space to keep parseOidArray from
5132                          * complaining.
5133                          */
5134                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5135                         parseOidArray(PQgetvalue(res, j, i_indkey),
5136                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5137                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5138                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5139                         contype = *(PQgetvalue(res, j, i_contype));
5140
5141                         if (contype == 'p' || contype == 'u' || contype == 'x')
5142                         {
5143                                 /*
5144                                  * If we found a constraint matching the index, create an
5145                                  * entry for it.
5146                                  *
5147                                  * In a pre-7.3 database, we take this path iff the index was
5148                                  * marked indisprimary.
5149                                  */
5150                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5151                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5152                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5153                                 AssignDumpId(&constrinfo[j].dobj);
5154                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5155                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5156                                 constrinfo[j].contable = tbinfo;
5157                                 constrinfo[j].condomain = NULL;
5158                                 constrinfo[j].contype = contype;
5159                                 if (contype == 'x')
5160                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5161                                 else
5162                                         constrinfo[j].condef = NULL;
5163                                 constrinfo[j].confrelid = InvalidOid;
5164                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5165                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5166                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5167                                 constrinfo[j].conislocal = true;
5168                                 constrinfo[j].separate = true;
5169
5170                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5171
5172                                 /* If pre-7.3 DB, better make sure table comes first */
5173                                 addObjectDependency(&constrinfo[j].dobj,
5174                                                                         tbinfo->dobj.dumpId);
5175                         }
5176                         else
5177                         {
5178                                 /* Plain secondary index */
5179                                 indxinfo[j].indexconstraint = 0;
5180                         }
5181                 }
5182
5183                 PQclear(res);
5184         }
5185
5186         destroyPQExpBuffer(query);
5187 }
5188
5189 /*
5190  * getConstraints
5191  *
5192  * Get info about constraints on dumpable tables.
5193  *
5194  * Currently handles foreign keys only.
5195  * Unique and primary key constraints are handled with indexes,
5196  * while check constraints are processed in getTableAttrs().
5197  */
5198 void
5199 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5200 {
5201         int                     i,
5202                                 j;
5203         ConstraintInfo *constrinfo;
5204         PQExpBuffer query;
5205         PGresult   *res;
5206         int                     i_contableoid,
5207                                 i_conoid,
5208                                 i_conname,
5209                                 i_confrelid,
5210                                 i_condef;
5211         int                     ntups;
5212
5213         /* pg_constraint was created in 7.3, so nothing to do if older */
5214         if (fout->remoteVersion < 70300)
5215                 return;
5216
5217         query = createPQExpBuffer();
5218
5219         for (i = 0; i < numTables; i++)
5220         {
5221                 TableInfo  *tbinfo = &tblinfo[i];
5222
5223                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5224                         continue;
5225
5226                 if (g_verbose)
5227                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5228                                           tbinfo->dobj.name);
5229
5230                 /*
5231                  * select table schema to ensure constraint expr is qualified if
5232                  * needed
5233                  */
5234                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5235
5236                 resetPQExpBuffer(query);
5237                 appendPQExpBuffer(query,
5238                                                   "SELECT tableoid, oid, conname, confrelid, "
5239                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5240                                                   "FROM pg_catalog.pg_constraint "
5241                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5242                                                   "AND contype = 'f'",
5243                                                   tbinfo->dobj.catId.oid);
5244                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5245
5246                 ntups = PQntuples(res);
5247
5248                 i_contableoid = PQfnumber(res, "tableoid");
5249                 i_conoid = PQfnumber(res, "oid");
5250                 i_conname = PQfnumber(res, "conname");
5251                 i_confrelid = PQfnumber(res, "confrelid");
5252                 i_condef = PQfnumber(res, "condef");
5253
5254                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5255
5256                 for (j = 0; j < ntups; j++)
5257                 {
5258                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5259                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5260                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5261                         AssignDumpId(&constrinfo[j].dobj);
5262                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5263                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5264                         constrinfo[j].contable = tbinfo;
5265                         constrinfo[j].condomain = NULL;
5266                         constrinfo[j].contype = 'f';
5267                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5268                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5269                         constrinfo[j].conindex = 0;
5270                         constrinfo[j].condeferrable = false;
5271                         constrinfo[j].condeferred = false;
5272                         constrinfo[j].conislocal = true;
5273                         constrinfo[j].separate = true;
5274                 }
5275
5276                 PQclear(res);
5277         }
5278
5279         destroyPQExpBuffer(query);
5280 }
5281
5282 /*
5283  * getDomainConstraints
5284  *
5285  * Get info about constraints on a domain.
5286  */
5287 static void
5288 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5289 {
5290         int                     i;
5291         ConstraintInfo *constrinfo;
5292         PQExpBuffer query;
5293         PGresult   *res;
5294         int                     i_tableoid,
5295                                 i_oid,
5296                                 i_conname,
5297                                 i_consrc;
5298         int                     ntups;
5299
5300         /* pg_constraint was created in 7.3, so nothing to do if older */
5301         if (fout->remoteVersion < 70300)
5302                 return;
5303
5304         /*
5305          * select appropriate schema to ensure names in constraint are properly
5306          * qualified
5307          */
5308         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5309
5310         query = createPQExpBuffer();
5311
5312         if (fout->remoteVersion >= 90100)
5313                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5314                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5315                                                   "convalidated "
5316                                                   "FROM pg_catalog.pg_constraint "
5317                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5318                                                   "ORDER BY conname",
5319                                                   tyinfo->dobj.catId.oid);
5320
5321         else if (fout->remoteVersion >= 70400)
5322                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5323                                                   "pg_catalog.pg_get_constraintdef(oid) 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         else
5330                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5331                                                   "'CHECK (' || consrc || ')' AS consrc, "
5332                                                   "true as convalidated "
5333                                                   "FROM pg_catalog.pg_constraint "
5334                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5335                                                   "ORDER BY conname",
5336                                                   tyinfo->dobj.catId.oid);
5337
5338         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5339
5340         ntups = PQntuples(res);
5341
5342         i_tableoid = PQfnumber(res, "tableoid");
5343         i_oid = PQfnumber(res, "oid");
5344         i_conname = PQfnumber(res, "conname");
5345         i_consrc = PQfnumber(res, "consrc");
5346
5347         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5348
5349         tyinfo->nDomChecks = ntups;
5350         tyinfo->domChecks = constrinfo;
5351
5352         for (i = 0; i < ntups; i++)
5353         {
5354                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5355
5356                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5357                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5358                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5359                 AssignDumpId(&constrinfo[i].dobj);
5360                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5361                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5362                 constrinfo[i].contable = NULL;
5363                 constrinfo[i].condomain = tyinfo;
5364                 constrinfo[i].contype = 'c';
5365                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5366                 constrinfo[i].confrelid = InvalidOid;
5367                 constrinfo[i].conindex = 0;
5368                 constrinfo[i].condeferrable = false;
5369                 constrinfo[i].condeferred = false;
5370                 constrinfo[i].conislocal = true;
5371
5372                 constrinfo[i].separate = !validated;
5373
5374                 /*
5375                  * Make the domain depend on the constraint, ensuring it won't be
5376                  * output till any constraint dependencies are OK.      If the constraint
5377                  * has not been validated, it's going to be dumped after the domain
5378                  * anyway, so this doesn't matter.
5379                  */
5380                 if (validated)
5381                         addObjectDependency(&tyinfo->dobj,
5382                                                                 constrinfo[i].dobj.dumpId);
5383         }
5384
5385         PQclear(res);
5386
5387         destroyPQExpBuffer(query);
5388 }
5389
5390 /*
5391  * getRules
5392  *        get basic information about every rule in the system
5393  *
5394  * numRules is set to the number of rules read in
5395  */
5396 RuleInfo *
5397 getRules(Archive *fout, int *numRules)
5398 {
5399         PGresult   *res;
5400         int                     ntups;
5401         int                     i;
5402         PQExpBuffer query = createPQExpBuffer();
5403         RuleInfo   *ruleinfo;
5404         int                     i_tableoid;
5405         int                     i_oid;
5406         int                     i_rulename;
5407         int                     i_ruletable;
5408         int                     i_ev_type;
5409         int                     i_is_instead;
5410         int                     i_ev_enabled;
5411
5412         /* Make sure we are in proper schema */
5413         selectSourceSchema(fout, "pg_catalog");
5414
5415         if (fout->remoteVersion >= 80300)
5416         {
5417                 appendPQExpBuffer(query, "SELECT "
5418                                                   "tableoid, oid, rulename, "
5419                                                   "ev_class AS ruletable, ev_type, is_instead, "
5420                                                   "ev_enabled "
5421                                                   "FROM pg_rewrite "
5422                                                   "ORDER BY oid");
5423         }
5424         else if (fout->remoteVersion >= 70100)
5425         {
5426                 appendPQExpBuffer(query, "SELECT "
5427                                                   "tableoid, oid, rulename, "
5428                                                   "ev_class AS ruletable, ev_type, is_instead, "
5429                                                   "'O'::char AS ev_enabled "
5430                                                   "FROM pg_rewrite "
5431                                                   "ORDER BY oid");
5432         }
5433         else
5434         {
5435                 appendPQExpBuffer(query, "SELECT "
5436                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5437                                                   "oid, rulename, "
5438                                                   "ev_class AS ruletable, ev_type, is_instead, "
5439                                                   "'O'::char AS ev_enabled "
5440                                                   "FROM pg_rewrite "
5441                                                   "ORDER BY oid");
5442         }
5443
5444         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5445
5446         ntups = PQntuples(res);
5447
5448         *numRules = ntups;
5449
5450         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5451
5452         i_tableoid = PQfnumber(res, "tableoid");
5453         i_oid = PQfnumber(res, "oid");
5454         i_rulename = PQfnumber(res, "rulename");
5455         i_ruletable = PQfnumber(res, "ruletable");
5456         i_ev_type = PQfnumber(res, "ev_type");
5457         i_is_instead = PQfnumber(res, "is_instead");
5458         i_ev_enabled = PQfnumber(res, "ev_enabled");
5459
5460         for (i = 0; i < ntups; i++)
5461         {
5462                 Oid                     ruletableoid;
5463
5464                 ruleinfo[i].dobj.objType = DO_RULE;
5465                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5466                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5467                 AssignDumpId(&ruleinfo[i].dobj);
5468                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5469                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5470                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5471                 if (ruleinfo[i].ruletable == NULL)
5472                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5473                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5474                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5475                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5476                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5477                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5478                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5479                 if (ruleinfo[i].ruletable)
5480                 {
5481                         /*
5482                          * If the table is a view or materialized view, force its ON
5483                          * SELECT rule to be sorted before the view itself --- this
5484                          * ensures that any dependencies for the rule affect the table's
5485                          * positioning. Other rules are forced to appear after their
5486                          * table.
5487                          */
5488                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5489                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5490                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5491                         {
5492                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5493                                                                         ruleinfo[i].dobj.dumpId);
5494                                 /* We'll merge the rule into CREATE VIEW, if possible */
5495                                 ruleinfo[i].separate = false;
5496                         }
5497                         else
5498                         {
5499                                 addObjectDependency(&ruleinfo[i].dobj,
5500                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5501                                 ruleinfo[i].separate = true;
5502                         }
5503                 }
5504                 else
5505                         ruleinfo[i].separate = true;
5506
5507                 /*
5508                  * If we're forced to break a dependency loop by dumping a view as a
5509                  * table and separate _RETURN rule, we'll move the view's reloptions
5510                  * to the rule.  (This is necessary because tables and views have
5511                  * different valid reloptions, so we can't apply the options until the
5512                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5513                  * NULL.
5514                  */
5515                 ruleinfo[i].reloptions = NULL;
5516         }
5517
5518         PQclear(res);
5519
5520         destroyPQExpBuffer(query);
5521
5522         return ruleinfo;
5523 }
5524
5525 /*
5526  * getTriggers
5527  *        get information about every trigger on a dumpable table
5528  *
5529  * Note: trigger data is not returned directly to the caller, but it
5530  * does get entered into the DumpableObject tables.
5531  */
5532 void
5533 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5534 {
5535         int                     i,
5536                                 j;
5537         PQExpBuffer query = createPQExpBuffer();
5538         PGresult   *res;
5539         TriggerInfo *tginfo;
5540         int                     i_tableoid,
5541                                 i_oid,
5542                                 i_tgname,
5543                                 i_tgfname,
5544                                 i_tgtype,
5545                                 i_tgnargs,
5546                                 i_tgargs,
5547                                 i_tgisconstraint,
5548                                 i_tgconstrname,
5549                                 i_tgconstrrelid,
5550                                 i_tgconstrrelname,
5551                                 i_tgenabled,
5552                                 i_tgdeferrable,
5553                                 i_tginitdeferred,
5554                                 i_tgdef;
5555         int                     ntups;
5556
5557         for (i = 0; i < numTables; i++)
5558         {
5559                 TableInfo  *tbinfo = &tblinfo[i];
5560
5561                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5562                         continue;
5563
5564                 if (g_verbose)
5565                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5566                                           tbinfo->dobj.name);
5567
5568                 /*
5569                  * select table schema to ensure regproc name is qualified if needed
5570                  */
5571                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5572
5573                 resetPQExpBuffer(query);
5574                 if (fout->remoteVersion >= 90000)
5575                 {
5576                         /*
5577                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5578                          * could result in non-forward-compatible dumps of WHEN clauses
5579                          * due to under-parenthesization.
5580                          */
5581                         appendPQExpBuffer(query,
5582                                                           "SELECT tgname, "
5583                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5584                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5585                                                           "tgenabled, tableoid, oid "
5586                                                           "FROM pg_catalog.pg_trigger t "
5587                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5588                                                           "AND NOT tgisinternal",
5589                                                           tbinfo->dobj.catId.oid);
5590                 }
5591                 else if (fout->remoteVersion >= 80300)
5592                 {
5593                         /*
5594                          * We ignore triggers that are tied to a foreign-key constraint
5595                          */
5596                         appendPQExpBuffer(query,
5597                                                           "SELECT tgname, "
5598                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5599                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5600                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5601                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5602                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5603                                                           "FROM pg_catalog.pg_trigger t "
5604                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5605                                                           "AND tgconstraint = 0",
5606                                                           tbinfo->dobj.catId.oid);
5607                 }
5608                 else if (fout->remoteVersion >= 70300)
5609                 {
5610                         /*
5611                          * We ignore triggers that are tied to a foreign-key constraint,
5612                          * but in these versions we have to grovel through pg_constraint
5613                          * to find out
5614                          */
5615                         appendPQExpBuffer(query,
5616                                                           "SELECT tgname, "
5617                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5618                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5619                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5620                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5621                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5622                                                           "FROM pg_catalog.pg_trigger t "
5623                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5624                                                           "AND (NOT tgisconstraint "
5625                                                           " OR NOT EXISTS"
5626                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5627                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5628                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5629                                                           tbinfo->dobj.catId.oid);
5630                 }
5631                 else if (fout->remoteVersion >= 70100)
5632                 {
5633                         appendPQExpBuffer(query,
5634                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5635                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5636                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5637                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5638                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5639                                                           "             AS tgconstrrelname "
5640                                                           "FROM pg_trigger "
5641                                                           "WHERE tgrelid = '%u'::oid",
5642                                                           tbinfo->dobj.catId.oid);
5643                 }
5644                 else
5645                 {
5646                         appendPQExpBuffer(query,
5647                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5648                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5649                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5650                                                           "tgconstrrelid, tginitdeferred, "
5651                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5652                                                           "oid, "
5653                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5654                                                           "             AS tgconstrrelname "
5655                                                           "FROM pg_trigger "
5656                                                           "WHERE tgrelid = '%u'::oid",
5657                                                           tbinfo->dobj.catId.oid);
5658                 }
5659                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5660
5661                 ntups = PQntuples(res);
5662
5663                 i_tableoid = PQfnumber(res, "tableoid");
5664                 i_oid = PQfnumber(res, "oid");
5665                 i_tgname = PQfnumber(res, "tgname");
5666                 i_tgfname = PQfnumber(res, "tgfname");
5667                 i_tgtype = PQfnumber(res, "tgtype");
5668                 i_tgnargs = PQfnumber(res, "tgnargs");
5669                 i_tgargs = PQfnumber(res, "tgargs");
5670                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5671                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5672                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5673                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5674                 i_tgenabled = PQfnumber(res, "tgenabled");
5675                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5676                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5677                 i_tgdef = PQfnumber(res, "tgdef");
5678
5679                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5680
5681                 for (j = 0; j < ntups; j++)
5682                 {
5683                         tginfo[j].dobj.objType = DO_TRIGGER;
5684                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5685                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5686                         AssignDumpId(&tginfo[j].dobj);
5687                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5688                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5689                         tginfo[j].tgtable = tbinfo;
5690                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5691                         if (i_tgdef >= 0)
5692                         {
5693                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5694
5695                                 /* remaining fields are not valid if we have tgdef */
5696                                 tginfo[j].tgfname = NULL;
5697                                 tginfo[j].tgtype = 0;
5698                                 tginfo[j].tgnargs = 0;
5699                                 tginfo[j].tgargs = NULL;
5700                                 tginfo[j].tgisconstraint = false;
5701                                 tginfo[j].tgdeferrable = false;
5702                                 tginfo[j].tginitdeferred = false;
5703                                 tginfo[j].tgconstrname = NULL;
5704                                 tginfo[j].tgconstrrelid = InvalidOid;
5705                                 tginfo[j].tgconstrrelname = NULL;
5706                         }
5707                         else
5708                         {
5709                                 tginfo[j].tgdef = NULL;
5710
5711                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5712                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5713                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5714                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5715                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5716                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5717                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5718
5719                                 if (tginfo[j].tgisconstraint)
5720                                 {
5721                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5722                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5723                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5724                                         {
5725                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5726                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5727                                                                                   tginfo[j].dobj.name,
5728                                                                                   tbinfo->dobj.name,
5729                                                                                   tginfo[j].tgconstrrelid);
5730                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5731                                         }
5732                                         else
5733                                                 tginfo[j].tgconstrrelname = NULL;
5734                                 }
5735                                 else
5736                                 {
5737                                         tginfo[j].tgconstrname = NULL;
5738                                         tginfo[j].tgconstrrelid = InvalidOid;
5739                                         tginfo[j].tgconstrrelname = NULL;
5740                                 }
5741                         }
5742                 }
5743
5744                 PQclear(res);
5745         }
5746
5747         destroyPQExpBuffer(query);
5748 }
5749
5750 /*
5751  * getEventTriggers
5752  *        get information about event triggers
5753  */
5754 EventTriggerInfo *
5755 getEventTriggers(Archive *fout, int *numEventTriggers)
5756 {
5757         int                     i;
5758         PQExpBuffer query;
5759         PGresult   *res;
5760         EventTriggerInfo *evtinfo;
5761         int                     i_tableoid,
5762                                 i_oid,
5763                                 i_evtname,
5764                                 i_evtevent,
5765                                 i_evtowner,
5766                                 i_evttags,
5767                                 i_evtfname,
5768                                 i_evtenabled;
5769         int                     ntups;
5770
5771         /* Before 9.3, there are no event triggers */
5772         if (fout->remoteVersion < 90300)
5773         {
5774                 *numEventTriggers = 0;
5775                 return NULL;
5776         }
5777
5778         query = createPQExpBuffer();
5779
5780         /* Make sure we are in proper schema */
5781         selectSourceSchema(fout, "pg_catalog");
5782
5783         appendPQExpBuffer(query,
5784                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5785                                           "evtevent, (%s evtowner) AS evtowner, "
5786                                           "array_to_string(array("
5787                                           "select quote_literal(x) "
5788                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5789                                           "e.evtfoid::regproc as evtfname "
5790                                           "FROM pg_event_trigger e "
5791                                           "ORDER BY e.oid",
5792                                           username_subquery);
5793
5794         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5795
5796         ntups = PQntuples(res);
5797
5798         *numEventTriggers = ntups;
5799
5800         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5801
5802         i_tableoid = PQfnumber(res, "tableoid");
5803         i_oid = PQfnumber(res, "oid");
5804         i_evtname = PQfnumber(res, "evtname");
5805         i_evtevent = PQfnumber(res, "evtevent");
5806         i_evtowner = PQfnumber(res, "evtowner");
5807         i_evttags = PQfnumber(res, "evttags");
5808         i_evtfname = PQfnumber(res, "evtfname");
5809         i_evtenabled = PQfnumber(res, "evtenabled");
5810
5811         for (i = 0; i < ntups; i++)
5812         {
5813                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5814                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5815                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5816                 AssignDumpId(&evtinfo[i].dobj);
5817                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5818                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5819                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5820                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5821                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5822                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5823                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5824         }
5825
5826         PQclear(res);
5827
5828         destroyPQExpBuffer(query);
5829
5830         return evtinfo;
5831 }
5832
5833 /*
5834  * getProcLangs
5835  *        get basic information about every procedural language in the system
5836  *
5837  * numProcLangs is set to the number of langs read in
5838  *
5839  * NB: this must run after getFuncs() because we assume we can do
5840  * findFuncByOid().
5841  */
5842 ProcLangInfo *
5843 getProcLangs(Archive *fout, int *numProcLangs)
5844 {
5845         PGresult   *res;
5846         int                     ntups;
5847         int                     i;
5848         PQExpBuffer query = createPQExpBuffer();
5849         ProcLangInfo *planginfo;
5850         int                     i_tableoid;
5851         int                     i_oid;
5852         int                     i_lanname;
5853         int                     i_lanpltrusted;
5854         int                     i_lanplcallfoid;
5855         int                     i_laninline;
5856         int                     i_lanvalidator;
5857         int                     i_lanacl;
5858         int                     i_lanowner;
5859
5860         /* Make sure we are in proper schema */
5861         selectSourceSchema(fout, "pg_catalog");
5862
5863         if (fout->remoteVersion >= 90000)
5864         {
5865                 /* pg_language has a laninline column */
5866                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5867                                                   "lanname, lanpltrusted, lanplcallfoid, "
5868                                                   "laninline, lanvalidator,  lanacl, "
5869                                                   "(%s lanowner) AS lanowner "
5870                                                   "FROM pg_language "
5871                                                   "WHERE lanispl "
5872                                                   "ORDER BY oid",
5873                                                   username_subquery);
5874         }
5875         else if (fout->remoteVersion >= 80300)
5876         {
5877                 /* pg_language has a lanowner column */
5878                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5879                                                   "lanname, lanpltrusted, lanplcallfoid, "
5880                                                   "lanvalidator,  lanacl, "
5881                                                   "(%s lanowner) AS lanowner "
5882                                                   "FROM pg_language "
5883                                                   "WHERE lanispl "
5884                                                   "ORDER BY oid",
5885                                                   username_subquery);
5886         }
5887         else if (fout->remoteVersion >= 80100)
5888         {
5889                 /* Languages are owned by the bootstrap superuser, OID 10 */
5890                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5891                                                   "(%s '10') AS lanowner "
5892                                                   "FROM pg_language "
5893                                                   "WHERE lanispl "
5894                                                   "ORDER BY oid",
5895                                                   username_subquery);
5896         }
5897         else if (fout->remoteVersion >= 70400)
5898         {
5899                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5900                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5901                                                   "(%s '1') AS lanowner "
5902                                                   "FROM pg_language "
5903                                                   "WHERE lanispl "
5904                                                   "ORDER BY oid",
5905                                                   username_subquery);
5906         }
5907         else if (fout->remoteVersion >= 70100)
5908         {
5909                 /* No clear notion of an owner at all before 7.4 ... */
5910                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5911                                                   "WHERE lanispl "
5912                                                   "ORDER BY oid");
5913         }
5914         else
5915         {
5916                 appendPQExpBuffer(query, "SELECT "
5917                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5918                                                   "oid, * FROM pg_language "
5919                                                   "WHERE lanispl "
5920                                                   "ORDER BY oid");
5921         }
5922
5923         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5924
5925         ntups = PQntuples(res);
5926
5927         *numProcLangs = ntups;
5928
5929         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5930
5931         i_tableoid = PQfnumber(res, "tableoid");
5932         i_oid = PQfnumber(res, "oid");
5933         i_lanname = PQfnumber(res, "lanname");
5934         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5935         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5936         /* these may fail and return -1: */
5937         i_laninline = PQfnumber(res, "laninline");
5938         i_lanvalidator = PQfnumber(res, "lanvalidator");
5939         i_lanacl = PQfnumber(res, "lanacl");
5940         i_lanowner = PQfnumber(res, "lanowner");
5941
5942         for (i = 0; i < ntups; i++)
5943         {
5944                 planginfo[i].dobj.objType = DO_PROCLANG;
5945                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5946                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5947                 AssignDumpId(&planginfo[i].dobj);
5948
5949                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5950                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5951                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5952                 if (i_laninline >= 0)
5953                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5954                 else
5955                         planginfo[i].laninline = InvalidOid;
5956                 if (i_lanvalidator >= 0)
5957                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5958                 else
5959                         planginfo[i].lanvalidator = InvalidOid;
5960                 if (i_lanacl >= 0)
5961                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5962                 else
5963                         planginfo[i].lanacl = pg_strdup("{=U}");
5964                 if (i_lanowner >= 0)
5965                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5966                 else
5967                         planginfo[i].lanowner = pg_strdup("");
5968
5969                 if (fout->remoteVersion < 70300)
5970                 {
5971                         /*
5972                          * We need to make a dependency to ensure the function will be
5973                          * dumped first.  (In 7.3 and later the regular dependency
5974                          * mechanism will handle this for us.)
5975                          */
5976                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5977
5978                         if (funcInfo)
5979                                 addObjectDependency(&planginfo[i].dobj,
5980                                                                         funcInfo->dobj.dumpId);
5981                 }
5982         }
5983
5984         PQclear(res);
5985
5986         destroyPQExpBuffer(query);
5987
5988         return planginfo;
5989 }
5990
5991 /*
5992  * getCasts
5993  *        get basic information about every cast in the system
5994  *
5995  * numCasts is set to the number of casts read in
5996  */
5997 CastInfo *
5998 getCasts(Archive *fout, int *numCasts)
5999 {
6000         PGresult   *res;
6001         int                     ntups;
6002         int                     i;
6003         PQExpBuffer query = createPQExpBuffer();
6004         CastInfo   *castinfo;
6005         int                     i_tableoid;
6006         int                     i_oid;
6007         int                     i_castsource;
6008         int                     i_casttarget;
6009         int                     i_castfunc;
6010         int                     i_castcontext;
6011         int                     i_castmethod;
6012
6013         /* Make sure we are in proper schema */
6014         selectSourceSchema(fout, "pg_catalog");
6015
6016         if (fout->remoteVersion >= 80400)
6017         {
6018                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6019                                                   "castsource, casttarget, castfunc, castcontext, "
6020                                                   "castmethod "
6021                                                   "FROM pg_cast ORDER BY 3,4");
6022         }
6023         else if (fout->remoteVersion >= 70300)
6024         {
6025                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6026                                                   "castsource, casttarget, castfunc, castcontext, "
6027                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6028                                                   "FROM pg_cast ORDER BY 3,4");
6029         }
6030         else
6031         {
6032                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
6033                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
6034                                                   "p.oid AS castfunc, 'e' AS castcontext, "
6035                                                   "'f' AS castmethod "
6036                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
6037                                                   "WHERE p.pronargs = 1 AND "
6038                                                   "p.proargtypes[0] = t1.oid AND "
6039                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6040                                                   "ORDER BY 3,4");
6041         }
6042
6043         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6044
6045         ntups = PQntuples(res);
6046
6047         *numCasts = ntups;
6048
6049         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6050
6051         i_tableoid = PQfnumber(res, "tableoid");
6052         i_oid = PQfnumber(res, "oid");
6053         i_castsource = PQfnumber(res, "castsource");
6054         i_casttarget = PQfnumber(res, "casttarget");
6055         i_castfunc = PQfnumber(res, "castfunc");
6056         i_castcontext = PQfnumber(res, "castcontext");
6057         i_castmethod = PQfnumber(res, "castmethod");
6058
6059         for (i = 0; i < ntups; i++)
6060         {
6061                 PQExpBufferData namebuf;
6062                 TypeInfo   *sTypeInfo;
6063                 TypeInfo   *tTypeInfo;
6064
6065                 castinfo[i].dobj.objType = DO_CAST;
6066                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6067                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6068                 AssignDumpId(&castinfo[i].dobj);
6069                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6070                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6071                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6072                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6073                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6074
6075                 /*
6076                  * Try to name cast as concatenation of typnames.  This is only used
6077                  * for purposes of sorting.  If we fail to find either type, the name
6078                  * will be an empty string.
6079                  */
6080                 initPQExpBuffer(&namebuf);
6081                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6082                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6083                 if (sTypeInfo && tTypeInfo)
6084                         appendPQExpBuffer(&namebuf, "%s %s",
6085                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6086                 castinfo[i].dobj.name = namebuf.data;
6087
6088                 if (OidIsValid(castinfo[i].castfunc))
6089                 {
6090                         /*
6091                          * We need to make a dependency to ensure the function will be
6092                          * dumped first.  (In 7.3 and later the regular dependency
6093                          * mechanism will handle this for us.)
6094                          */
6095                         FuncInfo   *funcInfo;
6096
6097                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6098                         if (funcInfo)
6099                                 addObjectDependency(&castinfo[i].dobj,
6100                                                                         funcInfo->dobj.dumpId);
6101                 }
6102         }
6103
6104         PQclear(res);
6105
6106         destroyPQExpBuffer(query);
6107
6108         return castinfo;
6109 }
6110
6111 /*
6112  * getTableAttrs -
6113  *        for each interesting table, read info about its attributes
6114  *        (names, types, default values, CHECK constraints, etc)
6115  *
6116  * This is implemented in a very inefficient way right now, looping
6117  * through the tblinfo and doing a join per table to find the attrs and their
6118  * types.  However, because we want type names and so forth to be named
6119  * relative to the schema of each table, we couldn't do it in just one
6120  * query.  (Maybe one query per schema?)
6121  *
6122  *      modifies tblinfo
6123  */
6124 void
6125 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6126 {
6127         int                     i,
6128                                 j;
6129         PQExpBuffer q = createPQExpBuffer();
6130         int                     i_attnum;
6131         int                     i_attname;
6132         int                     i_atttypname;
6133         int                     i_atttypmod;
6134         int                     i_attstattarget;
6135         int                     i_attstorage;
6136         int                     i_typstorage;
6137         int                     i_attnotnull;
6138         int                     i_atthasdef;
6139         int                     i_attisdropped;
6140         int                     i_attlen;
6141         int                     i_attalign;
6142         int                     i_attislocal;
6143         int                     i_attoptions;
6144         int                     i_attcollation;
6145         int                     i_attfdwoptions;
6146         PGresult   *res;
6147         int                     ntups;
6148         bool            hasdefaults;
6149
6150         for (i = 0; i < numTables; i++)
6151         {
6152                 TableInfo  *tbinfo = &tblinfo[i];
6153
6154                 /* Don't bother to collect info for sequences */
6155                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6156                         continue;
6157
6158                 /* Don't bother with uninteresting tables, either */
6159                 if (!tbinfo->interesting)
6160                         continue;
6161
6162                 /*
6163                  * Make sure we are in proper schema for this table; this allows
6164                  * correct retrieval of formatted type names and default exprs
6165                  */
6166                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6167
6168                 /* find all the user attributes and their types */
6169
6170                 /*
6171                  * we must read the attribute names in attribute number order! because
6172                  * we will use the attnum to index into the attnames array later.  We
6173                  * actually ask to order by "attrelid, attnum" because (at least up to
6174                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6175                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6176                  */
6177                 if (g_verbose)
6178                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6179                                           tbinfo->dobj.name);
6180
6181                 resetPQExpBuffer(q);
6182
6183                 if (fout->remoteVersion >= 90200)
6184                 {
6185                         /*
6186                          * attfdwoptions is new in 9.2.
6187                          */
6188                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6189                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6190                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6191                                                           "a.attlen, a.attalign, a.attislocal, "
6192                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6193                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6194                                                           "CASE WHEN a.attcollation <> t.typcollation "
6195                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6196                                                           "pg_catalog.array_to_string(ARRAY("
6197                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6198                                                           "' ' || pg_catalog.quote_literal(option_value) "
6199                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6200                                                           "ORDER BY option_name"
6201                                                           "), E',\n    ') AS attfdwoptions "
6202                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6203                                                           "ON a.atttypid = t.oid "
6204                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6205                                                           "AND a.attnum > 0::pg_catalog.int2 "
6206                                                           "ORDER BY a.attrelid, a.attnum",
6207                                                           tbinfo->dobj.catId.oid);
6208                 }
6209                 else if (fout->remoteVersion >= 90100)
6210                 {
6211                         /*
6212                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6213                          * clauses for attributes whose collation is different from their
6214                          * type's default, we use a CASE here to suppress uninteresting
6215                          * attcollations cheaply.
6216                          */
6217                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6218                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6219                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6220                                                           "a.attlen, a.attalign, a.attislocal, "
6221                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6222                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6223                                                           "CASE WHEN a.attcollation <> t.typcollation "
6224                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6225                                                           "NULL AS attfdwoptions "
6226                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6227                                                           "ON a.atttypid = t.oid "
6228                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6229                                                           "AND a.attnum > 0::pg_catalog.int2 "
6230                                                           "ORDER BY a.attrelid, a.attnum",
6231                                                           tbinfo->dobj.catId.oid);
6232                 }
6233                 else if (fout->remoteVersion >= 90000)
6234                 {
6235                         /* attoptions is new in 9.0 */
6236                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6237                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6238                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6239                                                           "a.attlen, a.attalign, a.attislocal, "
6240                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6241                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6242                                                           "0 AS attcollation, "
6243                                                           "NULL AS attfdwoptions "
6244                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6245                                                           "ON a.atttypid = t.oid "
6246                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6247                                                           "AND a.attnum > 0::pg_catalog.int2 "
6248                                                           "ORDER BY a.attrelid, a.attnum",
6249                                                           tbinfo->dobj.catId.oid);
6250                 }
6251                 else if (fout->remoteVersion >= 70300)
6252                 {
6253                         /* need left join here to not fail on dropped columns ... */
6254                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6255                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6256                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6257                                                           "a.attlen, a.attalign, a.attislocal, "
6258                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6259                                                           "'' AS attoptions, 0 AS attcollation, "
6260                                                           "NULL AS attfdwoptions "
6261                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6262                                                           "ON a.atttypid = t.oid "
6263                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6264                                                           "AND a.attnum > 0::pg_catalog.int2 "
6265                                                           "ORDER BY a.attrelid, a.attnum",
6266                                                           tbinfo->dobj.catId.oid);
6267                 }
6268                 else if (fout->remoteVersion >= 70100)
6269                 {
6270                         /*
6271                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6272                          * we don't dump it because we can't tell whether it's been
6273                          * explicitly set or was just a default.
6274                          *
6275                          * attislocal doesn't exist before 7.3, either; in older databases
6276                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6277                          */
6278                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6279                                                           "-1 AS attstattarget, a.attstorage, "
6280                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6281                                                           "false AS attisdropped, a.attlen, "
6282                                                           "a.attalign, true AS attislocal, "
6283                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6284                                                           "'' AS attoptions, 0 AS attcollation, "
6285                                                           "NULL AS attfdwoptions "
6286                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6287                                                           "ON a.atttypid = t.oid "
6288                                                           "WHERE a.attrelid = '%u'::oid "
6289                                                           "AND a.attnum > 0::int2 "
6290                                                           "ORDER BY a.attrelid, a.attnum",
6291                                                           tbinfo->dobj.catId.oid);
6292                 }
6293                 else
6294                 {
6295                         /* format_type not available before 7.1 */
6296                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6297                                                           "-1 AS attstattarget, "
6298                                                           "attstorage, attstorage AS typstorage, "
6299                                                           "attnotnull, atthasdef, false AS attisdropped, "
6300                                                           "attlen, attalign, "
6301                                                           "true AS attislocal, "
6302                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6303                                                           "'' AS attoptions, 0 AS attcollation, "
6304                                                           "NULL AS attfdwoptions "
6305                                                           "FROM pg_attribute a "
6306                                                           "WHERE attrelid = '%u'::oid "
6307                                                           "AND attnum > 0::int2 "
6308                                                           "ORDER BY attrelid, attnum",
6309                                                           tbinfo->dobj.catId.oid);
6310                 }
6311
6312                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6313
6314                 ntups = PQntuples(res);
6315
6316                 i_attnum = PQfnumber(res, "attnum");
6317                 i_attname = PQfnumber(res, "attname");
6318                 i_atttypname = PQfnumber(res, "atttypname");
6319                 i_atttypmod = PQfnumber(res, "atttypmod");
6320                 i_attstattarget = PQfnumber(res, "attstattarget");
6321                 i_attstorage = PQfnumber(res, "attstorage");
6322                 i_typstorage = PQfnumber(res, "typstorage");
6323                 i_attnotnull = PQfnumber(res, "attnotnull");
6324                 i_atthasdef = PQfnumber(res, "atthasdef");
6325                 i_attisdropped = PQfnumber(res, "attisdropped");
6326                 i_attlen = PQfnumber(res, "attlen");
6327                 i_attalign = PQfnumber(res, "attalign");
6328                 i_attislocal = PQfnumber(res, "attislocal");
6329                 i_attoptions = PQfnumber(res, "attoptions");
6330                 i_attcollation = PQfnumber(res, "attcollation");
6331                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6332
6333                 tbinfo->numatts = ntups;
6334                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6335                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6336                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6337                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6338                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6339                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6340                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6341                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6342                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6343                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6344                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6345                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6346                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6347                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6348                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6349                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6350                 hasdefaults = false;
6351
6352                 for (j = 0; j < ntups; j++)
6353                 {
6354                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6355                                 exit_horribly(NULL,
6356                                                           "invalid column numbering in table \"%s\"\n",
6357                                                           tbinfo->dobj.name);
6358                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6359                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6360                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6361                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6362                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6363                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6364                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6365                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6366                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6367                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6368                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6369                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6370                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6371                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6372                         tbinfo->attrdefs[j] = NULL; /* fix below */
6373                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6374                                 hasdefaults = true;
6375                         /* these flags will be set in flagInhAttrs() */
6376                         tbinfo->inhNotNull[j] = false;
6377                 }
6378
6379                 PQclear(res);
6380
6381                 /*
6382                  * Get info about column defaults
6383                  */
6384                 if (hasdefaults)
6385                 {
6386                         AttrDefInfo *attrdefs;
6387                         int                     numDefaults;
6388
6389                         if (g_verbose)
6390                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6391                                                   tbinfo->dobj.name);
6392
6393                         resetPQExpBuffer(q);
6394                         if (fout->remoteVersion >= 70300)
6395                         {
6396                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6397                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6398                                                                   "FROM pg_catalog.pg_attrdef "
6399                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6400                                                                   tbinfo->dobj.catId.oid);
6401                         }
6402                         else if (fout->remoteVersion >= 70200)
6403                         {
6404                                 /* 7.2 did not have OIDs in pg_attrdef */
6405                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6406                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6407                                                                   "FROM pg_attrdef "
6408                                                                   "WHERE adrelid = '%u'::oid",
6409                                                                   tbinfo->dobj.catId.oid);
6410                         }
6411                         else if (fout->remoteVersion >= 70100)
6412                         {
6413                                 /* no pg_get_expr, so must rely on adsrc */
6414                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6415                                                                   "FROM pg_attrdef "
6416                                                                   "WHERE adrelid = '%u'::oid",
6417                                                                   tbinfo->dobj.catId.oid);
6418                         }
6419                         else
6420                         {
6421                                 /* no pg_get_expr, no tableoid either */
6422                                 appendPQExpBuffer(q, "SELECT "
6423                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6424                                                                   "oid, adnum, adsrc "
6425                                                                   "FROM pg_attrdef "
6426                                                                   "WHERE adrelid = '%u'::oid",
6427                                                                   tbinfo->dobj.catId.oid);
6428                         }
6429                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6430
6431                         numDefaults = PQntuples(res);
6432                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6433
6434                         for (j = 0; j < numDefaults; j++)
6435                         {
6436                                 int                     adnum;
6437
6438                                 adnum = atoi(PQgetvalue(res, j, 2));
6439
6440                                 if (adnum <= 0 || adnum > ntups)
6441                                         exit_horribly(NULL,
6442                                                                   "invalid adnum value %d for table \"%s\"\n",
6443                                                                   adnum, tbinfo->dobj.name);
6444
6445                                 /*
6446                                  * dropped columns shouldn't have defaults, but just in case,
6447                                  * ignore 'em
6448                                  */
6449                                 if (tbinfo->attisdropped[adnum - 1])
6450                                         continue;
6451
6452                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6453                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6454                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6455                                 AssignDumpId(&attrdefs[j].dobj);
6456                                 attrdefs[j].adtable = tbinfo;
6457                                 attrdefs[j].adnum = adnum;
6458                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6459
6460                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6461                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6462
6463                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6464
6465                                 /*
6466                                  * Defaults on a VIEW must always be dumped as separate ALTER
6467                                  * TABLE commands.      Defaults on regular tables are dumped as
6468                                  * part of the CREATE TABLE if possible, which it won't be if
6469                                  * the column is not going to be emitted explicitly.
6470                                  */
6471                                 if (tbinfo->relkind == RELKIND_VIEW)
6472                                 {
6473                                         attrdefs[j].separate = true;
6474                                         /* needed in case pre-7.3 DB: */
6475                                         addObjectDependency(&attrdefs[j].dobj,
6476                                                                                 tbinfo->dobj.dumpId);
6477                                 }
6478                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6479                                 {
6480                                         /* column will be suppressed, print default separately */
6481                                         attrdefs[j].separate = true;
6482                                         /* needed in case pre-7.3 DB: */
6483                                         addObjectDependency(&attrdefs[j].dobj,
6484                                                                                 tbinfo->dobj.dumpId);
6485                                 }
6486                                 else
6487                                 {
6488                                         attrdefs[j].separate = false;
6489
6490                                         /*
6491                                          * Mark the default as needing to appear before the table,
6492                                          * so that any dependencies it has must be emitted before
6493                                          * the CREATE TABLE.  If this is not possible, we'll
6494                                          * change to "separate" mode while sorting dependencies.
6495                                          */
6496                                         addObjectDependency(&tbinfo->dobj,
6497                                                                                 attrdefs[j].dobj.dumpId);
6498                                 }
6499
6500                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6501                         }
6502                         PQclear(res);
6503                 }
6504
6505                 /*
6506                  * Get info about table CHECK constraints
6507                  */
6508                 if (tbinfo->ncheck > 0)
6509                 {
6510                         ConstraintInfo *constrs;
6511                         int                     numConstrs;
6512
6513                         if (g_verbose)
6514                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6515                                                   tbinfo->dobj.name);
6516
6517                         resetPQExpBuffer(q);
6518                         if (fout->remoteVersion >= 90200)
6519                         {
6520                                 /*
6521                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6522                                  * but it wasn't ever false for check constraints until 9.2).
6523                                  */
6524                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6525                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6526                                                                   "conislocal, convalidated "
6527                                                                   "FROM pg_catalog.pg_constraint "
6528                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6529                                                                   "   AND contype = 'c' "
6530                                                                   "ORDER BY conname",
6531                                                                   tbinfo->dobj.catId.oid);
6532                         }
6533                         else if (fout->remoteVersion >= 80400)
6534                         {
6535                                 /* conislocal is new in 8.4 */
6536                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6537                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6538                                                                   "conislocal, true AS convalidated "
6539                                                                   "FROM pg_catalog.pg_constraint "
6540                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6541                                                                   "   AND contype = 'c' "
6542                                                                   "ORDER BY conname",
6543                                                                   tbinfo->dobj.catId.oid);
6544                         }
6545                         else if (fout->remoteVersion >= 70400)
6546                         {
6547                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6548                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6549                                                                   "true AS conislocal, true AS convalidated "
6550                                                                   "FROM pg_catalog.pg_constraint "
6551                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6552                                                                   "   AND contype = 'c' "
6553                                                                   "ORDER BY conname",
6554                                                                   tbinfo->dobj.catId.oid);
6555                         }
6556                         else if (fout->remoteVersion >= 70300)
6557                         {
6558                                 /* no pg_get_constraintdef, must use consrc */
6559                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6560                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6561                                                                   "true AS conislocal, true AS convalidated "
6562                                                                   "FROM pg_catalog.pg_constraint "
6563                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6564                                                                   "   AND contype = 'c' "
6565                                                                   "ORDER BY conname",
6566                                                                   tbinfo->dobj.catId.oid);
6567                         }
6568                         else if (fout->remoteVersion >= 70200)
6569                         {
6570                                 /* 7.2 did not have OIDs in pg_relcheck */
6571                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6572                                                                   "rcname AS conname, "
6573                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6574                                                                   "true AS conislocal, true AS convalidated "
6575                                                                   "FROM pg_relcheck "
6576                                                                   "WHERE rcrelid = '%u'::oid "
6577                                                                   "ORDER BY rcname",
6578                                                                   tbinfo->dobj.catId.oid);
6579                         }
6580                         else if (fout->remoteVersion >= 70100)
6581                         {
6582                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6583                                                                   "rcname AS conname, "
6584                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6585                                                                   "true AS conislocal, true AS convalidated "
6586                                                                   "FROM pg_relcheck "
6587                                                                   "WHERE rcrelid = '%u'::oid "
6588                                                                   "ORDER BY rcname",
6589                                                                   tbinfo->dobj.catId.oid);
6590                         }
6591                         else
6592                         {
6593                                 /* no tableoid in 7.0 */
6594                                 appendPQExpBuffer(q, "SELECT "
6595                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6596                                                                   "oid, rcname AS conname, "
6597                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6598                                                                   "true AS conislocal, true AS convalidated "
6599                                                                   "FROM pg_relcheck "
6600                                                                   "WHERE rcrelid = '%u'::oid "
6601                                                                   "ORDER BY rcname",
6602                                                                   tbinfo->dobj.catId.oid);
6603                         }
6604                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6605
6606                         numConstrs = PQntuples(res);
6607                         if (numConstrs != tbinfo->ncheck)
6608                         {
6609                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6610                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6611                                                                                  tbinfo->ncheck),
6612                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6613                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6614                                 exit_nicely(1);
6615                         }
6616
6617                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6618                         tbinfo->checkexprs = constrs;
6619
6620                         for (j = 0; j < numConstrs; j++)
6621                         {
6622                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6623
6624                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6625                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6626                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6627                                 AssignDumpId(&constrs[j].dobj);
6628                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6629                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6630                                 constrs[j].contable = tbinfo;
6631                                 constrs[j].condomain = NULL;
6632                                 constrs[j].contype = 'c';
6633                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6634                                 constrs[j].confrelid = InvalidOid;
6635                                 constrs[j].conindex = 0;
6636                                 constrs[j].condeferrable = false;
6637                                 constrs[j].condeferred = false;
6638                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6639
6640                                 /*
6641                                  * An unvalidated constraint needs to be dumped separately, so
6642                                  * that potentially-violating existing data is loaded before
6643                                  * the constraint.
6644                                  */
6645                                 constrs[j].separate = !validated;
6646
6647                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6648
6649                                 /*
6650                                  * Mark the constraint as needing to appear before the table
6651                                  * --- this is so that any other dependencies of the
6652                                  * constraint will be emitted before we try to create the
6653                                  * table.  If the constraint is to be dumped separately, it
6654                                  * will be dumped after data is loaded anyway, so don't do it.
6655                                  * (There's an automatic dependency in the opposite direction
6656                                  * anyway, so don't need to add one manually here.)
6657                                  */
6658                                 if (!constrs[j].separate)
6659                                         addObjectDependency(&tbinfo->dobj,
6660                                                                                 constrs[j].dobj.dumpId);
6661
6662                                 /*
6663                                  * If the constraint is inherited, this will be detected later
6664                                  * (in pre-8.4 databases).      We also detect later if the
6665                                  * constraint must be split out from the table definition.
6666                                  */
6667                         }
6668                         PQclear(res);
6669                 }
6670         }
6671
6672         destroyPQExpBuffer(q);
6673 }
6674
6675 /*
6676  * Test whether a column should be printed as part of table's CREATE TABLE.
6677  * Column number is zero-based.
6678  *
6679  * Normally this is always true, but it's false for dropped columns, as well
6680  * as those that were inherited without any local definition.  (If we print
6681  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6682  * However, in binary_upgrade mode, we must print all such columns anyway and
6683  * fix the attislocal/attisdropped state later, so as to keep control of the
6684  * physical column order.
6685  *
6686  * This function exists because there are scattered nonobvious places that
6687  * must be kept in sync with this decision.
6688  */
6689 bool
6690 shouldPrintColumn(TableInfo *tbinfo, int colno)
6691 {
6692         if (binary_upgrade)
6693                 return true;
6694         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6695 }
6696
6697
6698 /*
6699  * getTSParsers:
6700  *        read all text search parsers in the system catalogs and return them
6701  *        in the TSParserInfo* structure
6702  *
6703  *      numTSParsers is set to the number of parsers read in
6704  */
6705 TSParserInfo *
6706 getTSParsers(Archive *fout, int *numTSParsers)
6707 {
6708         PGresult   *res;
6709         int                     ntups;
6710         int                     i;
6711         PQExpBuffer query;
6712         TSParserInfo *prsinfo;
6713         int                     i_tableoid;
6714         int                     i_oid;
6715         int                     i_prsname;
6716         int                     i_prsnamespace;
6717         int                     i_prsstart;
6718         int                     i_prstoken;
6719         int                     i_prsend;
6720         int                     i_prsheadline;
6721         int                     i_prslextype;
6722
6723         /* Before 8.3, there is no built-in text search support */
6724         if (fout->remoteVersion < 80300)
6725         {
6726                 *numTSParsers = 0;
6727                 return NULL;
6728         }
6729
6730         query = createPQExpBuffer();
6731
6732         /*
6733          * find all text search objects, including builtin ones; we filter out
6734          * system-defined objects at dump-out time.
6735          */
6736
6737         /* Make sure we are in proper schema */
6738         selectSourceSchema(fout, "pg_catalog");
6739
6740         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6741                                           "prsstart::oid, prstoken::oid, "
6742                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6743                                           "FROM pg_ts_parser");
6744
6745         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6746
6747         ntups = PQntuples(res);
6748         *numTSParsers = ntups;
6749
6750         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6751
6752         i_tableoid = PQfnumber(res, "tableoid");
6753         i_oid = PQfnumber(res, "oid");
6754         i_prsname = PQfnumber(res, "prsname");
6755         i_prsnamespace = PQfnumber(res, "prsnamespace");
6756         i_prsstart = PQfnumber(res, "prsstart");
6757         i_prstoken = PQfnumber(res, "prstoken");
6758         i_prsend = PQfnumber(res, "prsend");
6759         i_prsheadline = PQfnumber(res, "prsheadline");
6760         i_prslextype = PQfnumber(res, "prslextype");
6761
6762         for (i = 0; i < ntups; i++)
6763         {
6764                 prsinfo[i].dobj.objType = DO_TSPARSER;
6765                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6766                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6767                 AssignDumpId(&prsinfo[i].dobj);
6768                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6769                 prsinfo[i].dobj.namespace =
6770                         findNamespace(fout,
6771                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6772                                                   prsinfo[i].dobj.catId.oid);
6773                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6774                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6775                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6776                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6777                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6778
6779                 /* Decide whether we want to dump it */
6780                 selectDumpableObject(&(prsinfo[i].dobj));
6781         }
6782
6783         PQclear(res);
6784
6785         destroyPQExpBuffer(query);
6786
6787         return prsinfo;
6788 }
6789
6790 /*
6791  * getTSDictionaries:
6792  *        read all text search dictionaries in the system catalogs and return them
6793  *        in the TSDictInfo* structure
6794  *
6795  *      numTSDicts is set to the number of dictionaries read in
6796  */
6797 TSDictInfo *
6798 getTSDictionaries(Archive *fout, int *numTSDicts)
6799 {
6800         PGresult   *res;
6801         int                     ntups;
6802         int                     i;
6803         PQExpBuffer query;
6804         TSDictInfo *dictinfo;
6805         int                     i_tableoid;
6806         int                     i_oid;
6807         int                     i_dictname;
6808         int                     i_dictnamespace;
6809         int                     i_rolname;
6810         int                     i_dicttemplate;
6811         int                     i_dictinitoption;
6812
6813         /* Before 8.3, there is no built-in text search support */
6814         if (fout->remoteVersion < 80300)
6815         {
6816                 *numTSDicts = 0;
6817                 return NULL;
6818         }
6819
6820         query = createPQExpBuffer();
6821
6822         /* Make sure we are in proper schema */
6823         selectSourceSchema(fout, "pg_catalog");
6824
6825         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6826                                           "dictnamespace, (%s dictowner) AS rolname, "
6827                                           "dicttemplate, dictinitoption "
6828                                           "FROM pg_ts_dict",
6829                                           username_subquery);
6830
6831         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6832
6833         ntups = PQntuples(res);
6834         *numTSDicts = ntups;
6835
6836         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6837
6838         i_tableoid = PQfnumber(res, "tableoid");
6839         i_oid = PQfnumber(res, "oid");
6840         i_dictname = PQfnumber(res, "dictname");
6841         i_dictnamespace = PQfnumber(res, "dictnamespace");
6842         i_rolname = PQfnumber(res, "rolname");
6843         i_dictinitoption = PQfnumber(res, "dictinitoption");
6844         i_dicttemplate = PQfnumber(res, "dicttemplate");
6845
6846         for (i = 0; i < ntups; i++)
6847         {
6848                 dictinfo[i].dobj.objType = DO_TSDICT;
6849                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6850                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6851                 AssignDumpId(&dictinfo[i].dobj);
6852                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6853                 dictinfo[i].dobj.namespace =
6854                         findNamespace(fout,
6855                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6856                                                   dictinfo[i].dobj.catId.oid);
6857                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6858                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6859                 if (PQgetisnull(res, i, i_dictinitoption))
6860                         dictinfo[i].dictinitoption = NULL;
6861                 else
6862                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6863
6864                 /* Decide whether we want to dump it */
6865                 selectDumpableObject(&(dictinfo[i].dobj));
6866         }
6867
6868         PQclear(res);
6869
6870         destroyPQExpBuffer(query);
6871
6872         return dictinfo;
6873 }
6874
6875 /*
6876  * getTSTemplates:
6877  *        read all text search templates in the system catalogs and return them
6878  *        in the TSTemplateInfo* structure
6879  *
6880  *      numTSTemplates is set to the number of templates read in
6881  */
6882 TSTemplateInfo *
6883 getTSTemplates(Archive *fout, int *numTSTemplates)
6884 {
6885         PGresult   *res;
6886         int                     ntups;
6887         int                     i;
6888         PQExpBuffer query;
6889         TSTemplateInfo *tmplinfo;
6890         int                     i_tableoid;
6891         int                     i_oid;
6892         int                     i_tmplname;
6893         int                     i_tmplnamespace;
6894         int                     i_tmplinit;
6895         int                     i_tmpllexize;
6896
6897         /* Before 8.3, there is no built-in text search support */
6898         if (fout->remoteVersion < 80300)
6899         {
6900                 *numTSTemplates = 0;
6901                 return NULL;
6902         }
6903
6904         query = createPQExpBuffer();
6905
6906         /* Make sure we are in proper schema */
6907         selectSourceSchema(fout, "pg_catalog");
6908
6909         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6910                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6911                                           "FROM pg_ts_template");
6912
6913         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6914
6915         ntups = PQntuples(res);
6916         *numTSTemplates = ntups;
6917
6918         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6919
6920         i_tableoid = PQfnumber(res, "tableoid");
6921         i_oid = PQfnumber(res, "oid");
6922         i_tmplname = PQfnumber(res, "tmplname");
6923         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6924         i_tmplinit = PQfnumber(res, "tmplinit");
6925         i_tmpllexize = PQfnumber(res, "tmpllexize");
6926
6927         for (i = 0; i < ntups; i++)
6928         {
6929                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6930                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6931                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6932                 AssignDumpId(&tmplinfo[i].dobj);
6933                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6934                 tmplinfo[i].dobj.namespace =
6935                         findNamespace(fout,
6936                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
6937                                                   tmplinfo[i].dobj.catId.oid);
6938                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6939                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6940
6941                 /* Decide whether we want to dump it */
6942                 selectDumpableObject(&(tmplinfo[i].dobj));
6943         }
6944
6945         PQclear(res);
6946
6947         destroyPQExpBuffer(query);
6948
6949         return tmplinfo;
6950 }
6951
6952 /*
6953  * getTSConfigurations:
6954  *        read all text search configurations in the system catalogs and return
6955  *        them in the TSConfigInfo* structure
6956  *
6957  *      numTSConfigs is set to the number of configurations read in
6958  */
6959 TSConfigInfo *
6960 getTSConfigurations(Archive *fout, int *numTSConfigs)
6961 {
6962         PGresult   *res;
6963         int                     ntups;
6964         int                     i;
6965         PQExpBuffer query;
6966         TSConfigInfo *cfginfo;
6967         int                     i_tableoid;
6968         int                     i_oid;
6969         int                     i_cfgname;
6970         int                     i_cfgnamespace;
6971         int                     i_rolname;
6972         int                     i_cfgparser;
6973
6974         /* Before 8.3, there is no built-in text search support */
6975         if (fout->remoteVersion < 80300)
6976         {
6977                 *numTSConfigs = 0;
6978                 return NULL;
6979         }
6980
6981         query = createPQExpBuffer();
6982
6983         /* Make sure we are in proper schema */
6984         selectSourceSchema(fout, "pg_catalog");
6985
6986         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6987                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6988                                           "FROM pg_ts_config",
6989                                           username_subquery);
6990
6991         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6992
6993         ntups = PQntuples(res);
6994         *numTSConfigs = ntups;
6995
6996         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6997
6998         i_tableoid = PQfnumber(res, "tableoid");
6999         i_oid = PQfnumber(res, "oid");
7000         i_cfgname = PQfnumber(res, "cfgname");
7001         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
7002         i_rolname = PQfnumber(res, "rolname");
7003         i_cfgparser = PQfnumber(res, "cfgparser");
7004
7005         for (i = 0; i < ntups; i++)
7006         {
7007                 cfginfo[i].dobj.objType = DO_TSCONFIG;
7008                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7009                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7010                 AssignDumpId(&cfginfo[i].dobj);
7011                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7012                 cfginfo[i].dobj.namespace =
7013                         findNamespace(fout,
7014                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7015                                                   cfginfo[i].dobj.catId.oid);
7016                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7017                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7018
7019                 /* Decide whether we want to dump it */
7020                 selectDumpableObject(&(cfginfo[i].dobj));
7021         }
7022
7023         PQclear(res);
7024
7025         destroyPQExpBuffer(query);
7026
7027         return cfginfo;
7028 }
7029
7030 /*
7031  * getForeignDataWrappers:
7032  *        read all foreign-data wrappers in the system catalogs and return
7033  *        them in the FdwInfo* structure
7034  *
7035  *      numForeignDataWrappers is set to the number of fdws read in
7036  */
7037 FdwInfo *
7038 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7039 {
7040         PGresult   *res;
7041         int                     ntups;
7042         int                     i;
7043         PQExpBuffer query = createPQExpBuffer();
7044         FdwInfo    *fdwinfo;
7045         int                     i_tableoid;
7046         int                     i_oid;
7047         int                     i_fdwname;
7048         int                     i_rolname;
7049         int                     i_fdwhandler;
7050         int                     i_fdwvalidator;
7051         int                     i_fdwacl;
7052         int                     i_fdwoptions;
7053
7054         /* Before 8.4, there are no foreign-data wrappers */
7055         if (fout->remoteVersion < 80400)
7056         {
7057                 *numForeignDataWrappers = 0;
7058                 return NULL;
7059         }
7060
7061         /* Make sure we are in proper schema */
7062         selectSourceSchema(fout, "pg_catalog");
7063
7064         if (fout->remoteVersion >= 90100)
7065         {
7066                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7067                                                   "(%s fdwowner) AS rolname, "
7068                                                   "fdwhandler::pg_catalog.regproc, "
7069                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7070                                                   "array_to_string(ARRAY("
7071                                                   "SELECT quote_ident(option_name) || ' ' || "
7072                                                   "quote_literal(option_value) "
7073                                                   "FROM pg_options_to_table(fdwoptions) "
7074                                                   "ORDER BY option_name"
7075                                                   "), E',\n    ') AS fdwoptions "
7076                                                   "FROM pg_foreign_data_wrapper",
7077                                                   username_subquery);
7078         }
7079         else
7080         {
7081                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7082                                                   "(%s fdwowner) AS rolname, "
7083                                                   "'-' AS fdwhandler, "
7084                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7085                                                   "array_to_string(ARRAY("
7086                                                   "SELECT quote_ident(option_name) || ' ' || "
7087                                                   "quote_literal(option_value) "
7088                                                   "FROM pg_options_to_table(fdwoptions) "
7089                                                   "ORDER BY option_name"
7090                                                   "), E',\n    ') AS fdwoptions "
7091                                                   "FROM pg_foreign_data_wrapper",
7092                                                   username_subquery);
7093         }
7094
7095         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7096
7097         ntups = PQntuples(res);
7098         *numForeignDataWrappers = ntups;
7099
7100         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7101
7102         i_tableoid = PQfnumber(res, "tableoid");
7103         i_oid = PQfnumber(res, "oid");
7104         i_fdwname = PQfnumber(res, "fdwname");
7105         i_rolname = PQfnumber(res, "rolname");
7106         i_fdwhandler = PQfnumber(res, "fdwhandler");
7107         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7108         i_fdwacl = PQfnumber(res, "fdwacl");
7109         i_fdwoptions = PQfnumber(res, "fdwoptions");
7110
7111         for (i = 0; i < ntups; i++)
7112         {
7113                 fdwinfo[i].dobj.objType = DO_FDW;
7114                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7115                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7116                 AssignDumpId(&fdwinfo[i].dobj);
7117                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7118                 fdwinfo[i].dobj.namespace = NULL;
7119                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7120                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7121                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7122                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7123                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7124
7125                 /* Decide whether we want to dump it */
7126                 selectDumpableObject(&(fdwinfo[i].dobj));
7127         }
7128
7129         PQclear(res);
7130
7131         destroyPQExpBuffer(query);
7132
7133         return fdwinfo;
7134 }
7135
7136 /*
7137  * getForeignServers:
7138  *        read all foreign servers in the system catalogs and return
7139  *        them in the ForeignServerInfo * structure
7140  *
7141  *      numForeignServers is set to the number of servers read in
7142  */
7143 ForeignServerInfo *
7144 getForeignServers(Archive *fout, int *numForeignServers)
7145 {
7146         PGresult   *res;
7147         int                     ntups;
7148         int                     i;
7149         PQExpBuffer query = createPQExpBuffer();
7150         ForeignServerInfo *srvinfo;
7151         int                     i_tableoid;
7152         int                     i_oid;
7153         int                     i_srvname;
7154         int                     i_rolname;
7155         int                     i_srvfdw;
7156         int                     i_srvtype;
7157         int                     i_srvversion;
7158         int                     i_srvacl;
7159         int                     i_srvoptions;
7160
7161         /* Before 8.4, there are no foreign servers */
7162         if (fout->remoteVersion < 80400)
7163         {
7164                 *numForeignServers = 0;
7165                 return NULL;
7166         }
7167
7168         /* Make sure we are in proper schema */
7169         selectSourceSchema(fout, "pg_catalog");
7170
7171         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7172                                           "(%s srvowner) AS rolname, "
7173                                           "srvfdw, srvtype, srvversion, srvacl,"
7174                                           "array_to_string(ARRAY("
7175                                           "SELECT quote_ident(option_name) || ' ' || "
7176                                           "quote_literal(option_value) "
7177                                           "FROM pg_options_to_table(srvoptions) "
7178                                           "ORDER BY option_name"
7179                                           "), E',\n    ') AS srvoptions "
7180                                           "FROM pg_foreign_server",
7181                                           username_subquery);
7182
7183         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7184
7185         ntups = PQntuples(res);
7186         *numForeignServers = ntups;
7187
7188         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7189
7190         i_tableoid = PQfnumber(res, "tableoid");
7191         i_oid = PQfnumber(res, "oid");
7192         i_srvname = PQfnumber(res, "srvname");
7193         i_rolname = PQfnumber(res, "rolname");
7194         i_srvfdw = PQfnumber(res, "srvfdw");
7195         i_srvtype = PQfnumber(res, "srvtype");
7196         i_srvversion = PQfnumber(res, "srvversion");
7197         i_srvacl = PQfnumber(res, "srvacl");
7198         i_srvoptions = PQfnumber(res, "srvoptions");
7199
7200         for (i = 0; i < ntups; i++)
7201         {
7202                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7203                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7204                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7205                 AssignDumpId(&srvinfo[i].dobj);
7206                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7207                 srvinfo[i].dobj.namespace = NULL;
7208                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7209                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7210                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7211                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7212                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7213                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7214
7215                 /* Decide whether we want to dump it */
7216                 selectDumpableObject(&(srvinfo[i].dobj));
7217         }
7218
7219         PQclear(res);
7220
7221         destroyPQExpBuffer(query);
7222
7223         return srvinfo;
7224 }
7225
7226 /*
7227  * getDefaultACLs:
7228  *        read all default ACL information in the system catalogs and return
7229  *        them in the DefaultACLInfo structure
7230  *
7231  *      numDefaultACLs is set to the number of ACLs read in
7232  */
7233 DefaultACLInfo *
7234 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7235 {
7236         DefaultACLInfo *daclinfo;
7237         PQExpBuffer query;
7238         PGresult   *res;
7239         int                     i_oid;
7240         int                     i_tableoid;
7241         int                     i_defaclrole;
7242         int                     i_defaclnamespace;
7243         int                     i_defaclobjtype;
7244         int                     i_defaclacl;
7245         int                     i,
7246                                 ntups;
7247
7248         if (fout->remoteVersion < 90000)
7249         {
7250                 *numDefaultACLs = 0;
7251                 return NULL;
7252         }
7253
7254         query = createPQExpBuffer();
7255
7256         /* Make sure we are in proper schema */
7257         selectSourceSchema(fout, "pg_catalog");
7258
7259         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7260                                           "(%s defaclrole) AS defaclrole, "
7261                                           "defaclnamespace, "
7262                                           "defaclobjtype, "
7263                                           "defaclacl "
7264                                           "FROM pg_default_acl",
7265                                           username_subquery);
7266
7267         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7268
7269         ntups = PQntuples(res);
7270         *numDefaultACLs = ntups;
7271
7272         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7273
7274         i_oid = PQfnumber(res, "oid");
7275         i_tableoid = PQfnumber(res, "tableoid");
7276         i_defaclrole = PQfnumber(res, "defaclrole");
7277         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7278         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7279         i_defaclacl = PQfnumber(res, "defaclacl");
7280
7281         for (i = 0; i < ntups; i++)
7282         {
7283                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7284
7285                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7286                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7287                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7288                 AssignDumpId(&daclinfo[i].dobj);
7289                 /* cheesy ... is it worth coming up with a better object name? */
7290                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7291
7292                 if (nspid != InvalidOid)
7293                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7294                                                                                                  daclinfo[i].dobj.catId.oid);
7295                 else
7296                         daclinfo[i].dobj.namespace = NULL;
7297
7298                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7299                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7300                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7301
7302                 /* Decide whether we want to dump it */
7303                 selectDumpableDefaultACL(&(daclinfo[i]));
7304         }
7305
7306         PQclear(res);
7307
7308         destroyPQExpBuffer(query);
7309
7310         return daclinfo;
7311 }
7312
7313 /*
7314  * dumpComment --
7315  *
7316  * This routine is used to dump any comments associated with the
7317  * object handed to this routine. The routine takes a constant character
7318  * string for the target part of the comment-creation command, plus
7319  * the namespace and owner of the object (for labeling the ArchiveEntry),
7320  * plus catalog ID and subid which are the lookup key for pg_description,
7321  * plus the dump ID for the object (for setting a dependency).
7322  * If a matching pg_description entry is found, it is dumped.
7323  *
7324  * Note: although this routine takes a dumpId for dependency purposes,
7325  * that purpose is just to mark the dependency in the emitted dump file
7326  * for possible future use by pg_restore.  We do NOT use it for determining
7327  * ordering of the comment in the dump file, because this routine is called
7328  * after dependency sorting occurs.  This routine should be called just after
7329  * calling ArchiveEntry() for the specified object.
7330  */
7331 static void
7332 dumpComment(Archive *fout, const char *target,
7333                         const char *namespace, const char *owner,
7334                         CatalogId catalogId, int subid, DumpId dumpId)
7335 {
7336         CommentItem *comments;
7337         int                     ncomments;
7338
7339         /* Comments are schema not data ... except blob comments are data */
7340         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7341         {
7342                 if (dataOnly)
7343                         return;
7344         }
7345         else
7346         {
7347                 if (schemaOnly)
7348                         return;
7349         }
7350
7351         /* Search for comments associated with catalogId, using table */
7352         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7353                                                          &comments);
7354
7355         /* Is there one matching the subid? */
7356         while (ncomments > 0)
7357         {
7358                 if (comments->objsubid == subid)
7359                         break;
7360                 comments++;
7361                 ncomments--;
7362         }
7363
7364         /* If a comment exists, build COMMENT ON statement */
7365         if (ncomments > 0)
7366         {
7367                 PQExpBuffer query = createPQExpBuffer();
7368
7369                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7370                 appendStringLiteralAH(query, comments->descr, fout);
7371                 appendPQExpBuffer(query, ";\n");
7372
7373                 /*
7374                  * We mark comments as SECTION_NONE because they really belong in the
7375                  * same section as their parent, whether that is pre-data or
7376                  * post-data.
7377                  */
7378                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7379                                          target, namespace, NULL, owner,
7380                                          false, "COMMENT", SECTION_NONE,
7381                                          query->data, "", NULL,
7382                                          &(dumpId), 1,
7383                                          NULL, NULL);
7384
7385                 destroyPQExpBuffer(query);
7386         }
7387 }
7388
7389 /*
7390  * dumpTableComment --
7391  *
7392  * As above, but dump comments for both the specified table (or view)
7393  * and its columns.
7394  */
7395 static void
7396 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7397                                  const char *reltypename)
7398 {
7399         CommentItem *comments;
7400         int                     ncomments;
7401         PQExpBuffer query;
7402         PQExpBuffer target;
7403
7404         /* Comments are SCHEMA not data */
7405         if (dataOnly)
7406                 return;
7407
7408         /* Search for comments associated with relation, using table */
7409         ncomments = findComments(fout,
7410                                                          tbinfo->dobj.catId.tableoid,
7411                                                          tbinfo->dobj.catId.oid,
7412                                                          &comments);
7413
7414         /* If comments exist, build COMMENT ON statements */
7415         if (ncomments <= 0)
7416                 return;
7417
7418         query = createPQExpBuffer();
7419         target = createPQExpBuffer();
7420
7421         while (ncomments > 0)
7422         {
7423                 const char *descr = comments->descr;
7424                 int                     objsubid = comments->objsubid;
7425
7426                 if (objsubid == 0)
7427                 {
7428                         resetPQExpBuffer(target);
7429                         appendPQExpBuffer(target, "%s %s", reltypename,
7430                                                           fmtId(tbinfo->dobj.name));
7431
7432                         resetPQExpBuffer(query);
7433                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7434                         appendStringLiteralAH(query, descr, fout);
7435                         appendPQExpBuffer(query, ";\n");
7436
7437                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7438                                                  target->data,
7439                                                  tbinfo->dobj.namespace->dobj.name,
7440                                                  NULL, tbinfo->rolname,
7441                                                  false, "COMMENT", SECTION_NONE,
7442                                                  query->data, "", NULL,
7443                                                  &(tbinfo->dobj.dumpId), 1,
7444                                                  NULL, NULL);
7445                 }
7446                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7447                 {
7448                         resetPQExpBuffer(target);
7449                         appendPQExpBuffer(target, "COLUMN %s.",
7450                                                           fmtId(tbinfo->dobj.name));
7451                         appendPQExpBuffer(target, "%s",
7452                                                           fmtId(tbinfo->attnames[objsubid - 1]));
7453
7454                         resetPQExpBuffer(query);
7455                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7456                         appendStringLiteralAH(query, descr, fout);
7457                         appendPQExpBuffer(query, ";\n");
7458
7459                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7460                                                  target->data,
7461                                                  tbinfo->dobj.namespace->dobj.name,
7462                                                  NULL, tbinfo->rolname,
7463                                                  false, "COMMENT", SECTION_NONE,
7464                                                  query->data, "", NULL,
7465                                                  &(tbinfo->dobj.dumpId), 1,
7466                                                  NULL, NULL);
7467                 }
7468
7469                 comments++;
7470                 ncomments--;
7471         }
7472
7473         destroyPQExpBuffer(query);
7474         destroyPQExpBuffer(target);
7475 }
7476
7477 /*
7478  * findComments --
7479  *
7480  * Find the comment(s), if any, associated with the given object.  All the
7481  * objsubid values associated with the given classoid/objoid are found with
7482  * one search.
7483  */
7484 static int
7485 findComments(Archive *fout, Oid classoid, Oid objoid,
7486                          CommentItem **items)
7487 {
7488         /* static storage for table of comments */
7489         static CommentItem *comments = NULL;
7490         static int      ncomments = -1;
7491
7492         CommentItem *middle = NULL;
7493         CommentItem *low;
7494         CommentItem *high;
7495         int                     nmatch;
7496
7497         /* Get comments if we didn't already */
7498         if (ncomments < 0)
7499                 ncomments = collectComments(fout, &comments);
7500
7501         /*
7502          * Pre-7.2, pg_description does not contain classoid, so collectComments
7503          * just stores a zero.  If there's a collision on object OID, well, you
7504          * get duplicate comments.
7505          */
7506         if (fout->remoteVersion < 70200)
7507                 classoid = 0;
7508
7509         /*
7510          * Do binary search to find some item matching the object.
7511          */
7512         low = &comments[0];
7513         high = &comments[ncomments - 1];
7514         while (low <= high)
7515         {
7516                 middle = low + (high - low) / 2;
7517
7518                 if (classoid < middle->classoid)
7519                         high = middle - 1;
7520                 else if (classoid > middle->classoid)
7521                         low = middle + 1;
7522                 else if (objoid < middle->objoid)
7523                         high = middle - 1;
7524                 else if (objoid > middle->objoid)
7525                         low = middle + 1;
7526                 else
7527                         break;                          /* found a match */
7528         }
7529
7530         if (low > high)                         /* no matches */
7531         {
7532                 *items = NULL;
7533                 return 0;
7534         }
7535
7536         /*
7537          * Now determine how many items match the object.  The search loop
7538          * invariant still holds: only items between low and high inclusive could
7539          * match.
7540          */
7541         nmatch = 1;
7542         while (middle > low)
7543         {
7544                 if (classoid != middle[-1].classoid ||
7545                         objoid != middle[-1].objoid)
7546                         break;
7547                 middle--;
7548                 nmatch++;
7549         }
7550
7551         *items = middle;
7552
7553         middle += nmatch;
7554         while (middle <= high)
7555         {
7556                 if (classoid != middle->classoid ||
7557                         objoid != middle->objoid)
7558                         break;
7559                 middle++;
7560                 nmatch++;
7561         }
7562
7563         return nmatch;
7564 }
7565
7566 /*
7567  * collectComments --
7568  *
7569  * Construct a table of all comments available for database objects.
7570  * We used to do per-object queries for the comments, but it's much faster
7571  * to pull them all over at once, and on most databases the memory cost
7572  * isn't high.
7573  *
7574  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7575  */
7576 static int
7577 collectComments(Archive *fout, CommentItem **items)
7578 {
7579         PGresult   *res;
7580         PQExpBuffer query;
7581         int                     i_description;
7582         int                     i_classoid;
7583         int                     i_objoid;
7584         int                     i_objsubid;
7585         int                     ntups;
7586         int                     i;
7587         CommentItem *comments;
7588
7589         /*
7590          * Note we do NOT change source schema here; preserve the caller's
7591          * setting, instead.
7592          */
7593
7594         query = createPQExpBuffer();
7595
7596         if (fout->remoteVersion >= 70300)
7597         {
7598                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7599                                                   "FROM pg_catalog.pg_description "
7600                                                   "ORDER BY classoid, objoid, objsubid");
7601         }
7602         else if (fout->remoteVersion >= 70200)
7603         {
7604                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7605                                                   "FROM pg_description "
7606                                                   "ORDER BY classoid, objoid, objsubid");
7607         }
7608         else
7609         {
7610                 /* Note: this will fail to find attribute comments in pre-7.2... */
7611                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7612                                                   "FROM pg_description "
7613                                                   "ORDER BY objoid");
7614         }
7615
7616         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7617
7618         /* Construct lookup table containing OIDs in numeric form */
7619
7620         i_description = PQfnumber(res, "description");
7621         i_classoid = PQfnumber(res, "classoid");
7622         i_objoid = PQfnumber(res, "objoid");
7623         i_objsubid = PQfnumber(res, "objsubid");
7624
7625         ntups = PQntuples(res);
7626
7627         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7628
7629         for (i = 0; i < ntups; i++)
7630         {
7631                 comments[i].descr = PQgetvalue(res, i, i_description);
7632                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7633                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7634                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7635         }
7636
7637         /* Do NOT free the PGresult since we are keeping pointers into it */
7638         destroyPQExpBuffer(query);
7639
7640         *items = comments;
7641         return ntups;
7642 }
7643
7644 /*
7645  * dumpDumpableObject
7646  *
7647  * This routine and its subsidiaries are responsible for creating
7648  * ArchiveEntries (TOC objects) for each object to be dumped.
7649  */
7650 static void
7651 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7652 {
7653         switch (dobj->objType)
7654         {
7655                 case DO_NAMESPACE:
7656                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7657                         break;
7658                 case DO_EXTENSION:
7659                         dumpExtension(fout, (ExtensionInfo *) dobj);
7660                         break;
7661                 case DO_TYPE:
7662                         dumpType(fout, (TypeInfo *) dobj);
7663                         break;
7664                 case DO_SHELL_TYPE:
7665                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7666                         break;
7667                 case DO_FUNC:
7668                         dumpFunc(fout, (FuncInfo *) dobj);
7669                         break;
7670                 case DO_AGG:
7671                         dumpAgg(fout, (AggInfo *) dobj);
7672                         break;
7673                 case DO_OPERATOR:
7674                         dumpOpr(fout, (OprInfo *) dobj);
7675                         break;
7676                 case DO_OPCLASS:
7677                         dumpOpclass(fout, (OpclassInfo *) dobj);
7678                         break;
7679                 case DO_OPFAMILY:
7680                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7681                         break;
7682                 case DO_COLLATION:
7683                         dumpCollation(fout, (CollInfo *) dobj);
7684                         break;
7685                 case DO_CONVERSION:
7686                         dumpConversion(fout, (ConvInfo *) dobj);
7687                         break;
7688                 case DO_TABLE:
7689                         dumpTable(fout, (TableInfo *) dobj);
7690                         break;
7691                 case DO_ATTRDEF:
7692                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7693                         break;
7694                 case DO_INDEX:
7695                         dumpIndex(fout, (IndxInfo *) dobj);
7696                         break;
7697                 case DO_REFRESH_MATVIEW:
7698                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7699                         break;
7700                 case DO_RULE:
7701                         dumpRule(fout, (RuleInfo *) dobj);
7702                         break;
7703                 case DO_TRIGGER:
7704                         dumpTrigger(fout, (TriggerInfo *) dobj);
7705                         break;
7706                 case DO_EVENT_TRIGGER:
7707                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7708                         break;
7709                 case DO_CONSTRAINT:
7710                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7711                         break;
7712                 case DO_FK_CONSTRAINT:
7713                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7714                         break;
7715                 case DO_PROCLANG:
7716                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7717                         break;
7718                 case DO_CAST:
7719                         dumpCast(fout, (CastInfo *) dobj);
7720                         break;
7721                 case DO_TABLE_DATA:
7722                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7723                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7724                         else
7725                                 dumpTableData(fout, (TableDataInfo *) dobj);
7726                         break;
7727                 case DO_DUMMY_TYPE:
7728                         /* table rowtypes and array types are never dumped separately */
7729                         break;
7730                 case DO_TSPARSER:
7731                         dumpTSParser(fout, (TSParserInfo *) dobj);
7732                         break;
7733                 case DO_TSDICT:
7734                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7735                         break;
7736                 case DO_TSTEMPLATE:
7737                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7738                         break;
7739                 case DO_TSCONFIG:
7740                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7741                         break;
7742                 case DO_FDW:
7743                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7744                         break;
7745                 case DO_FOREIGN_SERVER:
7746                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7747                         break;
7748                 case DO_DEFAULT_ACL:
7749                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7750                         break;
7751                 case DO_BLOB:
7752                         dumpBlob(fout, (BlobInfo *) dobj);
7753                         break;
7754                 case DO_BLOB_DATA:
7755                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7756                                                  dobj->name, NULL, NULL, "",
7757                                                  false, "BLOBS", SECTION_DATA,
7758                                                  "", "", NULL,
7759                                                  NULL, 0,
7760                                                  dumpBlobs, NULL);
7761                         break;
7762                 case DO_PRE_DATA_BOUNDARY:
7763                 case DO_POST_DATA_BOUNDARY:
7764                         /* never dumped, nothing to do */
7765                         break;
7766         }
7767 }
7768
7769 /*
7770  * dumpNamespace
7771  *        writes out to fout the queries to recreate a user-defined namespace
7772  */
7773 static void
7774 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7775 {
7776         PQExpBuffer q;
7777         PQExpBuffer delq;
7778         PQExpBuffer labelq;
7779         char       *qnspname;
7780
7781         /* Skip if not to be dumped */
7782         if (!nspinfo->dobj.dump || dataOnly)
7783                 return;
7784
7785         /* don't dump dummy namespace from pre-7.3 source */
7786         if (strlen(nspinfo->dobj.name) == 0)
7787                 return;
7788
7789         q = createPQExpBuffer();
7790         delq = createPQExpBuffer();
7791         labelq = createPQExpBuffer();
7792
7793         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7794
7795         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7796
7797         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7798
7799         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7800
7801         if (binary_upgrade)
7802                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7803
7804         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7805                                  nspinfo->dobj.name,
7806                                  NULL, NULL,
7807                                  nspinfo->rolname,
7808                                  false, "SCHEMA", SECTION_PRE_DATA,
7809                                  q->data, delq->data, NULL,
7810                                  NULL, 0,
7811                                  NULL, NULL);
7812
7813         /* Dump Schema Comments and Security Labels */
7814         dumpComment(fout, labelq->data,
7815                                 NULL, nspinfo->rolname,
7816                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7817         dumpSecLabel(fout, labelq->data,
7818                                  NULL, nspinfo->rolname,
7819                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7820
7821         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7822                         qnspname, NULL, nspinfo->dobj.name, NULL,
7823                         nspinfo->rolname, nspinfo->nspacl);
7824
7825         free(qnspname);
7826
7827         destroyPQExpBuffer(q);
7828         destroyPQExpBuffer(delq);
7829         destroyPQExpBuffer(labelq);
7830 }
7831
7832 /*
7833  * dumpExtension
7834  *        writes out to fout the queries to recreate an extension
7835  */
7836 static void
7837 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7838 {
7839         PQExpBuffer q;
7840         PQExpBuffer delq;
7841         PQExpBuffer labelq;
7842         char       *qextname;
7843
7844         /* Skip if not to be dumped */
7845         if (!extinfo->dobj.dump || dataOnly)
7846                 return;
7847
7848         q = createPQExpBuffer();
7849         delq = createPQExpBuffer();
7850         labelq = createPQExpBuffer();
7851
7852         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7853
7854         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7855
7856         if (!binary_upgrade)
7857         {
7858                 /*
7859                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7860                  * problem if the extension already exists in the target database;
7861                  * this is essential for installed-by-default extensions such as
7862                  * plpgsql.
7863                  *
7864                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7865                  * built-in extensions based on their OIDs; see
7866                  * selectDumpableExtension.
7867                  */
7868                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7869                                                   qextname, fmtId(extinfo->namespace));
7870         }
7871         else
7872         {
7873                 int                     i;
7874                 int                     n;
7875
7876                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7877
7878                 /*
7879                  * We unconditionally create the extension, so we must drop it if it
7880                  * exists.      This could happen if the user deleted 'plpgsql' and then
7881                  * readded it, causing its oid to be greater than FirstNormalObjectId.
7882                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
7883                  * and recreating extensions like 'plpgsql'.
7884                  */
7885                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
7886
7887                 appendPQExpBuffer(q,
7888                                                   "SELECT binary_upgrade.create_empty_extension(");
7889                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7890                 appendPQExpBuffer(q, ", ");
7891                 appendStringLiteralAH(q, extinfo->namespace, fout);
7892                 appendPQExpBuffer(q, ", ");
7893                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7894                 appendStringLiteralAH(q, extinfo->extversion, fout);
7895                 appendPQExpBuffer(q, ", ");
7896
7897                 /*
7898                  * Note that we're pushing extconfig (an OID array) back into
7899                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7900                  * preserved in binary upgrade.
7901                  */
7902                 if (strlen(extinfo->extconfig) > 2)
7903                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7904                 else
7905                         appendPQExpBuffer(q, "NULL");
7906                 appendPQExpBuffer(q, ", ");
7907                 if (strlen(extinfo->extcondition) > 2)
7908                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7909                 else
7910                         appendPQExpBuffer(q, "NULL");
7911                 appendPQExpBuffer(q, ", ");
7912                 appendPQExpBuffer(q, "ARRAY[");
7913                 n = 0;
7914                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7915                 {
7916                         DumpableObject *extobj;
7917
7918                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7919                         if (extobj && extobj->objType == DO_EXTENSION)
7920                         {
7921                                 if (n++ > 0)
7922                                         appendPQExpBuffer(q, ",");
7923                                 appendStringLiteralAH(q, extobj->name, fout);
7924                         }
7925                 }
7926                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7927                 appendPQExpBuffer(q, ");\n");
7928         }
7929
7930         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7931
7932         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7933                                  extinfo->dobj.name,
7934                                  NULL, NULL,
7935                                  "",
7936                                  false, "EXTENSION", SECTION_PRE_DATA,
7937                                  q->data, delq->data, NULL,
7938                                  NULL, 0,
7939                                  NULL, NULL);
7940
7941         /* Dump Extension Comments and Security Labels */
7942         dumpComment(fout, labelq->data,
7943                                 NULL, "",
7944                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7945         dumpSecLabel(fout, labelq->data,
7946                                  NULL, "",
7947                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7948
7949         free(qextname);
7950
7951         destroyPQExpBuffer(q);
7952         destroyPQExpBuffer(delq);
7953         destroyPQExpBuffer(labelq);
7954 }
7955
7956 /*
7957  * dumpType
7958  *        writes out to fout the queries to recreate a user-defined type
7959  */
7960 static void
7961 dumpType(Archive *fout, TypeInfo *tyinfo)
7962 {
7963         /* Skip if not to be dumped */
7964         if (!tyinfo->dobj.dump || dataOnly)
7965                 return;
7966
7967         /* Dump out in proper style */
7968         if (tyinfo->typtype == TYPTYPE_BASE)
7969                 dumpBaseType(fout, tyinfo);
7970         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7971                 dumpDomain(fout, tyinfo);
7972         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7973                 dumpCompositeType(fout, tyinfo);
7974         else if (tyinfo->typtype == TYPTYPE_ENUM)
7975                 dumpEnumType(fout, tyinfo);
7976         else if (tyinfo->typtype == TYPTYPE_RANGE)
7977                 dumpRangeType(fout, tyinfo);
7978         else
7979                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7980                                   tyinfo->dobj.name);
7981 }
7982
7983 /*
7984  * dumpEnumType
7985  *        writes out to fout the queries to recreate a user-defined enum type
7986  */
7987 static void
7988 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7989 {
7990         PQExpBuffer q = createPQExpBuffer();
7991         PQExpBuffer delq = createPQExpBuffer();
7992         PQExpBuffer labelq = createPQExpBuffer();
7993         PQExpBuffer query = createPQExpBuffer();
7994         PGresult   *res;
7995         int                     num,
7996                                 i;
7997         Oid                     enum_oid;
7998         char       *qtypname;
7999         char       *label;
8000
8001         /* Set proper schema search path */
8002         selectSourceSchema(fout, "pg_catalog");
8003
8004         if (fout->remoteVersion >= 90100)
8005                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8006                                                   "FROM pg_catalog.pg_enum "
8007                                                   "WHERE enumtypid = '%u'"
8008                                                   "ORDER BY enumsortorder",
8009                                                   tyinfo->dobj.catId.oid);
8010         else
8011                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8012                                                   "FROM pg_catalog.pg_enum "
8013                                                   "WHERE enumtypid = '%u'"
8014                                                   "ORDER BY oid",
8015                                                   tyinfo->dobj.catId.oid);
8016
8017         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8018
8019         num = PQntuples(res);
8020
8021         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8022
8023         /*
8024          * DROP must be fully qualified in case same name appears in pg_catalog.
8025          * CASCADE shouldn't be required here as for normal types since the I/O
8026          * functions are generic and do not get dropped.
8027          */
8028         appendPQExpBuffer(delq, "DROP TYPE %s.",
8029                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8030         appendPQExpBuffer(delq, "%s;\n",
8031                                           qtypname);
8032
8033         if (binary_upgrade)
8034                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8035                                                                                                  tyinfo->dobj.catId.oid);
8036
8037         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8038                                           qtypname);
8039
8040         if (!binary_upgrade)
8041         {
8042                 /* Labels with server-assigned oids */
8043                 for (i = 0; i < num; i++)
8044                 {
8045                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8046                         if (i > 0)
8047                                 appendPQExpBuffer(q, ",");
8048                         appendPQExpBuffer(q, "\n    ");
8049                         appendStringLiteralAH(q, label, fout);
8050                 }
8051         }
8052
8053         appendPQExpBuffer(q, "\n);\n");
8054
8055         if (binary_upgrade)
8056         {
8057                 /* Labels with dump-assigned (preserved) oids */
8058                 for (i = 0; i < num; i++)
8059                 {
8060                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8061                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8062
8063                         if (i == 0)
8064                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8065                         appendPQExpBuffer(q,
8066                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8067                                                           enum_oid);
8068                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8069                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8070                         appendPQExpBuffer(q, "%s ADD VALUE ",
8071                                                           qtypname);
8072                         appendStringLiteralAH(q, label, fout);
8073                         appendPQExpBuffer(q, ";\n\n");
8074                 }
8075         }
8076
8077         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8078
8079         if (binary_upgrade)
8080                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8081
8082         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8083                                  tyinfo->dobj.name,
8084                                  tyinfo->dobj.namespace->dobj.name,
8085                                  NULL,
8086                                  tyinfo->rolname, false,
8087                                  "TYPE", SECTION_PRE_DATA,
8088                                  q->data, delq->data, NULL,
8089                                  NULL, 0,
8090                                  NULL, NULL);
8091
8092         /* Dump Type Comments and Security Labels */
8093         dumpComment(fout, labelq->data,
8094                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8095                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8096         dumpSecLabel(fout, labelq->data,
8097                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8098                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8099
8100         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8101                         qtypname, NULL, tyinfo->dobj.name,
8102                         tyinfo->dobj.namespace->dobj.name,
8103                         tyinfo->rolname, tyinfo->typacl);
8104
8105         PQclear(res);
8106         destroyPQExpBuffer(q);
8107         destroyPQExpBuffer(delq);
8108         destroyPQExpBuffer(labelq);
8109         destroyPQExpBuffer(query);
8110 }
8111
8112 /*
8113  * dumpRangeType
8114  *        writes out to fout the queries to recreate a user-defined range type
8115  */
8116 static void
8117 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8118 {
8119         PQExpBuffer q = createPQExpBuffer();
8120         PQExpBuffer delq = createPQExpBuffer();
8121         PQExpBuffer labelq = createPQExpBuffer();
8122         PQExpBuffer query = createPQExpBuffer();
8123         PGresult   *res;
8124         Oid                     collationOid;
8125         char       *qtypname;
8126         char       *procname;
8127
8128         /*
8129          * select appropriate schema to ensure names in CREATE are properly
8130          * qualified
8131          */
8132         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8133
8134         appendPQExpBuffer(query,
8135                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8136                                           "opc.opcname AS opcname, "
8137                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8138                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8139                                           "opc.opcdefault, "
8140                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8141                                           "     ELSE rngcollation END AS collation, "
8142                                           "rngcanonical, rngsubdiff "
8143                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8144                                           "     pg_catalog.pg_opclass opc "
8145                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8146                                           "rngtypid = '%u'",
8147                                           tyinfo->dobj.catId.oid);
8148
8149         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8150
8151         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8152
8153         /*
8154          * DROP must be fully qualified in case same name appears in pg_catalog.
8155          * CASCADE shouldn't be required here as for normal types since the I/O
8156          * functions are generic and do not get dropped.
8157          */
8158         appendPQExpBuffer(delq, "DROP TYPE %s.",
8159                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8160         appendPQExpBuffer(delq, "%s;\n",
8161                                           qtypname);
8162
8163         if (binary_upgrade)
8164                 binary_upgrade_set_type_oids_by_type_oid(fout,
8165                                                                                                  q, tyinfo->dobj.catId.oid);
8166
8167         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8168                                           qtypname);
8169
8170         appendPQExpBuffer(q, "\n    subtype = %s",
8171                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8172
8173         /* print subtype_opclass only if not default for subtype */
8174         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8175         {
8176                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8177                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8178
8179                 /* always schema-qualify, don't try to be smart */
8180                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8181                                                   fmtId(nspname));
8182                 appendPQExpBuffer(q, "%s", fmtId(opcname));
8183         }
8184
8185         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8186         if (OidIsValid(collationOid))
8187         {
8188                 CollInfo   *coll = findCollationByOid(collationOid);
8189
8190                 if (coll)
8191                 {
8192                         /* always schema-qualify, don't try to be smart */
8193                         appendPQExpBuffer(q, ",\n    collation = %s.",
8194                                                           fmtId(coll->dobj.namespace->dobj.name));
8195                         appendPQExpBuffer(q, "%s",
8196                                                           fmtId(coll->dobj.name));
8197                 }
8198         }
8199
8200         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8201         if (strcmp(procname, "-") != 0)
8202                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8203
8204         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8205         if (strcmp(procname, "-") != 0)
8206                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8207
8208         appendPQExpBuffer(q, "\n);\n");
8209
8210         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8211
8212         if (binary_upgrade)
8213                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8214
8215         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8216                                  tyinfo->dobj.name,
8217                                  tyinfo->dobj.namespace->dobj.name,
8218                                  NULL,
8219                                  tyinfo->rolname, false,
8220                                  "TYPE", SECTION_PRE_DATA,
8221                                  q->data, delq->data, NULL,
8222                                  NULL, 0,
8223                                  NULL, NULL);
8224
8225         /* Dump Type Comments and Security Labels */
8226         dumpComment(fout, labelq->data,
8227                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8228                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8229         dumpSecLabel(fout, labelq->data,
8230                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8231                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8232
8233         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8234                         qtypname, NULL, tyinfo->dobj.name,
8235                         tyinfo->dobj.namespace->dobj.name,
8236                         tyinfo->rolname, tyinfo->typacl);
8237
8238         PQclear(res);
8239         destroyPQExpBuffer(q);
8240         destroyPQExpBuffer(delq);
8241         destroyPQExpBuffer(labelq);
8242         destroyPQExpBuffer(query);
8243 }
8244
8245 /*
8246  * dumpBaseType
8247  *        writes out to fout the queries to recreate a user-defined base type
8248  */
8249 static void
8250 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8251 {
8252         PQExpBuffer q = createPQExpBuffer();
8253         PQExpBuffer delq = createPQExpBuffer();
8254         PQExpBuffer labelq = createPQExpBuffer();
8255         PQExpBuffer query = createPQExpBuffer();
8256         PGresult   *res;
8257         char       *qtypname;
8258         char       *typlen;
8259         char       *typinput;
8260         char       *typoutput;
8261         char       *typreceive;
8262         char       *typsend;
8263         char       *typmodin;
8264         char       *typmodout;
8265         char       *typanalyze;
8266         Oid                     typreceiveoid;
8267         Oid                     typsendoid;
8268         Oid                     typmodinoid;
8269         Oid                     typmodoutoid;
8270         Oid                     typanalyzeoid;
8271         char       *typcategory;
8272         char       *typispreferred;
8273         char       *typdelim;
8274         char       *typbyval;
8275         char       *typalign;
8276         char       *typstorage;
8277         char       *typcollatable;
8278         char       *typdefault;
8279         bool            typdefault_is_literal = false;
8280
8281         /* Set proper schema search path so regproc references list correctly */
8282         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8283
8284         /* Fetch type-specific details */
8285         if (fout->remoteVersion >= 90100)
8286         {
8287                 appendPQExpBuffer(query, "SELECT typlen, "
8288                                                   "typinput, typoutput, typreceive, typsend, "
8289                                                   "typmodin, typmodout, typanalyze, "
8290                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8291                                                   "typsend::pg_catalog.oid AS typsendoid, "
8292                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8293                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8294                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8295                                                   "typcategory, typispreferred, "
8296                                                   "typdelim, typbyval, typalign, typstorage, "
8297                                                   "(typcollation <> 0) AS typcollatable, "
8298                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8299                                                   "FROM pg_catalog.pg_type "
8300                                                   "WHERE oid = '%u'::pg_catalog.oid",
8301                                                   tyinfo->dobj.catId.oid);
8302         }
8303         else if (fout->remoteVersion >= 80400)
8304         {
8305                 appendPQExpBuffer(query, "SELECT typlen, "
8306                                                   "typinput, typoutput, typreceive, typsend, "
8307                                                   "typmodin, typmodout, typanalyze, "
8308                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8309                                                   "typsend::pg_catalog.oid AS typsendoid, "
8310                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8311                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8312                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8313                                                   "typcategory, typispreferred, "
8314                                                   "typdelim, typbyval, typalign, typstorage, "
8315                                                   "false AS typcollatable, "
8316                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8317                                                   "FROM pg_catalog.pg_type "
8318                                                   "WHERE oid = '%u'::pg_catalog.oid",
8319                                                   tyinfo->dobj.catId.oid);
8320         }
8321         else if (fout->remoteVersion >= 80300)
8322         {
8323                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8324                 appendPQExpBuffer(query, "SELECT typlen, "
8325                                                   "typinput, typoutput, typreceive, typsend, "
8326                                                   "typmodin, typmodout, typanalyze, "
8327                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8328                                                   "typsend::pg_catalog.oid AS typsendoid, "
8329                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8330                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8331                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8332                                                   "'U' AS typcategory, false AS typispreferred, "
8333                                                   "typdelim, typbyval, typalign, typstorage, "
8334                                                   "false AS typcollatable, "
8335                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8336                                                   "FROM pg_catalog.pg_type "
8337                                                   "WHERE oid = '%u'::pg_catalog.oid",
8338                                                   tyinfo->dobj.catId.oid);
8339         }
8340         else if (fout->remoteVersion >= 80000)
8341         {
8342                 appendPQExpBuffer(query, "SELECT typlen, "
8343                                                   "typinput, typoutput, typreceive, typsend, "
8344                                                   "'-' AS typmodin, '-' AS typmodout, "
8345                                                   "typanalyze, "
8346                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8347                                                   "typsend::pg_catalog.oid AS typsendoid, "
8348                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8349                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8350                                                   "'U' AS typcategory, false AS typispreferred, "
8351                                                   "typdelim, typbyval, typalign, typstorage, "
8352                                                   "false AS typcollatable, "
8353                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8354                                                   "FROM pg_catalog.pg_type "
8355                                                   "WHERE oid = '%u'::pg_catalog.oid",
8356                                                   tyinfo->dobj.catId.oid);
8357         }
8358         else if (fout->remoteVersion >= 70400)
8359         {
8360                 appendPQExpBuffer(query, "SELECT typlen, "
8361                                                   "typinput, typoutput, typreceive, typsend, "
8362                                                   "'-' AS typmodin, '-' AS typmodout, "
8363                                                   "'-' AS typanalyze, "
8364                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8365                                                   "typsend::pg_catalog.oid AS typsendoid, "
8366                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8367                                                   "0 AS typanalyzeoid, "
8368                                                   "'U' AS typcategory, false AS typispreferred, "
8369                                                   "typdelim, typbyval, typalign, typstorage, "
8370                                                   "false AS typcollatable, "
8371                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8372                                                   "FROM pg_catalog.pg_type "
8373                                                   "WHERE oid = '%u'::pg_catalog.oid",
8374                                                   tyinfo->dobj.catId.oid);
8375         }
8376         else if (fout->remoteVersion >= 70300)
8377         {
8378                 appendPQExpBuffer(query, "SELECT typlen, "
8379                                                   "typinput, typoutput, "
8380                                                   "'-' AS typreceive, '-' AS typsend, "
8381                                                   "'-' AS typmodin, '-' AS typmodout, "
8382                                                   "'-' AS typanalyze, "
8383                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8384                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8385                                                   "0 AS typanalyzeoid, "
8386                                                   "'U' AS typcategory, false AS typispreferred, "
8387                                                   "typdelim, typbyval, typalign, typstorage, "
8388                                                   "false AS typcollatable, "
8389                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8390                                                   "FROM pg_catalog.pg_type "
8391                                                   "WHERE oid = '%u'::pg_catalog.oid",
8392                                                   tyinfo->dobj.catId.oid);
8393         }
8394         else if (fout->remoteVersion >= 70200)
8395         {
8396                 /*
8397                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8398                  * ignore them because they are not right.
8399                  */
8400                 appendPQExpBuffer(query, "SELECT typlen, "
8401                                                   "typinput, typoutput, "
8402                                                   "'-' AS typreceive, '-' AS typsend, "
8403                                                   "'-' AS typmodin, '-' AS typmodout, "
8404                                                   "'-' AS typanalyze, "
8405                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8406                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8407                                                   "0 AS typanalyzeoid, "
8408                                                   "'U' AS typcategory, false AS typispreferred, "
8409                                                   "typdelim, typbyval, typalign, typstorage, "
8410                                                   "false AS typcollatable, "
8411                                                   "NULL AS typdefaultbin, typdefault "
8412                                                   "FROM pg_type "
8413                                                   "WHERE oid = '%u'::oid",
8414                                                   tyinfo->dobj.catId.oid);
8415         }
8416         else if (fout->remoteVersion >= 70100)
8417         {
8418                 /*
8419                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8420                  * representation.
8421                  */
8422                 appendPQExpBuffer(query, "SELECT typlen, "
8423                                                   "typinput, typoutput, "
8424                                                   "'-' AS typreceive, '-' AS typsend, "
8425                                                   "'-' AS typmodin, '-' AS typmodout, "
8426                                                   "'-' AS typanalyze, "
8427                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8428                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8429                                                   "0 AS typanalyzeoid, "
8430                                                   "'U' AS typcategory, false AS typispreferred, "
8431                                                   "typdelim, typbyval, typalign, typstorage, "
8432                                                   "false AS typcollatable, "
8433                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8434                                                   "FROM pg_type "
8435                                                   "WHERE oid = '%u'::oid",
8436                                                   tyinfo->dobj.catId.oid);
8437         }
8438         else
8439         {
8440                 appendPQExpBuffer(query, "SELECT typlen, "
8441                                                   "typinput, typoutput, "
8442                                                   "'-' AS typreceive, '-' AS typsend, "
8443                                                   "'-' AS typmodin, '-' AS typmodout, "
8444                                                   "'-' AS typanalyze, "
8445                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8446                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8447                                                   "0 AS typanalyzeoid, "
8448                                                   "'U' AS typcategory, false AS typispreferred, "
8449                                                   "typdelim, typbyval, typalign, "
8450                                                   "'p'::char AS typstorage, "
8451                                                   "false AS typcollatable, "
8452                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8453                                                   "FROM pg_type "
8454                                                   "WHERE oid = '%u'::oid",
8455                                                   tyinfo->dobj.catId.oid);
8456         }
8457
8458         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8459
8460         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8461         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8462         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8463         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8464         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8465         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8466         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8467         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8468         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8469         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8470         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8471         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8472         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8473         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8474         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8475         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8476         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8477         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8478         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8479         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8480         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8481                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8482         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8483         {
8484                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8485                 typdefault_is_literal = true;   /* it needs quotes */
8486         }
8487         else
8488                 typdefault = NULL;
8489
8490         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8491
8492         /*
8493          * DROP must be fully qualified in case same name appears in pg_catalog.
8494          * The reason we include CASCADE is that the circular dependency between
8495          * the type and its I/O functions makes it impossible to drop the type any
8496          * other way.
8497          */
8498         appendPQExpBuffer(delq, "DROP TYPE %s.",
8499                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8500         appendPQExpBuffer(delq, "%s CASCADE;\n",
8501                                           qtypname);
8502
8503         /* We might already have a shell type, but setting pg_type_oid is harmless */
8504         if (binary_upgrade)
8505                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8506                                                                                                  tyinfo->dobj.catId.oid);
8507
8508         appendPQExpBuffer(q,
8509                                           "CREATE TYPE %s (\n"
8510                                           "    INTERNALLENGTH = %s",
8511                                           qtypname,
8512                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8513
8514         if (fout->remoteVersion >= 70300)
8515         {
8516                 /* regproc result is correctly quoted as of 7.3 */
8517                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8518                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8519                 if (OidIsValid(typreceiveoid))
8520                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8521                 if (OidIsValid(typsendoid))
8522                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8523                 if (OidIsValid(typmodinoid))
8524                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8525                 if (OidIsValid(typmodoutoid))
8526                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8527                 if (OidIsValid(typanalyzeoid))
8528                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8529         }
8530         else
8531         {
8532                 /* regproc delivers an unquoted name before 7.3 */
8533                 /* cannot combine these because fmtId uses static result area */
8534                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8535                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8536                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8537         }
8538
8539         if (strcmp(typcollatable, "t") == 0)
8540                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8541
8542         if (typdefault != NULL)
8543         {
8544                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8545                 if (typdefault_is_literal)
8546                         appendStringLiteralAH(q, typdefault, fout);
8547                 else
8548                         appendPQExpBufferStr(q, typdefault);
8549         }
8550
8551         if (OidIsValid(tyinfo->typelem))
8552         {
8553                 char       *elemType;
8554
8555                 /* reselect schema in case changed by function dump */
8556                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8557                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8558                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8559                 free(elemType);
8560         }
8561
8562         if (strcmp(typcategory, "U") != 0)
8563         {
8564                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8565                 appendStringLiteralAH(q, typcategory, fout);
8566         }
8567
8568         if (strcmp(typispreferred, "t") == 0)
8569                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8570
8571         if (typdelim && strcmp(typdelim, ",") != 0)
8572         {
8573                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8574                 appendStringLiteralAH(q, typdelim, fout);
8575         }
8576
8577         if (strcmp(typalign, "c") == 0)
8578                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8579         else if (strcmp(typalign, "s") == 0)
8580                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8581         else if (strcmp(typalign, "i") == 0)
8582                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8583         else if (strcmp(typalign, "d") == 0)
8584                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8585
8586         if (strcmp(typstorage, "p") == 0)
8587                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8588         else if (strcmp(typstorage, "e") == 0)
8589                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8590         else if (strcmp(typstorage, "x") == 0)
8591                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8592         else if (strcmp(typstorage, "m") == 0)
8593                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8594
8595         if (strcmp(typbyval, "t") == 0)
8596                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8597
8598         appendPQExpBuffer(q, "\n);\n");
8599
8600         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8601
8602         if (binary_upgrade)
8603                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8604
8605         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8606                                  tyinfo->dobj.name,
8607                                  tyinfo->dobj.namespace->dobj.name,
8608                                  NULL,
8609                                  tyinfo->rolname, false,
8610                                  "TYPE", SECTION_PRE_DATA,
8611                                  q->data, delq->data, NULL,
8612                                  NULL, 0,
8613                                  NULL, NULL);
8614
8615         /* Dump Type Comments and Security Labels */
8616         dumpComment(fout, labelq->data,
8617                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8618                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8619         dumpSecLabel(fout, labelq->data,
8620                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8621                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8622
8623         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8624                         qtypname, NULL, tyinfo->dobj.name,
8625                         tyinfo->dobj.namespace->dobj.name,
8626                         tyinfo->rolname, tyinfo->typacl);
8627
8628         PQclear(res);
8629         destroyPQExpBuffer(q);
8630         destroyPQExpBuffer(delq);
8631         destroyPQExpBuffer(labelq);
8632         destroyPQExpBuffer(query);
8633 }
8634
8635 /*
8636  * dumpDomain
8637  *        writes out to fout the queries to recreate a user-defined domain
8638  */
8639 static void
8640 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8641 {
8642         PQExpBuffer q = createPQExpBuffer();
8643         PQExpBuffer delq = createPQExpBuffer();
8644         PQExpBuffer labelq = createPQExpBuffer();
8645         PQExpBuffer query = createPQExpBuffer();
8646         PGresult   *res;
8647         int                     i;
8648         char       *qtypname;
8649         char       *typnotnull;
8650         char       *typdefn;
8651         char       *typdefault;
8652         Oid                     typcollation;
8653         bool            typdefault_is_literal = false;
8654
8655         /* Set proper schema search path so type references list correctly */
8656         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8657
8658         /* Fetch domain specific details */
8659         if (fout->remoteVersion >= 90100)
8660         {
8661                 /* typcollation is new in 9.1 */
8662                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8663                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8664                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8665                                                   "t.typdefault, "
8666                                                   "CASE WHEN t.typcollation <> u.typcollation "
8667                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8668                                                   "FROM pg_catalog.pg_type t "
8669                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8670                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8671                                                   tyinfo->dobj.catId.oid);
8672         }
8673         else
8674         {
8675                 /* We assume here that remoteVersion must be at least 70300 */
8676                 appendPQExpBuffer(query, "SELECT typnotnull, "
8677                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8678                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8679                                                   "typdefault, 0 AS typcollation "
8680                                                   "FROM pg_catalog.pg_type "
8681                                                   "WHERE oid = '%u'::pg_catalog.oid",
8682                                                   tyinfo->dobj.catId.oid);
8683         }
8684
8685         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8686
8687         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8688         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8689         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8690                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8691         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8692         {
8693                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8694                 typdefault_is_literal = true;   /* it needs quotes */
8695         }
8696         else
8697                 typdefault = NULL;
8698         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8699
8700         if (binary_upgrade)
8701                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8702                                                                                                  tyinfo->dobj.catId.oid);
8703
8704         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8705
8706         appendPQExpBuffer(q,
8707                                           "CREATE DOMAIN %s AS %s",
8708                                           qtypname,
8709                                           typdefn);
8710
8711         /* Print collation only if different from base type's collation */
8712         if (OidIsValid(typcollation))
8713         {
8714                 CollInfo   *coll;
8715
8716                 coll = findCollationByOid(typcollation);
8717                 if (coll)
8718                 {
8719                         /* always schema-qualify, don't try to be smart */
8720                         appendPQExpBuffer(q, " COLLATE %s.",
8721                                                           fmtId(coll->dobj.namespace->dobj.name));
8722                         appendPQExpBuffer(q, "%s",
8723                                                           fmtId(coll->dobj.name));
8724                 }
8725         }
8726
8727         if (typnotnull[0] == 't')
8728                 appendPQExpBuffer(q, " NOT NULL");
8729
8730         if (typdefault != NULL)
8731         {
8732                 appendPQExpBuffer(q, " DEFAULT ");
8733                 if (typdefault_is_literal)
8734                         appendStringLiteralAH(q, typdefault, fout);
8735                 else
8736                         appendPQExpBufferStr(q, typdefault);
8737         }
8738
8739         PQclear(res);
8740
8741         /*
8742          * Add any CHECK constraints for the domain
8743          */
8744         for (i = 0; i < tyinfo->nDomChecks; i++)
8745         {
8746                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8747
8748                 if (!domcheck->separate)
8749                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8750                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8751         }
8752
8753         appendPQExpBuffer(q, ";\n");
8754
8755         /*
8756          * DROP must be fully qualified in case same name appears in pg_catalog
8757          */
8758         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8759                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8760         appendPQExpBuffer(delq, "%s;\n",
8761                                           qtypname);
8762
8763         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8764
8765         if (binary_upgrade)
8766                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8767
8768         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8769                                  tyinfo->dobj.name,
8770                                  tyinfo->dobj.namespace->dobj.name,
8771                                  NULL,
8772                                  tyinfo->rolname, false,
8773                                  "DOMAIN", SECTION_PRE_DATA,
8774                                  q->data, delq->data, NULL,
8775                                  NULL, 0,
8776                                  NULL, NULL);
8777
8778         /* Dump Domain Comments and Security Labels */
8779         dumpComment(fout, labelq->data,
8780                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8781                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8782         dumpSecLabel(fout, labelq->data,
8783                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8784                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8785
8786         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8787                         qtypname, NULL, tyinfo->dobj.name,
8788                         tyinfo->dobj.namespace->dobj.name,
8789                         tyinfo->rolname, tyinfo->typacl);
8790
8791         destroyPQExpBuffer(q);
8792         destroyPQExpBuffer(delq);
8793         destroyPQExpBuffer(labelq);
8794         destroyPQExpBuffer(query);
8795 }
8796
8797 /*
8798  * dumpCompositeType
8799  *        writes out to fout the queries to recreate a user-defined stand-alone
8800  *        composite type
8801  */
8802 static void
8803 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8804 {
8805         PQExpBuffer q = createPQExpBuffer();
8806         PQExpBuffer dropped = createPQExpBuffer();
8807         PQExpBuffer delq = createPQExpBuffer();
8808         PQExpBuffer labelq = createPQExpBuffer();
8809         PQExpBuffer query = createPQExpBuffer();
8810         PGresult   *res;
8811         char       *qtypname;
8812         int                     ntups;
8813         int                     i_attname;
8814         int                     i_atttypdefn;
8815         int                     i_attlen;
8816         int                     i_attalign;
8817         int                     i_attisdropped;
8818         int                     i_attcollation;
8819         int                     i_typrelid;
8820         int                     i;
8821         int                     actual_atts;
8822
8823         /* Set proper schema search path so type references list correctly */
8824         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8825
8826         /* Fetch type specific details */
8827         if (fout->remoteVersion >= 90100)
8828         {
8829                 /*
8830                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8831                  * clauses for attributes whose collation is different from their
8832                  * type's default, we use a CASE here to suppress uninteresting
8833                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8834                  * collation does not matter for those.
8835                  */
8836                 appendPQExpBuffer(query, "SELECT a.attname, "
8837                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8838                                                   "a.attlen, a.attalign, a.attisdropped, "
8839                                                   "CASE WHEN a.attcollation <> at.typcollation "
8840                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8841                                                   "ct.typrelid "
8842                                                   "FROM pg_catalog.pg_type ct "
8843                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8844                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8845                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8846                                                   "ORDER BY a.attnum ",
8847                                                   tyinfo->dobj.catId.oid);
8848         }
8849         else
8850         {
8851                 /*
8852                  * We assume here that remoteVersion must be at least 70300.  Since
8853                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8854                  * always be false.
8855                  */
8856                 appendPQExpBuffer(query, "SELECT a.attname, "
8857                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8858                                                   "a.attlen, a.attalign, a.attisdropped, "
8859                                                   "0 AS attcollation, "
8860                                                   "ct.typrelid "
8861                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8862                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8863                                                   "AND a.attrelid = ct.typrelid "
8864                                                   "ORDER BY a.attnum ",
8865                                                   tyinfo->dobj.catId.oid);
8866         }
8867
8868         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8869
8870         ntups = PQntuples(res);
8871
8872         i_attname = PQfnumber(res, "attname");
8873         i_atttypdefn = PQfnumber(res, "atttypdefn");
8874         i_attlen = PQfnumber(res, "attlen");
8875         i_attalign = PQfnumber(res, "attalign");
8876         i_attisdropped = PQfnumber(res, "attisdropped");
8877         i_attcollation = PQfnumber(res, "attcollation");
8878         i_typrelid = PQfnumber(res, "typrelid");
8879
8880         if (binary_upgrade)
8881         {
8882                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8883
8884                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8885                                                                                                  tyinfo->dobj.catId.oid);
8886                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8887         }
8888
8889         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8890
8891         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8892                                           qtypname);
8893
8894         actual_atts = 0;
8895         for (i = 0; i < ntups; i++)
8896         {
8897                 char       *attname;
8898                 char       *atttypdefn;
8899                 char       *attlen;
8900                 char       *attalign;
8901                 bool            attisdropped;
8902                 Oid                     attcollation;
8903
8904                 attname = PQgetvalue(res, i, i_attname);
8905                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8906                 attlen = PQgetvalue(res, i, i_attlen);
8907                 attalign = PQgetvalue(res, i, i_attalign);
8908                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8909                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8910
8911                 if (attisdropped && !binary_upgrade)
8912                         continue;
8913
8914                 /* Format properly if not first attr */
8915                 if (actual_atts++ > 0)
8916                         appendPQExpBuffer(q, ",");
8917                 appendPQExpBuffer(q, "\n\t");
8918
8919                 if (!attisdropped)
8920                 {
8921                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8922
8923                         /* Add collation if not default for the column type */
8924                         if (OidIsValid(attcollation))
8925                         {
8926                                 CollInfo   *coll;
8927
8928                                 coll = findCollationByOid(attcollation);
8929                                 if (coll)
8930                                 {
8931                                         /* always schema-qualify, don't try to be smart */
8932                                         appendPQExpBuffer(q, " COLLATE %s.",
8933                                                                           fmtId(coll->dobj.namespace->dobj.name));
8934                                         appendPQExpBuffer(q, "%s",
8935                                                                           fmtId(coll->dobj.name));
8936                                 }
8937                         }
8938                 }
8939                 else
8940                 {
8941                         /*
8942                          * This is a dropped attribute and we're in binary_upgrade mode.
8943                          * Insert a placeholder for it in the CREATE TYPE command, and set
8944                          * length and alignment with direct UPDATE to the catalogs
8945                          * afterwards. See similar code in dumpTableSchema().
8946                          */
8947                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8948
8949                         /* stash separately for insertion after the CREATE TYPE */
8950                         appendPQExpBuffer(dropped,
8951                                           "\n-- For binary upgrade, recreate dropped column.\n");
8952                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8953                                                           "SET attlen = %s, "
8954                                                           "attalign = '%s', attbyval = false\n"
8955                                                           "WHERE attname = ", attlen, attalign);
8956                         appendStringLiteralAH(dropped, attname, fout);
8957                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8958                         appendStringLiteralAH(dropped, qtypname, fout);
8959                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8960
8961                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8962                                                           qtypname);
8963                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8964                                                           fmtId(attname));
8965                 }
8966         }
8967         appendPQExpBuffer(q, "\n);\n");
8968         appendPQExpBufferStr(q, dropped->data);
8969
8970         /*
8971          * DROP must be fully qualified in case same name appears in pg_catalog
8972          */
8973         appendPQExpBuffer(delq, "DROP TYPE %s.",
8974                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8975         appendPQExpBuffer(delq, "%s;\n",
8976                                           qtypname);
8977
8978         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8979
8980         if (binary_upgrade)
8981                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8982
8983         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8984                                  tyinfo->dobj.name,
8985                                  tyinfo->dobj.namespace->dobj.name,
8986                                  NULL,
8987                                  tyinfo->rolname, false,
8988                                  "TYPE", SECTION_PRE_DATA,
8989                                  q->data, delq->data, NULL,
8990                                  NULL, 0,
8991                                  NULL, NULL);
8992
8993
8994         /* Dump Type Comments and Security Labels */
8995         dumpComment(fout, labelq->data,
8996                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8997                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8998         dumpSecLabel(fout, labelq->data,
8999                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9000                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9001
9002         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9003                         qtypname, NULL, tyinfo->dobj.name,
9004                         tyinfo->dobj.namespace->dobj.name,
9005                         tyinfo->rolname, tyinfo->typacl);
9006
9007         PQclear(res);
9008         destroyPQExpBuffer(q);
9009         destroyPQExpBuffer(dropped);
9010         destroyPQExpBuffer(delq);
9011         destroyPQExpBuffer(labelq);
9012         destroyPQExpBuffer(query);
9013
9014         /* Dump any per-column comments */
9015         dumpCompositeTypeColComments(fout, tyinfo);
9016 }
9017
9018 /*
9019  * dumpCompositeTypeColComments
9020  *        writes out to fout the queries to recreate comments on the columns of
9021  *        a user-defined stand-alone composite type
9022  */
9023 static void
9024 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9025 {
9026         CommentItem *comments;
9027         int                     ncomments;
9028         PGresult   *res;
9029         PQExpBuffer query;
9030         PQExpBuffer target;
9031         Oid                     pgClassOid;
9032         int                     i;
9033         int                     ntups;
9034         int                     i_attname;
9035         int                     i_attnum;
9036
9037         query = createPQExpBuffer();
9038
9039         /* We assume here that remoteVersion must be at least 70300 */
9040         appendPQExpBuffer(query,
9041                                           "SELECT c.tableoid, a.attname, a.attnum "
9042                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9043                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9044                                           "  AND NOT a.attisdropped "
9045                                           "ORDER BY a.attnum ",
9046                                           tyinfo->typrelid);
9047
9048         /* Fetch column attnames */
9049         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9050
9051         ntups = PQntuples(res);
9052         if (ntups < 1)
9053         {
9054                 PQclear(res);
9055                 destroyPQExpBuffer(query);
9056                 return;
9057         }
9058
9059         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9060
9061         /* Search for comments associated with type's pg_class OID */
9062         ncomments = findComments(fout,
9063                                                          pgClassOid,
9064                                                          tyinfo->typrelid,
9065                                                          &comments);
9066
9067         /* If no comments exist, we're done */
9068         if (ncomments <= 0)
9069         {
9070                 PQclear(res);
9071                 destroyPQExpBuffer(query);
9072                 return;
9073         }
9074
9075         /* Build COMMENT ON statements */
9076         target = createPQExpBuffer();
9077
9078         i_attnum = PQfnumber(res, "attnum");
9079         i_attname = PQfnumber(res, "attname");
9080         while (ncomments > 0)
9081         {
9082                 const char *attname;
9083
9084                 attname = NULL;
9085                 for (i = 0; i < ntups; i++)
9086                 {
9087                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9088                         {
9089                                 attname = PQgetvalue(res, i, i_attname);
9090                                 break;
9091                         }
9092                 }
9093                 if (attname)                    /* just in case we don't find it */
9094                 {
9095                         const char *descr = comments->descr;
9096
9097                         resetPQExpBuffer(target);
9098                         appendPQExpBuffer(target, "COLUMN %s.",
9099                                                           fmtId(tyinfo->dobj.name));
9100                         appendPQExpBuffer(target, "%s",
9101                                                           fmtId(attname));
9102
9103                         resetPQExpBuffer(query);
9104                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9105                         appendStringLiteralAH(query, descr, fout);
9106                         appendPQExpBuffer(query, ";\n");
9107
9108                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9109                                                  target->data,
9110                                                  tyinfo->dobj.namespace->dobj.name,
9111                                                  NULL, tyinfo->rolname,
9112                                                  false, "COMMENT", SECTION_NONE,
9113                                                  query->data, "", NULL,
9114                                                  &(tyinfo->dobj.dumpId), 1,
9115                                                  NULL, NULL);
9116                 }
9117
9118                 comments++;
9119                 ncomments--;
9120         }
9121
9122         PQclear(res);
9123         destroyPQExpBuffer(query);
9124         destroyPQExpBuffer(target);
9125 }
9126
9127 /*
9128  * dumpShellType
9129  *        writes out to fout the queries to create a shell type
9130  *
9131  * We dump a shell definition in advance of the I/O functions for the type.
9132  */
9133 static void
9134 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9135 {
9136         PQExpBuffer q;
9137
9138         /* Skip if not to be dumped */
9139         if (!stinfo->dobj.dump || dataOnly)
9140                 return;
9141
9142         q = createPQExpBuffer();
9143
9144         /*
9145          * Note the lack of a DROP command for the shell type; any required DROP
9146          * is driven off the base type entry, instead.  This interacts with
9147          * _printTocEntry()'s use of the presence of a DROP command to decide
9148          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9149          * the shell type's owner immediately on creation; that should happen only
9150          * after it's filled in, otherwise the backend complains.
9151          */
9152
9153         if (binary_upgrade)
9154                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9155                                                                                    stinfo->baseType->dobj.catId.oid);
9156
9157         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9158                                           fmtId(stinfo->dobj.name));
9159
9160         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9161                                  stinfo->dobj.name,
9162                                  stinfo->dobj.namespace->dobj.name,
9163                                  NULL,
9164                                  stinfo->baseType->rolname, false,
9165                                  "SHELL TYPE", SECTION_PRE_DATA,
9166                                  q->data, "", NULL,
9167                                  NULL, 0,
9168                                  NULL, NULL);
9169
9170         destroyPQExpBuffer(q);
9171 }
9172
9173 /*
9174  * Determine whether we want to dump definitions for procedural languages.
9175  * Since the languages themselves don't have schemas, we can't rely on
9176  * the normal schema-based selection mechanism.  We choose to dump them
9177  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9178  * the dump flag of the PL's call handler function, but in 8.1 this will
9179  * probably always be false since call handlers are created in pg_catalog.)
9180  *
9181  * For some backwards compatibility with the older behavior, we forcibly
9182  * dump a PL if its handler function (and validator if any) are in a
9183  * dumpable namespace.  That case is not checked here.
9184  *
9185  * Also, if the PL belongs to an extension, we do not use this heuristic.
9186  * That case isn't checked here either.
9187  */
9188 static bool
9189 shouldDumpProcLangs(void)
9190 {
9191         if (!include_everything)
9192                 return false;
9193         /* And they're schema not data */
9194         if (dataOnly)
9195                 return false;
9196         return true;
9197 }
9198
9199 /*
9200  * dumpProcLang
9201  *                writes out to fout the queries to recreate a user-defined
9202  *                procedural language
9203  */
9204 static void
9205 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9206 {
9207         PQExpBuffer defqry;
9208         PQExpBuffer delqry;
9209         PQExpBuffer labelq;
9210         bool            useParams;
9211         char       *qlanname;
9212         char       *lanschema;
9213         FuncInfo   *funcInfo;
9214         FuncInfo   *inlineInfo = NULL;
9215         FuncInfo   *validatorInfo = NULL;
9216
9217         /* Skip if not to be dumped */
9218         if (!plang->dobj.dump || dataOnly)
9219                 return;
9220
9221         /*
9222          * Try to find the support function(s).  It is not an error if we don't
9223          * find them --- if the functions are in the pg_catalog schema, as is
9224          * standard in 8.1 and up, then we won't have loaded them. (In this case
9225          * we will emit a parameterless CREATE LANGUAGE command, which will
9226          * require PL template knowledge in the backend to reload.)
9227          */
9228
9229         funcInfo = findFuncByOid(plang->lanplcallfoid);
9230         if (funcInfo != NULL && !funcInfo->dobj.dump)
9231                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9232
9233         if (OidIsValid(plang->laninline))
9234         {
9235                 inlineInfo = findFuncByOid(plang->laninline);
9236                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9237                         inlineInfo = NULL;
9238         }
9239
9240         if (OidIsValid(plang->lanvalidator))
9241         {
9242                 validatorInfo = findFuncByOid(plang->lanvalidator);
9243                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9244                         validatorInfo = NULL;
9245         }
9246
9247         /*
9248          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9249          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9250          * dump it.
9251          *
9252          * However, for a language that belongs to an extension, we must not use
9253          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9254          * told to (via dobj.dump).  Generally the support functions will belong
9255          * to the same extension and so have the same dump flags ... if they
9256          * don't, this might not work terribly nicely.
9257          */
9258         useParams = (funcInfo != NULL &&
9259                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9260                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9261
9262         if (!plang->dobj.ext_member)
9263         {
9264                 if (!useParams && !shouldDumpProcLangs())
9265                         return;
9266         }
9267
9268         defqry = createPQExpBuffer();
9269         delqry = createPQExpBuffer();
9270         labelq = createPQExpBuffer();
9271
9272         qlanname = pg_strdup(fmtId(plang->dobj.name));
9273
9274         /*
9275          * If dumping a HANDLER clause, treat the language as being in the handler
9276          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9277          * it doesn't really have a schema.
9278          */
9279         if (useParams)
9280                 lanschema = funcInfo->dobj.namespace->dobj.name;
9281         else
9282                 lanschema = NULL;
9283
9284         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9285                                           qlanname);
9286
9287         if (useParams)
9288         {
9289                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9290                                                   plang->lanpltrusted ? "TRUSTED " : "",
9291                                                   qlanname);
9292                 appendPQExpBuffer(defqry, " HANDLER %s",
9293                                                   fmtId(funcInfo->dobj.name));
9294                 if (OidIsValid(plang->laninline))
9295                 {
9296                         appendPQExpBuffer(defqry, " INLINE ");
9297                         /* Cope with possibility that inline is in different schema */
9298                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9299                                 appendPQExpBuffer(defqry, "%s.",
9300                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9301                         appendPQExpBuffer(defqry, "%s",
9302                                                           fmtId(inlineInfo->dobj.name));
9303                 }
9304                 if (OidIsValid(plang->lanvalidator))
9305                 {
9306                         appendPQExpBuffer(defqry, " VALIDATOR ");
9307                         /* Cope with possibility that validator is in different schema */
9308                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9309                                 appendPQExpBuffer(defqry, "%s.",
9310                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9311                         appendPQExpBuffer(defqry, "%s",
9312                                                           fmtId(validatorInfo->dobj.name));
9313                 }
9314         }
9315         else
9316         {
9317                 /*
9318                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9319                  * command will not fail if the language is preinstalled in the target
9320                  * database.  We restrict the use of REPLACE to this case so as to
9321                  * eliminate the risk of replacing a language with incompatible
9322                  * parameter settings: this command will only succeed at all if there
9323                  * is a pg_pltemplate entry, and if there is one, the existing entry
9324                  * must match it too.
9325                  */
9326                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9327                                                   qlanname);
9328         }
9329         appendPQExpBuffer(defqry, ";\n");
9330
9331         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9332
9333         if (binary_upgrade)
9334                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9335
9336         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9337                                  plang->dobj.name,
9338                                  lanschema, NULL, plang->lanowner,
9339                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9340                                  defqry->data, delqry->data, NULL,
9341                                  NULL, 0,
9342                                  NULL, NULL);
9343
9344         /* Dump Proc Lang Comments and Security Labels */
9345         dumpComment(fout, labelq->data,
9346                                 NULL, "",
9347                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9348         dumpSecLabel(fout, labelq->data,
9349                                  NULL, "",
9350                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9351
9352         if (plang->lanpltrusted)
9353                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9354                                 qlanname, NULL, plang->dobj.name,
9355                                 lanschema,
9356                                 plang->lanowner, plang->lanacl);
9357
9358         free(qlanname);
9359
9360         destroyPQExpBuffer(defqry);
9361         destroyPQExpBuffer(delqry);
9362         destroyPQExpBuffer(labelq);
9363 }
9364
9365 /*
9366  * format_function_arguments: generate function name and argument list
9367  *
9368  * This is used when we can rely on pg_get_function_arguments to format
9369  * the argument list.  Note, however, that pg_get_function_arguments
9370  * does not special-case zero-argument aggregates.
9371  */
9372 static char *
9373 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
9374 {
9375         PQExpBufferData fn;
9376
9377         initPQExpBuffer(&fn);
9378         appendPQExpBuffer(&fn, "%s", fmtId(finfo->dobj.name));
9379         if (is_agg && finfo->nargs == 0)
9380                 appendPQExpBuffer(&fn, "(*)");
9381         else
9382                 appendPQExpBuffer(&fn, "(%s)", funcargs);
9383         return fn.data;
9384 }
9385
9386 /*
9387  * format_function_arguments_old: generate function name and argument list
9388  *
9389  * The argument type names are qualified if needed.  The function name
9390  * is never qualified.
9391  *
9392  * This is used only with pre-8.4 servers, so we aren't expecting to see
9393  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9394  *
9395  * Any or all of allargtypes, argmodes, argnames may be NULL.
9396  */
9397 static char *
9398 format_function_arguments_old(Archive *fout,
9399                                                           FuncInfo *finfo, int nallargs,
9400                                                           char **allargtypes,
9401                                                           char **argmodes,
9402                                                           char **argnames)
9403 {
9404         PQExpBufferData fn;
9405         int                     j;
9406
9407         initPQExpBuffer(&fn);
9408         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9409         for (j = 0; j < nallargs; j++)
9410         {
9411                 Oid                     typid;
9412                 char       *typname;
9413                 const char *argmode;
9414                 const char *argname;
9415
9416                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9417                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9418
9419                 if (argmodes)
9420                 {
9421                         switch (argmodes[j][0])
9422                         {
9423                                 case PROARGMODE_IN:
9424                                         argmode = "";
9425                                         break;
9426                                 case PROARGMODE_OUT:
9427                                         argmode = "OUT ";
9428                                         break;
9429                                 case PROARGMODE_INOUT:
9430                                         argmode = "INOUT ";
9431                                         break;
9432                                 default:
9433                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9434                                         argmode = "";
9435                                         break;
9436                         }
9437                 }
9438                 else
9439                         argmode = "";
9440
9441                 argname = argnames ? argnames[j] : (char *) NULL;
9442                 if (argname && argname[0] == '\0')
9443                         argname = NULL;
9444
9445                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9446                                                   (j > 0) ? ", " : "",
9447                                                   argmode,
9448                                                   argname ? fmtId(argname) : "",
9449                                                   argname ? " " : "",
9450                                                   typname);
9451                 free(typname);
9452         }
9453         appendPQExpBuffer(&fn, ")");
9454         return fn.data;
9455 }
9456
9457 /*
9458  * format_function_signature: generate function name and argument list
9459  *
9460  * This is like format_function_arguments_old except that only a minimal
9461  * list of input argument types is generated; this is sufficient to
9462  * reference the function, but not to define it.
9463  *
9464  * If honor_quotes is false then the function name is never quoted.
9465  * This is appropriate for use in TOC tags, but not in SQL commands.
9466  */
9467 static char *
9468 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9469 {
9470         PQExpBufferData fn;
9471         int                     j;
9472
9473         initPQExpBuffer(&fn);
9474         if (honor_quotes)
9475                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9476         else
9477                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9478         for (j = 0; j < finfo->nargs; j++)
9479         {
9480                 char       *typname;
9481
9482                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9483                                                                            zeroAsOpaque);
9484
9485                 appendPQExpBuffer(&fn, "%s%s",
9486                                                   (j > 0) ? ", " : "",
9487                                                   typname);
9488                 free(typname);
9489         }
9490         appendPQExpBuffer(&fn, ")");
9491         return fn.data;
9492 }
9493
9494
9495 /*
9496  * dumpFunc:
9497  *        dump out one function
9498  */
9499 static void
9500 dumpFunc(Archive *fout, FuncInfo *finfo)
9501 {
9502         PQExpBuffer query;
9503         PQExpBuffer q;
9504         PQExpBuffer delqry;
9505         PQExpBuffer labelq;
9506         PQExpBuffer asPart;
9507         PGresult   *res;
9508         char       *funcsig;            /* identity signature */
9509         char       *funcfullsig;        /* full signature */
9510         char       *funcsig_tag;
9511         char       *proretset;
9512         char       *prosrc;
9513         char       *probin;
9514         char       *funcargs;
9515         char       *funciargs;
9516         char       *funcresult;
9517         char       *proallargtypes;
9518         char       *proargmodes;
9519         char       *proargnames;
9520         char       *proiswindow;
9521         char       *provolatile;
9522         char       *proisstrict;
9523         char       *prosecdef;
9524         char       *proleakproof;
9525         char       *proconfig;
9526         char       *procost;
9527         char       *prorows;
9528         char       *lanname;
9529         char       *rettypename;
9530         int                     nallargs;
9531         char      **allargtypes = NULL;
9532         char      **argmodes = NULL;
9533         char      **argnames = NULL;
9534         char      **configitems = NULL;
9535         int                     nconfigitems = 0;
9536         int                     i;
9537
9538         /* Skip if not to be dumped */
9539         if (!finfo->dobj.dump || dataOnly)
9540                 return;
9541
9542         query = createPQExpBuffer();
9543         q = createPQExpBuffer();
9544         delqry = createPQExpBuffer();
9545         labelq = createPQExpBuffer();
9546         asPart = createPQExpBuffer();
9547
9548         /* Set proper schema search path so type references list correctly */
9549         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9550
9551         /* Fetch function-specific details */
9552         if (fout->remoteVersion >= 90200)
9553         {
9554                 /*
9555                  * proleakproof was added at v9.2
9556                  */
9557                 appendPQExpBuffer(query,
9558                                                   "SELECT proretset, prosrc, probin, "
9559                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9560                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9561                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9562                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9563                                                   "proleakproof, proconfig, procost, prorows, "
9564                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9565                                                   "FROM pg_catalog.pg_proc "
9566                                                   "WHERE oid = '%u'::pg_catalog.oid",
9567                                                   finfo->dobj.catId.oid);
9568         }
9569         else if (fout->remoteVersion >= 80400)
9570         {
9571                 /*
9572                  * In 8.4 and up we rely on pg_get_function_arguments and
9573                  * pg_get_function_result instead of examining proallargtypes etc.
9574                  */
9575                 appendPQExpBuffer(query,
9576                                                   "SELECT proretset, prosrc, probin, "
9577                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9578                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9579                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9580                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9581                                                   "false AS proleakproof, "
9582                                                   " proconfig, procost, prorows, "
9583                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9584                                                   "FROM pg_catalog.pg_proc "
9585                                                   "WHERE oid = '%u'::pg_catalog.oid",
9586                                                   finfo->dobj.catId.oid);
9587         }
9588         else if (fout->remoteVersion >= 80300)
9589         {
9590                 appendPQExpBuffer(query,
9591                                                   "SELECT proretset, prosrc, probin, "
9592                                                   "proallargtypes, proargmodes, proargnames, "
9593                                                   "false AS proiswindow, "
9594                                                   "provolatile, proisstrict, prosecdef, "
9595                                                   "false AS proleakproof, "
9596                                                   "proconfig, procost, prorows, "
9597                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9598                                                   "FROM pg_catalog.pg_proc "
9599                                                   "WHERE oid = '%u'::pg_catalog.oid",
9600                                                   finfo->dobj.catId.oid);
9601         }
9602         else if (fout->remoteVersion >= 80100)
9603         {
9604                 appendPQExpBuffer(query,
9605                                                   "SELECT proretset, prosrc, probin, "
9606                                                   "proallargtypes, proargmodes, proargnames, "
9607                                                   "false AS proiswindow, "
9608                                                   "provolatile, proisstrict, prosecdef, "
9609                                                   "false AS proleakproof, "
9610                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9611                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9612                                                   "FROM pg_catalog.pg_proc "
9613                                                   "WHERE oid = '%u'::pg_catalog.oid",
9614                                                   finfo->dobj.catId.oid);
9615         }
9616         else if (fout->remoteVersion >= 80000)
9617         {
9618                 appendPQExpBuffer(query,
9619                                                   "SELECT proretset, prosrc, probin, "
9620                                                   "null AS proallargtypes, "
9621                                                   "null AS proargmodes, "
9622                                                   "proargnames, "
9623                                                   "false AS proiswindow, "
9624                                                   "provolatile, proisstrict, prosecdef, "
9625                                                   "false AS proleakproof, "
9626                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9627                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9628                                                   "FROM pg_catalog.pg_proc "
9629                                                   "WHERE oid = '%u'::pg_catalog.oid",
9630                                                   finfo->dobj.catId.oid);
9631         }
9632         else if (fout->remoteVersion >= 70300)
9633         {
9634                 appendPQExpBuffer(query,
9635                                                   "SELECT proretset, prosrc, probin, "
9636                                                   "null AS proallargtypes, "
9637                                                   "null AS proargmodes, "
9638                                                   "null AS proargnames, "
9639                                                   "false AS proiswindow, "
9640                                                   "provolatile, proisstrict, prosecdef, "
9641                                                   "false AS proleakproof, "
9642                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9643                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9644                                                   "FROM pg_catalog.pg_proc "
9645                                                   "WHERE oid = '%u'::pg_catalog.oid",
9646                                                   finfo->dobj.catId.oid);
9647         }
9648         else if (fout->remoteVersion >= 70100)
9649         {
9650                 appendPQExpBuffer(query,
9651                                                   "SELECT proretset, prosrc, probin, "
9652                                                   "null AS proallargtypes, "
9653                                                   "null AS proargmodes, "
9654                                                   "null AS proargnames, "
9655                                                   "false AS proiswindow, "
9656                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9657                                                   "proisstrict, "
9658                                                   "false AS prosecdef, "
9659                                                   "false AS proleakproof, "
9660                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9661                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9662                                                   "FROM pg_proc "
9663                                                   "WHERE oid = '%u'::oid",
9664                                                   finfo->dobj.catId.oid);
9665         }
9666         else
9667         {
9668                 appendPQExpBuffer(query,
9669                                                   "SELECT proretset, prosrc, probin, "
9670                                                   "null AS proallargtypes, "
9671                                                   "null AS proargmodes, "
9672                                                   "null AS proargnames, "
9673                                                   "false AS proiswindow, "
9674                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9675                                                   "false AS proisstrict, "
9676                                                   "false AS prosecdef, "
9677                                                   "false AS proleakproof, "
9678                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9679                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9680                                                   "FROM pg_proc "
9681                                                   "WHERE oid = '%u'::oid",
9682                                                   finfo->dobj.catId.oid);
9683         }
9684
9685         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9686
9687         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9688         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9689         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9690         if (fout->remoteVersion >= 80400)
9691         {
9692                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9693                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9694                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9695                 proallargtypes = proargmodes = proargnames = NULL;
9696         }
9697         else
9698         {
9699                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9700                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9701                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9702                 funcargs = funciargs = funcresult = NULL;
9703         }
9704         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9705         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9706         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9707         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9708         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9709         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9710         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9711         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9712         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9713
9714         /*
9715          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9716          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9717          * versions would set it to "-".  There are no known cases in which prosrc
9718          * is unused, so the tests below for "-" are probably useless.
9719          */
9720         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9721         {
9722                 appendPQExpBuffer(asPart, "AS ");
9723                 appendStringLiteralAH(asPart, probin, fout);
9724                 if (strcmp(prosrc, "-") != 0)
9725                 {
9726                         appendPQExpBuffer(asPart, ", ");
9727
9728                         /*
9729                          * where we have bin, use dollar quoting if allowed and src
9730                          * contains quote or backslash; else use regular quoting.
9731                          */
9732                         if (disable_dollar_quoting ||
9733                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9734                                 appendStringLiteralAH(asPart, prosrc, fout);
9735                         else
9736                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9737                 }
9738         }
9739         else
9740         {
9741                 if (strcmp(prosrc, "-") != 0)
9742                 {
9743                         appendPQExpBuffer(asPart, "AS ");
9744                         /* with no bin, dollar quote src unconditionally if allowed */
9745                         if (disable_dollar_quoting)
9746                                 appendStringLiteralAH(asPart, prosrc, fout);
9747                         else
9748                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9749                 }
9750         }
9751
9752         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9753
9754         if (proallargtypes && *proallargtypes)
9755         {
9756                 int                     nitems = 0;
9757
9758                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9759                         nitems < finfo->nargs)
9760                 {
9761                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9762                         if (allargtypes)
9763                                 free(allargtypes);
9764                         allargtypes = NULL;
9765                 }
9766                 else
9767                         nallargs = nitems;
9768         }
9769
9770         if (proargmodes && *proargmodes)
9771         {
9772                 int                     nitems = 0;
9773
9774                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9775                         nitems != nallargs)
9776                 {
9777                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9778                         if (argmodes)
9779                                 free(argmodes);
9780                         argmodes = NULL;
9781                 }
9782         }
9783
9784         if (proargnames && *proargnames)
9785         {
9786                 int                     nitems = 0;
9787
9788                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9789                         nitems != nallargs)
9790                 {
9791                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9792                         if (argnames)
9793                                 free(argnames);
9794                         argnames = NULL;
9795                 }
9796         }
9797
9798         if (proconfig && *proconfig)
9799         {
9800                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9801                 {
9802                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9803                         if (configitems)
9804                                 free(configitems);
9805                         configitems = NULL;
9806                         nconfigitems = 0;
9807                 }
9808         }
9809
9810         if (funcargs)
9811         {
9812                 /* 8.4 or later; we rely on server-side code for most of the work */
9813                 funcfullsig = format_function_arguments(finfo, funcargs, false);
9814                 funcsig = format_function_arguments(finfo, funciargs, false);
9815         }
9816         else
9817         {
9818                 /* pre-8.4, do it ourselves */
9819                 funcsig = format_function_arguments_old(fout,
9820                                                                                                 finfo, nallargs, allargtypes,
9821                                                                                                 argmodes, argnames);
9822                 funcfullsig = funcsig;
9823         }
9824
9825         funcsig_tag = format_function_signature(fout, finfo, false);
9826
9827         /*
9828          * DROP must be fully qualified in case same name appears in pg_catalog
9829          */
9830         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9831                                           fmtId(finfo->dobj.namespace->dobj.name),
9832                                           funcsig);
9833
9834         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9835         if (funcresult)
9836                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9837         else
9838         {
9839                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9840                                                                                    zeroAsOpaque);
9841                 appendPQExpBuffer(q, "RETURNS %s%s",
9842                                                   (proretset[0] == 't') ? "SETOF " : "",
9843                                                   rettypename);
9844                 free(rettypename);
9845         }
9846
9847         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9848
9849         if (proiswindow[0] == 't')
9850                 appendPQExpBuffer(q, " WINDOW");
9851
9852         if (provolatile[0] != PROVOLATILE_VOLATILE)
9853         {
9854                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9855                         appendPQExpBuffer(q, " IMMUTABLE");
9856                 else if (provolatile[0] == PROVOLATILE_STABLE)
9857                         appendPQExpBuffer(q, " STABLE");
9858                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9859                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9860                                                   finfo->dobj.name);
9861         }
9862
9863         if (proisstrict[0] == 't')
9864                 appendPQExpBuffer(q, " STRICT");
9865
9866         if (prosecdef[0] == 't')
9867                 appendPQExpBuffer(q, " SECURITY DEFINER");
9868
9869         if (proleakproof[0] == 't')
9870                 appendPQExpBuffer(q, " LEAKPROOF");
9871
9872         /*
9873          * COST and ROWS are emitted only if present and not default, so as not to
9874          * break backwards-compatibility of the dump without need.      Keep this code
9875          * in sync with the defaults in functioncmds.c.
9876          */
9877         if (strcmp(procost, "0") != 0)
9878         {
9879                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9880                 {
9881                         /* default cost is 1 */
9882                         if (strcmp(procost, "1") != 0)
9883                                 appendPQExpBuffer(q, " COST %s", procost);
9884                 }
9885                 else
9886                 {
9887                         /* default cost is 100 */
9888                         if (strcmp(procost, "100") != 0)
9889                                 appendPQExpBuffer(q, " COST %s", procost);
9890                 }
9891         }
9892         if (proretset[0] == 't' &&
9893                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9894                 appendPQExpBuffer(q, " ROWS %s", prorows);
9895
9896         for (i = 0; i < nconfigitems; i++)
9897         {
9898                 /* we feel free to scribble on configitems[] here */
9899                 char       *configitem = configitems[i];
9900                 char       *pos;
9901
9902                 pos = strchr(configitem, '=');
9903                 if (pos == NULL)
9904                         continue;
9905                 *pos++ = '\0';
9906                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9907
9908                 /*
9909                  * Some GUC variable names are 'LIST' type and hence must not be
9910                  * quoted.
9911                  */
9912                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9913                         || pg_strcasecmp(configitem, "search_path") == 0)
9914                         appendPQExpBuffer(q, "%s", pos);
9915                 else
9916                         appendStringLiteralAH(q, pos, fout);
9917         }
9918
9919         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9920
9921         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9922
9923         if (binary_upgrade)
9924                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9925
9926         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9927                                  funcsig_tag,
9928                                  finfo->dobj.namespace->dobj.name,
9929                                  NULL,
9930                                  finfo->rolname, false,
9931                                  "FUNCTION", SECTION_PRE_DATA,
9932                                  q->data, delqry->data, NULL,
9933                                  NULL, 0,
9934                                  NULL, NULL);
9935
9936         /* Dump Function Comments and Security Labels */
9937         dumpComment(fout, labelq->data,
9938                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9939                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9940         dumpSecLabel(fout, labelq->data,
9941                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9942                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9943
9944         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9945                         funcsig, NULL, funcsig_tag,
9946                         finfo->dobj.namespace->dobj.name,
9947                         finfo->rolname, finfo->proacl);
9948
9949         PQclear(res);
9950
9951         destroyPQExpBuffer(query);
9952         destroyPQExpBuffer(q);
9953         destroyPQExpBuffer(delqry);
9954         destroyPQExpBuffer(labelq);
9955         destroyPQExpBuffer(asPart);
9956         free(funcsig);
9957         free(funcsig_tag);
9958         if (allargtypes)
9959                 free(allargtypes);
9960         if (argmodes)
9961                 free(argmodes);
9962         if (argnames)
9963                 free(argnames);
9964         if (configitems)
9965                 free(configitems);
9966 }
9967
9968
9969 /*
9970  * Dump a user-defined cast
9971  */
9972 static void
9973 dumpCast(Archive *fout, CastInfo *cast)
9974 {
9975         PQExpBuffer defqry;
9976         PQExpBuffer delqry;
9977         PQExpBuffer labelq;
9978         FuncInfo   *funcInfo = NULL;
9979
9980         /* Skip if not to be dumped */
9981         if (!cast->dobj.dump || dataOnly)
9982                 return;
9983
9984         /* Cannot dump if we don't have the cast function's info */
9985         if (OidIsValid(cast->castfunc))
9986         {
9987                 funcInfo = findFuncByOid(cast->castfunc);
9988                 if (funcInfo == NULL)
9989                         return;
9990         }
9991
9992         /*
9993          * As per discussion we dump casts if one or more of the underlying
9994          * objects (the conversion function and the two data types) are not
9995          * builtin AND if all of the non-builtin objects are included in the dump.
9996          * Builtin meaning, the namespace name does not start with "pg_".
9997          *
9998          * However, for a cast that belongs to an extension, we must not use this
9999          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
10000          */
10001         if (!cast->dobj.ext_member)
10002         {
10003                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
10004                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
10005
10006                 if (sourceInfo == NULL || targetInfo == NULL)
10007                         return;
10008
10009                 /*
10010                  * Skip this cast if all objects are from pg_
10011                  */
10012                 if ((funcInfo == NULL ||
10013                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
10014                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10015                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10016                         return;
10017
10018                 /*
10019                  * Skip cast if function isn't from pg_ and is not to be dumped.
10020                  */
10021                 if (funcInfo &&
10022                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10023                         !funcInfo->dobj.dump)
10024                         return;
10025
10026                 /*
10027                  * Same for the source type
10028                  */
10029                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10030                         !sourceInfo->dobj.dump)
10031                         return;
10032
10033                 /*
10034                  * and the target type.
10035                  */
10036                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10037                         !targetInfo->dobj.dump)
10038                         return;
10039         }
10040
10041         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10042         selectSourceSchema(fout, "pg_catalog");
10043
10044         defqry = createPQExpBuffer();
10045         delqry = createPQExpBuffer();
10046         labelq = createPQExpBuffer();
10047
10048         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10049                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10050                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10051
10052         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10053                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10054                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10055
10056         switch (cast->castmethod)
10057         {
10058                 case COERCION_METHOD_BINARY:
10059                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
10060                         break;
10061                 case COERCION_METHOD_INOUT:
10062                         appendPQExpBuffer(defqry, "WITH INOUT");
10063                         break;
10064                 case COERCION_METHOD_FUNCTION:
10065                         if (funcInfo)
10066                         {
10067                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10068
10069                                 /*
10070                                  * Always qualify the function name, in case it is not in
10071                                  * pg_catalog schema (format_function_signature won't qualify
10072                                  * it).
10073                                  */
10074                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10075                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10076                                 free(fsig);
10077                         }
10078                         else
10079                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10080                         break;
10081                 default:
10082                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10083         }
10084
10085         if (cast->castcontext == 'a')
10086                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
10087         else if (cast->castcontext == 'i')
10088                 appendPQExpBuffer(defqry, " AS IMPLICIT");
10089         appendPQExpBuffer(defqry, ";\n");
10090
10091         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10092                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10093                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10094
10095         if (binary_upgrade)
10096                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10097
10098         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10099                                  labelq->data,
10100                                  "pg_catalog", NULL, "",
10101                                  false, "CAST", SECTION_PRE_DATA,
10102                                  defqry->data, delqry->data, NULL,
10103                                  NULL, 0,
10104                                  NULL, NULL);
10105
10106         /* Dump Cast Comments */
10107         dumpComment(fout, labelq->data,
10108                                 NULL, "",
10109                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10110
10111         destroyPQExpBuffer(defqry);
10112         destroyPQExpBuffer(delqry);
10113         destroyPQExpBuffer(labelq);
10114 }
10115
10116 /*
10117  * dumpOpr
10118  *        write out a single operator definition
10119  */
10120 static void
10121 dumpOpr(Archive *fout, OprInfo *oprinfo)
10122 {
10123         PQExpBuffer query;
10124         PQExpBuffer q;
10125         PQExpBuffer delq;
10126         PQExpBuffer labelq;
10127         PQExpBuffer oprid;
10128         PQExpBuffer details;
10129         const char *name;
10130         PGresult   *res;
10131         int                     i_oprkind;
10132         int                     i_oprcode;
10133         int                     i_oprleft;
10134         int                     i_oprright;
10135         int                     i_oprcom;
10136         int                     i_oprnegate;
10137         int                     i_oprrest;
10138         int                     i_oprjoin;
10139         int                     i_oprcanmerge;
10140         int                     i_oprcanhash;
10141         char       *oprkind;
10142         char       *oprcode;
10143         char       *oprleft;
10144         char       *oprright;
10145         char       *oprcom;
10146         char       *oprnegate;
10147         char       *oprrest;
10148         char       *oprjoin;
10149         char       *oprcanmerge;
10150         char       *oprcanhash;
10151
10152         /* Skip if not to be dumped */
10153         if (!oprinfo->dobj.dump || dataOnly)
10154                 return;
10155
10156         /*
10157          * some operators are invalid because they were the result of user
10158          * defining operators before commutators exist
10159          */
10160         if (!OidIsValid(oprinfo->oprcode))
10161                 return;
10162
10163         query = createPQExpBuffer();
10164         q = createPQExpBuffer();
10165         delq = createPQExpBuffer();
10166         labelq = createPQExpBuffer();
10167         oprid = createPQExpBuffer();
10168         details = createPQExpBuffer();
10169
10170         /* Make sure we are in proper schema so regoperator works correctly */
10171         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10172
10173         if (fout->remoteVersion >= 80300)
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                                                   "oprcanmerge, oprcanhash "
10184                                                   "FROM pg_catalog.pg_operator "
10185                                                   "WHERE oid = '%u'::pg_catalog.oid",
10186                                                   oprinfo->dobj.catId.oid);
10187         }
10188         else if (fout->remoteVersion >= 70300)
10189         {
10190                 appendPQExpBuffer(query, "SELECT oprkind, "
10191                                                   "oprcode::pg_catalog.regprocedure, "
10192                                                   "oprleft::pg_catalog.regtype, "
10193                                                   "oprright::pg_catalog.regtype, "
10194                                                   "oprcom::pg_catalog.regoperator, "
10195                                                   "oprnegate::pg_catalog.regoperator, "
10196                                                   "oprrest::pg_catalog.regprocedure, "
10197                                                   "oprjoin::pg_catalog.regprocedure, "
10198                                                   "(oprlsortop != 0) AS oprcanmerge, "
10199                                                   "oprcanhash "
10200                                                   "FROM pg_catalog.pg_operator "
10201                                                   "WHERE oid = '%u'::pg_catalog.oid",
10202                                                   oprinfo->dobj.catId.oid);
10203         }
10204         else if (fout->remoteVersion >= 70100)
10205         {
10206                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10207                                                   "CASE WHEN oprleft = 0 THEN '-' "
10208                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10209                                                   "CASE WHEN oprright = 0 THEN '-' "
10210                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10211                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10212                                                   "(oprlsortop != 0) AS oprcanmerge, "
10213                                                   "oprcanhash "
10214                                                   "FROM pg_operator "
10215                                                   "WHERE oid = '%u'::oid",
10216                                                   oprinfo->dobj.catId.oid);
10217         }
10218         else
10219         {
10220                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10221                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10222                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10223                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10224                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10225                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10226                                                   "(oprlsortop != 0) AS oprcanmerge, "
10227                                                   "oprcanhash "
10228                                                   "FROM pg_operator "
10229                                                   "WHERE oid = '%u'::oid",
10230                                                   oprinfo->dobj.catId.oid);
10231         }
10232
10233         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10234
10235         i_oprkind = PQfnumber(res, "oprkind");
10236         i_oprcode = PQfnumber(res, "oprcode");
10237         i_oprleft = PQfnumber(res, "oprleft");
10238         i_oprright = PQfnumber(res, "oprright");
10239         i_oprcom = PQfnumber(res, "oprcom");
10240         i_oprnegate = PQfnumber(res, "oprnegate");
10241         i_oprrest = PQfnumber(res, "oprrest");
10242         i_oprjoin = PQfnumber(res, "oprjoin");
10243         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10244         i_oprcanhash = PQfnumber(res, "oprcanhash");
10245
10246         oprkind = PQgetvalue(res, 0, i_oprkind);
10247         oprcode = PQgetvalue(res, 0, i_oprcode);
10248         oprleft = PQgetvalue(res, 0, i_oprleft);
10249         oprright = PQgetvalue(res, 0, i_oprright);
10250         oprcom = PQgetvalue(res, 0, i_oprcom);
10251         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10252         oprrest = PQgetvalue(res, 0, i_oprrest);
10253         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10254         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10255         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10256
10257         appendPQExpBuffer(details, "    PROCEDURE = %s",
10258                                           convertRegProcReference(fout, oprcode));
10259
10260         appendPQExpBuffer(oprid, "%s (",
10261                                           oprinfo->dobj.name);
10262
10263         /*
10264          * right unary means there's a left arg and left unary means there's a
10265          * right arg
10266          */
10267         if (strcmp(oprkind, "r") == 0 ||
10268                 strcmp(oprkind, "b") == 0)
10269         {
10270                 if (fout->remoteVersion >= 70100)
10271                         name = oprleft;
10272                 else
10273                         name = fmtId(oprleft);
10274                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10275                 appendPQExpBuffer(oprid, "%s", name);
10276         }
10277         else
10278                 appendPQExpBuffer(oprid, "NONE");
10279
10280         if (strcmp(oprkind, "l") == 0 ||
10281                 strcmp(oprkind, "b") == 0)
10282         {
10283                 if (fout->remoteVersion >= 70100)
10284                         name = oprright;
10285                 else
10286                         name = fmtId(oprright);
10287                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10288                 appendPQExpBuffer(oprid, ", %s)", name);
10289         }
10290         else
10291                 appendPQExpBuffer(oprid, ", NONE)");
10292
10293         name = convertOperatorReference(fout, oprcom);
10294         if (name)
10295                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
10296
10297         name = convertOperatorReference(fout, oprnegate);
10298         if (name)
10299                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
10300
10301         if (strcmp(oprcanmerge, "t") == 0)
10302                 appendPQExpBuffer(details, ",\n    MERGES");
10303
10304         if (strcmp(oprcanhash, "t") == 0)
10305                 appendPQExpBuffer(details, ",\n    HASHES");
10306
10307         name = convertRegProcReference(fout, oprrest);
10308         if (name)
10309                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
10310
10311         name = convertRegProcReference(fout, oprjoin);
10312         if (name)
10313                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
10314
10315         /*
10316          * DROP must be fully qualified in case same name appears in pg_catalog
10317          */
10318         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10319                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10320                                           oprid->data);
10321
10322         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10323                                           oprinfo->dobj.name, details->data);
10324
10325         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10326
10327         if (binary_upgrade)
10328                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10329
10330         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10331                                  oprinfo->dobj.name,
10332                                  oprinfo->dobj.namespace->dobj.name,
10333                                  NULL,
10334                                  oprinfo->rolname,
10335                                  false, "OPERATOR", SECTION_PRE_DATA,
10336                                  q->data, delq->data, NULL,
10337                                  NULL, 0,
10338                                  NULL, NULL);
10339
10340         /* Dump Operator Comments */
10341         dumpComment(fout, labelq->data,
10342                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10343                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10344
10345         PQclear(res);
10346
10347         destroyPQExpBuffer(query);
10348         destroyPQExpBuffer(q);
10349         destroyPQExpBuffer(delq);
10350         destroyPQExpBuffer(labelq);
10351         destroyPQExpBuffer(oprid);
10352         destroyPQExpBuffer(details);
10353 }
10354
10355 /*
10356  * Convert a function reference obtained from pg_operator
10357  *
10358  * Returns what to print, or NULL if function references is InvalidOid
10359  *
10360  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10361  * argument-types part.  In prior versions, the input is a REGPROC display.
10362  */
10363 static const char *
10364 convertRegProcReference(Archive *fout, const char *proc)
10365 {
10366         /* In all cases "-" means a null reference */
10367         if (strcmp(proc, "-") == 0)
10368                 return NULL;
10369
10370         if (fout->remoteVersion >= 70300)
10371         {
10372                 char       *name;
10373                 char       *paren;
10374                 bool            inquote;
10375
10376                 name = pg_strdup(proc);
10377                 /* find non-double-quoted left paren */
10378                 inquote = false;
10379                 for (paren = name; *paren; paren++)
10380                 {
10381                         if (*paren == '(' && !inquote)
10382                         {
10383                                 *paren = '\0';
10384                                 break;
10385                         }
10386                         if (*paren == '"')
10387                                 inquote = !inquote;
10388                 }
10389                 return name;
10390         }
10391
10392         /* REGPROC before 7.3 does not quote its result */
10393         return fmtId(proc);
10394 }
10395
10396 /*
10397  * Convert an operator cross-reference obtained from pg_operator
10398  *
10399  * Returns what to print, or NULL to print nothing
10400  *
10401  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10402  * argument-types part, and add OPERATOR() decoration if the name is
10403  * schema-qualified.  In older versions, the input is just a numeric OID,
10404  * which we search our operator list for.
10405  */
10406 static const char *
10407 convertOperatorReference(Archive *fout, const char *opr)
10408 {
10409         OprInfo    *oprInfo;
10410
10411         /* In all cases "0" means a null reference */
10412         if (strcmp(opr, "0") == 0)
10413                 return NULL;
10414
10415         if (fout->remoteVersion >= 70300)
10416         {
10417                 char       *name;
10418                 char       *oname;
10419                 char       *ptr;
10420                 bool            inquote;
10421                 bool            sawdot;
10422
10423                 name = pg_strdup(opr);
10424                 /* find non-double-quoted left paren, and check for non-quoted dot */
10425                 inquote = false;
10426                 sawdot = false;
10427                 for (ptr = name; *ptr; ptr++)
10428                 {
10429                         if (*ptr == '"')
10430                                 inquote = !inquote;
10431                         else if (*ptr == '.' && !inquote)
10432                                 sawdot = true;
10433                         else if (*ptr == '(' && !inquote)
10434                         {
10435                                 *ptr = '\0';
10436                                 break;
10437                         }
10438                 }
10439                 /* If not schema-qualified, don't need to add OPERATOR() */
10440                 if (!sawdot)
10441                         return name;
10442                 pg_asprintf(&oname, "OPERATOR(%s)", name);
10443                 free(name);
10444                 return oname;
10445         }
10446
10447         oprInfo = findOprByOid(atooid(opr));
10448         if (oprInfo == NULL)
10449         {
10450                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10451                                   opr);
10452                 return NULL;
10453         }
10454         return oprInfo->dobj.name;
10455 }
10456
10457 /*
10458  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10459  *
10460  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10461  * argument lists of these functions are predetermined.  Note that the
10462  * caller should ensure we are in the proper schema, because the results
10463  * are search path dependent!
10464  */
10465 static const char *
10466 convertTSFunction(Archive *fout, Oid funcOid)
10467 {
10468         char       *result;
10469         char            query[128];
10470         PGresult   *res;
10471
10472         snprintf(query, sizeof(query),
10473                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10474         res = ExecuteSqlQueryForSingleRow(fout, query);
10475
10476         result = pg_strdup(PQgetvalue(res, 0, 0));
10477
10478         PQclear(res);
10479
10480         return result;
10481 }
10482
10483
10484 /*
10485  * dumpOpclass
10486  *        write out a single operator class definition
10487  */
10488 static void
10489 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10490 {
10491         PQExpBuffer query;
10492         PQExpBuffer q;
10493         PQExpBuffer delq;
10494         PQExpBuffer labelq;
10495         PGresult   *res;
10496         int                     ntups;
10497         int                     i_opcintype;
10498         int                     i_opckeytype;
10499         int                     i_opcdefault;
10500         int                     i_opcfamily;
10501         int                     i_opcfamilyname;
10502         int                     i_opcfamilynsp;
10503         int                     i_amname;
10504         int                     i_amopstrategy;
10505         int                     i_amopreqcheck;
10506         int                     i_amopopr;
10507         int                     i_sortfamily;
10508         int                     i_sortfamilynsp;
10509         int                     i_amprocnum;
10510         int                     i_amproc;
10511         int                     i_amproclefttype;
10512         int                     i_amprocrighttype;
10513         char       *opcintype;
10514         char       *opckeytype;
10515         char       *opcdefault;
10516         char       *opcfamily;
10517         char       *opcfamilyname;
10518         char       *opcfamilynsp;
10519         char       *amname;
10520         char       *amopstrategy;
10521         char       *amopreqcheck;
10522         char       *amopopr;
10523         char       *sortfamily;
10524         char       *sortfamilynsp;
10525         char       *amprocnum;
10526         char       *amproc;
10527         char       *amproclefttype;
10528         char       *amprocrighttype;
10529         bool            needComma;
10530         int                     i;
10531
10532         /* Skip if not to be dumped */
10533         if (!opcinfo->dobj.dump || dataOnly)
10534                 return;
10535
10536         /*
10537          * XXX currently we do not implement dumping of operator classes from
10538          * pre-7.3 databases.  This could be done but it seems not worth the
10539          * trouble.
10540          */
10541         if (fout->remoteVersion < 70300)
10542                 return;
10543
10544         query = createPQExpBuffer();
10545         q = createPQExpBuffer();
10546         delq = createPQExpBuffer();
10547         labelq = createPQExpBuffer();
10548
10549         /* Make sure we are in proper schema so regoperator works correctly */
10550         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10551
10552         /* Get additional fields from the pg_opclass row */
10553         if (fout->remoteVersion >= 80300)
10554         {
10555                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10556                                                   "opckeytype::pg_catalog.regtype, "
10557                                                   "opcdefault, opcfamily, "
10558                                                   "opfname AS opcfamilyname, "
10559                                                   "nspname AS opcfamilynsp, "
10560                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10561                                                   "FROM pg_catalog.pg_opclass c "
10562                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10563                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10564                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10565                                                   opcinfo->dobj.catId.oid);
10566         }
10567         else
10568         {
10569                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10570                                                   "opckeytype::pg_catalog.regtype, "
10571                                                   "opcdefault, NULL AS opcfamily, "
10572                                                   "NULL AS opcfamilyname, "
10573                                                   "NULL AS opcfamilynsp, "
10574                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10575                                                   "FROM pg_catalog.pg_opclass "
10576                                                   "WHERE oid = '%u'::pg_catalog.oid",
10577                                                   opcinfo->dobj.catId.oid);
10578         }
10579
10580         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10581
10582         i_opcintype = PQfnumber(res, "opcintype");
10583         i_opckeytype = PQfnumber(res, "opckeytype");
10584         i_opcdefault = PQfnumber(res, "opcdefault");
10585         i_opcfamily = PQfnumber(res, "opcfamily");
10586         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10587         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10588         i_amname = PQfnumber(res, "amname");
10589
10590         opcintype = PQgetvalue(res, 0, i_opcintype);
10591         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10592         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10593         /* opcfamily will still be needed after we PQclear res */
10594         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10595         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10596         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10597         /* amname will still be needed after we PQclear res */
10598         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10599
10600         /*
10601          * DROP must be fully qualified in case same name appears in pg_catalog
10602          */
10603         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10604                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10605         appendPQExpBuffer(delq, ".%s",
10606                                           fmtId(opcinfo->dobj.name));
10607         appendPQExpBuffer(delq, " USING %s;\n",
10608                                           fmtId(amname));
10609
10610         /* Build the fixed portion of the CREATE command */
10611         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10612                                           fmtId(opcinfo->dobj.name));
10613         if (strcmp(opcdefault, "t") == 0)
10614                 appendPQExpBuffer(q, "DEFAULT ");
10615         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10616                                           opcintype,
10617                                           fmtId(amname));
10618         if (strlen(opcfamilyname) > 0 &&
10619                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10620                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10621         {
10622                 appendPQExpBuffer(q, " FAMILY ");
10623                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10624                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10625                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10626         }
10627         appendPQExpBuffer(q, " AS\n    ");
10628
10629         needComma = false;
10630
10631         if (strcmp(opckeytype, "-") != 0)
10632         {
10633                 appendPQExpBuffer(q, "STORAGE %s",
10634                                                   opckeytype);
10635                 needComma = true;
10636         }
10637
10638         PQclear(res);
10639
10640         /*
10641          * Now fetch and print the OPERATOR entries (pg_amop rows).
10642          *
10643          * Print only those opfamily members that are tied to the opclass by
10644          * pg_depend entries.
10645          *
10646          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10647          * older server's opclass in which it is used.  This is to avoid
10648          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10649          * older server and then reload into that old version.  This can go away
10650          * once 8.3 is so old as to not be of interest to anyone.
10651          */
10652         resetPQExpBuffer(query);
10653
10654         if (fout->remoteVersion >= 90100)
10655         {
10656                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10657                                                   "amopopr::pg_catalog.regoperator, "
10658                                                   "opfname AS sortfamily, "
10659                                                   "nspname AS sortfamilynsp "
10660                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10661                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10662                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10663                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10664                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10665                                                   "AND refobjid = '%u'::pg_catalog.oid "
10666                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10667                                                   "ORDER BY amopstrategy",
10668                                                   opcinfo->dobj.catId.oid,
10669                                                   opcfamily);
10670         }
10671         else if (fout->remoteVersion >= 80400)
10672         {
10673                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS 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 if (fout->remoteVersion >= 80300)
10686         {
10687                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10688                                                   "amopopr::pg_catalog.regoperator, "
10689                                                   "NULL AS sortfamily, "
10690                                                   "NULL AS sortfamilynsp "
10691                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10692                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10693                                                   "AND refobjid = '%u'::pg_catalog.oid "
10694                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10695                                                   "AND objid = ao.oid "
10696                                                   "ORDER BY amopstrategy",
10697                                                   opcinfo->dobj.catId.oid);
10698         }
10699         else
10700         {
10701                 /*
10702                  * Here, we print all entries since there are no opfamilies and hence
10703                  * no loose operators to worry about.
10704                  */
10705                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10706                                                   "amopopr::pg_catalog.regoperator, "
10707                                                   "NULL AS sortfamily, "
10708                                                   "NULL AS sortfamilynsp "
10709                                                   "FROM pg_catalog.pg_amop "
10710                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10711                                                   "ORDER BY amopstrategy",
10712                                                   opcinfo->dobj.catId.oid);
10713         }
10714
10715         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10716
10717         ntups = PQntuples(res);
10718
10719         i_amopstrategy = PQfnumber(res, "amopstrategy");
10720         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10721         i_amopopr = PQfnumber(res, "amopopr");
10722         i_sortfamily = PQfnumber(res, "sortfamily");
10723         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10724
10725         for (i = 0; i < ntups; i++)
10726         {
10727                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10728                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10729                 amopopr = PQgetvalue(res, i, i_amopopr);
10730                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10731                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10732
10733                 if (needComma)
10734                         appendPQExpBuffer(q, " ,\n    ");
10735
10736                 appendPQExpBuffer(q, "OPERATOR %s %s",
10737                                                   amopstrategy, amopopr);
10738
10739                 if (strlen(sortfamily) > 0)
10740                 {
10741                         appendPQExpBuffer(q, " FOR ORDER BY ");
10742                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10743                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10744                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10745                 }
10746
10747                 if (strcmp(amopreqcheck, "t") == 0)
10748                         appendPQExpBuffer(q, " RECHECK");
10749
10750                 needComma = true;
10751         }
10752
10753         PQclear(res);
10754
10755         /*
10756          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10757          *
10758          * Print only those opfamily members that are tied to the opclass by
10759          * pg_depend entries.
10760          *
10761          * We print the amproclefttype/amprocrighttype even though in most cases
10762          * the backend could deduce the right values, because of the corner case
10763          * of a btree sort support function for a cross-type comparison.  That's
10764          * only allowed in 9.2 and later, but for simplicity print them in all
10765          * versions that have the columns.
10766          */
10767         resetPQExpBuffer(query);
10768
10769         if (fout->remoteVersion >= 80300)
10770         {
10771                 appendPQExpBuffer(query, "SELECT amprocnum, "
10772                                                   "amproc::pg_catalog.regprocedure, "
10773                                                   "amproclefttype::pg_catalog.regtype, "
10774                                                   "amprocrighttype::pg_catalog.regtype "
10775                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10776                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10777                                                   "AND refobjid = '%u'::pg_catalog.oid "
10778                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10779                                                   "AND objid = ap.oid "
10780                                                   "ORDER BY amprocnum",
10781                                                   opcinfo->dobj.catId.oid);
10782         }
10783         else
10784         {
10785                 appendPQExpBuffer(query, "SELECT amprocnum, "
10786                                                   "amproc::pg_catalog.regprocedure, "
10787                                                   "'' AS amproclefttype, "
10788                                                   "'' AS amprocrighttype "
10789                                                   "FROM pg_catalog.pg_amproc "
10790                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10791                                                   "ORDER BY amprocnum",
10792                                                   opcinfo->dobj.catId.oid);
10793         }
10794
10795         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10796
10797         ntups = PQntuples(res);
10798
10799         i_amprocnum = PQfnumber(res, "amprocnum");
10800         i_amproc = PQfnumber(res, "amproc");
10801         i_amproclefttype = PQfnumber(res, "amproclefttype");
10802         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10803
10804         for (i = 0; i < ntups; i++)
10805         {
10806                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10807                 amproc = PQgetvalue(res, i, i_amproc);
10808                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10809                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10810
10811                 if (needComma)
10812                         appendPQExpBuffer(q, " ,\n    ");
10813
10814                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10815
10816                 if (*amproclefttype && *amprocrighttype)
10817                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10818
10819                 appendPQExpBuffer(q, " %s", amproc);
10820
10821                 needComma = true;
10822         }
10823
10824         PQclear(res);
10825
10826         appendPQExpBuffer(q, ";\n");
10827
10828         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10829                                           fmtId(opcinfo->dobj.name));
10830         appendPQExpBuffer(labelq, " USING %s",
10831                                           fmtId(amname));
10832
10833         if (binary_upgrade)
10834                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10835
10836         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10837                                  opcinfo->dobj.name,
10838                                  opcinfo->dobj.namespace->dobj.name,
10839                                  NULL,
10840                                  opcinfo->rolname,
10841                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10842                                  q->data, delq->data, NULL,
10843                                  NULL, 0,
10844                                  NULL, NULL);
10845
10846         /* Dump Operator Class Comments */
10847         dumpComment(fout, labelq->data,
10848                                 NULL, opcinfo->rolname,
10849                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10850
10851         free(amname);
10852         destroyPQExpBuffer(query);
10853         destroyPQExpBuffer(q);
10854         destroyPQExpBuffer(delq);
10855         destroyPQExpBuffer(labelq);
10856 }
10857
10858 /*
10859  * dumpOpfamily
10860  *        write out a single operator family definition
10861  *
10862  * Note: this also dumps any "loose" operator members that aren't bound to a
10863  * specific opclass within the opfamily.
10864  */
10865 static void
10866 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10867 {
10868         PQExpBuffer query;
10869         PQExpBuffer q;
10870         PQExpBuffer delq;
10871         PQExpBuffer labelq;
10872         PGresult   *res;
10873         PGresult   *res_ops;
10874         PGresult   *res_procs;
10875         int                     ntups;
10876         int                     i_amname;
10877         int                     i_amopstrategy;
10878         int                     i_amopreqcheck;
10879         int                     i_amopopr;
10880         int                     i_sortfamily;
10881         int                     i_sortfamilynsp;
10882         int                     i_amprocnum;
10883         int                     i_amproc;
10884         int                     i_amproclefttype;
10885         int                     i_amprocrighttype;
10886         char       *amname;
10887         char       *amopstrategy;
10888         char       *amopreqcheck;
10889         char       *amopopr;
10890         char       *sortfamily;
10891         char       *sortfamilynsp;
10892         char       *amprocnum;
10893         char       *amproc;
10894         char       *amproclefttype;
10895         char       *amprocrighttype;
10896         bool            needComma;
10897         int                     i;
10898
10899         /* Skip if not to be dumped */
10900         if (!opfinfo->dobj.dump || dataOnly)
10901                 return;
10902
10903         /*
10904          * We want to dump the opfamily only if (1) it contains "loose" operators
10905          * or functions, or (2) it contains an opclass with a different name or
10906          * owner.  Otherwise it's sufficient to let it be created during creation
10907          * of the contained opclass, and not dumping it improves portability of
10908          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10909          * that first.
10910          */
10911
10912         query = createPQExpBuffer();
10913         q = createPQExpBuffer();
10914         delq = createPQExpBuffer();
10915         labelq = createPQExpBuffer();
10916
10917         /* Make sure we are in proper schema so regoperator works correctly */
10918         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10919
10920         /*
10921          * Fetch only those opfamily members that are tied directly to the
10922          * opfamily by pg_depend entries.
10923          *
10924          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10925          * older server's opclass in which it is used.  This is to avoid
10926          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10927          * older server and then reload into that old version.  This can go away
10928          * once 8.3 is so old as to not be of interest to anyone.
10929          */
10930         if (fout->remoteVersion >= 90100)
10931         {
10932                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10933                                                   "amopopr::pg_catalog.regoperator, "
10934                                                   "opfname AS sortfamily, "
10935                                                   "nspname AS sortfamilynsp "
10936                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10937                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10938                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10939                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10940                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10941                                                   "AND refobjid = '%u'::pg_catalog.oid "
10942                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10943                                                   "ORDER BY amopstrategy",
10944                                                   opfinfo->dobj.catId.oid,
10945                                                   opfinfo->dobj.catId.oid);
10946         }
10947         else if (fout->remoteVersion >= 80400)
10948         {
10949                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS 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         else
10962         {
10963                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10964                                                   "amopopr::pg_catalog.regoperator, "
10965                                                   "NULL AS sortfamily, "
10966                                                   "NULL AS sortfamilynsp "
10967                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10968                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10969                                                   "AND refobjid = '%u'::pg_catalog.oid "
10970                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10971                                                   "AND objid = ao.oid "
10972                                                   "ORDER BY amopstrategy",
10973                                                   opfinfo->dobj.catId.oid);
10974         }
10975
10976         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10977
10978         resetPQExpBuffer(query);
10979
10980         appendPQExpBuffer(query, "SELECT amprocnum, "
10981                                           "amproc::pg_catalog.regprocedure, "
10982                                           "amproclefttype::pg_catalog.regtype, "
10983                                           "amprocrighttype::pg_catalog.regtype "
10984                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10985                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10986                                           "AND refobjid = '%u'::pg_catalog.oid "
10987                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10988                                           "AND objid = ap.oid "
10989                                           "ORDER BY amprocnum",
10990                                           opfinfo->dobj.catId.oid);
10991
10992         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10993
10994         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10995         {
10996                 /* No loose members, so check contained opclasses */
10997                 resetPQExpBuffer(query);
10998
10999                 appendPQExpBuffer(query, "SELECT 1 "
11000                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
11001                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
11002                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11003                                                   "AND refobjid = f.oid "
11004                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11005                                                   "AND objid = c.oid "
11006                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
11007                                                   "LIMIT 1",
11008                                                   opfinfo->dobj.catId.oid);
11009
11010                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11011
11012                 if (PQntuples(res) == 0)
11013                 {
11014                         /* no need to dump it, so bail out */
11015                         PQclear(res);
11016                         PQclear(res_ops);
11017                         PQclear(res_procs);
11018                         destroyPQExpBuffer(query);
11019                         destroyPQExpBuffer(q);
11020                         destroyPQExpBuffer(delq);
11021                         destroyPQExpBuffer(labelq);
11022                         return;
11023                 }
11024
11025                 PQclear(res);
11026         }
11027
11028         /* Get additional fields from the pg_opfamily row */
11029         resetPQExpBuffer(query);
11030
11031         appendPQExpBuffer(query, "SELECT "
11032          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11033                                           "FROM pg_catalog.pg_opfamily "
11034                                           "WHERE oid = '%u'::pg_catalog.oid",
11035                                           opfinfo->dobj.catId.oid);
11036
11037         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11038
11039         i_amname = PQfnumber(res, "amname");
11040
11041         /* amname will still be needed after we PQclear res */
11042         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11043
11044         /*
11045          * DROP must be fully qualified in case same name appears in pg_catalog
11046          */
11047         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11048                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11049         appendPQExpBuffer(delq, ".%s",
11050                                           fmtId(opfinfo->dobj.name));
11051         appendPQExpBuffer(delq, " USING %s;\n",
11052                                           fmtId(amname));
11053
11054         /* Build the fixed portion of the CREATE command */
11055         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11056                                           fmtId(opfinfo->dobj.name));
11057         appendPQExpBuffer(q, " USING %s;\n",
11058                                           fmtId(amname));
11059
11060         PQclear(res);
11061
11062         /* Do we need an ALTER to add loose members? */
11063         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11064         {
11065                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11066                                                   fmtId(opfinfo->dobj.name));
11067                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11068                                                   fmtId(amname));
11069
11070                 needComma = false;
11071
11072                 /*
11073                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11074                  */
11075                 ntups = PQntuples(res_ops);
11076
11077                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11078                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11079                 i_amopopr = PQfnumber(res_ops, "amopopr");
11080                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11081                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11082
11083                 for (i = 0; i < ntups; i++)
11084                 {
11085                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11086                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11087                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11088                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11089                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11090
11091                         if (needComma)
11092                                 appendPQExpBuffer(q, " ,\n    ");
11093
11094                         appendPQExpBuffer(q, "OPERATOR %s %s",
11095                                                           amopstrategy, amopopr);
11096
11097                         if (strlen(sortfamily) > 0)
11098                         {
11099                                 appendPQExpBuffer(q, " FOR ORDER BY ");
11100                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11101                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11102                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
11103                         }
11104
11105                         if (strcmp(amopreqcheck, "t") == 0)
11106                                 appendPQExpBuffer(q, " RECHECK");
11107
11108                         needComma = true;
11109                 }
11110
11111                 /*
11112                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11113                  */
11114                 ntups = PQntuples(res_procs);
11115
11116                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11117                 i_amproc = PQfnumber(res_procs, "amproc");
11118                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11119                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11120
11121                 for (i = 0; i < ntups; i++)
11122                 {
11123                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11124                         amproc = PQgetvalue(res_procs, i, i_amproc);
11125                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11126                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11127
11128                         if (needComma)
11129                                 appendPQExpBuffer(q, " ,\n    ");
11130
11131                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11132                                                           amprocnum, amproclefttype, amprocrighttype,
11133                                                           amproc);
11134
11135                         needComma = true;
11136                 }
11137
11138                 appendPQExpBuffer(q, ";\n");
11139         }
11140
11141         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11142                                           fmtId(opfinfo->dobj.name));
11143         appendPQExpBuffer(labelq, " USING %s",
11144                                           fmtId(amname));
11145
11146         if (binary_upgrade)
11147                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11148
11149         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11150                                  opfinfo->dobj.name,
11151                                  opfinfo->dobj.namespace->dobj.name,
11152                                  NULL,
11153                                  opfinfo->rolname,
11154                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11155                                  q->data, delq->data, NULL,
11156                                  NULL, 0,
11157                                  NULL, NULL);
11158
11159         /* Dump Operator Family Comments */
11160         dumpComment(fout, labelq->data,
11161                                 NULL, opfinfo->rolname,
11162                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11163
11164         free(amname);
11165         PQclear(res_ops);
11166         PQclear(res_procs);
11167         destroyPQExpBuffer(query);
11168         destroyPQExpBuffer(q);
11169         destroyPQExpBuffer(delq);
11170         destroyPQExpBuffer(labelq);
11171 }
11172
11173 /*
11174  * dumpCollation
11175  *        write out a single collation definition
11176  */
11177 static void
11178 dumpCollation(Archive *fout, CollInfo *collinfo)
11179 {
11180         PQExpBuffer query;
11181         PQExpBuffer q;
11182         PQExpBuffer delq;
11183         PQExpBuffer labelq;
11184         PGresult   *res;
11185         int                     i_collcollate;
11186         int                     i_collctype;
11187         const char *collcollate;
11188         const char *collctype;
11189
11190         /* Skip if not to be dumped */
11191         if (!collinfo->dobj.dump || dataOnly)
11192                 return;
11193
11194         query = createPQExpBuffer();
11195         q = createPQExpBuffer();
11196         delq = createPQExpBuffer();
11197         labelq = createPQExpBuffer();
11198
11199         /* Make sure we are in proper schema */
11200         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11201
11202         /* Get conversion-specific details */
11203         appendPQExpBuffer(query, "SELECT "
11204                                           "collcollate, "
11205                                           "collctype "
11206                                           "FROM pg_catalog.pg_collation c "
11207                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11208                                           collinfo->dobj.catId.oid);
11209
11210         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11211
11212         i_collcollate = PQfnumber(res, "collcollate");
11213         i_collctype = PQfnumber(res, "collctype");
11214
11215         collcollate = PQgetvalue(res, 0, i_collcollate);
11216         collctype = PQgetvalue(res, 0, i_collctype);
11217
11218         /*
11219          * DROP must be fully qualified in case same name appears in pg_catalog
11220          */
11221         appendPQExpBuffer(delq, "DROP COLLATION %s",
11222                                           fmtId(collinfo->dobj.namespace->dobj.name));
11223         appendPQExpBuffer(delq, ".%s;\n",
11224                                           fmtId(collinfo->dobj.name));
11225
11226         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11227                                           fmtId(collinfo->dobj.name));
11228         appendStringLiteralAH(q, collcollate, fout);
11229         appendPQExpBuffer(q, ", lc_ctype = ");
11230         appendStringLiteralAH(q, collctype, fout);
11231         appendPQExpBuffer(q, ");\n");
11232
11233         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11234
11235         if (binary_upgrade)
11236                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11237
11238         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11239                                  collinfo->dobj.name,
11240                                  collinfo->dobj.namespace->dobj.name,
11241                                  NULL,
11242                                  collinfo->rolname,
11243                                  false, "COLLATION", SECTION_PRE_DATA,
11244                                  q->data, delq->data, NULL,
11245                                  NULL, 0,
11246                                  NULL, NULL);
11247
11248         /* Dump Collation Comments */
11249         dumpComment(fout, labelq->data,
11250                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11251                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11252
11253         PQclear(res);
11254
11255         destroyPQExpBuffer(query);
11256         destroyPQExpBuffer(q);
11257         destroyPQExpBuffer(delq);
11258         destroyPQExpBuffer(labelq);
11259 }
11260
11261 /*
11262  * dumpConversion
11263  *        write out a single conversion definition
11264  */
11265 static void
11266 dumpConversion(Archive *fout, ConvInfo *convinfo)
11267 {
11268         PQExpBuffer query;
11269         PQExpBuffer q;
11270         PQExpBuffer delq;
11271         PQExpBuffer labelq;
11272         PGresult   *res;
11273         int                     i_conforencoding;
11274         int                     i_contoencoding;
11275         int                     i_conproc;
11276         int                     i_condefault;
11277         const char *conforencoding;
11278         const char *contoencoding;
11279         const char *conproc;
11280         bool            condefault;
11281
11282         /* Skip if not to be dumped */
11283         if (!convinfo->dobj.dump || dataOnly)
11284                 return;
11285
11286         query = createPQExpBuffer();
11287         q = createPQExpBuffer();
11288         delq = createPQExpBuffer();
11289         labelq = createPQExpBuffer();
11290
11291         /* Make sure we are in proper schema */
11292         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11293
11294         /* Get conversion-specific details */
11295         appendPQExpBuffer(query, "SELECT "
11296                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11297                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11298                                           "conproc, condefault "
11299                                           "FROM pg_catalog.pg_conversion c "
11300                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11301                                           convinfo->dobj.catId.oid);
11302
11303         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11304
11305         i_conforencoding = PQfnumber(res, "conforencoding");
11306         i_contoencoding = PQfnumber(res, "contoencoding");
11307         i_conproc = PQfnumber(res, "conproc");
11308         i_condefault = PQfnumber(res, "condefault");
11309
11310         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11311         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11312         conproc = PQgetvalue(res, 0, i_conproc);
11313         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11314
11315         /*
11316          * DROP must be fully qualified in case same name appears in pg_catalog
11317          */
11318         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11319                                           fmtId(convinfo->dobj.namespace->dobj.name));
11320         appendPQExpBuffer(delq, ".%s;\n",
11321                                           fmtId(convinfo->dobj.name));
11322
11323         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11324                                           (condefault) ? "DEFAULT " : "",
11325                                           fmtId(convinfo->dobj.name));
11326         appendStringLiteralAH(q, conforencoding, fout);
11327         appendPQExpBuffer(q, " TO ");
11328         appendStringLiteralAH(q, contoencoding, fout);
11329         /* regproc is automatically quoted in 7.3 and above */
11330         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11331
11332         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11333
11334         if (binary_upgrade)
11335                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11336
11337         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11338                                  convinfo->dobj.name,
11339                                  convinfo->dobj.namespace->dobj.name,
11340                                  NULL,
11341                                  convinfo->rolname,
11342                                  false, "CONVERSION", SECTION_PRE_DATA,
11343                                  q->data, delq->data, NULL,
11344                                  NULL, 0,
11345                                  NULL, NULL);
11346
11347         /* Dump Conversion Comments */
11348         dumpComment(fout, labelq->data,
11349                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11350                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11351
11352         PQclear(res);
11353
11354         destroyPQExpBuffer(query);
11355         destroyPQExpBuffer(q);
11356         destroyPQExpBuffer(delq);
11357         destroyPQExpBuffer(labelq);
11358 }
11359
11360 /*
11361  * format_aggregate_signature: generate aggregate name and argument list
11362  *
11363  * The argument type names are qualified if needed.  The aggregate name
11364  * is never qualified.
11365  */
11366 static char *
11367 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11368 {
11369         PQExpBufferData buf;
11370         int                     j;
11371
11372         initPQExpBuffer(&buf);
11373         if (honor_quotes)
11374                 appendPQExpBuffer(&buf, "%s",
11375                                                   fmtId(agginfo->aggfn.dobj.name));
11376         else
11377                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
11378
11379         if (agginfo->aggfn.nargs == 0)
11380                 appendPQExpBuffer(&buf, "(*)");
11381         else
11382         {
11383                 appendPQExpBuffer(&buf, "(");
11384                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11385                 {
11386                         char       *typname;
11387
11388                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11389                                                                                    zeroAsOpaque);
11390
11391                         appendPQExpBuffer(&buf, "%s%s",
11392                                                           (j > 0) ? ", " : "",
11393                                                           typname);
11394                         free(typname);
11395                 }
11396                 appendPQExpBuffer(&buf, ")");
11397         }
11398         return buf.data;
11399 }
11400
11401 /*
11402  * dumpAgg
11403  *        write out a single aggregate definition
11404  */
11405 static void
11406 dumpAgg(Archive *fout, AggInfo *agginfo)
11407 {
11408         PQExpBuffer query;
11409         PQExpBuffer q;
11410         PQExpBuffer delq;
11411         PQExpBuffer labelq;
11412         PQExpBuffer details;
11413         char       *aggsig;                     /* identity signature */
11414         char       *aggfullsig;         /* full signature */
11415         char       *aggsig_tag;
11416         PGresult   *res;
11417         int                     i_aggtransfn;
11418         int                     i_aggfinalfn;
11419         int                     i_aggsortop;
11420         int                     i_aggtranstype;
11421         int                     i_agginitval;
11422         int                     i_convertok;
11423         const char *aggtransfn;
11424         const char *aggfinalfn;
11425         const char *aggsortop;
11426         const char *aggtranstype;
11427         const char *agginitval;
11428         bool            convertok;
11429
11430         /* Skip if not to be dumped */
11431         if (!agginfo->aggfn.dobj.dump || dataOnly)
11432                 return;
11433
11434         query = createPQExpBuffer();
11435         q = createPQExpBuffer();
11436         delq = createPQExpBuffer();
11437         labelq = createPQExpBuffer();
11438         details = createPQExpBuffer();
11439
11440         /* Make sure we are in proper schema */
11441         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11442
11443         /* Get aggregate-specific details */
11444         if (fout->remoteVersion >= 80400)
11445         {
11446                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11447                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11448                                                   "aggsortop::pg_catalog.regoperator, "
11449                                                   "agginitval, "
11450                                                   "'t'::boolean AS convertok, "
11451                                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11452                                                   "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11453                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11454                                                   "WHERE a.aggfnoid = p.oid "
11455                                                   "AND p.oid = '%u'::pg_catalog.oid",
11456                                                   agginfo->aggfn.dobj.catId.oid);
11457         }
11458         else if (fout->remoteVersion >= 80100)
11459         {
11460                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11461                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11462                                                   "aggsortop::pg_catalog.regoperator, "
11463                                                   "agginitval, "
11464                                                   "'t'::boolean AS convertok "
11465                                                   "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11466                                                   "WHERE a.aggfnoid = p.oid "
11467                                                   "AND p.oid = '%u'::pg_catalog.oid",
11468                                                   agginfo->aggfn.dobj.catId.oid);
11469         }
11470         else if (fout->remoteVersion >= 70300)
11471         {
11472                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11473                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11474                                                   "0 AS aggsortop, "
11475                                                   "agginitval, "
11476                                                   "'t'::boolean AS convertok "
11477                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11478                                                   "WHERE a.aggfnoid = p.oid "
11479                                                   "AND p.oid = '%u'::pg_catalog.oid",
11480                                                   agginfo->aggfn.dobj.catId.oid);
11481         }
11482         else if (fout->remoteVersion >= 70100)
11483         {
11484                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11485                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11486                                                   "0 AS aggsortop, "
11487                                                   "agginitval, "
11488                                                   "'t'::boolean AS convertok "
11489                                                   "FROM pg_aggregate "
11490                                                   "WHERE oid = '%u'::oid",
11491                                                   agginfo->aggfn.dobj.catId.oid);
11492         }
11493         else
11494         {
11495                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11496                                                   "aggfinalfn, "
11497                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11498                                                   "0 AS aggsortop, "
11499                                                   "agginitval1 AS agginitval, "
11500                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11501                                                   "FROM pg_aggregate "
11502                                                   "WHERE oid = '%u'::oid",
11503                                                   agginfo->aggfn.dobj.catId.oid);
11504         }
11505
11506         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11507
11508         i_aggtransfn = PQfnumber(res, "aggtransfn");
11509         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11510         i_aggsortop = PQfnumber(res, "aggsortop");
11511         i_aggtranstype = PQfnumber(res, "aggtranstype");
11512         i_agginitval = PQfnumber(res, "agginitval");
11513         i_convertok = PQfnumber(res, "convertok");
11514
11515         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11516         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11517         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11518         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11519         agginitval = PQgetvalue(res, 0, i_agginitval);
11520         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11521
11522         if (fout->remoteVersion >= 80400)
11523         {
11524                 /* 8.4 or later; we rely on server-side code for most of the work */
11525                 char       *funcargs;
11526                 char       *funciargs;
11527
11528                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11529                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11530                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
11531                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
11532         }
11533         else
11534         {
11535                 /* pre-8.4, do it ourselves */
11536                 aggsig = format_aggregate_signature(agginfo, fout, true);
11537                 aggfullsig = aggsig;
11538         }
11539
11540         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11541
11542         if (!convertok)
11543         {
11544                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11545                                   aggsig);
11546                 return;
11547         }
11548
11549         if (fout->remoteVersion >= 70300)
11550         {
11551                 /* If using 7.3's regproc or regtype, data is already quoted */
11552                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11553                                                   aggtransfn,
11554                                                   aggtranstype);
11555         }
11556         else if (fout->remoteVersion >= 70100)
11557         {
11558                 /* format_type quotes, regproc does not */
11559                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11560                                                   fmtId(aggtransfn),
11561                                                   aggtranstype);
11562         }
11563         else
11564         {
11565                 /* need quotes all around */
11566                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11567                                                   fmtId(aggtransfn));
11568                 appendPQExpBuffer(details, "    STYPE = %s",
11569                                                   fmtId(aggtranstype));
11570         }
11571
11572         if (!PQgetisnull(res, 0, i_agginitval))
11573         {
11574                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11575                 appendStringLiteralAH(details, agginitval, fout);
11576         }
11577
11578         if (strcmp(aggfinalfn, "-") != 0)
11579         {
11580                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11581                                                   aggfinalfn);
11582         }
11583
11584         aggsortop = convertOperatorReference(fout, aggsortop);
11585         if (aggsortop)
11586         {
11587                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11588                                                   aggsortop);
11589         }
11590
11591         /*
11592          * DROP must be fully qualified in case same name appears in pg_catalog
11593          */
11594         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11595                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11596                                           aggsig);
11597
11598         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11599                                           aggfullsig, details->data);
11600
11601         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11602
11603         if (binary_upgrade)
11604                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11605
11606         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11607                                  aggsig_tag,
11608                                  agginfo->aggfn.dobj.namespace->dobj.name,
11609                                  NULL,
11610                                  agginfo->aggfn.rolname,
11611                                  false, "AGGREGATE", SECTION_PRE_DATA,
11612                                  q->data, delq->data, NULL,
11613                                  NULL, 0,
11614                                  NULL, NULL);
11615
11616         /* Dump Aggregate Comments */
11617         dumpComment(fout, labelq->data,
11618                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11619                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11620         dumpSecLabel(fout, labelq->data,
11621                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11622                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11623
11624         /*
11625          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11626          * command look like a function's GRANT; in particular this affects the
11627          * syntax for zero-argument aggregates.
11628          */
11629         free(aggsig);
11630         free(aggsig_tag);
11631
11632         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11633         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11634
11635         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11636                         "FUNCTION",
11637                         aggsig, NULL, aggsig_tag,
11638                         agginfo->aggfn.dobj.namespace->dobj.name,
11639                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11640
11641         free(aggsig);
11642         free(aggsig_tag);
11643
11644         PQclear(res);
11645
11646         destroyPQExpBuffer(query);
11647         destroyPQExpBuffer(q);
11648         destroyPQExpBuffer(delq);
11649         destroyPQExpBuffer(labelq);
11650         destroyPQExpBuffer(details);
11651 }
11652
11653 /*
11654  * dumpTSParser
11655  *        write out a single text search parser
11656  */
11657 static void
11658 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11659 {
11660         PQExpBuffer q;
11661         PQExpBuffer delq;
11662         PQExpBuffer labelq;
11663
11664         /* Skip if not to be dumped */
11665         if (!prsinfo->dobj.dump || dataOnly)
11666                 return;
11667
11668         q = createPQExpBuffer();
11669         delq = createPQExpBuffer();
11670         labelq = createPQExpBuffer();
11671
11672         /* Make sure we are in proper schema */
11673         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11674
11675         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11676                                           fmtId(prsinfo->dobj.name));
11677
11678         appendPQExpBuffer(q, "    START = %s,\n",
11679                                           convertTSFunction(fout, prsinfo->prsstart));
11680         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11681                                           convertTSFunction(fout, prsinfo->prstoken));
11682         appendPQExpBuffer(q, "    END = %s,\n",
11683                                           convertTSFunction(fout, prsinfo->prsend));
11684         if (prsinfo->prsheadline != InvalidOid)
11685                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11686                                                   convertTSFunction(fout, prsinfo->prsheadline));
11687         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11688                                           convertTSFunction(fout, prsinfo->prslextype));
11689
11690         /*
11691          * DROP must be fully qualified in case same name appears in pg_catalog
11692          */
11693         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11694                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11695         appendPQExpBuffer(delq, ".%s;\n",
11696                                           fmtId(prsinfo->dobj.name));
11697
11698         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11699                                           fmtId(prsinfo->dobj.name));
11700
11701         if (binary_upgrade)
11702                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11703
11704         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11705                                  prsinfo->dobj.name,
11706                                  prsinfo->dobj.namespace->dobj.name,
11707                                  NULL,
11708                                  "",
11709                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11710                                  q->data, delq->data, NULL,
11711                                  NULL, 0,
11712                                  NULL, NULL);
11713
11714         /* Dump Parser Comments */
11715         dumpComment(fout, labelq->data,
11716                                 NULL, "",
11717                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11718
11719         destroyPQExpBuffer(q);
11720         destroyPQExpBuffer(delq);
11721         destroyPQExpBuffer(labelq);
11722 }
11723
11724 /*
11725  * dumpTSDictionary
11726  *        write out a single text search dictionary
11727  */
11728 static void
11729 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11730 {
11731         PQExpBuffer q;
11732         PQExpBuffer delq;
11733         PQExpBuffer labelq;
11734         PQExpBuffer query;
11735         PGresult   *res;
11736         char       *nspname;
11737         char       *tmplname;
11738
11739         /* Skip if not to be dumped */
11740         if (!dictinfo->dobj.dump || dataOnly)
11741                 return;
11742
11743         q = createPQExpBuffer();
11744         delq = createPQExpBuffer();
11745         labelq = createPQExpBuffer();
11746         query = createPQExpBuffer();
11747
11748         /* Fetch name and namespace of the dictionary's template */
11749         selectSourceSchema(fout, "pg_catalog");
11750         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11751                                           "FROM pg_ts_template p, pg_namespace n "
11752                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11753                                           dictinfo->dicttemplate);
11754         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11755         nspname = PQgetvalue(res, 0, 0);
11756         tmplname = PQgetvalue(res, 0, 1);
11757
11758         /* Make sure we are in proper schema */
11759         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11760
11761         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11762                                           fmtId(dictinfo->dobj.name));
11763
11764         appendPQExpBuffer(q, "    TEMPLATE = ");
11765         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11766                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11767         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11768
11769         PQclear(res);
11770
11771         /* the dictinitoption can be dumped straight into the command */
11772         if (dictinfo->dictinitoption)
11773                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11774
11775         appendPQExpBuffer(q, " );\n");
11776
11777         /*
11778          * DROP must be fully qualified in case same name appears in pg_catalog
11779          */
11780         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11781                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11782         appendPQExpBuffer(delq, ".%s;\n",
11783                                           fmtId(dictinfo->dobj.name));
11784
11785         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11786                                           fmtId(dictinfo->dobj.name));
11787
11788         if (binary_upgrade)
11789                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11790
11791         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11792                                  dictinfo->dobj.name,
11793                                  dictinfo->dobj.namespace->dobj.name,
11794                                  NULL,
11795                                  dictinfo->rolname,
11796                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11797                                  q->data, delq->data, NULL,
11798                                  NULL, 0,
11799                                  NULL, NULL);
11800
11801         /* Dump Dictionary Comments */
11802         dumpComment(fout, labelq->data,
11803                                 NULL, dictinfo->rolname,
11804                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11805
11806         destroyPQExpBuffer(q);
11807         destroyPQExpBuffer(delq);
11808         destroyPQExpBuffer(labelq);
11809         destroyPQExpBuffer(query);
11810 }
11811
11812 /*
11813  * dumpTSTemplate
11814  *        write out a single text search template
11815  */
11816 static void
11817 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11818 {
11819         PQExpBuffer q;
11820         PQExpBuffer delq;
11821         PQExpBuffer labelq;
11822
11823         /* Skip if not to be dumped */
11824         if (!tmplinfo->dobj.dump || dataOnly)
11825                 return;
11826
11827         q = createPQExpBuffer();
11828         delq = createPQExpBuffer();
11829         labelq = createPQExpBuffer();
11830
11831         /* Make sure we are in proper schema */
11832         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11833
11834         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11835                                           fmtId(tmplinfo->dobj.name));
11836
11837         if (tmplinfo->tmplinit != InvalidOid)
11838                 appendPQExpBuffer(q, "    INIT = %s,\n",
11839                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11840         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11841                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11842
11843         /*
11844          * DROP must be fully qualified in case same name appears in pg_catalog
11845          */
11846         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11847                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11848         appendPQExpBuffer(delq, ".%s;\n",
11849                                           fmtId(tmplinfo->dobj.name));
11850
11851         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11852                                           fmtId(tmplinfo->dobj.name));
11853
11854         if (binary_upgrade)
11855                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11856
11857         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11858                                  tmplinfo->dobj.name,
11859                                  tmplinfo->dobj.namespace->dobj.name,
11860                                  NULL,
11861                                  "",
11862                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11863                                  q->data, delq->data, NULL,
11864                                  NULL, 0,
11865                                  NULL, NULL);
11866
11867         /* Dump Template Comments */
11868         dumpComment(fout, labelq->data,
11869                                 NULL, "",
11870                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11871
11872         destroyPQExpBuffer(q);
11873         destroyPQExpBuffer(delq);
11874         destroyPQExpBuffer(labelq);
11875 }
11876
11877 /*
11878  * dumpTSConfig
11879  *        write out a single text search configuration
11880  */
11881 static void
11882 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11883 {
11884         PQExpBuffer q;
11885         PQExpBuffer delq;
11886         PQExpBuffer labelq;
11887         PQExpBuffer query;
11888         PGresult   *res;
11889         char       *nspname;
11890         char       *prsname;
11891         int                     ntups,
11892                                 i;
11893         int                     i_tokenname;
11894         int                     i_dictname;
11895
11896         /* Skip if not to be dumped */
11897         if (!cfginfo->dobj.dump || dataOnly)
11898                 return;
11899
11900         q = createPQExpBuffer();
11901         delq = createPQExpBuffer();
11902         labelq = createPQExpBuffer();
11903         query = createPQExpBuffer();
11904
11905         /* Fetch name and namespace of the config's parser */
11906         selectSourceSchema(fout, "pg_catalog");
11907         appendPQExpBuffer(query, "SELECT nspname, prsname "
11908                                           "FROM pg_ts_parser p, pg_namespace n "
11909                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11910                                           cfginfo->cfgparser);
11911         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11912         nspname = PQgetvalue(res, 0, 0);
11913         prsname = PQgetvalue(res, 0, 1);
11914
11915         /* Make sure we are in proper schema */
11916         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11917
11918         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11919                                           fmtId(cfginfo->dobj.name));
11920
11921         appendPQExpBuffer(q, "    PARSER = ");
11922         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11923                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11924         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11925
11926         PQclear(res);
11927
11928         resetPQExpBuffer(query);
11929         appendPQExpBuffer(query,
11930                                           "SELECT \n"
11931                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11932                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11933                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11934                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11935                                           "WHERE m.mapcfg = '%u' \n"
11936                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11937                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11938
11939         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11940         ntups = PQntuples(res);
11941
11942         i_tokenname = PQfnumber(res, "tokenname");
11943         i_dictname = PQfnumber(res, "dictname");
11944
11945         for (i = 0; i < ntups; i++)
11946         {
11947                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11948                 char       *dictname = PQgetvalue(res, i, i_dictname);
11949
11950                 if (i == 0 ||
11951                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11952                 {
11953                         /* starting a new token type, so start a new command */
11954                         if (i > 0)
11955                                 appendPQExpBuffer(q, ";\n");
11956                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11957                                                           fmtId(cfginfo->dobj.name));
11958                         /* tokenname needs quoting, dictname does NOT */
11959                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11960                                                           fmtId(tokenname), dictname);
11961                 }
11962                 else
11963                         appendPQExpBuffer(q, ", %s", dictname);
11964         }
11965
11966         if (ntups > 0)
11967                 appendPQExpBuffer(q, ";\n");
11968
11969         PQclear(res);
11970
11971         /*
11972          * DROP must be fully qualified in case same name appears in pg_catalog
11973          */
11974         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11975                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11976         appendPQExpBuffer(delq, ".%s;\n",
11977                                           fmtId(cfginfo->dobj.name));
11978
11979         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11980                                           fmtId(cfginfo->dobj.name));
11981
11982         if (binary_upgrade)
11983                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11984
11985         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11986                                  cfginfo->dobj.name,
11987                                  cfginfo->dobj.namespace->dobj.name,
11988                                  NULL,
11989                                  cfginfo->rolname,
11990                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11991                                  q->data, delq->data, NULL,
11992                                  NULL, 0,
11993                                  NULL, NULL);
11994
11995         /* Dump Configuration Comments */
11996         dumpComment(fout, labelq->data,
11997                                 NULL, cfginfo->rolname,
11998                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11999
12000         destroyPQExpBuffer(q);
12001         destroyPQExpBuffer(delq);
12002         destroyPQExpBuffer(labelq);
12003         destroyPQExpBuffer(query);
12004 }
12005
12006 /*
12007  * dumpForeignDataWrapper
12008  *        write out a single foreign-data wrapper definition
12009  */
12010 static void
12011 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
12012 {
12013         PQExpBuffer q;
12014         PQExpBuffer delq;
12015         PQExpBuffer labelq;
12016         char       *qfdwname;
12017
12018         /* Skip if not to be dumped */
12019         if (!fdwinfo->dobj.dump || dataOnly)
12020                 return;
12021
12022         /*
12023          * FDWs that belong to an extension are dumped based on their "dump"
12024          * field. Otherwise omit them if we are only dumping some specific object.
12025          */
12026         if (!fdwinfo->dobj.ext_member)
12027                 if (!include_everything)
12028                         return;
12029
12030         q = createPQExpBuffer();
12031         delq = createPQExpBuffer();
12032         labelq = createPQExpBuffer();
12033
12034         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
12035
12036         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
12037                                           qfdwname);
12038
12039         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
12040                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
12041
12042         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
12043                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
12044
12045         if (strlen(fdwinfo->fdwoptions) > 0)
12046                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12047
12048         appendPQExpBuffer(q, ";\n");
12049
12050         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12051                                           qfdwname);
12052
12053         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12054                                           qfdwname);
12055
12056         if (binary_upgrade)
12057                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12058
12059         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12060                                  fdwinfo->dobj.name,
12061                                  NULL,
12062                                  NULL,
12063                                  fdwinfo->rolname,
12064                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12065                                  q->data, delq->data, NULL,
12066                                  NULL, 0,
12067                                  NULL, NULL);
12068
12069         /* Handle the ACL */
12070         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12071                         "FOREIGN DATA WRAPPER",
12072                         qfdwname, NULL, fdwinfo->dobj.name,
12073                         NULL, fdwinfo->rolname,
12074                         fdwinfo->fdwacl);
12075
12076         /* Dump Foreign Data Wrapper Comments */
12077         dumpComment(fout, labelq->data,
12078                                 NULL, fdwinfo->rolname,
12079                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12080
12081         free(qfdwname);
12082
12083         destroyPQExpBuffer(q);
12084         destroyPQExpBuffer(delq);
12085         destroyPQExpBuffer(labelq);
12086 }
12087
12088 /*
12089  * dumpForeignServer
12090  *        write out a foreign server definition
12091  */
12092 static void
12093 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12094 {
12095         PQExpBuffer q;
12096         PQExpBuffer delq;
12097         PQExpBuffer labelq;
12098         PQExpBuffer query;
12099         PGresult   *res;
12100         char       *qsrvname;
12101         char       *fdwname;
12102
12103         /* Skip if not to be dumped */
12104         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12105                 return;
12106
12107         q = createPQExpBuffer();
12108         delq = createPQExpBuffer();
12109         labelq = createPQExpBuffer();
12110         query = createPQExpBuffer();
12111
12112         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12113
12114         /* look up the foreign-data wrapper */
12115         selectSourceSchema(fout, "pg_catalog");
12116         appendPQExpBuffer(query, "SELECT fdwname "
12117                                           "FROM pg_foreign_data_wrapper w "
12118                                           "WHERE w.oid = '%u'",
12119                                           srvinfo->srvfdw);
12120         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12121         fdwname = PQgetvalue(res, 0, 0);
12122
12123         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12124         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12125         {
12126                 appendPQExpBuffer(q, " TYPE ");
12127                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12128         }
12129         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12130         {
12131                 appendPQExpBuffer(q, " VERSION ");
12132                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12133         }
12134
12135         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
12136         appendPQExpBuffer(q, "%s", fmtId(fdwname));
12137
12138         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12139                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12140
12141         appendPQExpBuffer(q, ";\n");
12142
12143         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12144                                           qsrvname);
12145
12146         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12147
12148         if (binary_upgrade)
12149                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12150
12151         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12152                                  srvinfo->dobj.name,
12153                                  NULL,
12154                                  NULL,
12155                                  srvinfo->rolname,
12156                                  false, "SERVER", SECTION_PRE_DATA,
12157                                  q->data, delq->data, NULL,
12158                                  NULL, 0,
12159                                  NULL, NULL);
12160
12161         /* Handle the ACL */
12162         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12163                         "FOREIGN SERVER",
12164                         qsrvname, NULL, srvinfo->dobj.name,
12165                         NULL, srvinfo->rolname,
12166                         srvinfo->srvacl);
12167
12168         /* Dump user mappings */
12169         dumpUserMappings(fout,
12170                                          srvinfo->dobj.name, NULL,
12171                                          srvinfo->rolname,
12172                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12173
12174         /* Dump Foreign Server Comments */
12175         dumpComment(fout, labelq->data,
12176                                 NULL, srvinfo->rolname,
12177                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12178
12179         free(qsrvname);
12180
12181         destroyPQExpBuffer(q);
12182         destroyPQExpBuffer(delq);
12183         destroyPQExpBuffer(labelq);
12184 }
12185
12186 /*
12187  * dumpUserMappings
12188  *
12189  * This routine is used to dump any user mappings associated with the
12190  * server handed to this routine. Should be called after ArchiveEntry()
12191  * for the server.
12192  */
12193 static void
12194 dumpUserMappings(Archive *fout,
12195                                  const char *servername, const char *namespace,
12196                                  const char *owner,
12197                                  CatalogId catalogId, DumpId dumpId)
12198 {
12199         PQExpBuffer q;
12200         PQExpBuffer delq;
12201         PQExpBuffer query;
12202         PQExpBuffer tag;
12203         PGresult   *res;
12204         int                     ntups;
12205         int                     i_usename;
12206         int                     i_umoptions;
12207         int                     i;
12208
12209         q = createPQExpBuffer();
12210         tag = createPQExpBuffer();
12211         delq = createPQExpBuffer();
12212         query = createPQExpBuffer();
12213
12214         /*
12215          * We read from the publicly accessible view pg_user_mappings, so as not
12216          * to fail if run by a non-superuser.  Note that the view will show
12217          * umoptions as null if the user hasn't got privileges for the associated
12218          * server; this means that pg_dump will dump such a mapping, but with no
12219          * OPTIONS clause.      A possible alternative is to skip such mappings
12220          * altogether, but it's not clear that that's an improvement.
12221          */
12222         selectSourceSchema(fout, "pg_catalog");
12223
12224         appendPQExpBuffer(query,
12225                                           "SELECT usename, "
12226                                           "array_to_string(ARRAY("
12227                                           "SELECT quote_ident(option_name) || ' ' || "
12228                                           "quote_literal(option_value) "
12229                                           "FROM pg_options_to_table(umoptions) "
12230                                           "ORDER BY option_name"
12231                                           "), E',\n    ') AS umoptions "
12232                                           "FROM pg_user_mappings "
12233                                           "WHERE srvid = '%u' "
12234                                           "ORDER BY usename",
12235                                           catalogId.oid);
12236
12237         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12238
12239         ntups = PQntuples(res);
12240         i_usename = PQfnumber(res, "usename");
12241         i_umoptions = PQfnumber(res, "umoptions");
12242
12243         for (i = 0; i < ntups; i++)
12244         {
12245                 char       *usename;
12246                 char       *umoptions;
12247
12248                 usename = PQgetvalue(res, i, i_usename);
12249                 umoptions = PQgetvalue(res, i, i_umoptions);
12250
12251                 resetPQExpBuffer(q);
12252                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12253                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12254
12255                 if (umoptions && strlen(umoptions) > 0)
12256                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12257
12258                 appendPQExpBuffer(q, ";\n");
12259
12260                 resetPQExpBuffer(delq);
12261                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12262                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12263
12264                 resetPQExpBuffer(tag);
12265                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12266                                                   usename, servername);
12267
12268                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12269                                          tag->data,
12270                                          namespace,
12271                                          NULL,
12272                                          owner, false,
12273                                          "USER MAPPING", SECTION_PRE_DATA,
12274                                          q->data, delq->data, NULL,
12275                                          &dumpId, 1,
12276                                          NULL, NULL);
12277         }
12278
12279         PQclear(res);
12280
12281         destroyPQExpBuffer(query);
12282         destroyPQExpBuffer(delq);
12283         destroyPQExpBuffer(q);
12284 }
12285
12286 /*
12287  * Write out default privileges information
12288  */
12289 static void
12290 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12291 {
12292         PQExpBuffer q;
12293         PQExpBuffer tag;
12294         const char *type;
12295
12296         /* Skip if not to be dumped */
12297         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12298                 return;
12299
12300         q = createPQExpBuffer();
12301         tag = createPQExpBuffer();
12302
12303         switch (daclinfo->defaclobjtype)
12304         {
12305                 case DEFACLOBJ_RELATION:
12306                         type = "TABLES";
12307                         break;
12308                 case DEFACLOBJ_SEQUENCE:
12309                         type = "SEQUENCES";
12310                         break;
12311                 case DEFACLOBJ_FUNCTION:
12312                         type = "FUNCTIONS";
12313                         break;
12314                 case DEFACLOBJ_TYPE:
12315                         type = "TYPES";
12316                         break;
12317                 default:
12318                         /* shouldn't get here */
12319                         exit_horribly(NULL,
12320                                           "unrecognized object type in default privileges: %d\n",
12321                                                   (int) daclinfo->defaclobjtype);
12322                         type = "";                      /* keep compiler quiet */
12323         }
12324
12325         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12326
12327         /* build the actual command(s) for this tuple */
12328         if (!buildDefaultACLCommands(type,
12329                                                                  daclinfo->dobj.namespace != NULL ?
12330                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12331                                                                  daclinfo->defaclacl,
12332                                                                  daclinfo->defaclrole,
12333                                                                  fout->remoteVersion,
12334                                                                  q))
12335                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12336                                           daclinfo->defaclacl);
12337
12338         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12339                                  tag->data,
12340            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12341                                  NULL,
12342                                  daclinfo->defaclrole,
12343                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12344                                  q->data, "", NULL,
12345                                  NULL, 0,
12346                                  NULL, NULL);
12347
12348         destroyPQExpBuffer(tag);
12349         destroyPQExpBuffer(q);
12350 }
12351
12352 /*----------
12353  * Write out grant/revoke information
12354  *
12355  * 'objCatId' is the catalog ID of the underlying object.
12356  * 'objDumpId' is the dump ID of the underlying object.
12357  * 'type' must be one of
12358  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12359  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12360  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12361  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12362  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12363  * 'nspname' is the namespace the object is in (NULL if none).
12364  * 'owner' is the owner, NULL if there is no owner (for languages).
12365  * 'acls' is the string read out of the fooacl system catalog field;
12366  *              it will be parsed here.
12367  *----------
12368  */
12369 static void
12370 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12371                 const char *type, const char *name, const char *subname,
12372                 const char *tag, const char *nspname, const char *owner,
12373                 const char *acls)
12374 {
12375         PQExpBuffer sql;
12376
12377         /* Do nothing if ACL dump is not enabled */
12378         if (aclsSkip)
12379                 return;
12380
12381         /* --data-only skips ACLs *except* BLOB ACLs */
12382         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12383                 return;
12384
12385         sql = createPQExpBuffer();
12386
12387         if (!buildACLCommands(name, subname, type, acls, owner,
12388                                                   "", fout->remoteVersion, sql))
12389                 exit_horribly(NULL,
12390                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12391                                           acls, name, type);
12392
12393         if (sql->len > 0)
12394                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12395                                          tag, nspname,
12396                                          NULL,
12397                                          owner ? owner : "",
12398                                          false, "ACL", SECTION_NONE,
12399                                          sql->data, "", NULL,
12400                                          &(objDumpId), 1,
12401                                          NULL, NULL);
12402
12403         destroyPQExpBuffer(sql);
12404 }
12405
12406 /*
12407  * dumpSecLabel
12408  *
12409  * This routine is used to dump any security labels associated with the
12410  * object handed to this routine. The routine takes a constant character
12411  * string for the target part of the security-label command, plus
12412  * the namespace and owner of the object (for labeling the ArchiveEntry),
12413  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12414  * plus the dump ID for the object (for setting a dependency).
12415  * If a matching pg_seclabel entry is found, it is dumped.
12416  *
12417  * Note: although this routine takes a dumpId for dependency purposes,
12418  * that purpose is just to mark the dependency in the emitted dump file
12419  * for possible future use by pg_restore.  We do NOT use it for determining
12420  * ordering of the label in the dump file, because this routine is called
12421  * after dependency sorting occurs.  This routine should be called just after
12422  * calling ArchiveEntry() for the specified object.
12423  */
12424 static void
12425 dumpSecLabel(Archive *fout, const char *target,
12426                          const char *namespace, const char *owner,
12427                          CatalogId catalogId, int subid, DumpId dumpId)
12428 {
12429         SecLabelItem *labels;
12430         int                     nlabels;
12431         int                     i;
12432         PQExpBuffer query;
12433
12434         /* do nothing, if --no-security-labels is supplied */
12435         if (no_security_labels)
12436                 return;
12437
12438         /* Comments are schema not data ... except blob comments are data */
12439         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12440         {
12441                 if (dataOnly)
12442                         return;
12443         }
12444         else
12445         {
12446                 if (schemaOnly)
12447                         return;
12448         }
12449
12450         /* Search for security labels associated with catalogId, using table */
12451         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12452
12453         query = createPQExpBuffer();
12454
12455         for (i = 0; i < nlabels; i++)
12456         {
12457                 /*
12458                  * Ignore label entries for which the subid doesn't match.
12459                  */
12460                 if (labels[i].objsubid != subid)
12461                         continue;
12462
12463                 appendPQExpBuffer(query,
12464                                                   "SECURITY LABEL FOR %s ON %s IS ",
12465                                                   fmtId(labels[i].provider), target);
12466                 appendStringLiteralAH(query, labels[i].label, fout);
12467                 appendPQExpBuffer(query, ";\n");
12468         }
12469
12470         if (query->len > 0)
12471         {
12472                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12473                                          target, namespace, NULL, owner,
12474                                          false, "SECURITY LABEL", SECTION_NONE,
12475                                          query->data, "", NULL,
12476                                          &(dumpId), 1,
12477                                          NULL, NULL);
12478         }
12479         destroyPQExpBuffer(query);
12480 }
12481
12482 /*
12483  * dumpTableSecLabel
12484  *
12485  * As above, but dump security label for both the specified table (or view)
12486  * and its columns.
12487  */
12488 static void
12489 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12490 {
12491         SecLabelItem *labels;
12492         int                     nlabels;
12493         int                     i;
12494         PQExpBuffer query;
12495         PQExpBuffer target;
12496
12497         /* do nothing, if --no-security-labels is supplied */
12498         if (no_security_labels)
12499                 return;
12500
12501         /* SecLabel are SCHEMA not data */
12502         if (dataOnly)
12503                 return;
12504
12505         /* Search for comments associated with relation, using table */
12506         nlabels = findSecLabels(fout,
12507                                                         tbinfo->dobj.catId.tableoid,
12508                                                         tbinfo->dobj.catId.oid,
12509                                                         &labels);
12510
12511         /* If security labels exist, build SECURITY LABEL statements */
12512         if (nlabels <= 0)
12513                 return;
12514
12515         query = createPQExpBuffer();
12516         target = createPQExpBuffer();
12517
12518         for (i = 0; i < nlabels; i++)
12519         {
12520                 const char *colname;
12521                 const char *provider = labels[i].provider;
12522                 const char *label = labels[i].label;
12523                 int                     objsubid = labels[i].objsubid;
12524
12525                 resetPQExpBuffer(target);
12526                 if (objsubid == 0)
12527                 {
12528                         appendPQExpBuffer(target, "%s %s", reltypename,
12529                                                           fmtId(tbinfo->dobj.name));
12530                 }
12531                 else
12532                 {
12533                         colname = getAttrName(objsubid, tbinfo);
12534                         /* first fmtId result must be consumed before calling it again */
12535                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12536                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12537                 }
12538                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12539                                                   fmtId(provider), target->data);
12540                 appendStringLiteralAH(query, label, fout);
12541                 appendPQExpBuffer(query, ";\n");
12542         }
12543         if (query->len > 0)
12544         {
12545                 resetPQExpBuffer(target);
12546                 appendPQExpBuffer(target, "%s %s", reltypename,
12547                                                   fmtId(tbinfo->dobj.name));
12548                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12549                                          target->data,
12550                                          tbinfo->dobj.namespace->dobj.name,
12551                                          NULL, tbinfo->rolname,
12552                                          false, "SECURITY LABEL", SECTION_NONE,
12553                                          query->data, "", NULL,
12554                                          &(tbinfo->dobj.dumpId), 1,
12555                                          NULL, NULL);
12556         }
12557         destroyPQExpBuffer(query);
12558         destroyPQExpBuffer(target);
12559 }
12560
12561 /*
12562  * findSecLabels
12563  *
12564  * Find the security label(s), if any, associated with the given object.
12565  * All the objsubid values associated with the given classoid/objoid are
12566  * found with one search.
12567  */
12568 static int
12569 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12570 {
12571         /* static storage for table of security labels */
12572         static SecLabelItem *labels = NULL;
12573         static int      nlabels = -1;
12574
12575         SecLabelItem *middle = NULL;
12576         SecLabelItem *low;
12577         SecLabelItem *high;
12578         int                     nmatch;
12579
12580         /* Get security labels if we didn't already */
12581         if (nlabels < 0)
12582                 nlabels = collectSecLabels(fout, &labels);
12583
12584         if (nlabels <= 0)                       /* no labels, so no match is possible */
12585         {
12586                 *items = NULL;
12587                 return 0;
12588         }
12589
12590         /*
12591          * Do binary search to find some item matching the object.
12592          */
12593         low = &labels[0];
12594         high = &labels[nlabels - 1];
12595         while (low <= high)
12596         {
12597                 middle = low + (high - low) / 2;
12598
12599                 if (classoid < middle->classoid)
12600                         high = middle - 1;
12601                 else if (classoid > middle->classoid)
12602                         low = middle + 1;
12603                 else if (objoid < middle->objoid)
12604                         high = middle - 1;
12605                 else if (objoid > middle->objoid)
12606                         low = middle + 1;
12607                 else
12608                         break;                          /* found a match */
12609         }
12610
12611         if (low > high)                         /* no matches */
12612         {
12613                 *items = NULL;
12614                 return 0;
12615         }
12616
12617         /*
12618          * Now determine how many items match the object.  The search loop
12619          * invariant still holds: only items between low and high inclusive could
12620          * match.
12621          */
12622         nmatch = 1;
12623         while (middle > low)
12624         {
12625                 if (classoid != middle[-1].classoid ||
12626                         objoid != middle[-1].objoid)
12627                         break;
12628                 middle--;
12629                 nmatch++;
12630         }
12631
12632         *items = middle;
12633
12634         middle += nmatch;
12635         while (middle <= high)
12636         {
12637                 if (classoid != middle->classoid ||
12638                         objoid != middle->objoid)
12639                         break;
12640                 middle++;
12641                 nmatch++;
12642         }
12643
12644         return nmatch;
12645 }
12646
12647 /*
12648  * collectSecLabels
12649  *
12650  * Construct a table of all security labels available for database objects.
12651  * It's much faster to pull them all at once.
12652  *
12653  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12654  */
12655 static int
12656 collectSecLabels(Archive *fout, SecLabelItem **items)
12657 {
12658         PGresult   *res;
12659         PQExpBuffer query;
12660         int                     i_label;
12661         int                     i_provider;
12662         int                     i_classoid;
12663         int                     i_objoid;
12664         int                     i_objsubid;
12665         int                     ntups;
12666         int                     i;
12667         SecLabelItem *labels;
12668
12669         query = createPQExpBuffer();
12670
12671         appendPQExpBuffer(query,
12672                                           "SELECT label, provider, classoid, objoid, objsubid "
12673                                           "FROM pg_catalog.pg_seclabel "
12674                                           "ORDER BY classoid, objoid, objsubid");
12675
12676         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12677
12678         /* Construct lookup table containing OIDs in numeric form */
12679         i_label = PQfnumber(res, "label");
12680         i_provider = PQfnumber(res, "provider");
12681         i_classoid = PQfnumber(res, "classoid");
12682         i_objoid = PQfnumber(res, "objoid");
12683         i_objsubid = PQfnumber(res, "objsubid");
12684
12685         ntups = PQntuples(res);
12686
12687         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12688
12689         for (i = 0; i < ntups; i++)
12690         {
12691                 labels[i].label = PQgetvalue(res, i, i_label);
12692                 labels[i].provider = PQgetvalue(res, i, i_provider);
12693                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12694                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12695                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12696         }
12697
12698         /* Do NOT free the PGresult since we are keeping pointers into it */
12699         destroyPQExpBuffer(query);
12700
12701         *items = labels;
12702         return ntups;
12703 }
12704
12705 /*
12706  * dumpTable
12707  *        write out to fout the declarations (not data) of a user-defined table
12708  */
12709 static void
12710 dumpTable(Archive *fout, TableInfo *tbinfo)
12711 {
12712         if (tbinfo->dobj.dump && !dataOnly)
12713         {
12714                 char       *namecopy;
12715
12716                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12717                         dumpSequence(fout, tbinfo);
12718                 else
12719                         dumpTableSchema(fout, tbinfo);
12720
12721                 /* Handle the ACL here */
12722                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12723                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12724                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12725                                 "TABLE",
12726                                 namecopy, NULL, tbinfo->dobj.name,
12727                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12728                                 tbinfo->relacl);
12729
12730                 /*
12731                  * Handle column ACLs, if any.  Note: we pull these with a separate
12732                  * query rather than trying to fetch them during getTableAttrs, so
12733                  * that we won't miss ACLs on system columns.
12734                  */
12735                 if (fout->remoteVersion >= 80400)
12736                 {
12737                         PQExpBuffer query = createPQExpBuffer();
12738                         PGresult   *res;
12739                         int                     i;
12740
12741                         appendPQExpBuffer(query,
12742                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12743                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12744                                                           "ORDER BY attnum",
12745                                                           tbinfo->dobj.catId.oid);
12746                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12747
12748                         for (i = 0; i < PQntuples(res); i++)
12749                         {
12750                                 char       *attname = PQgetvalue(res, i, 0);
12751                                 char       *attacl = PQgetvalue(res, i, 1);
12752                                 char       *attnamecopy;
12753                                 char       *acltag;
12754
12755                                 attnamecopy = pg_strdup(fmtId(attname));
12756                                 pg_asprintf(&acltag, "%s.%s", tbinfo->dobj.name, attname);
12757                                 /* Column's GRANT type is always TABLE */
12758                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12759                                                 namecopy, attnamecopy, acltag,
12760                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12761                                                 attacl);
12762                                 free(attnamecopy);
12763                                 free(acltag);
12764                         }
12765                         PQclear(res);
12766                         destroyPQExpBuffer(query);
12767                 }
12768
12769                 free(namecopy);
12770         }
12771 }
12772
12773 /*
12774  * Create the AS clause for a view or materialized view. The semicolon is
12775  * stripped because a materialized view must add a WITH NO DATA clause.
12776  *
12777  * This returns a new buffer which must be freed by the caller.
12778  */
12779 static PQExpBuffer
12780 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12781 {
12782         PQExpBuffer query = createPQExpBuffer();
12783         PQExpBuffer result = createPQExpBuffer();
12784         PGresult   *res;
12785         int                     len;
12786
12787         /* Fetch the view definition */
12788         if (fout->remoteVersion >= 70300)
12789         {
12790                 /* Beginning in 7.3, viewname is not unique; rely on OID */
12791                 appendPQExpBuffer(query,
12792                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12793                                                   tbinfo->dobj.catId.oid);
12794         }
12795         else
12796         {
12797                 appendPQExpBuffer(query, "SELECT definition AS viewdef "
12798                                                   "FROM pg_views WHERE viewname = ");
12799                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12800         }
12801
12802         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12803
12804         if (PQntuples(res) != 1)
12805         {
12806                 if (PQntuples(res) < 1)
12807                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12808                                                   tbinfo->dobj.name);
12809                 else
12810                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12811                                                   tbinfo->dobj.name);
12812         }
12813
12814         len = PQgetlength(res, 0, 0);
12815
12816         if (len == 0)
12817                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12818                                           tbinfo->dobj.name);
12819
12820         /* Strip off the trailing semicolon so that other things may follow. */
12821         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12822         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12823
12824         PQclear(res);
12825         destroyPQExpBuffer(query);
12826
12827         return result;
12828 }
12829
12830 /*
12831  * dumpTableSchema
12832  *        write the declaration (not data) of one user-defined table or view
12833  */
12834 static void
12835 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12836 {
12837         PQExpBuffer q = createPQExpBuffer();
12838         PQExpBuffer delq = createPQExpBuffer();
12839         PQExpBuffer labelq = createPQExpBuffer();
12840         int                     numParents;
12841         TableInfo **parents;
12842         int                     actual_atts;    /* number of attrs in this CREATE statement */
12843         const char *reltypename;
12844         char       *storage;
12845         char       *srvname;
12846         char       *ftoptions;
12847         int                     j,
12848                                 k;
12849
12850         /* Make sure we are in proper schema */
12851         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12852
12853         if (binary_upgrade)
12854                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12855                                                                                                 tbinfo->dobj.catId.oid);
12856
12857         /* Is it a table or a view? */
12858         if (tbinfo->relkind == RELKIND_VIEW)
12859         {
12860                 PQExpBuffer result;
12861
12862                 reltypename = "VIEW";
12863
12864                 /*
12865                  * DROP must be fully qualified in case same name appears in
12866                  * pg_catalog
12867                  */
12868                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12869                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12870                 appendPQExpBuffer(delq, "%s;\n",
12871                                                   fmtId(tbinfo->dobj.name));
12872
12873                 if (binary_upgrade)
12874                         binary_upgrade_set_pg_class_oids(fout, q,
12875                                                                                          tbinfo->dobj.catId.oid, false);
12876
12877                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12878                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12879                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12880                 result = createViewAsClause(fout, tbinfo);
12881                 appendPQExpBuffer(q, " AS\n%s", result->data);
12882                 destroyPQExpBuffer(result);
12883
12884                 if (tbinfo->checkoption != NULL)
12885                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
12886                 appendPQExpBuffer(q, ";\n");
12887
12888                 appendPQExpBuffer(labelq, "VIEW %s",
12889                                                   fmtId(tbinfo->dobj.name));
12890         }
12891         else
12892         {
12893                 switch (tbinfo->relkind)
12894                 {
12895                         case (RELKIND_FOREIGN_TABLE):
12896                                 {
12897                                         PQExpBuffer query = createPQExpBuffer();
12898                                         PGresult   *res;
12899                                         int                     i_srvname;
12900                                         int                     i_ftoptions;
12901
12902                                         reltypename = "FOREIGN TABLE";
12903
12904                                         /* retrieve name of foreign server and generic options */
12905                                         appendPQExpBuffer(query,
12906                                                                           "SELECT fs.srvname, "
12907                                                                           "pg_catalog.array_to_string(ARRAY("
12908                                                          "SELECT pg_catalog.quote_ident(option_name) || "
12909                                                          "' ' || pg_catalog.quote_literal(option_value) "
12910                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
12911                                                                           "ORDER BY option_name"
12912                                                                           "), E',\n    ') AS ftoptions "
12913                                                                           "FROM pg_catalog.pg_foreign_table ft "
12914                                                                           "JOIN pg_catalog.pg_foreign_server fs "
12915                                                                           "ON (fs.oid = ft.ftserver) "
12916                                                                           "WHERE ft.ftrelid = '%u'",
12917                                                                           tbinfo->dobj.catId.oid);
12918                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12919                                         i_srvname = PQfnumber(res, "srvname");
12920                                         i_ftoptions = PQfnumber(res, "ftoptions");
12921                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12922                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12923                                         PQclear(res);
12924                                         destroyPQExpBuffer(query);
12925                                         break;
12926                                 }
12927                         case (RELKIND_MATVIEW):
12928                                 reltypename = "MATERIALIZED VIEW";
12929                                 srvname = NULL;
12930                                 ftoptions = NULL;
12931                                 break;
12932                         default:
12933                                 reltypename = "TABLE";
12934                                 srvname = NULL;
12935                                 ftoptions = NULL;
12936                 }
12937
12938                 numParents = tbinfo->numParents;
12939                 parents = tbinfo->parents;
12940
12941                 /*
12942                  * DROP must be fully qualified in case same name appears in
12943                  * pg_catalog
12944                  */
12945                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12946                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12947                 appendPQExpBuffer(delq, "%s;\n",
12948                                                   fmtId(tbinfo->dobj.name));
12949
12950                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12951                                                   fmtId(tbinfo->dobj.name));
12952
12953                 if (binary_upgrade)
12954                         binary_upgrade_set_pg_class_oids(fout, q,
12955                                                                                          tbinfo->dobj.catId.oid, false);
12956
12957                 appendPQExpBuffer(q, "CREATE %s%s %s",
12958                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12959                                                   "UNLOGGED " : "",
12960                                                   reltypename,
12961                                                   fmtId(tbinfo->dobj.name));
12962
12963                 /*
12964                  * Attach to type, if reloftype; except in case of a binary upgrade,
12965                  * we dump the table normally and attach it to the type afterward.
12966                  */
12967                 if (tbinfo->reloftype && !binary_upgrade)
12968                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12969
12970                 if (tbinfo->relkind != RELKIND_MATVIEW)
12971                 {
12972                         /* Dump the attributes */
12973                         actual_atts = 0;
12974                         for (j = 0; j < tbinfo->numatts; j++)
12975                         {
12976                                 /*
12977                                  * Normally, dump if it's locally defined in this table, and
12978                                  * not dropped.  But for binary upgrade, we'll dump all the
12979                                  * columns, and then fix up the dropped and nonlocal cases
12980                                  * below.
12981                                  */
12982                                 if (shouldPrintColumn(tbinfo, j))
12983                                 {
12984                                         /*
12985                                          * Default value --- suppress if to be printed separately.
12986                                          */
12987                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
12988                                                                                          !tbinfo->attrdefs[j]->separate);
12989
12990                                         /*
12991                                          * Not Null constraint --- suppress if inherited, except
12992                                          * in binary-upgrade case where that won't work.
12993                                          */
12994                                         bool            has_notnull = (tbinfo->notnull[j] &&
12995                                                                                            (!tbinfo->inhNotNull[j] ||
12996                                                                                                 binary_upgrade));
12997
12998                                         /* Skip column if fully defined by reloftype */
12999                                         if (tbinfo->reloftype &&
13000                                                 !has_default && !has_notnull && !binary_upgrade)
13001                                                 continue;
13002
13003                                         /* Format properly if not first attr */
13004                                         if (actual_atts == 0)
13005                                                 appendPQExpBuffer(q, " (");
13006                                         else
13007                                                 appendPQExpBuffer(q, ",");
13008                                         appendPQExpBuffer(q, "\n    ");
13009                                         actual_atts++;
13010
13011                                         /* Attribute name */
13012                                         appendPQExpBuffer(q, "%s",
13013                                                                           fmtId(tbinfo->attnames[j]));
13014
13015                                         if (tbinfo->attisdropped[j])
13016                                         {
13017                                                 /*
13018                                                  * ALTER TABLE DROP COLUMN clears
13019                                                  * pg_attribute.atttypid, so we will not have gotten a
13020                                                  * valid type name; insert INTEGER as a stopgap. We'll
13021                                                  * clean things up later.
13022                                                  */
13023                                                 appendPQExpBuffer(q, " INTEGER /* dummy */");
13024                                                 /* Skip all the rest, too */
13025                                                 continue;
13026                                         }
13027
13028                                         /* Attribute type */
13029                                         if (tbinfo->reloftype && !binary_upgrade)
13030                                         {
13031                                                 appendPQExpBuffer(q, " WITH OPTIONS");
13032                                         }
13033                                         else if (fout->remoteVersion >= 70100)
13034                                         {
13035                                                 appendPQExpBuffer(q, " %s",
13036                                                                                   tbinfo->atttypnames[j]);
13037                                         }
13038                                         else
13039                                         {
13040                                                 /* If no format_type, fake it */
13041                                                 appendPQExpBuffer(q, " %s",
13042                                                                                   myFormatType(tbinfo->atttypnames[j],
13043                                                                                                            tbinfo->atttypmod[j]));
13044                                         }
13045
13046                                         /* Add collation if not default for the type */
13047                                         if (OidIsValid(tbinfo->attcollation[j]))
13048                                         {
13049                                                 CollInfo   *coll;
13050
13051                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13052                                                 if (coll)
13053                                                 {
13054                                                         /* always schema-qualify, don't try to be smart */
13055                                                         appendPQExpBuffer(q, " COLLATE %s.",
13056                                                                          fmtId(coll->dobj.namespace->dobj.name));
13057                                                         appendPQExpBuffer(q, "%s",
13058                                                                                           fmtId(coll->dobj.name));
13059                                                 }
13060                                         }
13061
13062                                         if (has_default)
13063                                                 appendPQExpBuffer(q, " DEFAULT %s",
13064                                                                                   tbinfo->attrdefs[j]->adef_expr);
13065
13066                                         if (has_notnull)
13067                                                 appendPQExpBuffer(q, " NOT NULL");
13068                                 }
13069                         }
13070
13071                         /*
13072                          * Add non-inherited CHECK constraints, if any.
13073                          */
13074                         for (j = 0; j < tbinfo->ncheck; j++)
13075                         {
13076                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13077
13078                                 if (constr->separate || !constr->conislocal)
13079                                         continue;
13080
13081                                 if (actual_atts == 0)
13082                                         appendPQExpBuffer(q, " (\n    ");
13083                                 else
13084                                         appendPQExpBuffer(q, ",\n    ");
13085
13086                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13087                                                                   fmtId(constr->dobj.name));
13088                                 appendPQExpBuffer(q, "%s", constr->condef);
13089
13090                                 actual_atts++;
13091                         }
13092
13093                         if (actual_atts)
13094                                 appendPQExpBuffer(q, "\n)");
13095                         else if (!(tbinfo->reloftype && !binary_upgrade))
13096                         {
13097                                 /*
13098                                  * We must have a parenthesized attribute list, even though
13099                                  * empty, when not using the OF TYPE syntax.
13100                                  */
13101                                 appendPQExpBuffer(q, " (\n)");
13102                         }
13103
13104                         if (numParents > 0 && !binary_upgrade)
13105                         {
13106                                 appendPQExpBuffer(q, "\nINHERITS (");
13107                                 for (k = 0; k < numParents; k++)
13108                                 {
13109                                         TableInfo  *parentRel = parents[k];
13110
13111                                         if (k > 0)
13112                                                 appendPQExpBuffer(q, ", ");
13113                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13114                                                 appendPQExpBuffer(q, "%s.",
13115                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13116                                         appendPQExpBuffer(q, "%s",
13117                                                                           fmtId(parentRel->dobj.name));
13118                                 }
13119                                 appendPQExpBuffer(q, ")");
13120                         }
13121
13122                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13123                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13124                 }
13125
13126                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13127                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13128                 {
13129                         bool            addcomma = false;
13130
13131                         appendPQExpBuffer(q, "\nWITH (");
13132                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13133                         {
13134                                 addcomma = true;
13135                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
13136                         }
13137                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13138                         {
13139                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13140                                                                   tbinfo->toast_reloptions);
13141                         }
13142                         appendPQExpBuffer(q, ")");
13143                 }
13144
13145                 /* Dump generic options if any */
13146                 if (ftoptions && ftoptions[0])
13147                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13148
13149                 /*
13150                  * For materialized views, create the AS clause just like a view. At
13151                  * this point, we always mark the view as not populated.
13152                  */
13153                 if (tbinfo->relkind == RELKIND_MATVIEW)
13154                 {
13155                         PQExpBuffer result;
13156
13157                         result = createViewAsClause(fout, tbinfo);
13158                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13159                                                           result->data);
13160                         destroyPQExpBuffer(result);
13161                 }
13162                 else
13163                         appendPQExpBuffer(q, ";\n");
13164
13165                 /*
13166                  * To create binary-compatible heap files, we have to ensure the same
13167                  * physical column order, including dropped columns, as in the
13168                  * original.  Therefore, we create dropped columns above and drop them
13169                  * here, also updating their attlen/attalign values so that the
13170                  * dropped column can be skipped properly.      (We do not bother with
13171                  * restoring the original attbyval setting.)  Also, inheritance
13172                  * relationships are set up by doing ALTER INHERIT rather than using
13173                  * an INHERITS clause --- the latter would possibly mess up the column
13174                  * order.  That also means we have to take care about setting
13175                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13176                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13177                  */
13178                 if (binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
13179                                                            tbinfo->relkind == RELKIND_FOREIGN_TABLE) )
13180                 {
13181                         for (j = 0; j < tbinfo->numatts; j++)
13182                         {
13183                                 if (tbinfo->attisdropped[j])
13184                                 {
13185                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
13186                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13187                                                                           "SET attlen = %d, "
13188                                                                           "attalign = '%c', attbyval = false\n"
13189                                                                           "WHERE attname = ",
13190                                                                           tbinfo->attlen[j],
13191                                                                           tbinfo->attalign[j]);
13192                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13193                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13194                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13195                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13196
13197                                         if (tbinfo->relkind == RELKIND_RELATION)
13198                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13199                                                                                   fmtId(tbinfo->dobj.name));
13200                                         else
13201                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13202                                                                                   fmtId(tbinfo->dobj.name));
13203
13204                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13205                                                                           fmtId(tbinfo->attnames[j]));
13206                                 }
13207                                 else if (!tbinfo->attislocal[j])
13208                                 {
13209                                         Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
13210                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
13211                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13212                                                                           "SET attislocal = false\n"
13213                                                                           "WHERE attname = ");
13214                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13215                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13216                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13217                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13218                                 }
13219                         }
13220
13221                         for (k = 0; k < tbinfo->ncheck; k++)
13222                         {
13223                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13224
13225                                 if (constr->separate || constr->conislocal)
13226                                         continue;
13227
13228                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13229                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13230                                                                   fmtId(tbinfo->dobj.name));
13231                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13232                                                                   fmtId(constr->dobj.name));
13233                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13234                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
13235                                                                   "SET conislocal = false\n"
13236                                                                   "WHERE contype = 'c' AND conname = ");
13237                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13238                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
13239                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13240                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13241                         }
13242
13243                         if (numParents > 0)
13244                         {
13245                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13246                                 for (k = 0; k < numParents; k++)
13247                                 {
13248                                         TableInfo  *parentRel = parents[k];
13249
13250                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13251                                                                           fmtId(tbinfo->dobj.name));
13252                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13253                                                 appendPQExpBuffer(q, "%s.",
13254                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13255                                         appendPQExpBuffer(q, "%s;\n",
13256                                                                           fmtId(parentRel->dobj.name));
13257                                 }
13258                         }
13259
13260                         if (tbinfo->reloftype)
13261                         {
13262                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13263                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13264                                                                   fmtId(tbinfo->dobj.name),
13265                                                                   tbinfo->reloftype);
13266                         }
13267
13268                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13269                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13270                                                           "SET relfrozenxid = '%u'\n"
13271                                                           "WHERE oid = ",
13272                                                           tbinfo->frozenxid);
13273                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13274                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13275
13276                         if (tbinfo->toast_oid)
13277                         {
13278                                 /* We preserve the toast oids, so we can use it during restore */
13279                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13280                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13281                                                                   "SET relfrozenxid = '%u'\n"
13282                                                                   "WHERE oid = '%u';\n",
13283                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13284                         }
13285                 }
13286
13287                 /*
13288                  * In binary_upgrade mode, restore matviews' populated status by
13289                  * poking pg_class directly.  This is pretty ugly, but we can't use
13290                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
13291                  * matview is not populated even though this matview is.
13292                  */
13293                 if (binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
13294                         tbinfo->relispopulated)
13295                 {
13296                         appendPQExpBuffer(q, "\n-- For binary upgrade, mark materialized view as populated\n");
13297                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13298                                                           "SET relispopulated = 't'\n"
13299                                                           "WHERE oid = ");
13300                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13301                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13302                 }
13303
13304                 /*
13305                  * Dump additional per-column properties that we can't handle in the
13306                  * main CREATE TABLE command.
13307                  */
13308                 for (j = 0; j < tbinfo->numatts; j++)
13309                 {
13310                         /* None of this applies to dropped columns */
13311                         if (tbinfo->attisdropped[j])
13312                                 continue;
13313
13314                         /*
13315                          * If we didn't dump the column definition explicitly above, and
13316                          * it is NOT NULL and did not inherit that property from a parent,
13317                          * we have to mark it separately.
13318                          */
13319                         if (!shouldPrintColumn(tbinfo, j) &&
13320                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13321                         {
13322                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13323                                                                   fmtId(tbinfo->dobj.name));
13324                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13325                                                                   fmtId(tbinfo->attnames[j]));
13326                         }
13327
13328                         /*
13329                          * Dump per-column statistics information. We only issue an ALTER
13330                          * TABLE statement if the attstattarget entry for this column is
13331                          * non-negative (i.e. it's not the default value)
13332                          */
13333                         if (tbinfo->attstattarget[j] >= 0)
13334                         {
13335                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13336                                                                   fmtId(tbinfo->dobj.name));
13337                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13338                                                                   fmtId(tbinfo->attnames[j]));
13339                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13340                                                                   tbinfo->attstattarget[j]);
13341                         }
13342
13343                         /*
13344                          * Dump per-column storage information.  The statement is only
13345                          * dumped if the storage has been changed from the type's default.
13346                          */
13347                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13348                         {
13349                                 switch (tbinfo->attstorage[j])
13350                                 {
13351                                         case 'p':
13352                                                 storage = "PLAIN";
13353                                                 break;
13354                                         case 'e':
13355                                                 storage = "EXTERNAL";
13356                                                 break;
13357                                         case 'm':
13358                                                 storage = "MAIN";
13359                                                 break;
13360                                         case 'x':
13361                                                 storage = "EXTENDED";
13362                                                 break;
13363                                         default:
13364                                                 storage = NULL;
13365                                 }
13366
13367                                 /*
13368                                  * Only dump the statement if it's a storage type we recognize
13369                                  */
13370                                 if (storage != NULL)
13371                                 {
13372                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13373                                                                           fmtId(tbinfo->dobj.name));
13374                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13375                                                                           fmtId(tbinfo->attnames[j]));
13376                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13377                                                                           storage);
13378                                 }
13379                         }
13380
13381                         /*
13382                          * Dump per-column attributes.
13383                          */
13384                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13385                         {
13386                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13387                                                                   fmtId(tbinfo->dobj.name));
13388                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13389                                                                   fmtId(tbinfo->attnames[j]));
13390                                 appendPQExpBuffer(q, "SET (%s);\n",
13391                                                                   tbinfo->attoptions[j]);
13392                         }
13393
13394                         /*
13395                          * Dump per-column fdw options.
13396                          */
13397                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13398                                 tbinfo->attfdwoptions[j] &&
13399                                 tbinfo->attfdwoptions[j][0] != '\0')
13400                         {
13401                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13402                                                                   fmtId(tbinfo->dobj.name));
13403                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13404                                                                   fmtId(tbinfo->attnames[j]));
13405                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13406                                                                   tbinfo->attfdwoptions[j]);
13407                         }
13408                 }
13409         }
13410
13411         if (binary_upgrade)
13412                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13413
13414         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13415                                  tbinfo->dobj.name,
13416                                  tbinfo->dobj.namespace->dobj.name,
13417                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13418                                  tbinfo->rolname,
13419                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13420                                  reltypename, SECTION_PRE_DATA,
13421                                  q->data, delq->data, NULL,
13422                                  NULL, 0,
13423                                  NULL, NULL);
13424
13425
13426         /* Dump Table Comments */
13427         dumpTableComment(fout, tbinfo, reltypename);
13428
13429         /* Dump Table Security Labels */
13430         dumpTableSecLabel(fout, tbinfo, reltypename);
13431
13432         /* Dump comments on inlined table constraints */
13433         for (j = 0; j < tbinfo->ncheck; j++)
13434         {
13435                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13436
13437                 if (constr->separate || !constr->conislocal)
13438                         continue;
13439
13440                 dumpTableConstraintComment(fout, constr);
13441         }
13442
13443         destroyPQExpBuffer(q);
13444         destroyPQExpBuffer(delq);
13445         destroyPQExpBuffer(labelq);
13446 }
13447
13448 /*
13449  * dumpAttrDef --- dump an attribute's default-value declaration
13450  */
13451 static void
13452 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13453 {
13454         TableInfo  *tbinfo = adinfo->adtable;
13455         int                     adnum = adinfo->adnum;
13456         PQExpBuffer q;
13457         PQExpBuffer delq;
13458
13459         /* Skip if table definition not to be dumped */
13460         if (!tbinfo->dobj.dump || dataOnly)
13461                 return;
13462
13463         /* Skip if not "separate"; it was dumped in the table's definition */
13464         if (!adinfo->separate)
13465                 return;
13466
13467         q = createPQExpBuffer();
13468         delq = createPQExpBuffer();
13469
13470         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13471                                           fmtId(tbinfo->dobj.name));
13472         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13473                                           fmtId(tbinfo->attnames[adnum - 1]),
13474                                           adinfo->adef_expr);
13475
13476         /*
13477          * DROP must be fully qualified in case same name appears in pg_catalog
13478          */
13479         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13480                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13481         appendPQExpBuffer(delq, "%s ",
13482                                           fmtId(tbinfo->dobj.name));
13483         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13484                                           fmtId(tbinfo->attnames[adnum - 1]));
13485
13486         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13487                                  tbinfo->attnames[adnum - 1],
13488                                  tbinfo->dobj.namespace->dobj.name,
13489                                  NULL,
13490                                  tbinfo->rolname,
13491                                  false, "DEFAULT", SECTION_PRE_DATA,
13492                                  q->data, delq->data, NULL,
13493                                  NULL, 0,
13494                                  NULL, NULL);
13495
13496         destroyPQExpBuffer(q);
13497         destroyPQExpBuffer(delq);
13498 }
13499
13500 /*
13501  * getAttrName: extract the correct name for an attribute
13502  *
13503  * The array tblInfo->attnames[] only provides names of user attributes;
13504  * if a system attribute number is supplied, we have to fake it.
13505  * We also do a little bit of bounds checking for safety's sake.
13506  */
13507 static const char *
13508 getAttrName(int attrnum, TableInfo *tblInfo)
13509 {
13510         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13511                 return tblInfo->attnames[attrnum - 1];
13512         switch (attrnum)
13513         {
13514                 case SelfItemPointerAttributeNumber:
13515                         return "ctid";
13516                 case ObjectIdAttributeNumber:
13517                         return "oid";
13518                 case MinTransactionIdAttributeNumber:
13519                         return "xmin";
13520                 case MinCommandIdAttributeNumber:
13521                         return "cmin";
13522                 case MaxTransactionIdAttributeNumber:
13523                         return "xmax";
13524                 case MaxCommandIdAttributeNumber:
13525                         return "cmax";
13526                 case TableOidAttributeNumber:
13527                         return "tableoid";
13528         }
13529         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13530                                   attrnum, tblInfo->dobj.name);
13531         return NULL;                            /* keep compiler quiet */
13532 }
13533
13534 /*
13535  * dumpIndex
13536  *        write out to fout a user-defined index
13537  */
13538 static void
13539 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13540 {
13541         TableInfo  *tbinfo = indxinfo->indextable;
13542         bool            is_constraint = (indxinfo->indexconstraint != 0);
13543         PQExpBuffer q;
13544         PQExpBuffer delq;
13545         PQExpBuffer labelq;
13546
13547         if (dataOnly)
13548                 return;
13549
13550         q = createPQExpBuffer();
13551         delq = createPQExpBuffer();
13552         labelq = createPQExpBuffer();
13553
13554         appendPQExpBuffer(labelq, "INDEX %s",
13555                                           fmtId(indxinfo->dobj.name));
13556
13557         /*
13558          * If there's an associated constraint, don't dump the index per se, but
13559          * do dump any comment for it.  (This is safe because dependency ordering
13560          * will have ensured the constraint is emitted first.)  Note that the
13561          * emitted comment has to be shown as depending on the constraint, not
13562          * the index, in such cases.
13563          */
13564         if (!is_constraint)
13565         {
13566                 if (binary_upgrade)
13567                         binary_upgrade_set_pg_class_oids(fout, q,
13568                                                                                          indxinfo->dobj.catId.oid, true);
13569
13570                 /* Plain secondary index */
13571                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13572
13573                 /* If the index is clustered, we need to record that. */
13574                 if (indxinfo->indisclustered)
13575                 {
13576                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13577                                                           fmtId(tbinfo->dobj.name));
13578                         appendPQExpBuffer(q, " ON %s;\n",
13579                                                           fmtId(indxinfo->dobj.name));
13580                 }
13581
13582                 /*
13583                  * DROP must be fully qualified in case same name appears in
13584                  * pg_catalog
13585                  */
13586                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13587                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13588                 appendPQExpBuffer(delq, "%s;\n",
13589                                                   fmtId(indxinfo->dobj.name));
13590
13591                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13592                                          indxinfo->dobj.name,
13593                                          tbinfo->dobj.namespace->dobj.name,
13594                                          indxinfo->tablespace,
13595                                          tbinfo->rolname, false,
13596                                          "INDEX", SECTION_POST_DATA,
13597                                          q->data, delq->data, NULL,
13598                                          NULL, 0,
13599                                          NULL, NULL);
13600         }
13601
13602         /* Dump Index Comments */
13603         dumpComment(fout, labelq->data,
13604                                 tbinfo->dobj.namespace->dobj.name,
13605                                 tbinfo->rolname,
13606                                 indxinfo->dobj.catId, 0,
13607                                 is_constraint ? indxinfo->indexconstraint :
13608                                 indxinfo->dobj.dumpId);
13609
13610         destroyPQExpBuffer(q);
13611         destroyPQExpBuffer(delq);
13612         destroyPQExpBuffer(labelq);
13613 }
13614
13615 /*
13616  * dumpConstraint
13617  *        write out to fout a user-defined constraint
13618  */
13619 static void
13620 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13621 {
13622         TableInfo  *tbinfo = coninfo->contable;
13623         PQExpBuffer q;
13624         PQExpBuffer delq;
13625
13626         /* Skip if not to be dumped */
13627         if (!coninfo->dobj.dump || dataOnly)
13628                 return;
13629
13630         q = createPQExpBuffer();
13631         delq = createPQExpBuffer();
13632
13633         if (coninfo->contype == 'p' ||
13634                 coninfo->contype == 'u' ||
13635                 coninfo->contype == 'x')
13636         {
13637                 /* Index-related constraint */
13638                 IndxInfo   *indxinfo;
13639                 int                     k;
13640
13641                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13642
13643                 if (indxinfo == NULL)
13644                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13645                                                   coninfo->dobj.name);
13646
13647                 if (binary_upgrade)
13648                         binary_upgrade_set_pg_class_oids(fout, q,
13649                                                                                          indxinfo->dobj.catId.oid, true);
13650
13651                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13652                                                   fmtId(tbinfo->dobj.name));
13653                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13654                                                   fmtId(coninfo->dobj.name));
13655
13656                 if (coninfo->condef)
13657                 {
13658                         /* pg_get_constraintdef should have provided everything */
13659                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13660                 }
13661                 else
13662                 {
13663                         appendPQExpBuffer(q, "%s (",
13664                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13665                         for (k = 0; k < indxinfo->indnkeys; k++)
13666                         {
13667                                 int                     indkey = (int) indxinfo->indkeys[k];
13668                                 const char *attname;
13669
13670                                 if (indkey == InvalidAttrNumber)
13671                                         break;
13672                                 attname = getAttrName(indkey, tbinfo);
13673
13674                                 appendPQExpBuffer(q, "%s%s",
13675                                                                   (k == 0) ? "" : ", ",
13676                                                                   fmtId(attname));
13677                         }
13678
13679                         appendPQExpBuffer(q, ")");
13680
13681                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13682                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13683
13684                         if (coninfo->condeferrable)
13685                         {
13686                                 appendPQExpBuffer(q, " DEFERRABLE");
13687                                 if (coninfo->condeferred)
13688                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13689                         }
13690
13691                         appendPQExpBuffer(q, ";\n");
13692                 }
13693
13694                 /* If the index is clustered, we need to record that. */
13695                 if (indxinfo->indisclustered)
13696                 {
13697                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13698                                                           fmtId(tbinfo->dobj.name));
13699                         appendPQExpBuffer(q, " ON %s;\n",
13700                                                           fmtId(indxinfo->dobj.name));
13701                 }
13702
13703                 /*
13704                  * DROP must be fully qualified in case same name appears in
13705                  * pg_catalog
13706                  */
13707                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13708                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13709                 appendPQExpBuffer(delq, "%s ",
13710                                                   fmtId(tbinfo->dobj.name));
13711                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13712                                                   fmtId(coninfo->dobj.name));
13713
13714                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13715                                          coninfo->dobj.name,
13716                                          tbinfo->dobj.namespace->dobj.name,
13717                                          indxinfo->tablespace,
13718                                          tbinfo->rolname, false,
13719                                          "CONSTRAINT", SECTION_POST_DATA,
13720                                          q->data, delq->data, NULL,
13721                                          NULL, 0,
13722                                          NULL, NULL);
13723         }
13724         else if (coninfo->contype == 'f')
13725         {
13726                 /*
13727                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13728                  * current table data is not processed
13729                  */
13730                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13731                                                   fmtId(tbinfo->dobj.name));
13732                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13733                                                   fmtId(coninfo->dobj.name),
13734                                                   coninfo->condef);
13735
13736                 /*
13737                  * DROP must be fully qualified in case same name appears in
13738                  * pg_catalog
13739                  */
13740                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13741                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13742                 appendPQExpBuffer(delq, "%s ",
13743                                                   fmtId(tbinfo->dobj.name));
13744                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13745                                                   fmtId(coninfo->dobj.name));
13746
13747                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13748                                          coninfo->dobj.name,
13749                                          tbinfo->dobj.namespace->dobj.name,
13750                                          NULL,
13751                                          tbinfo->rolname, false,
13752                                          "FK CONSTRAINT", SECTION_POST_DATA,
13753                                          q->data, delq->data, NULL,
13754                                          NULL, 0,
13755                                          NULL, NULL);
13756         }
13757         else if (coninfo->contype == 'c' && tbinfo)
13758         {
13759                 /* CHECK constraint on a table */
13760
13761                 /* Ignore if not to be dumped separately */
13762                 if (coninfo->separate)
13763                 {
13764                         /* not ONLY since we want it to propagate to children */
13765                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13766                                                           fmtId(tbinfo->dobj.name));
13767                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13768                                                           fmtId(coninfo->dobj.name),
13769                                                           coninfo->condef);
13770
13771                         /*
13772                          * DROP must be fully qualified in case same name appears in
13773                          * pg_catalog
13774                          */
13775                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13776                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13777                         appendPQExpBuffer(delq, "%s ",
13778                                                           fmtId(tbinfo->dobj.name));
13779                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13780                                                           fmtId(coninfo->dobj.name));
13781
13782                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13783                                                  coninfo->dobj.name,
13784                                                  tbinfo->dobj.namespace->dobj.name,
13785                                                  NULL,
13786                                                  tbinfo->rolname, false,
13787                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13788                                                  q->data, delq->data, NULL,
13789                                                  NULL, 0,
13790                                                  NULL, NULL);
13791                 }
13792         }
13793         else if (coninfo->contype == 'c' && tbinfo == NULL)
13794         {
13795                 /* CHECK constraint on a domain */
13796                 TypeInfo   *tyinfo = coninfo->condomain;
13797
13798                 /* Ignore if not to be dumped separately */
13799                 if (coninfo->separate)
13800                 {
13801                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13802                                                           fmtId(tyinfo->dobj.name));
13803                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13804                                                           fmtId(coninfo->dobj.name),
13805                                                           coninfo->condef);
13806
13807                         /*
13808                          * DROP must be fully qualified in case same name appears in
13809                          * pg_catalog
13810                          */
13811                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13812                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13813                         appendPQExpBuffer(delq, "%s ",
13814                                                           fmtId(tyinfo->dobj.name));
13815                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13816                                                           fmtId(coninfo->dobj.name));
13817
13818                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13819                                                  coninfo->dobj.name,
13820                                                  tyinfo->dobj.namespace->dobj.name,
13821                                                  NULL,
13822                                                  tyinfo->rolname, false,
13823                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13824                                                  q->data, delq->data, NULL,
13825                                                  NULL, 0,
13826                                                  NULL, NULL);
13827                 }
13828         }
13829         else
13830         {
13831                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
13832                                           coninfo->contype);
13833         }
13834
13835         /* Dump Constraint Comments --- only works for table constraints */
13836         if (tbinfo && coninfo->separate)
13837                 dumpTableConstraintComment(fout, coninfo);
13838
13839         destroyPQExpBuffer(q);
13840         destroyPQExpBuffer(delq);
13841 }
13842
13843 /*
13844  * dumpTableConstraintComment --- dump a constraint's comment if any
13845  *
13846  * This is split out because we need the function in two different places
13847  * depending on whether the constraint is dumped as part of CREATE TABLE
13848  * or as a separate ALTER command.
13849  */
13850 static void
13851 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13852 {
13853         TableInfo  *tbinfo = coninfo->contable;
13854         PQExpBuffer labelq = createPQExpBuffer();
13855
13856         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13857                                           fmtId(coninfo->dobj.name));
13858         appendPQExpBuffer(labelq, "ON %s",
13859                                           fmtId(tbinfo->dobj.name));
13860         dumpComment(fout, labelq->data,
13861                                 tbinfo->dobj.namespace->dobj.name,
13862                                 tbinfo->rolname,
13863                                 coninfo->dobj.catId, 0,
13864                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13865
13866         destroyPQExpBuffer(labelq);
13867 }
13868
13869 /*
13870  * findLastBuiltInOid -
13871  * find the last built in oid
13872  *
13873  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13874  * pg_database entry for the current database
13875  */
13876 static Oid
13877 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13878 {
13879         PGresult   *res;
13880         Oid                     last_oid;
13881         PQExpBuffer query = createPQExpBuffer();
13882
13883         resetPQExpBuffer(query);
13884         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13885         appendStringLiteralAH(query, dbname, fout);
13886
13887         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13888         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13889         PQclear(res);
13890         destroyPQExpBuffer(query);
13891         return last_oid;
13892 }
13893
13894 /*
13895  * findLastBuiltInOid -
13896  * find the last built in oid
13897  *
13898  * For 7.0, we do this by assuming that the last thing that initdb does is to
13899  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13900  * initdb won't be changing anymore, it'll do.
13901  */
13902 static Oid
13903 findLastBuiltinOid_V70(Archive *fout)
13904 {
13905         PGresult   *res;
13906         int                     last_oid;
13907
13908         res = ExecuteSqlQueryForSingleRow(fout,
13909                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13910         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13911         PQclear(res);
13912         return last_oid;
13913 }
13914
13915 /*
13916  * dumpSequence
13917  *        write the declaration (not data) of one user-defined sequence
13918  */
13919 static void
13920 dumpSequence(Archive *fout, TableInfo *tbinfo)
13921 {
13922         PGresult   *res;
13923         char       *startv,
13924                            *incby,
13925                            *maxv = NULL,
13926                            *minv = NULL,
13927                            *cache;
13928         char            bufm[100],
13929                                 bufx[100];
13930         bool            cycled;
13931         PQExpBuffer query = createPQExpBuffer();
13932         PQExpBuffer delqry = createPQExpBuffer();
13933         PQExpBuffer labelq = createPQExpBuffer();
13934
13935         /* Make sure we are in proper schema */
13936         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13937
13938         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13939         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13940
13941         if (fout->remoteVersion >= 80400)
13942         {
13943                 appendPQExpBuffer(query,
13944                                                   "SELECT sequence_name, "
13945                                                   "start_value, increment_by, "
13946                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13947                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13948                                                   "     ELSE max_value "
13949                                                   "END AS max_value, "
13950                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13951                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13952                                                   "     ELSE min_value "
13953                                                   "END AS min_value, "
13954                                                   "cache_value, is_cycled FROM %s",
13955                                                   bufx, bufm,
13956                                                   fmtId(tbinfo->dobj.name));
13957         }
13958         else
13959         {
13960                 appendPQExpBuffer(query,
13961                                                   "SELECT sequence_name, "
13962                                                   "0 AS start_value, increment_by, "
13963                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13964                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13965                                                   "     ELSE max_value "
13966                                                   "END AS max_value, "
13967                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13968                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13969                                                   "     ELSE min_value "
13970                                                   "END AS min_value, "
13971                                                   "cache_value, is_cycled FROM %s",
13972                                                   bufx, bufm,
13973                                                   fmtId(tbinfo->dobj.name));
13974         }
13975
13976         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13977
13978         if (PQntuples(res) != 1)
13979         {
13980                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13981                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13982                                                                  PQntuples(res)),
13983                                   tbinfo->dobj.name, PQntuples(res));
13984                 exit_nicely(1);
13985         }
13986
13987         /* Disable this check: it fails if sequence has been renamed */
13988 #ifdef NOT_USED
13989         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13990         {
13991                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13992                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13993                 exit_nicely(1);
13994         }
13995 #endif
13996
13997         startv = PQgetvalue(res, 0, 1);
13998         incby = PQgetvalue(res, 0, 2);
13999         if (!PQgetisnull(res, 0, 3))
14000                 maxv = PQgetvalue(res, 0, 3);
14001         if (!PQgetisnull(res, 0, 4))
14002                 minv = PQgetvalue(res, 0, 4);
14003         cache = PQgetvalue(res, 0, 5);
14004         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
14005
14006         /*
14007          * DROP must be fully qualified in case same name appears in pg_catalog
14008          */
14009         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
14010                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14011         appendPQExpBuffer(delqry, "%s;\n",
14012                                           fmtId(tbinfo->dobj.name));
14013
14014         resetPQExpBuffer(query);
14015
14016         if (binary_upgrade)
14017         {
14018                 binary_upgrade_set_pg_class_oids(fout, query,
14019                                                                                  tbinfo->dobj.catId.oid, false);
14020                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
14021                                                                                                 tbinfo->dobj.catId.oid);
14022         }
14023
14024         appendPQExpBuffer(query,
14025                                           "CREATE SEQUENCE %s\n",
14026                                           fmtId(tbinfo->dobj.name));
14027
14028         if (fout->remoteVersion >= 80400)
14029                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
14030
14031         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
14032
14033         if (minv)
14034                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
14035         else
14036                 appendPQExpBuffer(query, "    NO MINVALUE\n");
14037
14038         if (maxv)
14039                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
14040         else
14041                 appendPQExpBuffer(query, "    NO MAXVALUE\n");
14042
14043         appendPQExpBuffer(query,
14044                                           "    CACHE %s%s",
14045                                           cache, (cycled ? "\n    CYCLE" : ""));
14046
14047         appendPQExpBuffer(query, ";\n");
14048
14049         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
14050
14051         /* binary_upgrade:      no need to clear TOAST table oid */
14052
14053         if (binary_upgrade)
14054                 binary_upgrade_extension_member(query, &tbinfo->dobj,
14055                                                                                 labelq->data);
14056
14057         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14058                                  tbinfo->dobj.name,
14059                                  tbinfo->dobj.namespace->dobj.name,
14060                                  NULL,
14061                                  tbinfo->rolname,
14062                                  false, "SEQUENCE", SECTION_PRE_DATA,
14063                                  query->data, delqry->data, NULL,
14064                                  NULL, 0,
14065                                  NULL, NULL);
14066
14067         /*
14068          * If the sequence is owned by a table column, emit the ALTER for it as a
14069          * separate TOC entry immediately following the sequence's own entry. It's
14070          * OK to do this rather than using full sorting logic, because the
14071          * dependency that tells us it's owned will have forced the table to be
14072          * created first.  We can't just include the ALTER in the TOC entry
14073          * because it will fail if we haven't reassigned the sequence owner to
14074          * match the table's owner.
14075          *
14076          * We need not schema-qualify the table reference because both sequence
14077          * and table must be in the same schema.
14078          */
14079         if (OidIsValid(tbinfo->owning_tab))
14080         {
14081                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14082
14083                 if (owning_tab && owning_tab->dobj.dump)
14084                 {
14085                         resetPQExpBuffer(query);
14086                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14087                                                           fmtId(tbinfo->dobj.name));
14088                         appendPQExpBuffer(query, " OWNED BY %s",
14089                                                           fmtId(owning_tab->dobj.name));
14090                         appendPQExpBuffer(query, ".%s;\n",
14091                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14092
14093                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14094                                                  tbinfo->dobj.name,
14095                                                  tbinfo->dobj.namespace->dobj.name,
14096                                                  NULL,
14097                                                  tbinfo->rolname,
14098                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14099                                                  query->data, "", NULL,
14100                                                  &(tbinfo->dobj.dumpId), 1,
14101                                                  NULL, NULL);
14102                 }
14103         }
14104
14105         /* Dump Sequence Comments and Security Labels */
14106         dumpComment(fout, labelq->data,
14107                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14108                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14109         dumpSecLabel(fout, labelq->data,
14110                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14111                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14112
14113         PQclear(res);
14114
14115         destroyPQExpBuffer(query);
14116         destroyPQExpBuffer(delqry);
14117         destroyPQExpBuffer(labelq);
14118 }
14119
14120 /*
14121  * dumpSequenceData
14122  *        write the data of one user-defined sequence
14123  */
14124 static void
14125 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14126 {
14127         TableInfo  *tbinfo = tdinfo->tdtable;
14128         PGresult   *res;
14129         char       *last;
14130         bool            called;
14131         PQExpBuffer query = createPQExpBuffer();
14132
14133         /* Make sure we are in proper schema */
14134         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14135
14136         appendPQExpBuffer(query,
14137                                           "SELECT last_value, is_called FROM %s",
14138                                           fmtId(tbinfo->dobj.name));
14139
14140         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14141
14142         if (PQntuples(res) != 1)
14143         {
14144                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14145                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14146                                                                  PQntuples(res)),
14147                                   tbinfo->dobj.name, PQntuples(res));
14148                 exit_nicely(1);
14149         }
14150
14151         last = PQgetvalue(res, 0, 0);
14152         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14153
14154         resetPQExpBuffer(query);
14155         appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
14156         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14157         appendPQExpBuffer(query, ", %s, %s);\n",
14158                                           last, (called ? "true" : "false"));
14159
14160         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14161                                  tbinfo->dobj.name,
14162                                  tbinfo->dobj.namespace->dobj.name,
14163                                  NULL,
14164                                  tbinfo->rolname,
14165                                  false, "SEQUENCE SET", SECTION_DATA,
14166                                  query->data, "", NULL,
14167                                  &(tbinfo->dobj.dumpId), 1,
14168                                  NULL, NULL);
14169
14170         PQclear(res);
14171
14172         destroyPQExpBuffer(query);
14173 }
14174
14175 static void
14176 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14177 {
14178         TableInfo  *tbinfo = tginfo->tgtable;
14179         PQExpBuffer query;
14180         PQExpBuffer delqry;
14181         PQExpBuffer labelq;
14182         char       *tgargs;
14183         size_t          lentgargs;
14184         const char *p;
14185         int                     findx;
14186
14187         if (dataOnly)
14188                 return;
14189
14190         query = createPQExpBuffer();
14191         delqry = createPQExpBuffer();
14192         labelq = createPQExpBuffer();
14193
14194         /*
14195          * DROP must be fully qualified in case same name appears in pg_catalog
14196          */
14197         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14198                                           fmtId(tginfo->dobj.name));
14199         appendPQExpBuffer(delqry, "ON %s.",
14200                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14201         appendPQExpBuffer(delqry, "%s;\n",
14202                                           fmtId(tbinfo->dobj.name));
14203
14204         if (tginfo->tgdef)
14205         {
14206                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14207         }
14208         else
14209         {
14210                 if (tginfo->tgisconstraint)
14211                 {
14212                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
14213                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14214                 }
14215                 else
14216                 {
14217                         appendPQExpBuffer(query, "CREATE TRIGGER ");
14218                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14219                 }
14220                 appendPQExpBuffer(query, "\n    ");
14221
14222                 /* Trigger type */
14223                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14224                         appendPQExpBuffer(query, "BEFORE");
14225                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14226                         appendPQExpBuffer(query, "AFTER");
14227                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14228                         appendPQExpBuffer(query, "INSTEAD OF");
14229                 else
14230                 {
14231                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14232                         exit_nicely(1);
14233                 }
14234
14235                 findx = 0;
14236                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14237                 {
14238                         appendPQExpBuffer(query, " INSERT");
14239                         findx++;
14240                 }
14241                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14242                 {
14243                         if (findx > 0)
14244                                 appendPQExpBuffer(query, " OR DELETE");
14245                         else
14246                                 appendPQExpBuffer(query, " DELETE");
14247                         findx++;
14248                 }
14249                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14250                 {
14251                         if (findx > 0)
14252                                 appendPQExpBuffer(query, " OR UPDATE");
14253                         else
14254                                 appendPQExpBuffer(query, " UPDATE");
14255                         findx++;
14256                 }
14257                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14258                 {
14259                         if (findx > 0)
14260                                 appendPQExpBuffer(query, " OR TRUNCATE");
14261                         else
14262                                 appendPQExpBuffer(query, " TRUNCATE");
14263                         findx++;
14264                 }
14265                 appendPQExpBuffer(query, " ON %s\n",
14266                                                   fmtId(tbinfo->dobj.name));
14267
14268                 if (tginfo->tgisconstraint)
14269                 {
14270                         if (OidIsValid(tginfo->tgconstrrelid))
14271                         {
14272                                 /* If we are using regclass, name is already quoted */
14273                                 if (fout->remoteVersion >= 70300)
14274                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14275                                                                           tginfo->tgconstrrelname);
14276                                 else
14277                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14278                                                                           fmtId(tginfo->tgconstrrelname));
14279                         }
14280                         if (!tginfo->tgdeferrable)
14281                                 appendPQExpBuffer(query, "NOT ");
14282                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
14283                         if (tginfo->tginitdeferred)
14284                                 appendPQExpBuffer(query, "DEFERRED\n");
14285                         else
14286                                 appendPQExpBuffer(query, "IMMEDIATE\n");
14287                 }
14288
14289                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14290                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
14291                 else
14292                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
14293
14294                 /* In 7.3, result of regproc is already quoted */
14295                 if (fout->remoteVersion >= 70300)
14296                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14297                                                           tginfo->tgfname);
14298                 else
14299                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14300                                                           fmtId(tginfo->tgfname));
14301
14302                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14303                                                                                   &lentgargs);
14304                 p = tgargs;
14305                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14306                 {
14307                         /* find the embedded null that terminates this trigger argument */
14308                         size_t          tlen = strlen(p);
14309
14310                         if (p + tlen >= tgargs + lentgargs)
14311                         {
14312                                 /* hm, not found before end of bytea value... */
14313                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14314                                                   tginfo->tgargs,
14315                                                   tginfo->dobj.name,
14316                                                   tbinfo->dobj.name);
14317                                 exit_nicely(1);
14318                         }
14319
14320                         if (findx > 0)
14321                                 appendPQExpBuffer(query, ", ");
14322                         appendStringLiteralAH(query, p, fout);
14323                         p += tlen + 1;
14324                 }
14325                 free(tgargs);
14326                 appendPQExpBuffer(query, ");\n");
14327         }
14328
14329         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14330         {
14331                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14332                                                   fmtId(tbinfo->dobj.name));
14333                 switch (tginfo->tgenabled)
14334                 {
14335                         case 'D':
14336                         case 'f':
14337                                 appendPQExpBuffer(query, "DISABLE");
14338                                 break;
14339                         case 'A':
14340                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14341                                 break;
14342                         case 'R':
14343                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14344                                 break;
14345                         default:
14346                                 appendPQExpBuffer(query, "ENABLE");
14347                                 break;
14348                 }
14349                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14350                                                   fmtId(tginfo->dobj.name));
14351         }
14352
14353         appendPQExpBuffer(labelq, "TRIGGER %s ",
14354                                           fmtId(tginfo->dobj.name));
14355         appendPQExpBuffer(labelq, "ON %s",
14356                                           fmtId(tbinfo->dobj.name));
14357
14358         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14359                                  tginfo->dobj.name,
14360                                  tbinfo->dobj.namespace->dobj.name,
14361                                  NULL,
14362                                  tbinfo->rolname, false,
14363                                  "TRIGGER", SECTION_POST_DATA,
14364                                  query->data, delqry->data, NULL,
14365                                  NULL, 0,
14366                                  NULL, NULL);
14367
14368         dumpComment(fout, labelq->data,
14369                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14370                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14371
14372         destroyPQExpBuffer(query);
14373         destroyPQExpBuffer(delqry);
14374         destroyPQExpBuffer(labelq);
14375 }
14376
14377 static void
14378 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14379 {
14380         PQExpBuffer query;
14381         PQExpBuffer labelq;
14382
14383         query = createPQExpBuffer();
14384         labelq = createPQExpBuffer();
14385
14386         appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
14387         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14388         appendPQExpBuffer(query, " ON ");
14389         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14390         appendPQExpBufferStr(query, " ");
14391
14392         if (strcmp("", evtinfo->evttags) != 0)
14393         {
14394                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14395                 appendPQExpBufferStr(query, evtinfo->evttags);
14396                 appendPQExpBufferStr(query, ") ");
14397         }
14398
14399         appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
14400         appendPQExpBufferStr(query, evtinfo->evtfname);
14401         appendPQExpBuffer(query, "();\n");
14402
14403         if (evtinfo->evtenabled != 'O')
14404         {
14405                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14406                                                   fmtId(evtinfo->dobj.name));
14407                 switch (evtinfo->evtenabled)
14408                 {
14409                         case 'D':
14410                                 appendPQExpBuffer(query, "DISABLE");
14411                                 break;
14412                         case 'A':
14413                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14414                                 break;
14415                         case 'R':
14416                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14417                                 break;
14418                         default:
14419                                 appendPQExpBuffer(query, "ENABLE");
14420                                 break;
14421                 }
14422                 appendPQExpBuffer(query, ";\n");
14423         }
14424         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14425                                           fmtId(evtinfo->dobj.name));
14426
14427         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14428                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14429                                  "EVENT TRIGGER", SECTION_POST_DATA,
14430                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14431
14432         dumpComment(fout, labelq->data,
14433                                 NULL, NULL,
14434                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14435
14436         destroyPQExpBuffer(query);
14437         destroyPQExpBuffer(labelq);
14438 }
14439
14440 /*
14441  * dumpRule
14442  *              Dump a rule
14443  */
14444 static void
14445 dumpRule(Archive *fout, RuleInfo *rinfo)
14446 {
14447         TableInfo  *tbinfo = rinfo->ruletable;
14448         PQExpBuffer query;
14449         PQExpBuffer cmd;
14450         PQExpBuffer delcmd;
14451         PQExpBuffer labelq;
14452         PGresult   *res;
14453
14454         /* Skip if not to be dumped */
14455         if (!rinfo->dobj.dump || dataOnly)
14456                 return;
14457
14458         /*
14459          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14460          * we do not want to dump it as a separate object.
14461          */
14462         if (!rinfo->separate)
14463                 return;
14464
14465         /*
14466          * Make sure we are in proper schema.
14467          */
14468         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14469
14470         query = createPQExpBuffer();
14471         cmd = createPQExpBuffer();
14472         delcmd = createPQExpBuffer();
14473         labelq = createPQExpBuffer();
14474
14475         if (fout->remoteVersion >= 70300)
14476         {
14477                 appendPQExpBuffer(query,
14478                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14479                                                   rinfo->dobj.catId.oid);
14480         }
14481         else
14482         {
14483                 /* Rule name was unique before 7.3 ... */
14484                 appendPQExpBuffer(query,
14485                                                   "SELECT pg_get_ruledef('%s') AS definition",
14486                                                   rinfo->dobj.name);
14487         }
14488
14489         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14490
14491         if (PQntuples(res) != 1)
14492         {
14493                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14494                                   rinfo->dobj.name, tbinfo->dobj.name);
14495                 exit_nicely(1);
14496         }
14497
14498         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14499
14500         /*
14501          * Add the command to alter the rules replication firing semantics if it
14502          * differs from the default.
14503          */
14504         if (rinfo->ev_enabled != 'O')
14505         {
14506                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14507                 switch (rinfo->ev_enabled)
14508                 {
14509                         case 'A':
14510                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14511                                                                   fmtId(rinfo->dobj.name));
14512                                 break;
14513                         case 'R':
14514                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14515                                                                   fmtId(rinfo->dobj.name));
14516                                 break;
14517                         case 'D':
14518                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14519                                                                   fmtId(rinfo->dobj.name));
14520                                 break;
14521                 }
14522         }
14523
14524         /*
14525          * Apply view's reloptions when its ON SELECT rule is separate.
14526          */
14527         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14528         {
14529                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14530                                                   fmtId(tbinfo->dobj.name),
14531                                                   rinfo->reloptions);
14532         }
14533
14534         /*
14535          * DROP must be fully qualified in case same name appears in pg_catalog
14536          */
14537         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14538                                           fmtId(rinfo->dobj.name));
14539         appendPQExpBuffer(delcmd, "ON %s.",
14540                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14541         appendPQExpBuffer(delcmd, "%s;\n",
14542                                           fmtId(tbinfo->dobj.name));
14543
14544         appendPQExpBuffer(labelq, "RULE %s",
14545                                           fmtId(rinfo->dobj.name));
14546         appendPQExpBuffer(labelq, " ON %s",
14547                                           fmtId(tbinfo->dobj.name));
14548
14549         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14550                                  rinfo->dobj.name,
14551                                  tbinfo->dobj.namespace->dobj.name,
14552                                  NULL,
14553                                  tbinfo->rolname, false,
14554                                  "RULE", SECTION_POST_DATA,
14555                                  cmd->data, delcmd->data, NULL,
14556                                  NULL, 0,
14557                                  NULL, NULL);
14558
14559         /* Dump rule comments */
14560         dumpComment(fout, labelq->data,
14561                                 tbinfo->dobj.namespace->dobj.name,
14562                                 tbinfo->rolname,
14563                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14564
14565         PQclear(res);
14566
14567         destroyPQExpBuffer(query);
14568         destroyPQExpBuffer(cmd);
14569         destroyPQExpBuffer(delcmd);
14570         destroyPQExpBuffer(labelq);
14571 }
14572
14573 /*
14574  * getExtensionMembership --- obtain extension membership data
14575  */
14576 void
14577 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14578                                            int numExtensions)
14579 {
14580         PQExpBuffer query;
14581         PGresult   *res;
14582         int                     ntups,
14583                                 i;
14584         int                     i_classid,
14585                                 i_objid,
14586                                 i_refclassid,
14587                                 i_refobjid;
14588         DumpableObject *dobj,
14589                            *refdobj;
14590
14591         /* Nothing to do if no extensions */
14592         if (numExtensions == 0)
14593                 return;
14594
14595         /* Make sure we are in proper schema */
14596         selectSourceSchema(fout, "pg_catalog");
14597
14598         query = createPQExpBuffer();
14599
14600         /* refclassid constraint is redundant but may speed the search */
14601         appendPQExpBuffer(query, "SELECT "
14602                                           "classid, objid, refclassid, refobjid "
14603                                           "FROM pg_depend "
14604                                           "WHERE refclassid = 'pg_extension'::regclass "
14605                                           "AND deptype = 'e' "
14606                                           "ORDER BY 3,4");
14607
14608         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14609
14610         ntups = PQntuples(res);
14611
14612         i_classid = PQfnumber(res, "classid");
14613         i_objid = PQfnumber(res, "objid");
14614         i_refclassid = PQfnumber(res, "refclassid");
14615         i_refobjid = PQfnumber(res, "refobjid");
14616
14617         /*
14618          * Since we ordered the SELECT by referenced ID, we can expect that
14619          * multiple entries for the same extension will appear together; this
14620          * saves on searches.
14621          */
14622         refdobj = NULL;
14623
14624         for (i = 0; i < ntups; i++)
14625         {
14626                 CatalogId       objId;
14627                 CatalogId       refobjId;
14628
14629                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14630                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14631                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14632                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14633
14634                 if (refdobj == NULL ||
14635                         refdobj->catId.tableoid != refobjId.tableoid ||
14636                         refdobj->catId.oid != refobjId.oid)
14637                         refdobj = findObjectByCatalogId(refobjId);
14638
14639                 /*
14640                  * Failure to find objects mentioned in pg_depend is not unexpected,
14641                  * since for example we don't collect info about TOAST tables.
14642                  */
14643                 if (refdobj == NULL)
14644                 {
14645 #ifdef NOT_USED
14646                         fprintf(stderr, "no referenced object %u %u\n",
14647                                         refobjId.tableoid, refobjId.oid);
14648 #endif
14649                         continue;
14650                 }
14651
14652                 dobj = findObjectByCatalogId(objId);
14653
14654                 if (dobj == NULL)
14655                 {
14656 #ifdef NOT_USED
14657                         fprintf(stderr, "no referencing object %u %u\n",
14658                                         objId.tableoid, objId.oid);
14659 #endif
14660                         continue;
14661                 }
14662
14663                 /* Record dependency so that getDependencies needn't repeat this */
14664                 addObjectDependency(dobj, refdobj->dumpId);
14665
14666                 dobj->ext_member = true;
14667
14668                 /*
14669                  * Normally, mark the member object as not to be dumped.  But in
14670                  * binary upgrades, we still dump the members individually, since the
14671                  * idea is to exactly reproduce the database contents rather than
14672                  * replace the extension contents with something different.
14673                  */
14674                 if (!binary_upgrade)
14675                         dobj->dump = false;
14676                 else
14677                         dobj->dump = refdobj->dump;
14678         }
14679
14680         PQclear(res);
14681
14682         /*
14683          * Now identify extension configuration tables and create TableDataInfo
14684          * objects for them, ensuring their data will be dumped even though the
14685          * tables themselves won't be.
14686          *
14687          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14688          * user data in a configuration table is treated like schema data. This
14689          * seems appropriate since system data in a config table would get
14690          * reloaded by CREATE EXTENSION.
14691          */
14692         for (i = 0; i < numExtensions; i++)
14693         {
14694                 ExtensionInfo *curext = &(extinfo[i]);
14695                 char       *extconfig = curext->extconfig;
14696                 char       *extcondition = curext->extcondition;
14697                 char      **extconfigarray = NULL;
14698                 char      **extconditionarray = NULL;
14699                 int                     nconfigitems;
14700                 int                     nconditionitems;
14701
14702                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14703                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14704                         nconfigitems == nconditionitems)
14705                 {
14706                         int                     j;
14707
14708                         for (j = 0; j < nconfigitems; j++)
14709                         {
14710                                 TableInfo  *configtbl;
14711                                 Oid                     configtbloid = atooid(extconfigarray[j]);
14712                                 bool            dumpobj = curext->dobj.dump;
14713
14714                                 configtbl = findTableByOid(configtbloid);
14715                                 if (configtbl == NULL)
14716                                         continue;
14717
14718                                 /*
14719                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
14720                                  * unless the table or its schema is explicitly included
14721                                  */
14722                                 if (!curext->dobj.dump)
14723                                 {
14724                                         /* check table explicitly requested */
14725                                         if (table_include_oids.head != NULL &&
14726                                                 simple_oid_list_member(&table_include_oids,
14727                                                                                            configtbloid))
14728                                                 dumpobj = true;
14729
14730                                         /* check table's schema explicitly requested */
14731                                         if (configtbl->dobj.namespace->dobj.dump)
14732                                                 dumpobj = true;
14733                                 }
14734
14735                                 /* check table excluded by an exclusion switch */
14736                                 if (table_exclude_oids.head != NULL &&
14737                                         simple_oid_list_member(&table_exclude_oids,
14738                                                                                    configtbloid))
14739                                         dumpobj = false;
14740
14741                                 /* check schema excluded by an exclusion switch */
14742                                 if (simple_oid_list_member(&schema_exclude_oids,
14743                                                                   configtbl->dobj.namespace->dobj.catId.oid))
14744                                         dumpobj = false;
14745
14746                                 if (dumpobj)
14747                                 {
14748                                         /*
14749                                          * Note: config tables are dumped without OIDs regardless
14750                                          * of the --oids setting.  This is because row filtering
14751                                          * conditions aren't compatible with dumping OIDs.
14752                                          */
14753                                         makeTableDataInfo(configtbl, false);
14754                                         if (configtbl->dataObj != NULL)
14755                                         {
14756                                                 if (strlen(extconditionarray[j]) > 0)
14757                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14758                                         }
14759                                 }
14760                         }
14761                 }
14762                 if (extconfigarray)
14763                         free(extconfigarray);
14764                 if (extconditionarray)
14765                         free(extconditionarray);
14766         }
14767
14768         destroyPQExpBuffer(query);
14769 }
14770
14771 /*
14772  * getDependencies --- obtain available dependency data
14773  */
14774 static void
14775 getDependencies(Archive *fout)
14776 {
14777         PQExpBuffer query;
14778         PGresult   *res;
14779         int                     ntups,
14780                                 i;
14781         int                     i_classid,
14782                                 i_objid,
14783                                 i_refclassid,
14784                                 i_refobjid,
14785                                 i_deptype;
14786         DumpableObject *dobj,
14787                            *refdobj;
14788
14789         /* No dependency info available before 7.3 */
14790         if (fout->remoteVersion < 70300)
14791                 return;
14792
14793         if (g_verbose)
14794                 write_msg(NULL, "reading dependency data\n");
14795
14796         /* Make sure we are in proper schema */
14797         selectSourceSchema(fout, "pg_catalog");
14798
14799         query = createPQExpBuffer();
14800
14801         /*
14802          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14803          * already processed by getExtensionMembership.
14804          */
14805         appendPQExpBuffer(query, "SELECT "
14806                                           "classid, objid, refclassid, refobjid, deptype "
14807                                           "FROM pg_depend "
14808                                           "WHERE deptype != 'p' AND deptype != 'e' "
14809                                           "ORDER BY 1,2");
14810
14811         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14812
14813         ntups = PQntuples(res);
14814
14815         i_classid = PQfnumber(res, "classid");
14816         i_objid = PQfnumber(res, "objid");
14817         i_refclassid = PQfnumber(res, "refclassid");
14818         i_refobjid = PQfnumber(res, "refobjid");
14819         i_deptype = PQfnumber(res, "deptype");
14820
14821         /*
14822          * Since we ordered the SELECT by referencing ID, we can expect that
14823          * multiple entries for the same object will appear together; this saves
14824          * on searches.
14825          */
14826         dobj = NULL;
14827
14828         for (i = 0; i < ntups; i++)
14829         {
14830                 CatalogId       objId;
14831                 CatalogId       refobjId;
14832                 char            deptype;
14833
14834                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14835                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14836                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14837                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14838                 deptype = *(PQgetvalue(res, i, i_deptype));
14839
14840                 if (dobj == NULL ||
14841                         dobj->catId.tableoid != objId.tableoid ||
14842                         dobj->catId.oid != objId.oid)
14843                         dobj = findObjectByCatalogId(objId);
14844
14845                 /*
14846                  * Failure to find objects mentioned in pg_depend is not unexpected,
14847                  * since for example we don't collect info about TOAST tables.
14848                  */
14849                 if (dobj == NULL)
14850                 {
14851 #ifdef NOT_USED
14852                         fprintf(stderr, "no referencing object %u %u\n",
14853                                         objId.tableoid, objId.oid);
14854 #endif
14855                         continue;
14856                 }
14857
14858                 refdobj = findObjectByCatalogId(refobjId);
14859
14860                 if (refdobj == NULL)
14861                 {
14862 #ifdef NOT_USED
14863                         fprintf(stderr, "no referenced object %u %u\n",
14864                                         refobjId.tableoid, refobjId.oid);
14865 #endif
14866                         continue;
14867                 }
14868
14869                 /*
14870                  * Ordinarily, table rowtypes have implicit dependencies on their
14871                  * tables.      However, for a composite type the implicit dependency goes
14872                  * the other way in pg_depend; which is the right thing for DROP but
14873                  * it doesn't produce the dependency ordering we need. So in that one
14874                  * case, we reverse the direction of the dependency.
14875                  */
14876                 if (deptype == 'i' &&
14877                         dobj->objType == DO_TABLE &&
14878                         refdobj->objType == DO_TYPE)
14879                         addObjectDependency(refdobj, dobj->dumpId);
14880                 else
14881                         /* normal case */
14882                         addObjectDependency(dobj, refdobj->dumpId);
14883         }
14884
14885         PQclear(res);
14886
14887         destroyPQExpBuffer(query);
14888 }
14889
14890
14891 /*
14892  * createBoundaryObjects - create dummy DumpableObjects to represent
14893  * dump section boundaries.
14894  */
14895 static DumpableObject *
14896 createBoundaryObjects(void)
14897 {
14898         DumpableObject *dobjs;
14899
14900         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
14901
14902         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
14903         dobjs[0].catId = nilCatalogId;
14904         AssignDumpId(dobjs + 0);
14905         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
14906
14907         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
14908         dobjs[1].catId = nilCatalogId;
14909         AssignDumpId(dobjs + 1);
14910         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
14911
14912         return dobjs;
14913 }
14914
14915 /*
14916  * addBoundaryDependencies - add dependencies as needed to enforce the dump
14917  * section boundaries.
14918  */
14919 static void
14920 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
14921                                                 DumpableObject *boundaryObjs)
14922 {
14923         DumpableObject *preDataBound = boundaryObjs + 0;
14924         DumpableObject *postDataBound = boundaryObjs + 1;
14925         int                     i;
14926
14927         for (i = 0; i < numObjs; i++)
14928         {
14929                 DumpableObject *dobj = dobjs[i];
14930
14931                 /*
14932                  * The classification of object types here must match the SECTION_xxx
14933                  * values assigned during subsequent ArchiveEntry calls!
14934                  */
14935                 switch (dobj->objType)
14936                 {
14937                         case DO_NAMESPACE:
14938                         case DO_EXTENSION:
14939                         case DO_TYPE:
14940                         case DO_SHELL_TYPE:
14941                         case DO_FUNC:
14942                         case DO_AGG:
14943                         case DO_OPERATOR:
14944                         case DO_OPCLASS:
14945                         case DO_OPFAMILY:
14946                         case DO_COLLATION:
14947                         case DO_CONVERSION:
14948                         case DO_TABLE:
14949                         case DO_ATTRDEF:
14950                         case DO_PROCLANG:
14951                         case DO_CAST:
14952                         case DO_DUMMY_TYPE:
14953                         case DO_TSPARSER:
14954                         case DO_TSDICT:
14955                         case DO_TSTEMPLATE:
14956                         case DO_TSCONFIG:
14957                         case DO_FDW:
14958                         case DO_FOREIGN_SERVER:
14959                         case DO_BLOB:
14960                                 /* Pre-data objects: must come before the pre-data boundary */
14961                                 addObjectDependency(preDataBound, dobj->dumpId);
14962                                 break;
14963                         case DO_TABLE_DATA:
14964                         case DO_BLOB_DATA:
14965                                 /* Data objects: must come between the boundaries */
14966                                 addObjectDependency(dobj, preDataBound->dumpId);
14967                                 addObjectDependency(postDataBound, dobj->dumpId);
14968                                 break;
14969                         case DO_INDEX:
14970                         case DO_REFRESH_MATVIEW:
14971                         case DO_TRIGGER:
14972                         case DO_EVENT_TRIGGER:
14973                         case DO_DEFAULT_ACL:
14974                                 /* Post-data objects: must come after the post-data boundary */
14975                                 addObjectDependency(dobj, postDataBound->dumpId);
14976                                 break;
14977                         case DO_RULE:
14978                                 /* Rules are post-data, but only if dumped separately */
14979                                 if (((RuleInfo *) dobj)->separate)
14980                                         addObjectDependency(dobj, postDataBound->dumpId);
14981                                 break;
14982                         case DO_CONSTRAINT:
14983                         case DO_FK_CONSTRAINT:
14984                                 /* Constraints are post-data, but only if dumped separately */
14985                                 if (((ConstraintInfo *) dobj)->separate)
14986                                         addObjectDependency(dobj, postDataBound->dumpId);
14987                                 break;
14988                         case DO_PRE_DATA_BOUNDARY:
14989                                 /* nothing to do */
14990                                 break;
14991                         case DO_POST_DATA_BOUNDARY:
14992                                 /* must come after the pre-data boundary */
14993                                 addObjectDependency(dobj, preDataBound->dumpId);
14994                                 break;
14995                 }
14996         }
14997 }
14998
14999
15000 /*
15001  * BuildArchiveDependencies - create dependency data for archive TOC entries
15002  *
15003  * The raw dependency data obtained by getDependencies() is not terribly
15004  * useful in an archive dump, because in many cases there are dependency
15005  * chains linking through objects that don't appear explicitly in the dump.
15006  * For example, a view will depend on its _RETURN rule while the _RETURN rule
15007  * will depend on other objects --- but the rule will not appear as a separate
15008  * object in the dump.  We need to adjust the view's dependencies to include
15009  * whatever the rule depends on that is included in the dump.
15010  *
15011  * Just to make things more complicated, there are also "special" dependencies
15012  * such as the dependency of a TABLE DATA item on its TABLE, which we must
15013  * not rearrange because pg_restore knows that TABLE DATA only depends on
15014  * its table.  In these cases we must leave the dependencies strictly as-is
15015  * even if they refer to not-to-be-dumped objects.
15016  *
15017  * To handle this, the convention is that "special" dependencies are created
15018  * during ArchiveEntry calls, and an archive TOC item that has any such
15019  * entries will not be touched here.  Otherwise, we recursively search the
15020  * DumpableObject data structures to build the correct dependencies for each
15021  * archive TOC item.
15022  */
15023 static void
15024 BuildArchiveDependencies(Archive *fout)
15025 {
15026         ArchiveHandle *AH = (ArchiveHandle *) fout;
15027         TocEntry   *te;
15028
15029         /* Scan all TOC entries in the archive */
15030         for (te = AH->toc->next; te != AH->toc; te = te->next)
15031         {
15032                 DumpableObject *dobj;
15033                 DumpId     *dependencies;
15034                 int                     nDeps;
15035                 int                     allocDeps;
15036
15037                 /* No need to process entries that will not be dumped */
15038                 if (te->reqs == 0)
15039                         continue;
15040                 /* Ignore entries that already have "special" dependencies */
15041                 if (te->nDeps > 0)
15042                         continue;
15043                 /* Otherwise, look up the item's original DumpableObject, if any */
15044                 dobj = findObjectByDumpId(te->dumpId);
15045                 if (dobj == NULL)
15046                         continue;
15047                 /* No work if it has no dependencies */
15048                 if (dobj->nDeps <= 0)
15049                         continue;
15050                 /* Set up work array */
15051                 allocDeps = 64;
15052                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
15053                 nDeps = 0;
15054                 /* Recursively find all dumpable dependencies */
15055                 findDumpableDependencies(AH, dobj,
15056                                                                  &dependencies, &nDeps, &allocDeps);
15057                 /* And save 'em ... */
15058                 if (nDeps > 0)
15059                 {
15060                         dependencies = (DumpId *) pg_realloc(dependencies,
15061                                                                                                  nDeps * sizeof(DumpId));
15062                         te->dependencies = dependencies;
15063                         te->nDeps = nDeps;
15064                 }
15065                 else
15066                         free(dependencies);
15067         }
15068 }
15069
15070 /* Recursive search subroutine for BuildArchiveDependencies */
15071 static void
15072 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
15073                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
15074 {
15075         int                     i;
15076
15077         /*
15078          * Ignore section boundary objects: if we search through them, we'll
15079          * report lots of bogus dependencies.
15080          */
15081         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15082                 dobj->objType == DO_POST_DATA_BOUNDARY)
15083                 return;
15084
15085         for (i = 0; i < dobj->nDeps; i++)
15086         {
15087                 DumpId          depid = dobj->dependencies[i];
15088
15089                 if (TocIDRequired(AH, depid) != 0)
15090                 {
15091                         /* Object will be dumped, so just reference it as a dependency */
15092                         if (*nDeps >= *allocDeps)
15093                         {
15094                                 *allocDeps *= 2;
15095                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15096                                                                                                 *allocDeps * sizeof(DumpId));
15097                         }
15098                         (*dependencies)[*nDeps] = depid;
15099                         (*nDeps)++;
15100                 }
15101                 else
15102                 {
15103                         /*
15104                          * Object will not be dumped, so recursively consider its deps. We
15105                          * rely on the assumption that sortDumpableObjects already broke
15106                          * any dependency loops, else we might recurse infinitely.
15107                          */
15108                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15109
15110                         if (otherdobj)
15111                                 findDumpableDependencies(AH, otherdobj,
15112                                                                                  dependencies, nDeps, allocDeps);
15113                 }
15114         }
15115 }
15116
15117
15118 /*
15119  * selectSourceSchema - make the specified schema the active search path
15120  * in the source database.
15121  *
15122  * NB: pg_catalog is explicitly searched after the specified schema;
15123  * so user names are only qualified if they are cross-schema references,
15124  * and system names are only qualified if they conflict with a user name
15125  * in the current schema.
15126  *
15127  * Whenever the selected schema is not pg_catalog, be careful to qualify
15128  * references to system catalogs and types in our emitted commands!
15129  *
15130  * This function is called only from selectSourceSchemaOnAH and
15131  * selectSourceSchema.
15132  */
15133 static void
15134 selectSourceSchema(Archive *fout, const char *schemaName)
15135 {
15136         PQExpBuffer query;
15137
15138         /* This is checked by the callers already */
15139         Assert(schemaName != NULL && *schemaName != '\0');
15140
15141         /* Not relevant if fetching from pre-7.3 DB */
15142         if (fout->remoteVersion < 70300)
15143                 return;
15144
15145         query = createPQExpBuffer();
15146         appendPQExpBuffer(query, "SET search_path = %s",
15147                                           fmtId(schemaName));
15148         if (strcmp(schemaName, "pg_catalog") != 0)
15149                 appendPQExpBuffer(query, ", pg_catalog");
15150
15151         ExecuteSqlStatement(fout, query->data);
15152
15153         destroyPQExpBuffer(query);
15154 }
15155
15156 /*
15157  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15158  * given type name.
15159  *
15160  * NB: in 7.3 and up the result may depend on the currently-selected
15161  * schema; this is why we don't try to cache the names.
15162  */
15163 static char *
15164 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15165 {
15166         char       *result;
15167         PQExpBuffer query;
15168         PGresult   *res;
15169
15170         if (oid == 0)
15171         {
15172                 if ((opts & zeroAsOpaque) != 0)
15173                         return pg_strdup(g_opaque_type);
15174                 else if ((opts & zeroAsAny) != 0)
15175                         return pg_strdup("'any'");
15176                 else if ((opts & zeroAsStar) != 0)
15177                         return pg_strdup("*");
15178                 else if ((opts & zeroAsNone) != 0)
15179                         return pg_strdup("NONE");
15180         }
15181
15182         query = createPQExpBuffer();
15183         if (fout->remoteVersion >= 70300)
15184         {
15185                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15186                                                   oid);
15187         }
15188         else if (fout->remoteVersion >= 70100)
15189         {
15190                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15191                                                   oid);
15192         }
15193         else
15194         {
15195                 appendPQExpBuffer(query, "SELECT typname "
15196                                                   "FROM pg_type "
15197                                                   "WHERE oid = '%u'::oid",
15198                                                   oid);
15199         }
15200
15201         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15202
15203         if (fout->remoteVersion >= 70100)
15204         {
15205                 /* already quoted */
15206                 result = pg_strdup(PQgetvalue(res, 0, 0));
15207         }
15208         else
15209         {
15210                 /* may need to quote it */
15211                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15212         }
15213
15214         PQclear(res);
15215         destroyPQExpBuffer(query);
15216
15217         return result;
15218 }
15219
15220 /*
15221  * myFormatType --- local implementation of format_type for use with 7.0.
15222  */
15223 static char *
15224 myFormatType(const char *typname, int32 typmod)
15225 {
15226         char       *result;
15227         bool            isarray = false;
15228         PQExpBuffer buf = createPQExpBuffer();
15229
15230         /* Handle array types */
15231         if (typname[0] == '_')
15232         {
15233                 isarray = true;
15234                 typname++;
15235         }
15236
15237         /* Show lengths on bpchar and varchar */
15238         if (strcmp(typname, "bpchar") == 0)
15239         {
15240                 int                     len = (typmod - VARHDRSZ);
15241
15242                 appendPQExpBuffer(buf, "character");
15243                 if (len > 1)
15244                         appendPQExpBuffer(buf, "(%d)",
15245                                                           typmod - VARHDRSZ);
15246         }
15247         else if (strcmp(typname, "varchar") == 0)
15248         {
15249                 appendPQExpBuffer(buf, "character varying");
15250                 if (typmod != -1)
15251                         appendPQExpBuffer(buf, "(%d)",
15252                                                           typmod - VARHDRSZ);
15253         }
15254         else if (strcmp(typname, "numeric") == 0)
15255         {
15256                 appendPQExpBuffer(buf, "numeric");
15257                 if (typmod != -1)
15258                 {
15259                         int32           tmp_typmod;
15260                         int                     precision;
15261                         int                     scale;
15262
15263                         tmp_typmod = typmod - VARHDRSZ;
15264                         precision = (tmp_typmod >> 16) & 0xffff;
15265                         scale = tmp_typmod & 0xffff;
15266                         appendPQExpBuffer(buf, "(%d,%d)",
15267                                                           precision, scale);
15268                 }
15269         }
15270
15271         /*
15272          * char is an internal single-byte data type; Let's make sure we force it
15273          * through with quotes. - thomas 1998-12-13
15274          */
15275         else if (strcmp(typname, "char") == 0)
15276                 appendPQExpBuffer(buf, "\"char\"");
15277         else
15278                 appendPQExpBuffer(buf, "%s", fmtId(typname));
15279
15280         /* Append array qualifier for array types */
15281         if (isarray)
15282                 appendPQExpBuffer(buf, "[]");
15283
15284         result = pg_strdup(buf->data);
15285         destroyPQExpBuffer(buf);
15286
15287         return result;
15288 }
15289
15290 /*
15291  * Return a column list clause for the given relation.
15292  *
15293  * Special case: if there are no undropped columns in the relation, return
15294  * "", not an invalid "()" column list.
15295  */
15296 static const char *
15297 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15298 {
15299         int                     numatts = ti->numatts;
15300         char      **attnames = ti->attnames;
15301         bool       *attisdropped = ti->attisdropped;
15302         bool            needComma;
15303         int                     i;
15304
15305         appendPQExpBuffer(buffer, "(");
15306         needComma = false;
15307         for (i = 0; i < numatts; i++)
15308         {
15309                 if (attisdropped[i])
15310                         continue;
15311                 if (needComma)
15312                         appendPQExpBuffer(buffer, ", ");
15313                 appendPQExpBuffer(buffer, "%s", fmtId(attnames[i]));
15314                 needComma = true;
15315         }
15316
15317         if (!needComma)
15318                 return "";                              /* no undropped columns */
15319
15320         appendPQExpBuffer(buffer, ")");
15321         return buffer->data;
15322 }
15323
15324 /*
15325  * Execute an SQL query and verify that we got exactly one row back.
15326  */
15327 static PGresult *
15328 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15329 {
15330         PGresult   *res;
15331         int                     ntups;
15332
15333         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15334
15335         /* Expecting a single result only */
15336         ntups = PQntuples(res);
15337         if (ntups != 1)
15338                 exit_horribly(NULL,
15339                                           ngettext("query returned %d row instead of one: %s\n",
15340                                                            "query returned %d rows instead of one: %s\n",
15341                                                            ntups),
15342                                           ntups, query);
15343
15344         return res;
15345 }