]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Fix dumping of security_barrier views with circular dependencies.
[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-2012, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to run on
18  *      SnapshotNow time, ie they look at the currently committed state.  So
19  *      it is possible to get 'cache lookup failed' error if someone
20  *      performs DDL changes while a dump is happening. The window for this
21  *      sort of thing is from the acquisition of the transaction snapshot to
22  *      getSchemaData() (when pg_dump acquires AccessShareLock on every
23  *      table it intends to dump). It isn't very large, but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32
33 #include "postgres_fe.h"
34
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef ENABLE_NLS
38 #include <locale.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h>
42 #endif
43
44 #include "getopt_long.h"
45
46 #include "access/attnum.h"
47 #include "access/sysattr.h"
48 #include "access/transam.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_event_trigger.h"
53 #include "catalog/pg_largeobject.h"
54 #include "catalog/pg_largeobject_metadata.h"
55 #include "catalog/pg_proc.h"
56 #include "catalog/pg_trigger.h"
57 #include "catalog/pg_type.h"
58 #include "libpq/libpq-fs.h"
59
60 #include "pg_backup_archiver.h"
61 #include "pg_backup_db.h"
62 #include "dumpmem.h"
63 #include "dumputils.h"
64
65 extern char *optarg;
66 extern int      optind,
67                         opterr;
68
69
70 typedef struct
71 {
72         const char *descr;                      /* comment for an object */
73         Oid                     classoid;               /* object class (catalog OID) */
74         Oid                     objoid;                 /* object OID */
75         int                     objsubid;               /* subobject (table column #) */
76 } CommentItem;
77
78 typedef struct
79 {
80         const char *provider;           /* label provider of this security label */
81         const char *label;                      /* security label for an object */
82         Oid                     classoid;               /* object class (catalog OID) */
83         Oid                     objoid;                 /* object OID */
84         int                     objsubid;               /* subobject (table column #) */
85 } SecLabelItem;
86
87 /* global decls */
88 bool            g_verbose;                      /* User wants verbose narration of our
89                                                                  * activities. */
90
91 /* various user-settable parameters */
92 bool            schemaOnly;
93 bool            dataOnly;
94 int                     dumpSections;           /* bitmask of chosen sections */
95 bool            aclsSkip;
96 const char *lockWaitTimeout;
97
98 /* subquery used to convert user ID (eg, datdba) to user name */
99 static const char *username_subquery;
100
101 /* obsolete as of 7.3: */
102 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
103
104 /*
105  * Object inclusion/exclusion lists
106  *
107  * The string lists record the patterns given by command-line switches,
108  * which we then convert to lists of OIDs of matching objects.
109  */
110 static SimpleStringList schema_include_patterns = {NULL, NULL};
111 static SimpleOidList schema_include_oids = {NULL, NULL};
112 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
113 static SimpleOidList schema_exclude_oids = {NULL, NULL};
114
115 static SimpleStringList table_include_patterns = {NULL, NULL};
116 static SimpleOidList table_include_oids = {NULL, NULL};
117 static SimpleStringList table_exclude_patterns = {NULL, NULL};
118 static SimpleOidList table_exclude_oids = {NULL, NULL};
119 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
120 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
121
122 /* default, if no "inclusion" switches appear, is to dump everything */
123 static bool include_everything = true;
124
125 char            g_opaque_type[10];      /* name for the opaque type */
126
127 /* placeholders for the delimiters for comments */
128 char            g_comment_start[10];
129 char            g_comment_end[10];
130
131 static const CatalogId nilCatalogId = {0, 0};
132
133 /* flags for various command-line long options */
134 static int      binary_upgrade = 0;
135 static int      disable_dollar_quoting = 0;
136 static int      dump_inserts = 0;
137 static int      column_inserts = 0;
138 static int      no_security_labels = 0;
139 static int      no_unlogged_table_data = 0;
140 static int      serializable_deferrable = 0;
141
142
143 static void help(const char *progname);
144 static void setup_connection(Archive *AH, const char *dumpencoding,
145                                  char *use_role);
146 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
147 static void expand_schema_name_patterns(Archive *fout,
148                                                         SimpleStringList *patterns,
149                                                         SimpleOidList *oids);
150 static void expand_table_name_patterns(Archive *fout,
151                                                    SimpleStringList *patterns,
152                                                    SimpleOidList *oids);
153 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
154 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
155 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
156 static void dumpComment(Archive *fout, const char *target,
157                         const char *namespace, const char *owner,
158                         CatalogId catalogId, int subid, DumpId dumpId);
159 static int findComments(Archive *fout, Oid classoid, Oid objoid,
160                          CommentItem **items);
161 static int      collectComments(Archive *fout, CommentItem **items);
162 static void dumpSecLabel(Archive *fout, const char *target,
163                          const char *namespace, const char *owner,
164                          CatalogId catalogId, int subid, DumpId dumpId);
165 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
166                           SecLabelItem **items);
167 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
168 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
169 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
170 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
171 static void dumpType(Archive *fout, TypeInfo *tyinfo);
172 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
173 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
174 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
176 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
178 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
179 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
180 static void dumpFunc(Archive *fout, FuncInfo *finfo);
181 static void dumpCast(Archive *fout, CastInfo *cast);
182 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
183 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
184 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
185 static void dumpCollation(Archive *fout, CollInfo *convinfo);
186 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
187 static void dumpRule(Archive *fout, RuleInfo *rinfo);
188 static void dumpAgg(Archive *fout, AggInfo *agginfo);
189 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
190 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
191 static void dumpTable(Archive *fout, TableInfo *tbinfo);
192 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
193 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
194 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
195 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
196 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
197 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
198 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
199 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
200 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
201 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
202 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
203 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
204 static void dumpUserMappings(Archive *fout,
205                                  const char *servername, const char *namespace,
206                                  const char *owner, CatalogId catalogId, DumpId dumpId);
207 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
208
209 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
210                 const char *type, const char *name, const char *subname,
211                 const char *tag, const char *nspname, const char *owner,
212                 const char *acls);
213
214 static void getDependencies(Archive *fout);
215 static void BuildArchiveDependencies(Archive *fout);
216 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
217                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
218
219 static DumpableObject *createBoundaryObjects(void);
220 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
221                                                 DumpableObject *boundaryObjs);
222
223 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
224 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
225 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
226 static void getTableDataFKConstraints(void);
227 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
228 static char *format_function_arguments_old(Archive *fout,
229                                                           FuncInfo *finfo, int nallargs,
230                                                           char **allargtypes,
231                                                           char **argmodes,
232                                                           char **argnames);
233 static char *format_function_signature(Archive *fout,
234                                                   FuncInfo *finfo, bool honor_quotes);
235 static const char *convertRegProcReference(Archive *fout,
236                                                 const char *proc);
237 static const char *convertOperatorReference(Archive *fout, const char *opr);
238 static const char *convertTSFunction(Archive *fout, Oid funcOid);
239 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
240 static Oid      findLastBuiltinOid_V70(Archive *fout);
241 static void selectSourceSchema(Archive *fout, const char *schemaName);
242 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
243 static char *myFormatType(const char *typname, int32 typmod);
244 static const char *fmtQualifiedId(Archive *fout,
245                            const char *schema, const char *id);
246 static void getBlobs(Archive *fout);
247 static void dumpBlob(Archive *fout, BlobInfo *binfo);
248 static int      dumpBlobs(Archive *fout, void *arg);
249 static void dumpDatabase(Archive *AH);
250 static void dumpEncoding(Archive *AH);
251 static void dumpStdStrings(Archive *AH);
252 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
253                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
254 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
255                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
256 static void binary_upgrade_set_pg_class_oids(Archive *fout,
257                                                                  PQExpBuffer upgrade_buffer,
258                                                                  Oid pg_class_oid, bool is_index);
259 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
260                                                                 DumpableObject *dobj,
261                                                                 const char *objlabel);
262 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
263 static const char *fmtCopyColumnList(const TableInfo *ti);
264 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
265
266
267 int
268 main(int argc, char **argv)
269 {
270         int                     c;
271         const char *filename = NULL;
272         const char *format = "p";
273         const char *dbname = NULL;
274         const char *pghost = NULL;
275         const char *pgport = NULL;
276         const char *username = NULL;
277         const char *dumpencoding = NULL;
278         bool            oids = false;
279         TableInfo  *tblinfo;
280         int                     numTables;
281         DumpableObject **dobjs;
282         int                     numObjs;
283         DumpableObject *boundaryObjs;
284         int                     i;
285         enum trivalue prompt_password = TRI_DEFAULT;
286         int                     compressLevel = -1;
287         int                     plainText = 0;
288         int                     outputClean = 0;
289         int                     outputCreateDB = 0;
290         bool            outputBlobs = false;
291         int                     outputNoOwner = 0;
292         char       *outputSuperuser = NULL;
293         char       *use_role = NULL;
294         int                     my_version;
295         int                     optindex;
296         RestoreOptions *ropt;
297         ArchiveFormat archiveFormat = archUnknown;
298         ArchiveMode archiveMode;
299         Archive    *fout;                       /* the script file */
300
301         static int      disable_triggers = 0;
302         static int      outputNoTablespaces = 0;
303         static int      use_setsessauth = 0;
304
305         static struct option long_options[] = {
306                 {"data-only", no_argument, NULL, 'a'},
307                 {"blobs", no_argument, NULL, 'b'},
308                 {"clean", no_argument, NULL, 'c'},
309                 {"create", no_argument, NULL, 'C'},
310                 {"file", required_argument, NULL, 'f'},
311                 {"format", required_argument, NULL, 'F'},
312                 {"host", required_argument, NULL, 'h'},
313                 {"ignore-version", no_argument, NULL, 'i'},
314                 {"no-reconnect", no_argument, NULL, 'R'},
315                 {"oids", no_argument, NULL, 'o'},
316                 {"no-owner", no_argument, NULL, 'O'},
317                 {"port", required_argument, NULL, 'p'},
318                 {"schema", required_argument, NULL, 'n'},
319                 {"exclude-schema", required_argument, NULL, 'N'},
320                 {"schema-only", no_argument, NULL, 's'},
321                 {"superuser", required_argument, NULL, 'S'},
322                 {"table", required_argument, NULL, 't'},
323                 {"exclude-table", required_argument, NULL, 'T'},
324                 {"no-password", no_argument, NULL, 'w'},
325                 {"password", no_argument, NULL, 'W'},
326                 {"username", required_argument, NULL, 'U'},
327                 {"verbose", no_argument, NULL, 'v'},
328                 {"no-privileges", no_argument, NULL, 'x'},
329                 {"no-acl", no_argument, NULL, 'x'},
330                 {"compress", required_argument, NULL, 'Z'},
331                 {"encoding", required_argument, NULL, 'E'},
332                 {"help", no_argument, NULL, '?'},
333                 {"version", no_argument, NULL, 'V'},
334
335                 /*
336                  * the following options don't have an equivalent short option letter
337                  */
338                 {"attribute-inserts", no_argument, &column_inserts, 1},
339                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
340                 {"column-inserts", no_argument, &column_inserts, 1},
341                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
342                 {"disable-triggers", no_argument, &disable_triggers, 1},
343                 {"exclude-table-data", required_argument, NULL, 4},
344                 {"inserts", no_argument, &dump_inserts, 1},
345                 {"lock-wait-timeout", required_argument, NULL, 2},
346                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
347                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
348                 {"role", required_argument, NULL, 3},
349                 {"section", required_argument, NULL, 5},
350                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
351                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
352                 {"no-security-labels", no_argument, &no_security_labels, 1},
353                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
354
355                 {NULL, 0, NULL, 0}
356         };
357
358         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
359
360         g_verbose = false;
361
362         strcpy(g_comment_start, "-- ");
363         g_comment_end[0] = '\0';
364         strcpy(g_opaque_type, "opaque");
365
366         dataOnly = schemaOnly = false;
367         dumpSections = DUMP_UNSECTIONED;
368         lockWaitTimeout = NULL;
369
370         progname = get_progname(argv[0]);
371
372         /* Set default options based on progname */
373         if (strcmp(progname, "pg_backup") == 0)
374                 format = "c";
375
376         if (argc > 1)
377         {
378                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
379                 {
380                         help(progname);
381                         exit_nicely(0);
382                 }
383                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
384                 {
385                         puts("pg_dump (PostgreSQL) " PG_VERSION);
386                         exit_nicely(0);
387                 }
388         }
389
390         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
391                                                         long_options, &optindex)) != -1)
392         {
393                 switch (c)
394                 {
395                         case 'a':                       /* Dump data only */
396                                 dataOnly = true;
397                                 break;
398
399                         case 'b':                       /* Dump blobs */
400                                 outputBlobs = true;
401                                 break;
402
403                         case 'c':                       /* clean (i.e., drop) schema prior to create */
404                                 outputClean = 1;
405                                 break;
406
407                         case 'C':                       /* Create DB */
408                                 outputCreateDB = 1;
409                                 break;
410
411                         case 'E':                       /* Dump encoding */
412                                 dumpencoding = optarg;
413                                 break;
414
415                         case 'f':
416                                 filename = optarg;
417                                 break;
418
419                         case 'F':
420                                 format = optarg;
421                                 break;
422
423                         case 'h':                       /* server host */
424                                 pghost = optarg;
425                                 break;
426
427                         case 'i':
428                                 /* ignored, deprecated option */
429                                 break;
430
431                         case 'n':                       /* include schema(s) */
432                                 simple_string_list_append(&schema_include_patterns, optarg);
433                                 include_everything = false;
434                                 break;
435
436                         case 'N':                       /* exclude schema(s) */
437                                 simple_string_list_append(&schema_exclude_patterns, optarg);
438                                 break;
439
440                         case 'o':                       /* Dump oids */
441                                 oids = true;
442                                 break;
443
444                         case 'O':                       /* Don't reconnect to match owner */
445                                 outputNoOwner = 1;
446                                 break;
447
448                         case 'p':                       /* server port */
449                                 pgport = optarg;
450                                 break;
451
452                         case 'R':
453                                 /* no-op, still accepted for backwards compatibility */
454                                 break;
455
456                         case 's':                       /* dump schema only */
457                                 schemaOnly = true;
458                                 break;
459
460                         case 'S':                       /* Username for superuser in plain text output */
461                                 outputSuperuser = pg_strdup(optarg);
462                                 break;
463
464                         case 't':                       /* include table(s) */
465                                 simple_string_list_append(&table_include_patterns, optarg);
466                                 include_everything = false;
467                                 break;
468
469                         case 'T':                       /* exclude table(s) */
470                                 simple_string_list_append(&table_exclude_patterns, optarg);
471                                 break;
472
473                         case 'U':
474                                 username = optarg;
475                                 break;
476
477                         case 'v':                       /* verbose */
478                                 g_verbose = true;
479                                 break;
480
481                         case 'w':
482                                 prompt_password = TRI_NO;
483                                 break;
484
485                         case 'W':
486                                 prompt_password = TRI_YES;
487                                 break;
488
489                         case 'x':                       /* skip ACL dump */
490                                 aclsSkip = true;
491                                 break;
492
493                         case 'Z':                       /* Compression Level */
494                                 compressLevel = atoi(optarg);
495                                 break;
496
497                         case 0:
498                                 /* This covers the long options. */
499                                 break;
500
501                         case 2:                         /* lock-wait-timeout */
502                                 lockWaitTimeout = optarg;
503                                 break;
504
505                         case 3:                         /* SET ROLE */
506                                 use_role = optarg;
507                                 break;
508
509                         case 4:                         /* exclude table(s) data */
510                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
511                                 break;
512
513                         case 5:                         /* section */
514                                 set_dump_section(optarg, &dumpSections);
515                                 break;
516
517                         default:
518                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
519                                 exit_nicely(1);
520                 }
521         }
522
523         /* Get database name from command line */
524         if (optind < argc)
525                 dbname = argv[optind++];
526
527         /* Complain if any arguments remain */
528         if (optind < argc)
529         {
530                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
531                                 progname, argv[optind]);
532                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
533                                 progname);
534                 exit_nicely(1);
535         }
536
537         /* --column-inserts implies --inserts */
538         if (column_inserts)
539                 dump_inserts = 1;
540
541         if (dataOnly && schemaOnly)
542                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
543
544         if (dataOnly && outputClean)
545                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
546
547         if (dump_inserts && oids)
548         {
549                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
550                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
551                 exit_nicely(1);
552         }
553
554         /* Identify archive format to emit */
555         archiveFormat = parseArchiveFormat(format, &archiveMode);
556
557         /* archiveFormat specific setup */
558         if (archiveFormat == archNull)
559                 plainText = 1;
560
561         /* Custom and directory formats are compressed by default, others not */
562         if (compressLevel == -1)
563         {
564                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
565                         compressLevel = Z_DEFAULT_COMPRESSION;
566                 else
567                         compressLevel = 0;
568         }
569
570         /* Open the output file */
571         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
572
573         /* Register the cleanup hook */
574         on_exit_close_archive(fout);
575
576         if (fout == NULL)
577                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
578
579         /* Let the archiver know how noisy to be */
580         fout->verbose = g_verbose;
581
582         my_version = parse_version(PG_VERSION);
583         if (my_version < 0)
584                 exit_horribly(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
585
586         /*
587          * We allow the server to be back to 7.0, and up to any minor release of
588          * our own major version.  (See also version check in pg_dumpall.c.)
589          */
590         fout->minRemoteVersion = 70000;
591         fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
592
593         /*
594          * Open the database using the Archiver, so it knows about it. Errors mean
595          * death.
596          */
597         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
598         setup_connection(fout, dumpencoding, use_role);
599
600         /*
601          * Disable security label support if server version < v9.1.x (prevents
602          * access to nonexistent pg_seclabel catalog)
603          */
604         if (fout->remoteVersion < 90100)
605                 no_security_labels = 1;
606
607         /*
608          * Start transaction-snapshot mode transaction to dump consistent data.
609          */
610         ExecuteSqlStatement(fout, "BEGIN");
611         if (fout->remoteVersion >= 90100)
612         {
613                 if (serializable_deferrable)
614                         ExecuteSqlStatement(fout,
615                                                                 "SET TRANSACTION ISOLATION LEVEL "
616                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
617                 else
618                         ExecuteSqlStatement(fout,
619                                                                 "SET TRANSACTION ISOLATION LEVEL "
620                                                                 "REPEATABLE READ");
621         }
622         else
623                 ExecuteSqlStatement(fout,
624                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
625
626         /* Select the appropriate subquery to convert user IDs to names */
627         if (fout->remoteVersion >= 80100)
628                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
629         else if (fout->remoteVersion >= 70300)
630                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
631         else
632                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
633
634         /* Find the last built-in OID, if needed */
635         if (fout->remoteVersion < 70300)
636         {
637                 if (fout->remoteVersion >= 70100)
638                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
639                                                                                                   PQdb(GetConnection(fout)));
640                 else
641                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
642                 if (g_verbose)
643                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
644         }
645
646         /* Expand schema selection patterns into OID lists */
647         if (schema_include_patterns.head != NULL)
648         {
649                 expand_schema_name_patterns(fout, &schema_include_patterns,
650                                                                         &schema_include_oids);
651                 if (schema_include_oids.head == NULL)
652                         exit_horribly(NULL, "No matching schemas were found\n");
653         }
654         expand_schema_name_patterns(fout, &schema_exclude_patterns,
655                                                                 &schema_exclude_oids);
656         /* non-matching exclusion patterns aren't an error */
657
658         /* Expand table selection patterns into OID lists */
659         if (table_include_patterns.head != NULL)
660         {
661                 expand_table_name_patterns(fout, &table_include_patterns,
662                                                                    &table_include_oids);
663                 if (table_include_oids.head == NULL)
664                         exit_horribly(NULL, "No matching tables were found\n");
665         }
666         expand_table_name_patterns(fout, &table_exclude_patterns,
667                                                            &table_exclude_oids);
668
669         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
670                                                            &tabledata_exclude_oids);
671
672         /* non-matching exclusion patterns aren't an error */
673
674         /*
675          * Dumping blobs is now default unless we saw an inclusion switch or -s
676          * ... but even if we did see one of these, -b turns it back on.
677          */
678         if (include_everything && !schemaOnly)
679                 outputBlobs = true;
680
681         /*
682          * Now scan the database and create DumpableObject structs for all the
683          * objects we intend to dump.
684          */
685         tblinfo = getSchemaData(fout, &numTables);
686
687         if (fout->remoteVersion < 80400)
688                 guessConstraintInheritance(tblinfo, numTables);
689
690         if (!schemaOnly)
691         {
692                 getTableData(tblinfo, numTables, oids);
693                 if (dataOnly)
694                         getTableDataFKConstraints();
695         }
696
697         if (outputBlobs)
698                 getBlobs(fout);
699
700         /*
701          * Collect dependency data to assist in ordering the objects.
702          */
703         getDependencies(fout);
704
705         /* Lastly, create dummy objects to represent the section boundaries */
706         boundaryObjs = createBoundaryObjects();
707
708         /* Get pointers to all the known DumpableObjects */
709         getDumpableObjects(&dobjs, &numObjs);
710
711         /*
712          * Add dummy dependencies to enforce the dump section ordering.
713          */
714         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
715
716         /*
717          * Sort the objects into a safe dump order (no forward references).
718          *
719          * In 7.3 or later, we can rely on dependency information to help us
720          * determine a safe order, so the initial sort is mostly for cosmetic
721          * purposes: we sort by name to ensure that logically identical schemas
722          * will dump identically.  Before 7.3 we don't have dependencies and we
723          * use OID ordering as an (unreliable) guide to creation order.
724          */
725         if (fout->remoteVersion >= 70300)
726                 sortDumpableObjectsByTypeName(dobjs, numObjs);
727         else
728                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
729
730         sortDumpableObjects(dobjs, numObjs,
731                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
732
733         /*
734          * Create archive TOC entries for all the objects to be dumped, in a safe
735          * order.
736          */
737
738         /* First the special ENCODING and STDSTRINGS entries. */
739         dumpEncoding(fout);
740         dumpStdStrings(fout);
741
742         /* The database item is always next, unless we don't want it at all */
743         if (include_everything && !dataOnly)
744                 dumpDatabase(fout);
745
746         /* Now the rearrangeable objects. */
747         for (i = 0; i < numObjs; i++)
748                 dumpDumpableObject(fout, dobjs[i]);
749
750         /*
751          * Set up options info to ensure we dump what we want.
752          */
753         ropt = NewRestoreOptions();
754         ropt->filename = filename;
755         ropt->dropSchema = outputClean;
756         ropt->dataOnly = dataOnly;
757         ropt->schemaOnly = schemaOnly;
758         ropt->dumpSections = dumpSections;
759         ropt->aclsSkip = aclsSkip;
760         ropt->superuser = outputSuperuser;
761         ropt->createDB = outputCreateDB;
762         ropt->noOwner = outputNoOwner;
763         ropt->noTablespace = outputNoTablespaces;
764         ropt->disable_triggers = disable_triggers;
765         ropt->use_setsessauth = use_setsessauth;
766
767         if (compressLevel == -1)
768                 ropt->compression = 0;
769         else
770                 ropt->compression = compressLevel;
771
772         ropt->suppressDumpWarnings = true;      /* We've already shown them */
773
774         SetArchiveRestoreOptions(fout, ropt);
775
776         /*
777          * The archive's TOC entries are now marked as to which ones will
778          * actually be output, so we can set up their dependency lists properly.
779          * This isn't necessary for plain-text output, though.
780          */
781         if (!plainText)
782                 BuildArchiveDependencies(fout);
783
784         /*
785          * And finally we can do the actual output.
786          *
787          * Note: for non-plain-text output formats, the output file is written
788          * inside CloseArchive().  This is, um, bizarre; but not worth changing
789          * right now.
790          */
791         if (plainText)
792                 RestoreArchive(fout);
793
794         CloseArchive(fout);
795
796         exit_nicely(0);
797 }
798
799
800 static void
801 help(const char *progname)
802 {
803         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
804         printf(_("Usage:\n"));
805         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
806
807         printf(_("\nGeneral options:\n"));
808         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
809         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
810                          "                               plain text (default))\n"));
811         printf(_("  -v, --verbose                verbose mode\n"));
812         printf(_("  -V, --version                output version information, then exit\n"));
813         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
814         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
815         printf(_("  -?, --help                   show this help, then exit\n"));
816
817         printf(_("\nOptions controlling the output content:\n"));
818         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
819         printf(_("  -b, --blobs                  include large objects in dump\n"));
820         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
821         printf(_("  -C, --create                 include commands to create database in dump\n"));
822         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
823         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
824         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
825         printf(_("  -o, --oids                   include OIDs in dump\n"));
826         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
827                          "                               plain-text format\n"));
828         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
829         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
830         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
831         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
832         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
833         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
834         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
835         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
836         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
837         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
838         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
839         printf(_("  --no-security-labels         do not dump security label assignments\n"));
840         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
841         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
842         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
843         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
844         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
845         printf(_("  --use-set-session-authorization\n"
846                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
847                          "                               ALTER OWNER commands to set ownership\n"));
848
849         printf(_("\nConnection options:\n"));
850         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
851         printf(_("  -p, --port=PORT          database server port number\n"));
852         printf(_("  -U, --username=NAME      connect as specified database user\n"));
853         printf(_("  -w, --no-password        never prompt for password\n"));
854         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
855         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
856
857         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
858                          "variable value is used.\n\n"));
859         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
860 }
861
862 static void
863 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
864 {
865         PGconn     *conn = GetConnection(AH);
866         const char *std_strings;
867
868         /* Set the client encoding if requested */
869         if (dumpencoding)
870         {
871                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
872                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
873                                                   dumpencoding);
874         }
875
876         /*
877          * Get the active encoding and the standard_conforming_strings setting, so
878          * we know how to escape strings.
879          */
880         AH->encoding = PQclientEncoding(conn);
881
882         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
883         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
884
885         /* Set the role if requested */
886         if (use_role && AH->remoteVersion >= 80100)
887         {
888                 PQExpBuffer query = createPQExpBuffer();
889
890                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
891                 ExecuteSqlStatement(AH, query->data);
892                 destroyPQExpBuffer(query);
893         }
894
895         /* Set the datestyle to ISO to ensure the dump's portability */
896         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
897
898         /* Likewise, avoid using sql_standard intervalstyle */
899         if (AH->remoteVersion >= 80400)
900                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
901
902         /*
903          * If supported, set extra_float_digits so that we can dump float data
904          * exactly (given correctly implemented float I/O code, anyway)
905          */
906         if (AH->remoteVersion >= 90000)
907                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
908         else if (AH->remoteVersion >= 70400)
909                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
910
911         /*
912          * If synchronized scanning is supported, disable it, to prevent
913          * unpredictable changes in row ordering across a dump and reload.
914          */
915         if (AH->remoteVersion >= 80300)
916                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
917
918         /*
919          * Disable timeouts if supported.
920          */
921         if (AH->remoteVersion >= 70300)
922                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
923
924         /*
925          * Quote all identifiers, if requested.
926          */
927         if (quote_all_identifiers && AH->remoteVersion >= 90100)
928                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
929 }
930
931 static ArchiveFormat
932 parseArchiveFormat(const char *format, ArchiveMode *mode)
933 {
934         ArchiveFormat archiveFormat;
935
936         *mode = archModeWrite;
937
938         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
939         {
940                 /* This is used by pg_dumpall, and is not documented */
941                 archiveFormat = archNull;
942                 *mode = archModeAppend;
943         }
944         else if (pg_strcasecmp(format, "c") == 0)
945                 archiveFormat = archCustom;
946         else if (pg_strcasecmp(format, "custom") == 0)
947                 archiveFormat = archCustom;
948         else if (pg_strcasecmp(format, "d") == 0)
949                 archiveFormat = archDirectory;
950         else if (pg_strcasecmp(format, "directory") == 0)
951                 archiveFormat = archDirectory;
952         else if (pg_strcasecmp(format, "p") == 0)
953                 archiveFormat = archNull;
954         else if (pg_strcasecmp(format, "plain") == 0)
955                 archiveFormat = archNull;
956         else if (pg_strcasecmp(format, "t") == 0)
957                 archiveFormat = archTar;
958         else if (pg_strcasecmp(format, "tar") == 0)
959                 archiveFormat = archTar;
960         else
961                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
962         return archiveFormat;
963 }
964
965 /*
966  * Find the OIDs of all schemas matching the given list of patterns,
967  * and append them to the given OID list.
968  */
969 static void
970 expand_schema_name_patterns(Archive *fout,
971                                                         SimpleStringList *patterns,
972                                                         SimpleOidList *oids)
973 {
974         PQExpBuffer query;
975         PGresult   *res;
976         SimpleStringListCell *cell;
977         int                     i;
978
979         if (patterns->head == NULL)
980                 return;                                 /* nothing to do */
981
982         if (fout->remoteVersion < 70300)
983                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
984
985         query = createPQExpBuffer();
986
987         /*
988          * We use UNION ALL rather than UNION; this might sometimes result in
989          * duplicate entries in the OID list, but we don't care.
990          */
991
992         for (cell = patterns->head; cell; cell = cell->next)
993         {
994                 if (cell != patterns->head)
995                         appendPQExpBuffer(query, "UNION ALL\n");
996                 appendPQExpBuffer(query,
997                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
998                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
999                                                           false, NULL, "n.nspname", NULL, NULL);
1000         }
1001
1002         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1003
1004         for (i = 0; i < PQntuples(res); i++)
1005         {
1006                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1007         }
1008
1009         PQclear(res);
1010         destroyPQExpBuffer(query);
1011 }
1012
1013 /*
1014  * Find the OIDs of all tables matching the given list of patterns,
1015  * and append them to the given OID list.
1016  */
1017 static void
1018 expand_table_name_patterns(Archive *fout,
1019                                                    SimpleStringList *patterns, SimpleOidList *oids)
1020 {
1021         PQExpBuffer query;
1022         PGresult   *res;
1023         SimpleStringListCell *cell;
1024         int                     i;
1025
1026         if (patterns->head == NULL)
1027                 return;                                 /* nothing to do */
1028
1029         query = createPQExpBuffer();
1030
1031         /*
1032          * We use UNION ALL rather than UNION; this might sometimes result in
1033          * duplicate entries in the OID list, but we don't care.
1034          */
1035
1036         for (cell = patterns->head; cell; cell = cell->next)
1037         {
1038                 if (cell != patterns->head)
1039                         appendPQExpBuffer(query, "UNION ALL\n");
1040                 appendPQExpBuffer(query,
1041                                                   "SELECT c.oid"
1042                                                   "\nFROM pg_catalog.pg_class c"
1043                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1044                                                   "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
1045                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1046                                                   RELKIND_FOREIGN_TABLE);
1047                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1048                                                           false, "n.nspname", "c.relname", NULL,
1049                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1050         }
1051
1052         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1053
1054         for (i = 0; i < PQntuples(res); i++)
1055         {
1056                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1057         }
1058
1059         PQclear(res);
1060         destroyPQExpBuffer(query);
1061 }
1062
1063 /*
1064  * selectDumpableNamespace: policy-setting subroutine
1065  *              Mark a namespace as to be dumped or not
1066  */
1067 static void
1068 selectDumpableNamespace(NamespaceInfo *nsinfo)
1069 {
1070         /*
1071          * If specific tables are being dumped, do not dump any complete
1072          * namespaces. If specific namespaces are being dumped, dump just those
1073          * namespaces. Otherwise, dump all non-system namespaces.
1074          */
1075         if (table_include_oids.head != NULL)
1076                 nsinfo->dobj.dump = false;
1077         else if (schema_include_oids.head != NULL)
1078                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1079                                                                                                    nsinfo->dobj.catId.oid);
1080         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1081                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1082                 nsinfo->dobj.dump = false;
1083         else
1084                 nsinfo->dobj.dump = true;
1085
1086         /*
1087          * In any case, a namespace can be excluded by an exclusion switch
1088          */
1089         if (nsinfo->dobj.dump &&
1090                 simple_oid_list_member(&schema_exclude_oids,
1091                                                            nsinfo->dobj.catId.oid))
1092                 nsinfo->dobj.dump = false;
1093 }
1094
1095 /*
1096  * selectDumpableTable: policy-setting subroutine
1097  *              Mark a table as to be dumped or not
1098  */
1099 static void
1100 selectDumpableTable(TableInfo *tbinfo)
1101 {
1102         /*
1103          * If specific tables are being dumped, dump just those tables; else, dump
1104          * according to the parent namespace's dump flag.
1105          */
1106         if (table_include_oids.head != NULL)
1107                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1108                                                                                                    tbinfo->dobj.catId.oid);
1109         else
1110                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1111
1112         /*
1113          * In any case, a table can be excluded by an exclusion switch
1114          */
1115         if (tbinfo->dobj.dump &&
1116                 simple_oid_list_member(&table_exclude_oids,
1117                                                            tbinfo->dobj.catId.oid))
1118                 tbinfo->dobj.dump = false;
1119 }
1120
1121 /*
1122  * selectDumpableType: policy-setting subroutine
1123  *              Mark a type as to be dumped or not
1124  *
1125  * If it's a table's rowtype or an autogenerated array type, we also apply a
1126  * special type code to facilitate sorting into the desired order.      (We don't
1127  * want to consider those to be ordinary types because that would bring tables
1128  * up into the datatype part of the dump order.)  We still set the object's
1129  * dump flag; that's not going to cause the dummy type to be dumped, but we
1130  * need it so that casts involving such types will be dumped correctly -- see
1131  * dumpCast.  This means the flag should be set the same as for the underlying
1132  * object (the table or base type).
1133  */
1134 static void
1135 selectDumpableType(TypeInfo *tyinfo)
1136 {
1137         /* skip complex types, except for standalone composite types */
1138         if (OidIsValid(tyinfo->typrelid) &&
1139                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1140         {
1141                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1142
1143                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1144                 if (tytable != NULL)
1145                         tyinfo->dobj.dump = tytable->dobj.dump;
1146                 else
1147                         tyinfo->dobj.dump = false;
1148                 return;
1149         }
1150
1151         /* skip auto-generated array types */
1152         if (tyinfo->isArray)
1153         {
1154                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1155
1156                 /*
1157                  * Fall through to set the dump flag; we assume that the subsequent
1158                  * rules will do the same thing as they would for the array's base
1159                  * type.  (We cannot reliably look up the base type here, since
1160                  * getTypes may not have processed it yet.)
1161                  */
1162         }
1163
1164         /* dump only types in dumpable namespaces */
1165         if (!tyinfo->dobj.namespace->dobj.dump)
1166                 tyinfo->dobj.dump = false;
1167
1168         /* skip undefined placeholder types */
1169         else if (!tyinfo->isDefined)
1170                 tyinfo->dobj.dump = false;
1171
1172         else
1173                 tyinfo->dobj.dump = true;
1174 }
1175
1176 /*
1177  * selectDumpableDefaultACL: policy-setting subroutine
1178  *              Mark a default ACL as to be dumped or not
1179  *
1180  * For per-schema default ACLs, dump if the schema is to be dumped.
1181  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1182  * and aclsSkip are checked separately.
1183  */
1184 static void
1185 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1186 {
1187         if (dinfo->dobj.namespace)
1188                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1189         else
1190                 dinfo->dobj.dump = include_everything;
1191 }
1192
1193 /*
1194  * selectDumpableExtension: policy-setting subroutine
1195  *              Mark an extension as to be dumped or not
1196  *
1197  * Normally, we dump all extensions, or none of them if include_everything
1198  * is false (i.e., a --schema or --table switch was given).  However, in
1199  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1200  * assume those will already be installed in the target database.  We identify
1201  * such extensions by their having OIDs in the range reserved for initdb.
1202  */
1203 static void
1204 selectDumpableExtension(ExtensionInfo *extinfo)
1205 {
1206         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1207                 extinfo->dobj.dump = false;
1208         else
1209                 extinfo->dobj.dump = include_everything;
1210 }
1211
1212 /*
1213  * selectDumpableObject: policy-setting subroutine
1214  *              Mark a generic dumpable object as to be dumped or not
1215  *
1216  * Use this only for object types without a special-case routine above.
1217  */
1218 static void
1219 selectDumpableObject(DumpableObject *dobj)
1220 {
1221         /*
1222          * Default policy is to dump if parent namespace is dumpable, or always
1223          * for non-namespace-associated items.
1224          */
1225         if (dobj->namespace)
1226                 dobj->dump = dobj->namespace->dobj.dump;
1227         else
1228                 dobj->dump = true;
1229 }
1230
1231 /*
1232  *      Dump a table's contents for loading using the COPY command
1233  *      - this routine is called by the Archiver when it wants the table
1234  *        to be dumped.
1235  */
1236
1237 static int
1238 dumpTableData_copy(Archive *fout, void *dcontext)
1239 {
1240         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1241         TableInfo  *tbinfo = tdinfo->tdtable;
1242         const char *classname = tbinfo->dobj.name;
1243         const bool      hasoids = tbinfo->hasoids;
1244         const bool      oids = tdinfo->oids;
1245         PQExpBuffer q = createPQExpBuffer();
1246         PGconn     *conn = GetConnection(fout);
1247         PGresult   *res;
1248         int                     ret;
1249         char       *copybuf;
1250         const char *column_list;
1251
1252         if (g_verbose)
1253                 write_msg(NULL, "dumping contents of table %s\n", classname);
1254
1255         /*
1256          * Make sure we are in proper schema.  We will qualify the table name
1257          * below anyway (in case its name conflicts with a pg_catalog table); but
1258          * this ensures reproducible results in case the table contains regproc,
1259          * regclass, etc columns.
1260          */
1261         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1262
1263         /*
1264          * If possible, specify the column list explicitly so that we have no
1265          * possibility of retrieving data in the wrong column order.  (The default
1266          * column ordering of COPY will not be what we want in certain corner
1267          * cases involving ADD COLUMN and inheritance.)
1268          */
1269         if (fout->remoteVersion >= 70300)
1270                 column_list = fmtCopyColumnList(tbinfo);
1271         else
1272                 column_list = "";               /* can't select columns in COPY */
1273
1274         if (oids && hasoids)
1275         {
1276                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1277                                                   fmtQualifiedId(fout,
1278                                                                                  tbinfo->dobj.namespace->dobj.name,
1279                                                                                  classname),
1280                                                   column_list);
1281         }
1282         else if (tdinfo->filtercond)
1283         {
1284                 /* Note: this syntax is only supported in 8.2 and up */
1285                 appendPQExpBufferStr(q, "COPY (SELECT ");
1286                 /* klugery to get rid of parens in column list */
1287                 if (strlen(column_list) > 2)
1288                 {
1289                         appendPQExpBufferStr(q, column_list + 1);
1290                         q->data[q->len - 1] = ' ';
1291                 }
1292                 else
1293                         appendPQExpBufferStr(q, "* ");
1294                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1295                                                   fmtQualifiedId(fout,
1296                                                                                  tbinfo->dobj.namespace->dobj.name,
1297                                                                                  classname),
1298                                                   tdinfo->filtercond);
1299         }
1300         else
1301         {
1302                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1303                                                   fmtQualifiedId(fout,
1304                                                                                  tbinfo->dobj.namespace->dobj.name,
1305                                                                                  classname),
1306                                                   column_list);
1307         }
1308         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1309         PQclear(res);
1310
1311         for (;;)
1312         {
1313                 ret = PQgetCopyData(conn, &copybuf, 0);
1314
1315                 if (ret < 0)
1316                         break;                          /* done or error */
1317
1318                 if (copybuf)
1319                 {
1320                         WriteData(fout, copybuf, ret);
1321                         PQfreemem(copybuf);
1322                 }
1323
1324                 /* ----------
1325                  * THROTTLE:
1326                  *
1327                  * There was considerable discussion in late July, 2000 regarding
1328                  * slowing down pg_dump when backing up large tables. Users with both
1329                  * slow & fast (multi-processor) machines experienced performance
1330                  * degradation when doing a backup.
1331                  *
1332                  * Initial attempts based on sleeping for a number of ms for each ms
1333                  * of work were deemed too complex, then a simple 'sleep in each loop'
1334                  * implementation was suggested. The latter failed because the loop
1335                  * was too tight. Finally, the following was implemented:
1336                  *
1337                  * If throttle is non-zero, then
1338                  *              See how long since the last sleep.
1339                  *              Work out how long to sleep (based on ratio).
1340                  *              If sleep is more than 100ms, then
1341                  *                      sleep
1342                  *                      reset timer
1343                  *              EndIf
1344                  * EndIf
1345                  *
1346                  * where the throttle value was the number of ms to sleep per ms of
1347                  * work. The calculation was done in each loop.
1348                  *
1349                  * Most of the hard work is done in the backend, and this solution
1350                  * still did not work particularly well: on slow machines, the ratio
1351                  * was 50:1, and on medium paced machines, 1:1, and on fast
1352                  * multi-processor machines, it had little or no effect, for reasons
1353                  * that were unclear.
1354                  *
1355                  * Further discussion ensued, and the proposal was dropped.
1356                  *
1357                  * For those people who want this feature, it can be implemented using
1358                  * gettimeofday in each loop, calculating the time since last sleep,
1359                  * multiplying that by the sleep ratio, then if the result is more
1360                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1361                  * function to sleep for a subsecond period ie.
1362                  *
1363                  * select(0, NULL, NULL, NULL, &tvi);
1364                  *
1365                  * This will return after the interval specified in the structure tvi.
1366                  * Finally, call gettimeofday again to save the 'last sleep time'.
1367                  * ----------
1368                  */
1369         }
1370         archprintf(fout, "\\.\n\n\n");
1371
1372         if (ret == -2)
1373         {
1374                 /* copy data transfer failed */
1375                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1376                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1377                 write_msg(NULL, "The command was: %s\n", q->data);
1378                 exit_nicely(1);
1379         }
1380
1381         /* Check command status and return to normal libpq state */
1382         res = PQgetResult(conn);
1383         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1384         {
1385                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1386                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1387                 write_msg(NULL, "The command was: %s\n", q->data);
1388                 exit_nicely(1);
1389         }
1390         PQclear(res);
1391
1392         destroyPQExpBuffer(q);
1393         return 1;
1394 }
1395
1396 /*
1397  * Dump table data using INSERT commands.
1398  *
1399  * Caution: when we restore from an archive file direct to database, the
1400  * INSERT commands emitted by this function have to be parsed by
1401  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1402  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1403  */
1404 static int
1405 dumpTableData_insert(Archive *fout, void *dcontext)
1406 {
1407         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1408         TableInfo  *tbinfo = tdinfo->tdtable;
1409         const char *classname = tbinfo->dobj.name;
1410         PQExpBuffer q = createPQExpBuffer();
1411         PGresult   *res;
1412         int                     tuple;
1413         int                     nfields;
1414         int                     field;
1415
1416         /*
1417          * Make sure we are in proper schema.  We will qualify the table name
1418          * below anyway (in case its name conflicts with a pg_catalog table); but
1419          * this ensures reproducible results in case the table contains regproc,
1420          * regclass, etc columns.
1421          */
1422         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1423
1424         if (fout->remoteVersion >= 70100)
1425         {
1426                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1427                                                   "SELECT * FROM ONLY %s",
1428                                                   fmtQualifiedId(fout,
1429                                                                                  tbinfo->dobj.namespace->dobj.name,
1430                                                                                  classname));
1431         }
1432         else
1433         {
1434                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1435                                                   "SELECT * FROM %s",
1436                                                   fmtQualifiedId(fout,
1437                                                                                  tbinfo->dobj.namespace->dobj.name,
1438                                                                                  classname));
1439         }
1440         if (tdinfo->filtercond)
1441                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1442
1443         ExecuteSqlStatement(fout, q->data);
1444
1445         while (1)
1446         {
1447                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1448                                                           PGRES_TUPLES_OK);
1449                 nfields = PQnfields(res);
1450                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1451                 {
1452                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1453                         if (nfields == 0)
1454                         {
1455                                 /* corner case for zero-column table */
1456                                 archprintf(fout, "DEFAULT VALUES;\n");
1457                                 continue;
1458                         }
1459                         if (column_inserts)
1460                         {
1461                                 resetPQExpBuffer(q);
1462                                 appendPQExpBuffer(q, "(");
1463                                 for (field = 0; field < nfields; field++)
1464                                 {
1465                                         if (field > 0)
1466                                                 appendPQExpBuffer(q, ", ");
1467                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1468                                 }
1469                                 appendPQExpBuffer(q, ") ");
1470                                 archputs(q->data, fout);
1471                         }
1472                         archprintf(fout, "VALUES (");
1473                         for (field = 0; field < nfields; field++)
1474                         {
1475                                 if (field > 0)
1476                                         archprintf(fout, ", ");
1477                                 if (PQgetisnull(res, tuple, field))
1478                                 {
1479                                         archprintf(fout, "NULL");
1480                                         continue;
1481                                 }
1482
1483                                 /* XXX This code is partially duplicated in ruleutils.c */
1484                                 switch (PQftype(res, field))
1485                                 {
1486                                         case INT2OID:
1487                                         case INT4OID:
1488                                         case INT8OID:
1489                                         case OIDOID:
1490                                         case FLOAT4OID:
1491                                         case FLOAT8OID:
1492                                         case NUMERICOID:
1493                                                 {
1494                                                         /*
1495                                                          * These types are printed without quotes unless
1496                                                          * they contain values that aren't accepted by the
1497                                                          * scanner unquoted (e.g., 'NaN').      Note that
1498                                                          * strtod() and friends might accept NaN, so we
1499                                                          * can't use that to test.
1500                                                          *
1501                                                          * In reality we only need to defend against
1502                                                          * infinity and NaN, so we need not get too crazy
1503                                                          * about pattern matching here.
1504                                                          */
1505                                                         const char *s = PQgetvalue(res, tuple, field);
1506
1507                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1508                                                                 archprintf(fout, "%s", s);
1509                                                         else
1510                                                                 archprintf(fout, "'%s'", s);
1511                                                 }
1512                                                 break;
1513
1514                                         case BITOID:
1515                                         case VARBITOID:
1516                                                 archprintf(fout, "B'%s'",
1517                                                                    PQgetvalue(res, tuple, field));
1518                                                 break;
1519
1520                                         case BOOLOID:
1521                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1522                                                         archprintf(fout, "true");
1523                                                 else
1524                                                         archprintf(fout, "false");
1525                                                 break;
1526
1527                                         default:
1528                                                 /* All other types are printed as string literals. */
1529                                                 resetPQExpBuffer(q);
1530                                                 appendStringLiteralAH(q,
1531                                                                                           PQgetvalue(res, tuple, field),
1532                                                                                           fout);
1533                                                 archputs(q->data, fout);
1534                                                 break;
1535                                 }
1536                         }
1537                         archprintf(fout, ");\n");
1538                 }
1539
1540                 if (PQntuples(res) <= 0)
1541                 {
1542                         PQclear(res);
1543                         break;
1544                 }
1545                 PQclear(res);
1546         }
1547
1548         archprintf(fout, "\n\n");
1549
1550         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1551
1552         destroyPQExpBuffer(q);
1553         return 1;
1554 }
1555
1556
1557 /*
1558  * dumpTableData -
1559  *        dump the contents of a single table
1560  *
1561  * Actually, this just makes an ArchiveEntry for the table contents.
1562  */
1563 static void
1564 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1565 {
1566         TableInfo  *tbinfo = tdinfo->tdtable;
1567         PQExpBuffer copyBuf = createPQExpBuffer();
1568         DataDumperPtr dumpFn;
1569         char       *copyStmt;
1570
1571         if (!dump_inserts)
1572         {
1573                 /* Dump/restore using COPY */
1574                 dumpFn = dumpTableData_copy;
1575                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1576                 appendPQExpBuffer(copyBuf, "COPY %s ",
1577                                                   fmtId(tbinfo->dobj.name));
1578                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1579                                                   fmtCopyColumnList(tbinfo),
1580                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1581                 copyStmt = copyBuf->data;
1582         }
1583         else
1584         {
1585                 /* Restore using INSERT */
1586                 dumpFn = dumpTableData_insert;
1587                 copyStmt = NULL;
1588         }
1589
1590         /*
1591          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1592          * dependency on its table as "special" and pass it to ArchiveEntry now.
1593          * See comments for BuildArchiveDependencies.
1594          */
1595         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1596                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1597                                  NULL, tbinfo->rolname,
1598                                  false, "TABLE DATA", SECTION_DATA,
1599                                  "", "", copyStmt,
1600                                  &(tbinfo->dobj.dumpId), 1,
1601                                  dumpFn, tdinfo);
1602
1603         destroyPQExpBuffer(copyBuf);
1604 }
1605
1606 /*
1607  * getTableData -
1608  *        set up dumpable objects representing the contents of tables
1609  */
1610 static void
1611 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1612 {
1613         int                     i;
1614
1615         for (i = 0; i < numTables; i++)
1616         {
1617                 if (tblinfo[i].dobj.dump)
1618                         makeTableDataInfo(&(tblinfo[i]), oids);
1619         }
1620 }
1621
1622 /*
1623  * Make a dumpable object for the data of this specific table
1624  *
1625  * Note: we make a TableDataInfo if and only if we are going to dump the
1626  * table data; the "dump" flag in such objects isn't used.
1627  */
1628 static void
1629 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1630 {
1631         TableDataInfo *tdinfo;
1632
1633         /*
1634          * Nothing to do if we already decided to dump the table.  This will
1635          * happen for "config" tables.
1636          */
1637         if (tbinfo->dataObj != NULL)
1638                 return;
1639
1640         /* Skip VIEWs (no data to dump) */
1641         if (tbinfo->relkind == RELKIND_VIEW)
1642                 return;
1643         /* Skip SEQUENCEs (handled elsewhere) */
1644         if (tbinfo->relkind == RELKIND_SEQUENCE)
1645                 return;
1646         /* Skip FOREIGN TABLEs (no data to dump) */
1647         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1648                 return;
1649
1650         /* Don't dump data in unlogged tables, if so requested */
1651         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1652                 no_unlogged_table_data)
1653                 return;
1654
1655         /* Check that the data is not explicitly excluded */
1656         if (simple_oid_list_member(&tabledata_exclude_oids,
1657                                                            tbinfo->dobj.catId.oid))
1658                 return;
1659
1660         /* OK, let's dump it */
1661         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1662
1663         tdinfo->dobj.objType = DO_TABLE_DATA;
1664
1665         /*
1666          * Note: use tableoid 0 so that this object won't be mistaken for
1667          * something that pg_depend entries apply to.
1668          */
1669         tdinfo->dobj.catId.tableoid = 0;
1670         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1671         AssignDumpId(&tdinfo->dobj);
1672         tdinfo->dobj.name = tbinfo->dobj.name;
1673         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1674         tdinfo->tdtable = tbinfo;
1675         tdinfo->oids = oids;
1676         tdinfo->filtercond = NULL;      /* might get set later */
1677         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1678
1679         tbinfo->dataObj = tdinfo;
1680 }
1681
1682 /*
1683  * getTableDataFKConstraints -
1684  *        add dump-order dependencies reflecting foreign key constraints
1685  *
1686  * This code is executed only in a data-only dump --- in schema+data dumps
1687  * we handle foreign key issues by not creating the FK constraints until
1688  * after the data is loaded.  In a data-only dump, however, we want to
1689  * order the table data objects in such a way that a table's referenced
1690  * tables are restored first.  (In the presence of circular references or
1691  * self-references this may be impossible; we'll detect and complain about
1692  * that during the dependency sorting step.)
1693  */
1694 static void
1695 getTableDataFKConstraints(void)
1696 {
1697         DumpableObject **dobjs;
1698         int                     numObjs;
1699         int                     i;
1700
1701         /* Search through all the dumpable objects for FK constraints */
1702         getDumpableObjects(&dobjs, &numObjs);
1703         for (i = 0; i < numObjs; i++)
1704         {
1705                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1706                 {
1707                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1708                         TableInfo  *ftable;
1709
1710                         /* Not interesting unless both tables are to be dumped */
1711                         if (cinfo->contable == NULL ||
1712                                 cinfo->contable->dataObj == NULL)
1713                                 continue;
1714                         ftable = findTableByOid(cinfo->confrelid);
1715                         if (ftable == NULL ||
1716                                 ftable->dataObj == NULL)
1717                                 continue;
1718
1719                         /*
1720                          * Okay, make referencing table's TABLE_DATA object depend on the
1721                          * referenced table's TABLE_DATA object.
1722                          */
1723                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1724                                                                 ftable->dataObj->dobj.dumpId);
1725                 }
1726         }
1727         free(dobjs);
1728 }
1729
1730
1731 /*
1732  * guessConstraintInheritance:
1733  *      In pre-8.4 databases, we can't tell for certain which constraints
1734  *      are inherited.  We assume a CHECK constraint is inherited if its name
1735  *      matches the name of any constraint in the parent.  Originally this code
1736  *      tried to compare the expression texts, but that can fail for various
1737  *      reasons --- for example, if the parent and child tables are in different
1738  *      schemas, reverse-listing of function calls may produce different text
1739  *      (schema-qualified or not) depending on search path.
1740  *
1741  *      In 8.4 and up we can rely on the conislocal field to decide which
1742  *      constraints must be dumped; much safer.
1743  *
1744  *      This function assumes all conislocal flags were initialized to TRUE.
1745  *      It clears the flag on anything that seems to be inherited.
1746  */
1747 static void
1748 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1749 {
1750         int                     i,
1751                                 j,
1752                                 k;
1753
1754         for (i = 0; i < numTables; i++)
1755         {
1756                 TableInfo  *tbinfo = &(tblinfo[i]);
1757                 int                     numParents;
1758                 TableInfo **parents;
1759                 TableInfo  *parent;
1760
1761                 /* Sequences and views never have parents */
1762                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1763                         tbinfo->relkind == RELKIND_VIEW)
1764                         continue;
1765
1766                 /* Don't bother computing anything for non-target tables, either */
1767                 if (!tbinfo->dobj.dump)
1768                         continue;
1769
1770                 numParents = tbinfo->numParents;
1771                 parents = tbinfo->parents;
1772
1773                 if (numParents == 0)
1774                         continue;                       /* nothing to see here, move along */
1775
1776                 /* scan for inherited CHECK constraints */
1777                 for (j = 0; j < tbinfo->ncheck; j++)
1778                 {
1779                         ConstraintInfo *constr;
1780
1781                         constr = &(tbinfo->checkexprs[j]);
1782
1783                         for (k = 0; k < numParents; k++)
1784                         {
1785                                 int                     l;
1786
1787                                 parent = parents[k];
1788                                 for (l = 0; l < parent->ncheck; l++)
1789                                 {
1790                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1791
1792                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1793                                         {
1794                                                 constr->conislocal = false;
1795                                                 break;
1796                                         }
1797                                 }
1798                                 if (!constr->conislocal)
1799                                         break;
1800                         }
1801                 }
1802         }
1803 }
1804
1805
1806 /*
1807  * dumpDatabase:
1808  *      dump the database definition
1809  */
1810 static void
1811 dumpDatabase(Archive *fout)
1812 {
1813         PQExpBuffer dbQry = createPQExpBuffer();
1814         PQExpBuffer delQry = createPQExpBuffer();
1815         PQExpBuffer creaQry = createPQExpBuffer();
1816         PGconn     *conn = GetConnection(fout);
1817         PGresult   *res;
1818         int                     i_tableoid,
1819                                 i_oid,
1820                                 i_dba,
1821                                 i_encoding,
1822                                 i_collate,
1823                                 i_ctype,
1824                                 i_frozenxid,
1825                                 i_tablespace;
1826         CatalogId       dbCatId;
1827         DumpId          dbDumpId;
1828         const char *datname,
1829                            *dba,
1830                            *encoding,
1831                            *collate,
1832                            *ctype,
1833                            *tablespace;
1834         uint32          frozenxid;
1835
1836         datname = PQdb(conn);
1837
1838         if (g_verbose)
1839                 write_msg(NULL, "saving database definition\n");
1840
1841         /* Make sure we are in proper schema */
1842         selectSourceSchema(fout, "pg_catalog");
1843
1844         /* Get the database owner and parameters from pg_database */
1845         if (fout->remoteVersion >= 80400)
1846         {
1847                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1848                                                   "(%s datdba) AS dba, "
1849                                                   "pg_encoding_to_char(encoding) AS encoding, "
1850                                                   "datcollate, datctype, datfrozenxid, "
1851                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1852                                           "shobj_description(oid, 'pg_database') AS description "
1853
1854                                                   "FROM pg_database "
1855                                                   "WHERE datname = ",
1856                                                   username_subquery);
1857                 appendStringLiteralAH(dbQry, datname, fout);
1858         }
1859         else if (fout->remoteVersion >= 80200)
1860         {
1861                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1862                                                   "(%s datdba) AS dba, "
1863                                                   "pg_encoding_to_char(encoding) AS encoding, "
1864                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1865                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1866                                           "shobj_description(oid, 'pg_database') AS description "
1867
1868                                                   "FROM pg_database "
1869                                                   "WHERE datname = ",
1870                                                   username_subquery);
1871                 appendStringLiteralAH(dbQry, datname, fout);
1872         }
1873         else if (fout->remoteVersion >= 80000)
1874         {
1875                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1876                                                   "(%s datdba) AS dba, "
1877                                                   "pg_encoding_to_char(encoding) AS encoding, "
1878                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1879                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1880                                                   "FROM pg_database "
1881                                                   "WHERE datname = ",
1882                                                   username_subquery);
1883                 appendStringLiteralAH(dbQry, datname, fout);
1884         }
1885         else if (fout->remoteVersion >= 70100)
1886         {
1887                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1888                                                   "(%s datdba) AS dba, "
1889                                                   "pg_encoding_to_char(encoding) AS encoding, "
1890                                                   "NULL AS datcollate, NULL AS datctype, "
1891                                                   "0 AS datfrozenxid, "
1892                                                   "NULL AS tablespace "
1893                                                   "FROM pg_database "
1894                                                   "WHERE datname = ",
1895                                                   username_subquery);
1896                 appendStringLiteralAH(dbQry, datname, fout);
1897         }
1898         else
1899         {
1900                 appendPQExpBuffer(dbQry, "SELECT "
1901                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1902                                                   "oid, "
1903                                                   "(%s datdba) AS dba, "
1904                                                   "pg_encoding_to_char(encoding) AS encoding, "
1905                                                   "NULL AS datcollate, NULL AS datctype, "
1906                                                   "0 AS datfrozenxid, "
1907                                                   "NULL AS tablespace "
1908                                                   "FROM pg_database "
1909                                                   "WHERE datname = ",
1910                                                   username_subquery);
1911                 appendStringLiteralAH(dbQry, datname, fout);
1912         }
1913
1914         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
1915
1916         i_tableoid = PQfnumber(res, "tableoid");
1917         i_oid = PQfnumber(res, "oid");
1918         i_dba = PQfnumber(res, "dba");
1919         i_encoding = PQfnumber(res, "encoding");
1920         i_collate = PQfnumber(res, "datcollate");
1921         i_ctype = PQfnumber(res, "datctype");
1922         i_frozenxid = PQfnumber(res, "datfrozenxid");
1923         i_tablespace = PQfnumber(res, "tablespace");
1924
1925         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1926         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1927         dba = PQgetvalue(res, 0, i_dba);
1928         encoding = PQgetvalue(res, 0, i_encoding);
1929         collate = PQgetvalue(res, 0, i_collate);
1930         ctype = PQgetvalue(res, 0, i_ctype);
1931         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1932         tablespace = PQgetvalue(res, 0, i_tablespace);
1933
1934         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1935                                           fmtId(datname));
1936         if (strlen(encoding) > 0)
1937         {
1938                 appendPQExpBuffer(creaQry, " ENCODING = ");
1939                 appendStringLiteralAH(creaQry, encoding, fout);
1940         }
1941         if (strlen(collate) > 0)
1942         {
1943                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1944                 appendStringLiteralAH(creaQry, collate, fout);
1945         }
1946         if (strlen(ctype) > 0)
1947         {
1948                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1949                 appendStringLiteralAH(creaQry, ctype, fout);
1950         }
1951         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1952                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1953                                                   fmtId(tablespace));
1954         appendPQExpBuffer(creaQry, ";\n");
1955
1956         if (binary_upgrade)
1957         {
1958                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1959                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
1960                                                   "SET datfrozenxid = '%u'\n"
1961                                                   "WHERE        datname = ",
1962                                                   frozenxid);
1963                 appendStringLiteralAH(creaQry, datname, fout);
1964                 appendPQExpBuffer(creaQry, ";\n");
1965
1966         }
1967
1968         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1969                                           fmtId(datname));
1970
1971         dbDumpId = createDumpId();
1972
1973         ArchiveEntry(fout,
1974                                  dbCatId,               /* catalog ID */
1975                                  dbDumpId,              /* dump ID */
1976                                  datname,               /* Name */
1977                                  NULL,                  /* Namespace */
1978                                  NULL,                  /* Tablespace */
1979                                  dba,                   /* Owner */
1980                                  false,                 /* with oids */
1981                                  "DATABASE",    /* Desc */
1982                                  SECTION_PRE_DATA,              /* Section */
1983                                  creaQry->data, /* Create */
1984                                  delQry->data,  /* Del */
1985                                  NULL,                  /* Copy */
1986                                  NULL,                  /* Deps */
1987                                  0,                             /* # Deps */
1988                                  NULL,                  /* Dumper */
1989                                  NULL);                 /* Dumper Arg */
1990
1991         /*
1992          * pg_largeobject and pg_largeobject_metadata come from the old system
1993          * intact, so set their relfrozenxids.
1994          */
1995         if (binary_upgrade)
1996         {
1997                 PGresult   *lo_res;
1998                 PQExpBuffer loFrozenQry = createPQExpBuffer();
1999                 PQExpBuffer loOutQry = createPQExpBuffer();
2000                 int                     i_relfrozenxid;
2001
2002                 /*
2003                  * pg_largeobject
2004                  */
2005                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2006                                                   "FROM pg_catalog.pg_class\n"
2007                                                   "WHERE oid = %u;\n",
2008                                                   LargeObjectRelationId);
2009
2010                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2011
2012                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2013
2014                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2015                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2016                                                   "SET relfrozenxid = '%u'\n"
2017                                                   "WHERE oid = %u;\n",
2018                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2019                                                   LargeObjectRelationId);
2020                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2021                                          "pg_largeobject", NULL, NULL, "",
2022                                          false, "pg_largeobject", SECTION_PRE_DATA,
2023                                          loOutQry->data, "", NULL,
2024                                          NULL, 0,
2025                                          NULL, NULL);
2026
2027                 PQclear(lo_res);
2028
2029                 /*
2030                  * pg_largeobject_metadata
2031                  */
2032                 if (fout->remoteVersion >= 90000)
2033                 {
2034                         resetPQExpBuffer(loFrozenQry);
2035                         resetPQExpBuffer(loOutQry);
2036
2037                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2038                                                           "FROM pg_catalog.pg_class\n"
2039                                                           "WHERE oid = %u;\n",
2040                                                           LargeObjectMetadataRelationId);
2041
2042                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2043
2044                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2045
2046                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2047                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2048                                                           "SET relfrozenxid = '%u'\n"
2049                                                           "WHERE oid = %u;\n",
2050                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2051                                                           LargeObjectMetadataRelationId);
2052                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2053                                                  "pg_largeobject_metadata", NULL, NULL, "",
2054                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2055                                                  loOutQry->data, "", NULL,
2056                                                  NULL, 0,
2057                                                  NULL, NULL);
2058
2059                         PQclear(lo_res);
2060                 }
2061
2062                 destroyPQExpBuffer(loFrozenQry);
2063                 destroyPQExpBuffer(loOutQry);
2064         }
2065
2066         /* Dump DB comment if any */
2067         if (fout->remoteVersion >= 80200)
2068         {
2069                 /*
2070                  * 8.2 keeps comments on shared objects in a shared table, so we
2071                  * cannot use the dumpComment used for other database objects.
2072                  */
2073                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2074
2075                 if (comment && strlen(comment))
2076                 {
2077                         resetPQExpBuffer(dbQry);
2078
2079                         /*
2080                          * Generates warning when loaded into a differently-named
2081                          * database.
2082                          */
2083                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2084                         appendStringLiteralAH(dbQry, comment, fout);
2085                         appendPQExpBuffer(dbQry, ";\n");
2086
2087                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2088                                                  dba, false, "COMMENT", SECTION_NONE,
2089                                                  dbQry->data, "", NULL,
2090                                                  &dbDumpId, 1, NULL, NULL);
2091                 }
2092         }
2093         else
2094         {
2095                 resetPQExpBuffer(dbQry);
2096                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2097                 dumpComment(fout, dbQry->data, NULL, "",
2098                                         dbCatId, 0, dbDumpId);
2099         }
2100
2101         PQclear(res);
2102
2103         /* Dump shared security label. */
2104         if (!no_security_labels && fout->remoteVersion >= 90200)
2105         {
2106                 PQExpBuffer seclabelQry = createPQExpBuffer();
2107
2108                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2109                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2110                 resetPQExpBuffer(seclabelQry);
2111                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2112                 if (strlen(seclabelQry->data))
2113                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2114                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2115                                                  seclabelQry->data, "", NULL,
2116                                                  &dbDumpId, 1, NULL, NULL);
2117                 destroyPQExpBuffer(seclabelQry);
2118         }
2119
2120         destroyPQExpBuffer(dbQry);
2121         destroyPQExpBuffer(delQry);
2122         destroyPQExpBuffer(creaQry);
2123 }
2124
2125
2126 /*
2127  * dumpEncoding: put the correct encoding into the archive
2128  */
2129 static void
2130 dumpEncoding(Archive *AH)
2131 {
2132         const char *encname = pg_encoding_to_char(AH->encoding);
2133         PQExpBuffer qry = createPQExpBuffer();
2134
2135         if (g_verbose)
2136                 write_msg(NULL, "saving encoding = %s\n", encname);
2137
2138         appendPQExpBuffer(qry, "SET client_encoding = ");
2139         appendStringLiteralAH(qry, encname, AH);
2140         appendPQExpBuffer(qry, ";\n");
2141
2142         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2143                                  "ENCODING", NULL, NULL, "",
2144                                  false, "ENCODING", SECTION_PRE_DATA,
2145                                  qry->data, "", NULL,
2146                                  NULL, 0,
2147                                  NULL, NULL);
2148
2149         destroyPQExpBuffer(qry);
2150 }
2151
2152
2153 /*
2154  * dumpStdStrings: put the correct escape string behavior into the archive
2155  */
2156 static void
2157 dumpStdStrings(Archive *AH)
2158 {
2159         const char *stdstrings = AH->std_strings ? "on" : "off";
2160         PQExpBuffer qry = createPQExpBuffer();
2161
2162         if (g_verbose)
2163                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2164                                   stdstrings);
2165
2166         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2167                                           stdstrings);
2168
2169         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2170                                  "STDSTRINGS", NULL, NULL, "",
2171                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2172                                  qry->data, "", NULL,
2173                                  NULL, 0,
2174                                  NULL, NULL);
2175
2176         destroyPQExpBuffer(qry);
2177 }
2178
2179
2180 /*
2181  * getBlobs:
2182  *      Collect schema-level data about large objects
2183  */
2184 static void
2185 getBlobs(Archive *fout)
2186 {
2187         PQExpBuffer blobQry = createPQExpBuffer();
2188         BlobInfo   *binfo;
2189         DumpableObject *bdata;
2190         PGresult   *res;
2191         int                     ntups;
2192         int                     i;
2193
2194         /* Verbose message */
2195         if (g_verbose)
2196                 write_msg(NULL, "reading large objects\n");
2197
2198         /* Make sure we are in proper schema */
2199         selectSourceSchema(fout, "pg_catalog");
2200
2201         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2202         if (fout->remoteVersion >= 90000)
2203                 appendPQExpBuffer(blobQry,
2204                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2205                                                   " FROM pg_largeobject_metadata",
2206                                                   username_subquery);
2207         else if (fout->remoteVersion >= 70100)
2208                 appendPQExpBuffer(blobQry,
2209                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2210                                                   " FROM pg_largeobject");
2211         else
2212                 appendPQExpBuffer(blobQry,
2213                                                   "SELECT oid, NULL::oid, NULL::oid"
2214                                                   " FROM pg_class WHERE relkind = 'l'");
2215
2216         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2217
2218         ntups = PQntuples(res);
2219         if (ntups > 0)
2220         {
2221                 /*
2222                  * Each large object has its own BLOB archive entry.
2223                  */
2224                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2225
2226                 for (i = 0; i < ntups; i++)
2227                 {
2228                         binfo[i].dobj.objType = DO_BLOB;
2229                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2230                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2231                         AssignDumpId(&binfo[i].dobj);
2232
2233                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2234                         if (!PQgetisnull(res, i, 1))
2235                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2236                         else
2237                                 binfo[i].rolname = "";
2238                         if (!PQgetisnull(res, i, 2))
2239                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2240                         else
2241                                 binfo[i].blobacl = NULL;
2242                 }
2243
2244                 /*
2245                  * If we have any large objects, a "BLOBS" archive entry is needed.
2246                  * This is just a placeholder for sorting; it carries no data now.
2247                  */
2248                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2249                 bdata->objType = DO_BLOB_DATA;
2250                 bdata->catId = nilCatalogId;
2251                 AssignDumpId(bdata);
2252                 bdata->name = pg_strdup("BLOBS");
2253         }
2254
2255         PQclear(res);
2256         destroyPQExpBuffer(blobQry);
2257 }
2258
2259 /*
2260  * dumpBlob
2261  *
2262  * dump the definition (metadata) of the given large object
2263  */
2264 static void
2265 dumpBlob(Archive *fout, BlobInfo *binfo)
2266 {
2267         PQExpBuffer cquery = createPQExpBuffer();
2268         PQExpBuffer dquery = createPQExpBuffer();
2269
2270         appendPQExpBuffer(cquery,
2271                                           "SELECT pg_catalog.lo_create('%s');\n",
2272                                           binfo->dobj.name);
2273
2274         appendPQExpBuffer(dquery,
2275                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2276                                           binfo->dobj.name);
2277
2278         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2279                                  binfo->dobj.name,
2280                                  NULL, NULL,
2281                                  binfo->rolname, false,
2282                                  "BLOB", SECTION_PRE_DATA,
2283                                  cquery->data, dquery->data, NULL,
2284                                  NULL, 0,
2285                                  NULL, NULL);
2286
2287         /* set up tag for comment and/or ACL */
2288         resetPQExpBuffer(cquery);
2289         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2290
2291         /* Dump comment if any */
2292         dumpComment(fout, cquery->data,
2293                                 NULL, binfo->rolname,
2294                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2295
2296         /* Dump security label if any */
2297         dumpSecLabel(fout, cquery->data,
2298                                  NULL, binfo->rolname,
2299                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2300
2301         /* Dump ACL if any */
2302         if (binfo->blobacl)
2303                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2304                                 binfo->dobj.name, NULL, cquery->data,
2305                                 NULL, binfo->rolname, binfo->blobacl);
2306
2307         destroyPQExpBuffer(cquery);
2308         destroyPQExpBuffer(dquery);
2309 }
2310
2311 /*
2312  * dumpBlobs:
2313  *      dump the data contents of all large objects
2314  */
2315 static int
2316 dumpBlobs(Archive *fout, void *arg)
2317 {
2318         const char *blobQry;
2319         const char *blobFetchQry;
2320         PGconn     *conn = GetConnection(fout);
2321         PGresult   *res;
2322         char            buf[LOBBUFSIZE];
2323         int                     ntups;
2324         int                     i;
2325         int                     cnt;
2326
2327         if (g_verbose)
2328                 write_msg(NULL, "saving large objects\n");
2329
2330         /* Make sure we are in proper schema */
2331         selectSourceSchema(fout, "pg_catalog");
2332
2333         /*
2334          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2335          * the already-in-memory dumpable objects instead...
2336          */
2337         if (fout->remoteVersion >= 90000)
2338                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2339         else if (fout->remoteVersion >= 70100)
2340                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2341         else
2342                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2343
2344         ExecuteSqlStatement(fout, blobQry);
2345
2346         /* Command to fetch from cursor */
2347         blobFetchQry = "FETCH 1000 IN bloboid";
2348
2349         do
2350         {
2351                 /* Do a fetch */
2352                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2353
2354                 /* Process the tuples, if any */
2355                 ntups = PQntuples(res);
2356                 for (i = 0; i < ntups; i++)
2357                 {
2358                         Oid                     blobOid;
2359                         int                     loFd;
2360
2361                         blobOid = atooid(PQgetvalue(res, i, 0));
2362                         /* Open the BLOB */
2363                         loFd = lo_open(conn, blobOid, INV_READ);
2364                         if (loFd == -1)
2365                                 exit_horribly(NULL, "could not open large object %u: %s",
2366                                                           blobOid, PQerrorMessage(conn));
2367
2368                         StartBlob(fout, blobOid);
2369
2370                         /* Now read it in chunks, sending data to archive */
2371                         do
2372                         {
2373                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2374                                 if (cnt < 0)
2375                                         exit_horribly(NULL, "error reading large object %u: %s",
2376                                                                   blobOid, PQerrorMessage(conn));
2377
2378                                 WriteData(fout, buf, cnt);
2379                         } while (cnt > 0);
2380
2381                         lo_close(conn, loFd);
2382
2383                         EndBlob(fout, blobOid);
2384                 }
2385
2386                 PQclear(res);
2387         } while (ntups > 0);
2388
2389         return 1;
2390 }
2391
2392 static void
2393 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2394                                                                                  PQExpBuffer upgrade_buffer,
2395                                                                                  Oid pg_type_oid)
2396 {
2397         PQExpBuffer upgrade_query = createPQExpBuffer();
2398         PGresult   *upgrade_res;
2399         Oid                     pg_type_array_oid;
2400
2401         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2402         appendPQExpBuffer(upgrade_buffer,
2403          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2404                                           pg_type_oid);
2405
2406         /* we only support old >= 8.3 for binary upgrades */
2407         appendPQExpBuffer(upgrade_query,
2408                                           "SELECT typarray "
2409                                           "FROM pg_catalog.pg_type "
2410                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2411                                           pg_type_oid);
2412
2413         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2414
2415         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2416
2417         if (OidIsValid(pg_type_array_oid))
2418         {
2419                 appendPQExpBuffer(upgrade_buffer,
2420                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2421                 appendPQExpBuffer(upgrade_buffer,
2422                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2423                                                   pg_type_array_oid);
2424         }
2425
2426         PQclear(upgrade_res);
2427         destroyPQExpBuffer(upgrade_query);
2428 }
2429
2430 static bool
2431 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2432                                                                                 PQExpBuffer upgrade_buffer,
2433                                                                                 Oid pg_rel_oid)
2434 {
2435         PQExpBuffer upgrade_query = createPQExpBuffer();
2436         PGresult   *upgrade_res;
2437         Oid                     pg_type_oid;
2438         bool            toast_set = false;
2439
2440         /* we only support old >= 8.3 for binary upgrades */
2441         appendPQExpBuffer(upgrade_query,
2442                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2443                                           "FROM pg_catalog.pg_class c "
2444                                           "LEFT JOIN pg_catalog.pg_class t ON "
2445                                           "  (c.reltoastrelid = t.oid) "
2446                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2447                                           pg_rel_oid);
2448
2449         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2450
2451         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2452
2453         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2454                                                                                          pg_type_oid);
2455
2456         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2457         {
2458                 /* Toast tables do not have pg_type array rows */
2459                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2460                                                                                         PQfnumber(upgrade_res, "trel")));
2461
2462                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2463                 appendPQExpBuffer(upgrade_buffer,
2464                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2465                                                   pg_type_toast_oid);
2466
2467                 toast_set = true;
2468         }
2469
2470         PQclear(upgrade_res);
2471         destroyPQExpBuffer(upgrade_query);
2472
2473         return toast_set;
2474 }
2475
2476 static void
2477 binary_upgrade_set_pg_class_oids(Archive *fout,
2478                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2479                                                                  bool is_index)
2480 {
2481         PQExpBuffer upgrade_query = createPQExpBuffer();
2482         PGresult   *upgrade_res;
2483         Oid                     pg_class_reltoastrelid;
2484         Oid                     pg_class_reltoastidxid;
2485
2486         appendPQExpBuffer(upgrade_query,
2487                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2488                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2489                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2490                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2491                                           pg_class_oid);
2492
2493         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2494
2495         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2496         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2497
2498         appendPQExpBuffer(upgrade_buffer,
2499                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2500
2501         if (!is_index)
2502         {
2503                 appendPQExpBuffer(upgrade_buffer,
2504                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2505                                                   pg_class_oid);
2506                 /* only tables have toast tables, not indexes */
2507                 if (OidIsValid(pg_class_reltoastrelid))
2508                 {
2509                         /*
2510                          * One complexity is that the table definition might not require
2511                          * the creation of a TOAST table, and the TOAST table might have
2512                          * been created long after table creation, when the table was
2513                          * loaded with wide data.  By setting the TOAST oid we force
2514                          * creation of the TOAST heap and TOAST index by the backend so we
2515                          * can cleanly copy the files during binary upgrade.
2516                          */
2517
2518                         appendPQExpBuffer(upgrade_buffer,
2519                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2520                                                           pg_class_reltoastrelid);
2521
2522                         /* every toast table has an index */
2523                         appendPQExpBuffer(upgrade_buffer,
2524                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2525                                                           pg_class_reltoastidxid);
2526                 }
2527         }
2528         else
2529                 appendPQExpBuffer(upgrade_buffer,
2530                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2531                                                   pg_class_oid);
2532
2533         appendPQExpBuffer(upgrade_buffer, "\n");
2534
2535         PQclear(upgrade_res);
2536         destroyPQExpBuffer(upgrade_query);
2537 }
2538
2539 /*
2540  * If the DumpableObject is a member of an extension, add a suitable
2541  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2542  */
2543 static void
2544 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2545                                                                 DumpableObject *dobj,
2546                                                                 const char *objlabel)
2547 {
2548         DumpableObject *extobj = NULL;
2549         int                     i;
2550
2551         if (!dobj->ext_member)
2552                 return;
2553
2554         /*
2555          * Find the parent extension.  We could avoid this search if we wanted to
2556          * add a link field to DumpableObject, but the space costs of that would
2557          * be considerable.  We assume that member objects could only have a
2558          * direct dependency on their own extension, not any others.
2559          */
2560         for (i = 0; i < dobj->nDeps; i++)
2561         {
2562                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2563                 if (extobj && extobj->objType == DO_EXTENSION)
2564                         break;
2565                 extobj = NULL;
2566         }
2567         if (extobj == NULL)
2568                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2569
2570         appendPQExpBuffer(upgrade_buffer,
2571           "\n-- For binary upgrade, handle extension membership the hard way\n");
2572         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2573                                           fmtId(extobj->name),
2574                                           objlabel);
2575 }
2576
2577 /*
2578  * getNamespaces:
2579  *        read all namespaces in the system catalogs and return them in the
2580  * NamespaceInfo* structure
2581  *
2582  *      numNamespaces is set to the number of namespaces read in
2583  */
2584 NamespaceInfo *
2585 getNamespaces(Archive *fout, int *numNamespaces)
2586 {
2587         PGresult   *res;
2588         int                     ntups;
2589         int                     i;
2590         PQExpBuffer query;
2591         NamespaceInfo *nsinfo;
2592         int                     i_tableoid;
2593         int                     i_oid;
2594         int                     i_nspname;
2595         int                     i_rolname;
2596         int                     i_nspacl;
2597
2598         /*
2599          * Before 7.3, there are no real namespaces; create two dummy entries, one
2600          * for user stuff and one for system stuff.
2601          */
2602         if (fout->remoteVersion < 70300)
2603         {
2604                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2605
2606                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2607                 nsinfo[0].dobj.catId.tableoid = 0;
2608                 nsinfo[0].dobj.catId.oid = 0;
2609                 AssignDumpId(&nsinfo[0].dobj);
2610                 nsinfo[0].dobj.name = pg_strdup("public");
2611                 nsinfo[0].rolname = pg_strdup("");
2612                 nsinfo[0].nspacl = pg_strdup("");
2613
2614                 selectDumpableNamespace(&nsinfo[0]);
2615
2616                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2617                 nsinfo[1].dobj.catId.tableoid = 0;
2618                 nsinfo[1].dobj.catId.oid = 1;
2619                 AssignDumpId(&nsinfo[1].dobj);
2620                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2621                 nsinfo[1].rolname = pg_strdup("");
2622                 nsinfo[1].nspacl = pg_strdup("");
2623
2624                 selectDumpableNamespace(&nsinfo[1]);
2625
2626                 *numNamespaces = 2;
2627
2628                 return nsinfo;
2629         }
2630
2631         query = createPQExpBuffer();
2632
2633         /* Make sure we are in proper schema */
2634         selectSourceSchema(fout, "pg_catalog");
2635
2636         /*
2637          * we fetch all namespaces including system ones, so that every object we
2638          * read in can be linked to a containing namespace.
2639          */
2640         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2641                                           "(%s nspowner) AS rolname, "
2642                                           "nspacl FROM pg_namespace",
2643                                           username_subquery);
2644
2645         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2646
2647         ntups = PQntuples(res);
2648
2649         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2650
2651         i_tableoid = PQfnumber(res, "tableoid");
2652         i_oid = PQfnumber(res, "oid");
2653         i_nspname = PQfnumber(res, "nspname");
2654         i_rolname = PQfnumber(res, "rolname");
2655         i_nspacl = PQfnumber(res, "nspacl");
2656
2657         for (i = 0; i < ntups; i++)
2658         {
2659                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2660                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2661                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2662                 AssignDumpId(&nsinfo[i].dobj);
2663                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2664                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2665                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2666
2667                 /* Decide whether to dump this namespace */
2668                 selectDumpableNamespace(&nsinfo[i]);
2669
2670                 if (strlen(nsinfo[i].rolname) == 0)
2671                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2672                                           nsinfo[i].dobj.name);
2673         }
2674
2675         PQclear(res);
2676         destroyPQExpBuffer(query);
2677
2678         *numNamespaces = ntups;
2679
2680         return nsinfo;
2681 }
2682
2683 /*
2684  * findNamespace:
2685  *              given a namespace OID and an object OID, look up the info read by
2686  *              getNamespaces
2687  *
2688  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2689  * a system object or not.      In 7.3 and later there is no guessing, and we
2690  * don't use objoid at all.
2691  */
2692 static NamespaceInfo *
2693 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2694 {
2695         NamespaceInfo *nsinfo;
2696
2697         if (fout->remoteVersion >= 70300)
2698         {
2699                 nsinfo = findNamespaceByOid(nsoid);
2700         }
2701         else
2702         {
2703                 /* This code depends on the dummy objects set up by getNamespaces. */
2704                 Oid                     i;
2705
2706                 if (objoid > g_last_builtin_oid)
2707                         i = 0;                          /* user object */
2708                 else
2709                         i = 1;                          /* system object */
2710                 nsinfo = findNamespaceByOid(i);
2711         }
2712
2713         if (nsinfo == NULL)
2714                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
2715
2716         return nsinfo;
2717 }
2718
2719 /*
2720  * getExtensions:
2721  *        read all extensions in the system catalogs and return them in the
2722  * ExtensionInfo* structure
2723  *
2724  *      numExtensions is set to the number of extensions read in
2725  */
2726 ExtensionInfo *
2727 getExtensions(Archive *fout, int *numExtensions)
2728 {
2729         PGresult   *res;
2730         int                     ntups;
2731         int                     i;
2732         PQExpBuffer query;
2733         ExtensionInfo *extinfo;
2734         int                     i_tableoid;
2735         int                     i_oid;
2736         int                     i_extname;
2737         int                     i_nspname;
2738         int                     i_extrelocatable;
2739         int                     i_extversion;
2740         int                     i_extconfig;
2741         int                     i_extcondition;
2742
2743         /*
2744          * Before 9.1, there are no extensions.
2745          */
2746         if (fout->remoteVersion < 90100)
2747         {
2748                 *numExtensions = 0;
2749                 return NULL;
2750         }
2751
2752         query = createPQExpBuffer();
2753
2754         /* Make sure we are in proper schema */
2755         selectSourceSchema(fout, "pg_catalog");
2756
2757         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
2758                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
2759                                           "FROM pg_extension x "
2760                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
2761
2762         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2763
2764         ntups = PQntuples(res);
2765
2766         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
2767
2768         i_tableoid = PQfnumber(res, "tableoid");
2769         i_oid = PQfnumber(res, "oid");
2770         i_extname = PQfnumber(res, "extname");
2771         i_nspname = PQfnumber(res, "nspname");
2772         i_extrelocatable = PQfnumber(res, "extrelocatable");
2773         i_extversion = PQfnumber(res, "extversion");
2774         i_extconfig = PQfnumber(res, "extconfig");
2775         i_extcondition = PQfnumber(res, "extcondition");
2776
2777         for (i = 0; i < ntups; i++)
2778         {
2779                 extinfo[i].dobj.objType = DO_EXTENSION;
2780                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2781                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2782                 AssignDumpId(&extinfo[i].dobj);
2783                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
2784                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
2785                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
2786                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
2787                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
2788                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
2789
2790                 /* Decide whether we want to dump it */
2791                 selectDumpableExtension(&(extinfo[i]));
2792         }
2793
2794         PQclear(res);
2795         destroyPQExpBuffer(query);
2796
2797         *numExtensions = ntups;
2798
2799         return extinfo;
2800 }
2801
2802 /*
2803  * getTypes:
2804  *        read all types in the system catalogs and return them in the
2805  * TypeInfo* structure
2806  *
2807  *      numTypes is set to the number of types read in
2808  *
2809  * NB: this must run after getFuncs() because we assume we can do
2810  * findFuncByOid().
2811  */
2812 TypeInfo *
2813 getTypes(Archive *fout, int *numTypes)
2814 {
2815         PGresult   *res;
2816         int                     ntups;
2817         int                     i;
2818         PQExpBuffer query = createPQExpBuffer();
2819         TypeInfo   *tyinfo;
2820         ShellTypeInfo *stinfo;
2821         int                     i_tableoid;
2822         int                     i_oid;
2823         int                     i_typname;
2824         int                     i_typnamespace;
2825         int                     i_rolname;
2826         int                     i_typinput;
2827         int                     i_typoutput;
2828         int                     i_typelem;
2829         int                     i_typrelid;
2830         int                     i_typrelkind;
2831         int                     i_typtype;
2832         int                     i_typisdefined;
2833         int                     i_isarray;
2834
2835         /*
2836          * we include even the built-in types because those may be used as array
2837          * elements by user-defined types
2838          *
2839          * we filter out the built-in types when we dump out the types
2840          *
2841          * same approach for undefined (shell) types and array types
2842          *
2843          * Note: as of 8.3 we can reliably detect whether a type is an
2844          * auto-generated array type by checking the element type's typarray.
2845          * (Before that the test is capable of generating false positives.) We
2846          * still check for name beginning with '_', though, so as to avoid the
2847          * cost of the subselect probe for all standard types.  This would have to
2848          * be revisited if the backend ever allows renaming of array types.
2849          */
2850
2851         /* Make sure we are in proper schema */
2852         selectSourceSchema(fout, "pg_catalog");
2853
2854         if (fout->remoteVersion >= 80300)
2855         {
2856                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2857                                                   "typnamespace, "
2858                                                   "(%s typowner) AS rolname, "
2859                                                   "typinput::oid AS typinput, "
2860                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2861                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2862                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2863                                                   "typtype, typisdefined, "
2864                                                   "typname[0] = '_' AND typelem != 0 AND "
2865                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2866                                                   "FROM pg_type",
2867                                                   username_subquery);
2868         }
2869         else if (fout->remoteVersion >= 70300)
2870         {
2871                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2872                                                   "typnamespace, "
2873                                                   "(%s typowner) AS rolname, "
2874                                                   "typinput::oid AS typinput, "
2875                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2876                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2877                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2878                                                   "typtype, typisdefined, "
2879                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2880                                                   "FROM pg_type",
2881                                                   username_subquery);
2882         }
2883         else if (fout->remoteVersion >= 70100)
2884         {
2885                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2886                                                   "0::oid AS typnamespace, "
2887                                                   "(%s typowner) AS rolname, "
2888                                                   "typinput::oid AS typinput, "
2889                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2890                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2891                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2892                                                   "typtype, typisdefined, "
2893                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2894                                                   "FROM pg_type",
2895                                                   username_subquery);
2896         }
2897         else
2898         {
2899                 appendPQExpBuffer(query, "SELECT "
2900                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2901                                                   "oid, typname, "
2902                                                   "0::oid AS typnamespace, "
2903                                                   "(%s typowner) AS rolname, "
2904                                                   "typinput::oid AS typinput, "
2905                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2906                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2907                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2908                                                   "typtype, typisdefined, "
2909                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2910                                                   "FROM pg_type",
2911                                                   username_subquery);
2912         }
2913
2914         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2915
2916         ntups = PQntuples(res);
2917
2918         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
2919
2920         i_tableoid = PQfnumber(res, "tableoid");
2921         i_oid = PQfnumber(res, "oid");
2922         i_typname = PQfnumber(res, "typname");
2923         i_typnamespace = PQfnumber(res, "typnamespace");
2924         i_rolname = PQfnumber(res, "rolname");
2925         i_typinput = PQfnumber(res, "typinput");
2926         i_typoutput = PQfnumber(res, "typoutput");
2927         i_typelem = PQfnumber(res, "typelem");
2928         i_typrelid = PQfnumber(res, "typrelid");
2929         i_typrelkind = PQfnumber(res, "typrelkind");
2930         i_typtype = PQfnumber(res, "typtype");
2931         i_typisdefined = PQfnumber(res, "typisdefined");
2932         i_isarray = PQfnumber(res, "isarray");
2933
2934         for (i = 0; i < ntups; i++)
2935         {
2936                 tyinfo[i].dobj.objType = DO_TYPE;
2937                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2938                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2939                 AssignDumpId(&tyinfo[i].dobj);
2940                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
2941                 tyinfo[i].dobj.namespace =
2942                         findNamespace(fout,
2943                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
2944                                                   tyinfo[i].dobj.catId.oid);
2945                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2946                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2947                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2948                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2949                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2950                 tyinfo[i].shellType = NULL;
2951
2952                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2953                         tyinfo[i].isDefined = true;
2954                 else
2955                         tyinfo[i].isDefined = false;
2956
2957                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2958                         tyinfo[i].isArray = true;
2959                 else
2960                         tyinfo[i].isArray = false;
2961
2962                 /* Decide whether we want to dump it */
2963                 selectDumpableType(&tyinfo[i]);
2964
2965                 /*
2966                  * If it's a domain, fetch info about its constraints, if any
2967                  */
2968                 tyinfo[i].nDomChecks = 0;
2969                 tyinfo[i].domChecks = NULL;
2970                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
2971                         getDomainConstraints(fout, &(tyinfo[i]));
2972
2973                 /*
2974                  * If it's a base type, make a DumpableObject representing a shell
2975                  * definition of the type.      We will need to dump that ahead of the I/O
2976                  * functions for the type.      Similarly, range types need a shell
2977                  * definition in case they have a canonicalize function.
2978                  *
2979                  * Note: the shell type doesn't have a catId.  You might think it
2980                  * should copy the base type's catId, but then it might capture the
2981                  * pg_depend entries for the type, which we don't want.
2982                  */
2983                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
2984                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
2985                 {
2986                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
2987                         stinfo->dobj.objType = DO_SHELL_TYPE;
2988                         stinfo->dobj.catId = nilCatalogId;
2989                         AssignDumpId(&stinfo->dobj);
2990                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
2991                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
2992                         stinfo->baseType = &(tyinfo[i]);
2993                         tyinfo[i].shellType = stinfo;
2994
2995                         /*
2996                          * Initially mark the shell type as not to be dumped.  We'll only
2997                          * dump it if the I/O or canonicalize functions need to be dumped;
2998                          * this is taken care of while sorting dependencies.
2999                          */
3000                         stinfo->dobj.dump = false;
3001
3002                         /*
3003                          * However, if dumping from pre-7.3, there will be no dependency
3004                          * info so we have to fake it here.  We only need to worry about
3005                          * typinput and typoutput since the other functions only exist
3006                          * post-7.3.
3007                          */
3008                         if (fout->remoteVersion < 70300)
3009                         {
3010                                 Oid                     typinput;
3011                                 Oid                     typoutput;
3012                                 FuncInfo   *funcInfo;
3013
3014                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3015                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3016
3017                                 funcInfo = findFuncByOid(typinput);
3018                                 if (funcInfo && funcInfo->dobj.dump)
3019                                 {
3020                                         /* base type depends on function */
3021                                         addObjectDependency(&tyinfo[i].dobj,
3022                                                                                 funcInfo->dobj.dumpId);
3023                                         /* function depends on shell type */
3024                                         addObjectDependency(&funcInfo->dobj,
3025                                                                                 stinfo->dobj.dumpId);
3026                                         /* mark shell type as to be dumped */
3027                                         stinfo->dobj.dump = true;
3028                                 }
3029
3030                                 funcInfo = findFuncByOid(typoutput);
3031                                 if (funcInfo && funcInfo->dobj.dump)
3032                                 {
3033                                         /* base type depends on function */
3034                                         addObjectDependency(&tyinfo[i].dobj,
3035                                                                                 funcInfo->dobj.dumpId);
3036                                         /* function depends on shell type */
3037                                         addObjectDependency(&funcInfo->dobj,
3038                                                                                 stinfo->dobj.dumpId);
3039                                         /* mark shell type as to be dumped */
3040                                         stinfo->dobj.dump = true;
3041                                 }
3042                         }
3043                 }
3044
3045                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3046                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3047                                           tyinfo[i].dobj.name);
3048         }
3049
3050         *numTypes = ntups;
3051
3052         PQclear(res);
3053
3054         destroyPQExpBuffer(query);
3055
3056         return tyinfo;
3057 }
3058
3059 /*
3060  * getOperators:
3061  *        read all operators in the system catalogs and return them in the
3062  * OprInfo* structure
3063  *
3064  *      numOprs is set to the number of operators read in
3065  */
3066 OprInfo *
3067 getOperators(Archive *fout, int *numOprs)
3068 {
3069         PGresult   *res;
3070         int                     ntups;
3071         int                     i;
3072         PQExpBuffer query = createPQExpBuffer();
3073         OprInfo    *oprinfo;
3074         int                     i_tableoid;
3075         int                     i_oid;
3076         int                     i_oprname;
3077         int                     i_oprnamespace;
3078         int                     i_rolname;
3079         int                     i_oprkind;
3080         int                     i_oprcode;
3081
3082         /*
3083          * find all operators, including builtin operators; we filter out
3084          * system-defined operators at dump-out time.
3085          */
3086
3087         /* Make sure we are in proper schema */
3088         selectSourceSchema(fout, "pg_catalog");
3089
3090         if (fout->remoteVersion >= 70300)
3091         {
3092                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3093                                                   "oprnamespace, "
3094                                                   "(%s oprowner) AS rolname, "
3095                                                   "oprkind, "
3096                                                   "oprcode::oid AS oprcode "
3097                                                   "FROM pg_operator",
3098                                                   username_subquery);
3099         }
3100         else if (fout->remoteVersion >= 70100)
3101         {
3102                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3103                                                   "0::oid AS oprnamespace, "
3104                                                   "(%s oprowner) AS rolname, "
3105                                                   "oprkind, "
3106                                                   "oprcode::oid AS oprcode "
3107                                                   "FROM pg_operator",
3108                                                   username_subquery);
3109         }
3110         else
3111         {
3112                 appendPQExpBuffer(query, "SELECT "
3113                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3114                                                   "oid, oprname, "
3115                                                   "0::oid AS oprnamespace, "
3116                                                   "(%s oprowner) AS rolname, "
3117                                                   "oprkind, "
3118                                                   "oprcode::oid AS oprcode "
3119                                                   "FROM pg_operator",
3120                                                   username_subquery);
3121         }
3122
3123         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3124
3125         ntups = PQntuples(res);
3126         *numOprs = ntups;
3127
3128         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3129
3130         i_tableoid = PQfnumber(res, "tableoid");
3131         i_oid = PQfnumber(res, "oid");
3132         i_oprname = PQfnumber(res, "oprname");
3133         i_oprnamespace = PQfnumber(res, "oprnamespace");
3134         i_rolname = PQfnumber(res, "rolname");
3135         i_oprkind = PQfnumber(res, "oprkind");
3136         i_oprcode = PQfnumber(res, "oprcode");
3137
3138         for (i = 0; i < ntups; i++)
3139         {
3140                 oprinfo[i].dobj.objType = DO_OPERATOR;
3141                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3142                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3143                 AssignDumpId(&oprinfo[i].dobj);
3144                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3145                 oprinfo[i].dobj.namespace =
3146                         findNamespace(fout,
3147                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3148                                                   oprinfo[i].dobj.catId.oid);
3149                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3150                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3151                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3152
3153                 /* Decide whether we want to dump it */
3154                 selectDumpableObject(&(oprinfo[i].dobj));
3155
3156                 if (strlen(oprinfo[i].rolname) == 0)
3157                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3158                                           oprinfo[i].dobj.name);
3159         }
3160
3161         PQclear(res);
3162
3163         destroyPQExpBuffer(query);
3164
3165         return oprinfo;
3166 }
3167
3168 /*
3169  * getCollations:
3170  *        read all collations in the system catalogs and return them in the
3171  * CollInfo* structure
3172  *
3173  *      numCollations is set to the number of collations read in
3174  */
3175 CollInfo *
3176 getCollations(Archive *fout, int *numCollations)
3177 {
3178         PGresult   *res;
3179         int                     ntups;
3180         int                     i;
3181         PQExpBuffer query;
3182         CollInfo   *collinfo;
3183         int                     i_tableoid;
3184         int                     i_oid;
3185         int                     i_collname;
3186         int                     i_collnamespace;
3187         int                     i_rolname;
3188
3189         /* Collations didn't exist pre-9.1 */
3190         if (fout->remoteVersion < 90100)
3191         {
3192                 *numCollations = 0;
3193                 return NULL;
3194         }
3195
3196         query = createPQExpBuffer();
3197
3198         /*
3199          * find all collations, including builtin collations; we filter out
3200          * system-defined collations at dump-out time.
3201          */
3202
3203         /* Make sure we are in proper schema */
3204         selectSourceSchema(fout, "pg_catalog");
3205
3206         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3207                                           "collnamespace, "
3208                                           "(%s collowner) AS rolname "
3209                                           "FROM pg_collation",
3210                                           username_subquery);
3211
3212         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3213
3214         ntups = PQntuples(res);
3215         *numCollations = ntups;
3216
3217         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3218
3219         i_tableoid = PQfnumber(res, "tableoid");
3220         i_oid = PQfnumber(res, "oid");
3221         i_collname = PQfnumber(res, "collname");
3222         i_collnamespace = PQfnumber(res, "collnamespace");
3223         i_rolname = PQfnumber(res, "rolname");
3224
3225         for (i = 0; i < ntups; i++)
3226         {
3227                 collinfo[i].dobj.objType = DO_COLLATION;
3228                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3229                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3230                 AssignDumpId(&collinfo[i].dobj);
3231                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3232                 collinfo[i].dobj.namespace =
3233                         findNamespace(fout,
3234                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3235                                                   collinfo[i].dobj.catId.oid);
3236                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3237
3238                 /* Decide whether we want to dump it */
3239                 selectDumpableObject(&(collinfo[i].dobj));
3240         }
3241
3242         PQclear(res);
3243
3244         destroyPQExpBuffer(query);
3245
3246         return collinfo;
3247 }
3248
3249 /*
3250  * getConversions:
3251  *        read all conversions in the system catalogs and return them in the
3252  * ConvInfo* structure
3253  *
3254  *      numConversions is set to the number of conversions read in
3255  */
3256 ConvInfo *
3257 getConversions(Archive *fout, int *numConversions)
3258 {
3259         PGresult   *res;
3260         int                     ntups;
3261         int                     i;
3262         PQExpBuffer query = createPQExpBuffer();
3263         ConvInfo   *convinfo;
3264         int                     i_tableoid;
3265         int                     i_oid;
3266         int                     i_conname;
3267         int                     i_connamespace;
3268         int                     i_rolname;
3269
3270         /* Conversions didn't exist pre-7.3 */
3271         if (fout->remoteVersion < 70300)
3272         {
3273                 *numConversions = 0;
3274                 return NULL;
3275         }
3276
3277         /*
3278          * find all conversions, including builtin conversions; we filter out
3279          * system-defined conversions at dump-out time.
3280          */
3281
3282         /* Make sure we are in proper schema */
3283         selectSourceSchema(fout, "pg_catalog");
3284
3285         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3286                                           "connamespace, "
3287                                           "(%s conowner) AS rolname "
3288                                           "FROM pg_conversion",
3289                                           username_subquery);
3290
3291         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3292
3293         ntups = PQntuples(res);
3294         *numConversions = ntups;
3295
3296         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3297
3298         i_tableoid = PQfnumber(res, "tableoid");
3299         i_oid = PQfnumber(res, "oid");
3300         i_conname = PQfnumber(res, "conname");
3301         i_connamespace = PQfnumber(res, "connamespace");
3302         i_rolname = PQfnumber(res, "rolname");
3303
3304         for (i = 0; i < ntups; i++)
3305         {
3306                 convinfo[i].dobj.objType = DO_CONVERSION;
3307                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3308                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3309                 AssignDumpId(&convinfo[i].dobj);
3310                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3311                 convinfo[i].dobj.namespace =
3312                         findNamespace(fout,
3313                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3314                                                   convinfo[i].dobj.catId.oid);
3315                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3316
3317                 /* Decide whether we want to dump it */
3318                 selectDumpableObject(&(convinfo[i].dobj));
3319         }
3320
3321         PQclear(res);
3322
3323         destroyPQExpBuffer(query);
3324
3325         return convinfo;
3326 }
3327
3328 /*
3329  * getOpclasses:
3330  *        read all opclasses in the system catalogs and return them in the
3331  * OpclassInfo* structure
3332  *
3333  *      numOpclasses is set to the number of opclasses read in
3334  */
3335 OpclassInfo *
3336 getOpclasses(Archive *fout, int *numOpclasses)
3337 {
3338         PGresult   *res;
3339         int                     ntups;
3340         int                     i;
3341         PQExpBuffer query = createPQExpBuffer();
3342         OpclassInfo *opcinfo;
3343         int                     i_tableoid;
3344         int                     i_oid;
3345         int                     i_opcname;
3346         int                     i_opcnamespace;
3347         int                     i_rolname;
3348
3349         /*
3350          * find all opclasses, including builtin opclasses; we filter out
3351          * system-defined opclasses at dump-out time.
3352          */
3353
3354         /* Make sure we are in proper schema */
3355         selectSourceSchema(fout, "pg_catalog");
3356
3357         if (fout->remoteVersion >= 70300)
3358         {
3359                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3360                                                   "opcnamespace, "
3361                                                   "(%s opcowner) AS rolname "
3362                                                   "FROM pg_opclass",
3363                                                   username_subquery);
3364         }
3365         else if (fout->remoteVersion >= 70100)
3366         {
3367                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3368                                                   "0::oid AS opcnamespace, "
3369                                                   "''::name AS rolname "
3370                                                   "FROM pg_opclass");
3371         }
3372         else
3373         {
3374                 appendPQExpBuffer(query, "SELECT "
3375                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3376                                                   "oid, opcname, "
3377                                                   "0::oid AS opcnamespace, "
3378                                                   "''::name AS rolname "
3379                                                   "FROM pg_opclass");
3380         }
3381
3382         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3383
3384         ntups = PQntuples(res);
3385         *numOpclasses = ntups;
3386
3387         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3388
3389         i_tableoid = PQfnumber(res, "tableoid");
3390         i_oid = PQfnumber(res, "oid");
3391         i_opcname = PQfnumber(res, "opcname");
3392         i_opcnamespace = PQfnumber(res, "opcnamespace");
3393         i_rolname = PQfnumber(res, "rolname");
3394
3395         for (i = 0; i < ntups; i++)
3396         {
3397                 opcinfo[i].dobj.objType = DO_OPCLASS;
3398                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3399                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3400                 AssignDumpId(&opcinfo[i].dobj);
3401                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3402                 opcinfo[i].dobj.namespace =
3403                         findNamespace(fout,
3404                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3405                                                   opcinfo[i].dobj.catId.oid);
3406                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3407
3408                 /* Decide whether we want to dump it */
3409                 selectDumpableObject(&(opcinfo[i].dobj));
3410
3411                 if (fout->remoteVersion >= 70300)
3412                 {
3413                         if (strlen(opcinfo[i].rolname) == 0)
3414                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3415                                                   opcinfo[i].dobj.name);
3416                 }
3417         }
3418
3419         PQclear(res);
3420
3421         destroyPQExpBuffer(query);
3422
3423         return opcinfo;
3424 }
3425
3426 /*
3427  * getOpfamilies:
3428  *        read all opfamilies in the system catalogs and return them in the
3429  * OpfamilyInfo* structure
3430  *
3431  *      numOpfamilies is set to the number of opfamilies read in
3432  */
3433 OpfamilyInfo *
3434 getOpfamilies(Archive *fout, int *numOpfamilies)
3435 {
3436         PGresult   *res;
3437         int                     ntups;
3438         int                     i;
3439         PQExpBuffer query;
3440         OpfamilyInfo *opfinfo;
3441         int                     i_tableoid;
3442         int                     i_oid;
3443         int                     i_opfname;
3444         int                     i_opfnamespace;
3445         int                     i_rolname;
3446
3447         /* Before 8.3, there is no separate concept of opfamilies */
3448         if (fout->remoteVersion < 80300)
3449         {
3450                 *numOpfamilies = 0;
3451                 return NULL;
3452         }
3453
3454         query = createPQExpBuffer();
3455
3456         /*
3457          * find all opfamilies, including builtin opfamilies; we filter out
3458          * system-defined opfamilies at dump-out time.
3459          */
3460
3461         /* Make sure we are in proper schema */
3462         selectSourceSchema(fout, "pg_catalog");
3463
3464         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3465                                           "opfnamespace, "
3466                                           "(%s opfowner) AS rolname "
3467                                           "FROM pg_opfamily",
3468                                           username_subquery);
3469
3470         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3471
3472         ntups = PQntuples(res);
3473         *numOpfamilies = ntups;
3474
3475         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3476
3477         i_tableoid = PQfnumber(res, "tableoid");
3478         i_oid = PQfnumber(res, "oid");
3479         i_opfname = PQfnumber(res, "opfname");
3480         i_opfnamespace = PQfnumber(res, "opfnamespace");
3481         i_rolname = PQfnumber(res, "rolname");
3482
3483         for (i = 0; i < ntups; i++)
3484         {
3485                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3486                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3487                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3488                 AssignDumpId(&opfinfo[i].dobj);
3489                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3490                 opfinfo[i].dobj.namespace =
3491                         findNamespace(fout,
3492                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3493                                                   opfinfo[i].dobj.catId.oid);
3494                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3495
3496                 /* Decide whether we want to dump it */
3497                 selectDumpableObject(&(opfinfo[i].dobj));
3498
3499                 if (fout->remoteVersion >= 70300)
3500                 {
3501                         if (strlen(opfinfo[i].rolname) == 0)
3502                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3503                                                   opfinfo[i].dobj.name);
3504                 }
3505         }
3506
3507         PQclear(res);
3508
3509         destroyPQExpBuffer(query);
3510
3511         return opfinfo;
3512 }
3513
3514 /*
3515  * getAggregates:
3516  *        read all the user-defined aggregates in the system catalogs and
3517  * return them in the AggInfo* structure
3518  *
3519  * numAggs is set to the number of aggregates read in
3520  */
3521 AggInfo *
3522 getAggregates(Archive *fout, int *numAggs)
3523 {
3524         PGresult   *res;
3525         int                     ntups;
3526         int                     i;
3527         PQExpBuffer query = createPQExpBuffer();
3528         AggInfo    *agginfo;
3529         int                     i_tableoid;
3530         int                     i_oid;
3531         int                     i_aggname;
3532         int                     i_aggnamespace;
3533         int                     i_pronargs;
3534         int                     i_proargtypes;
3535         int                     i_rolname;
3536         int                     i_aggacl;
3537
3538         /* Make sure we are in proper schema */
3539         selectSourceSchema(fout, "pg_catalog");
3540
3541         /*
3542          * Find all user-defined aggregates.  See comment in getFuncs() for the
3543          * rationale behind the filtering logic.
3544          */
3545
3546         if (fout->remoteVersion >= 80200)
3547         {
3548                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3549                                                   "pronamespace AS aggnamespace, "
3550                                                   "pronargs, proargtypes, "
3551                                                   "(%s proowner) AS rolname, "
3552                                                   "proacl AS aggacl "
3553                                                   "FROM pg_proc p "
3554                                                   "WHERE proisagg AND ("
3555                                                   "pronamespace != "
3556                                                   "(SELECT oid FROM pg_namespace "
3557                                                   "WHERE nspname = 'pg_catalog')",
3558                                                   username_subquery);
3559                 if (binary_upgrade && fout->remoteVersion >= 90100)
3560                         appendPQExpBuffer(query,
3561                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3562                                                           "classid = 'pg_proc'::regclass AND "
3563                                                           "objid = p.oid AND "
3564                                                           "refclassid = 'pg_extension'::regclass AND "
3565                                                           "deptype = 'e')");
3566                 appendPQExpBuffer(query, ")");
3567         }
3568         else if (fout->remoteVersion >= 70300)
3569         {
3570                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3571                                                   "pronamespace AS aggnamespace, "
3572                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3573                                                   "proargtypes, "
3574                                                   "(%s proowner) AS rolname, "
3575                                                   "proacl AS aggacl "
3576                                                   "FROM pg_proc "
3577                                                   "WHERE proisagg "
3578                                                   "AND pronamespace != "
3579                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3580                                                   username_subquery);
3581         }
3582         else if (fout->remoteVersion >= 70100)
3583         {
3584                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3585                                                   "0::oid AS aggnamespace, "
3586                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3587                                                   "aggbasetype AS proargtypes, "
3588                                                   "(%s aggowner) AS rolname, "
3589                                                   "'{=X}' AS aggacl "
3590                                                   "FROM pg_aggregate "
3591                                                   "where oid > '%u'::oid",
3592                                                   username_subquery,
3593                                                   g_last_builtin_oid);
3594         }
3595         else
3596         {
3597                 appendPQExpBuffer(query, "SELECT "
3598                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3599                                                   "oid, aggname, "
3600                                                   "0::oid AS aggnamespace, "
3601                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3602                                                   "aggbasetype AS proargtypes, "
3603                                                   "(%s aggowner) AS rolname, "
3604                                                   "'{=X}' AS aggacl "
3605                                                   "FROM pg_aggregate "
3606                                                   "where oid > '%u'::oid",
3607                                                   username_subquery,
3608                                                   g_last_builtin_oid);
3609         }
3610
3611         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3612
3613         ntups = PQntuples(res);
3614         *numAggs = ntups;
3615
3616         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3617
3618         i_tableoid = PQfnumber(res, "tableoid");
3619         i_oid = PQfnumber(res, "oid");
3620         i_aggname = PQfnumber(res, "aggname");
3621         i_aggnamespace = PQfnumber(res, "aggnamespace");
3622         i_pronargs = PQfnumber(res, "pronargs");
3623         i_proargtypes = PQfnumber(res, "proargtypes");
3624         i_rolname = PQfnumber(res, "rolname");
3625         i_aggacl = PQfnumber(res, "aggacl");
3626
3627         for (i = 0; i < ntups; i++)
3628         {
3629                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3630                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3631                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3632                 AssignDumpId(&agginfo[i].aggfn.dobj);
3633                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3634                 agginfo[i].aggfn.dobj.namespace =
3635                         findNamespace(fout,
3636                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3637                                                   agginfo[i].aggfn.dobj.catId.oid);
3638                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3639                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3640                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3641                                           agginfo[i].aggfn.dobj.name);
3642                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3643                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3644                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3645                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3646                 if (agginfo[i].aggfn.nargs == 0)
3647                         agginfo[i].aggfn.argtypes = NULL;
3648                 else
3649                 {
3650                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3651                         if (fout->remoteVersion >= 70300)
3652                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3653                                                           agginfo[i].aggfn.argtypes,
3654                                                           agginfo[i].aggfn.nargs);
3655                         else
3656                                 /* it's just aggbasetype */
3657                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3658                 }
3659
3660                 /* Decide whether we want to dump it */
3661                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3662         }
3663
3664         PQclear(res);
3665
3666         destroyPQExpBuffer(query);
3667
3668         return agginfo;
3669 }
3670
3671 /*
3672  * getFuncs:
3673  *        read all the user-defined functions in the system catalogs and
3674  * return them in the FuncInfo* structure
3675  *
3676  * numFuncs is set to the number of functions read in
3677  */
3678 FuncInfo *
3679 getFuncs(Archive *fout, int *numFuncs)
3680 {
3681         PGresult   *res;
3682         int                     ntups;
3683         int                     i;
3684         PQExpBuffer query = createPQExpBuffer();
3685         FuncInfo   *finfo;
3686         int                     i_tableoid;
3687         int                     i_oid;
3688         int                     i_proname;
3689         int                     i_pronamespace;
3690         int                     i_rolname;
3691         int                     i_prolang;
3692         int                     i_pronargs;
3693         int                     i_proargtypes;
3694         int                     i_prorettype;
3695         int                     i_proacl;
3696
3697         /* Make sure we are in proper schema */
3698         selectSourceSchema(fout, "pg_catalog");
3699
3700         /*
3701          * Find all user-defined functions.  Normally we can exclude functions in
3702          * pg_catalog, which is worth doing since there are several thousand of
3703          * 'em.  However, there are some extensions that create functions in
3704          * pg_catalog.  In normal dumps we can still ignore those --- but in
3705          * binary-upgrade mode, we must dump the member objects of the extension,
3706          * so be sure to fetch any such functions.
3707          *
3708          * Also, in 9.2 and up, exclude functions that are internally dependent on
3709          * something else, since presumably those will be created as a result of
3710          * creating the something else.  This currently only acts to suppress
3711          * constructor functions for range types.  Note that this is OK only
3712          * because the constructors don't have any dependencies the range type
3713          * doesn't have; otherwise we might not get creation ordering correct.
3714          */
3715
3716         if (fout->remoteVersion >= 70300)
3717         {
3718                 appendPQExpBuffer(query,
3719                                                   "SELECT tableoid, oid, proname, prolang, "
3720                                                   "pronargs, proargtypes, prorettype, proacl, "
3721                                                   "pronamespace, "
3722                                                   "(%s proowner) AS rolname "
3723                                                   "FROM pg_proc p "
3724                                                   "WHERE NOT proisagg AND ("
3725                                                   "pronamespace != "
3726                                                   "(SELECT oid FROM pg_namespace "
3727                                                   "WHERE nspname = 'pg_catalog')",
3728                                                   username_subquery);
3729                 if (fout->remoteVersion >= 90200)
3730                         appendPQExpBuffer(query,
3731                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
3732                                                           "WHERE classid = 'pg_proc'::regclass AND "
3733                                                           "objid = p.oid AND deptype = 'i')");
3734                 if (binary_upgrade && fout->remoteVersion >= 90100)
3735                         appendPQExpBuffer(query,
3736                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3737                                                           "classid = 'pg_proc'::regclass AND "
3738                                                           "objid = p.oid AND "
3739                                                           "refclassid = 'pg_extension'::regclass AND "
3740                                                           "deptype = 'e')");
3741                 appendPQExpBuffer(query, ")");
3742         }
3743         else if (fout->remoteVersion >= 70100)
3744         {
3745                 appendPQExpBuffer(query,
3746                                                   "SELECT tableoid, oid, proname, prolang, "
3747                                                   "pronargs, proargtypes, prorettype, "
3748                                                   "'{=X}' AS proacl, "
3749                                                   "0::oid AS pronamespace, "
3750                                                   "(%s proowner) AS rolname "
3751                                                   "FROM pg_proc "
3752                                                   "WHERE pg_proc.oid > '%u'::oid",
3753                                                   username_subquery,
3754                                                   g_last_builtin_oid);
3755         }
3756         else
3757         {
3758                 appendPQExpBuffer(query,
3759                                                   "SELECT "
3760                                                   "(SELECT oid FROM pg_class "
3761                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3762                                                   "oid, proname, prolang, "
3763                                                   "pronargs, proargtypes, prorettype, "
3764                                                   "'{=X}' AS proacl, "
3765                                                   "0::oid AS pronamespace, "
3766                                                   "(%s proowner) AS rolname "
3767                                                   "FROM pg_proc "
3768                                                   "where pg_proc.oid > '%u'::oid",
3769                                                   username_subquery,
3770                                                   g_last_builtin_oid);
3771         }
3772
3773         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3774
3775         ntups = PQntuples(res);
3776
3777         *numFuncs = ntups;
3778
3779         finfo = (FuncInfo *) pg_calloc(ntups, sizeof(FuncInfo));
3780
3781         i_tableoid = PQfnumber(res, "tableoid");
3782         i_oid = PQfnumber(res, "oid");
3783         i_proname = PQfnumber(res, "proname");
3784         i_pronamespace = PQfnumber(res, "pronamespace");
3785         i_rolname = PQfnumber(res, "rolname");
3786         i_prolang = PQfnumber(res, "prolang");
3787         i_pronargs = PQfnumber(res, "pronargs");
3788         i_proargtypes = PQfnumber(res, "proargtypes");
3789         i_prorettype = PQfnumber(res, "prorettype");
3790         i_proacl = PQfnumber(res, "proacl");
3791
3792         for (i = 0; i < ntups; i++)
3793         {
3794                 finfo[i].dobj.objType = DO_FUNC;
3795                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3796                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3797                 AssignDumpId(&finfo[i].dobj);
3798                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
3799                 finfo[i].dobj.namespace =
3800                         findNamespace(fout,
3801                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
3802                                                   finfo[i].dobj.catId.oid);
3803                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3804                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3805                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3806                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
3807                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3808                 if (finfo[i].nargs == 0)
3809                         finfo[i].argtypes = NULL;
3810                 else
3811                 {
3812                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
3813                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3814                                                   finfo[i].argtypes, finfo[i].nargs);
3815                 }
3816
3817                 /* Decide whether we want to dump it */
3818                 selectDumpableObject(&(finfo[i].dobj));
3819
3820                 if (strlen(finfo[i].rolname) == 0)
3821                         write_msg(NULL,
3822                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3823                                           finfo[i].dobj.name);
3824         }
3825
3826         PQclear(res);
3827
3828         destroyPQExpBuffer(query);
3829
3830         return finfo;
3831 }
3832
3833 /*
3834  * getTables
3835  *        read all the user-defined tables (no indexes, no catalogs)
3836  * in the system catalogs return them in the TableInfo* structure
3837  *
3838  * numTables is set to the number of tables read in
3839  */
3840 TableInfo *
3841 getTables(Archive *fout, int *numTables)
3842 {
3843         PGresult   *res;
3844         int                     ntups;
3845         int                     i;
3846         PQExpBuffer query = createPQExpBuffer();
3847         TableInfo  *tblinfo;
3848         int                     i_reltableoid;
3849         int                     i_reloid;
3850         int                     i_relname;
3851         int                     i_relnamespace;
3852         int                     i_relkind;
3853         int                     i_relacl;
3854         int                     i_rolname;
3855         int                     i_relchecks;
3856         int                     i_relhastriggers;
3857         int                     i_relhasindex;
3858         int                     i_relhasrules;
3859         int                     i_relhasoids;
3860         int                     i_relfrozenxid;
3861         int                     i_toastoid;
3862         int                     i_toastfrozenxid;
3863         int                     i_relpersistence;
3864         int                     i_owning_tab;
3865         int                     i_owning_col;
3866         int                     i_reltablespace;
3867         int                     i_reloptions;
3868         int                     i_toastreloptions;
3869         int                     i_reloftype;
3870
3871         /* Make sure we are in proper schema */
3872         selectSourceSchema(fout, "pg_catalog");
3873
3874         /*
3875          * Find all the tables and table-like objects.
3876          *
3877          * We include system catalogs, so that we can work if a user table is
3878          * defined to inherit from a system catalog (pretty weird, but...)
3879          *
3880          * We ignore relations that are not ordinary tables, sequences, views,
3881          * composite types, or foreign tables.
3882          *
3883          * Composite-type table entries won't be dumped as such, but we have to
3884          * make a DumpableObject for them so that we can track dependencies of the
3885          * composite type (pg_depend entries for columns of the composite type
3886          * link to the pg_class entry not the pg_type entry).
3887          *
3888          * Note: in this phase we should collect only a minimal amount of
3889          * information about each table, basically just enough to decide if it is
3890          * interesting. We must fetch all tables in this phase because otherwise
3891          * we cannot correctly identify inherited columns, owned sequences, etc.
3892          */
3893
3894         if (fout->remoteVersion >= 90100)
3895         {
3896                 /*
3897                  * Left join to pick up dependency info linking sequences to their
3898                  * owning column, if any (note this dependency is AUTO as of 8.2)
3899                  */
3900                 appendPQExpBuffer(query,
3901                                                   "SELECT c.tableoid, c.oid, c.relname, "
3902                                                   "c.relacl, c.relkind, c.relnamespace, "
3903                                                   "(%s c.relowner) AS rolname, "
3904                                                   "c.relchecks, c.relhastriggers, "
3905                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3906                                                   "c.relfrozenxid, tc.oid AS toid, "
3907                                                   "tc.relfrozenxid AS tfrozenxid, "
3908                                                   "c.relpersistence, "
3909                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3910                                                   "d.refobjid AS owning_tab, "
3911                                                   "d.refobjsubid AS owning_col, "
3912                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3913                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3914                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3915                                                   "FROM pg_class c "
3916                                                   "LEFT JOIN pg_depend d ON "
3917                                                   "(c.relkind = '%c' AND "
3918                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3919                                                   "d.objsubid = 0 AND "
3920                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3921                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3922                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
3923                                                   "ORDER BY c.oid",
3924                                                   username_subquery,
3925                                                   RELKIND_SEQUENCE,
3926                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3927                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
3928                                                   RELKIND_FOREIGN_TABLE);
3929         }
3930         else if (fout->remoteVersion >= 90000)
3931         {
3932                 /*
3933                  * Left join to pick up dependency info linking sequences to their
3934                  * owning column, if any (note this dependency is AUTO as of 8.2)
3935                  */
3936                 appendPQExpBuffer(query,
3937                                                   "SELECT c.tableoid, c.oid, c.relname, "
3938                                                   "c.relacl, c.relkind, c.relnamespace, "
3939                                                   "(%s c.relowner) AS rolname, "
3940                                                   "c.relchecks, c.relhastriggers, "
3941                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3942                                                   "c.relfrozenxid, tc.oid AS toid, "
3943                                                   "tc.relfrozenxid AS tfrozenxid, "
3944                                                   "'p' AS relpersistence, "
3945                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3946                                                   "d.refobjid AS owning_tab, "
3947                                                   "d.refobjsubid AS owning_col, "
3948                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3949                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3950                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3951                                                   "FROM pg_class c "
3952                                                   "LEFT JOIN pg_depend d ON "
3953                                                   "(c.relkind = '%c' AND "
3954                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3955                                                   "d.objsubid = 0 AND "
3956                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3957                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3958                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3959                                                   "ORDER BY c.oid",
3960                                                   username_subquery,
3961                                                   RELKIND_SEQUENCE,
3962                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3963                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3964         }
3965         else if (fout->remoteVersion >= 80400)
3966         {
3967                 /*
3968                  * Left join to pick up dependency info linking sequences to their
3969                  * owning column, if any (note this dependency is AUTO as of 8.2)
3970                  */
3971                 appendPQExpBuffer(query,
3972                                                   "SELECT c.tableoid, c.oid, c.relname, "
3973                                                   "c.relacl, c.relkind, c.relnamespace, "
3974                                                   "(%s c.relowner) AS rolname, "
3975                                                   "c.relchecks, c.relhastriggers, "
3976                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3977                                                   "c.relfrozenxid, tc.oid AS toid, "
3978                                                   "tc.relfrozenxid AS tfrozenxid, "
3979                                                   "'p' AS relpersistence, "
3980                                                   "NULL AS reloftype, "
3981                                                   "d.refobjid AS owning_tab, "
3982                                                   "d.refobjsubid AS owning_col, "
3983                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3984                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3985                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3986                                                   "FROM pg_class c "
3987                                                   "LEFT JOIN pg_depend d ON "
3988                                                   "(c.relkind = '%c' AND "
3989                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3990                                                   "d.objsubid = 0 AND "
3991                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3992                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3993                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3994                                                   "ORDER BY c.oid",
3995                                                   username_subquery,
3996                                                   RELKIND_SEQUENCE,
3997                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3998                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3999         }
4000         else if (fout->remoteVersion >= 80200)
4001         {
4002                 /*
4003                  * Left join to pick up dependency info linking sequences to their
4004                  * owning column, if any (note this dependency is AUTO as of 8.2)
4005                  */
4006                 appendPQExpBuffer(query,
4007                                                   "SELECT c.tableoid, c.oid, c.relname, "
4008                                                   "c.relacl, c.relkind, c.relnamespace, "
4009                                                   "(%s c.relowner) AS rolname, "
4010                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4011                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4012                                                   "c.relfrozenxid, tc.oid AS toid, "
4013                                                   "tc.relfrozenxid AS tfrozenxid, "
4014                                                   "'p' AS relpersistence, "
4015                                                   "NULL AS reloftype, "
4016                                                   "d.refobjid AS owning_tab, "
4017                                                   "d.refobjsubid AS owning_col, "
4018                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4019                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4020                                                   "NULL AS toast_reloptions "
4021                                                   "FROM pg_class c "
4022                                                   "LEFT JOIN pg_depend d ON "
4023                                                   "(c.relkind = '%c' AND "
4024                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4025                                                   "d.objsubid = 0 AND "
4026                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4027                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4028                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4029                                                   "ORDER BY c.oid",
4030                                                   username_subquery,
4031                                                   RELKIND_SEQUENCE,
4032                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4033                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4034         }
4035         else if (fout->remoteVersion >= 80000)
4036         {
4037                 /*
4038                  * Left join to pick up dependency info linking sequences to their
4039                  * owning column, if any
4040                  */
4041                 appendPQExpBuffer(query,
4042                                                   "SELECT c.tableoid, c.oid, relname, "
4043                                                   "relacl, relkind, relnamespace, "
4044                                                   "(%s relowner) AS rolname, "
4045                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4046                                                   "relhasindex, relhasrules, relhasoids, "
4047                                                   "0 AS relfrozenxid, "
4048                                                   "0 AS toid, "
4049                                                   "0 AS tfrozenxid, "
4050                                                   "'p' AS relpersistence, "
4051                                                   "NULL AS reloftype, "
4052                                                   "d.refobjid AS owning_tab, "
4053                                                   "d.refobjsubid AS owning_col, "
4054                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4055                                                   "NULL AS reloptions, "
4056                                                   "NULL AS toast_reloptions "
4057                                                   "FROM pg_class c "
4058                                                   "LEFT JOIN pg_depend d ON "
4059                                                   "(c.relkind = '%c' AND "
4060                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4061                                                   "d.objsubid = 0 AND "
4062                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4063                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4064                                                   "ORDER BY c.oid",
4065                                                   username_subquery,
4066                                                   RELKIND_SEQUENCE,
4067                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4068                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4069         }
4070         else if (fout->remoteVersion >= 70300)
4071         {
4072                 /*
4073                  * Left join to pick up dependency info linking sequences to their
4074                  * owning column, if any
4075                  */
4076                 appendPQExpBuffer(query,
4077                                                   "SELECT c.tableoid, c.oid, relname, "
4078                                                   "relacl, relkind, relnamespace, "
4079                                                   "(%s relowner) AS rolname, "
4080                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4081                                                   "relhasindex, relhasrules, relhasoids, "
4082                                                   "0 AS relfrozenxid, "
4083                                                   "0 AS toid, "
4084                                                   "0 AS tfrozenxid, "
4085                                                   "'p' AS relpersistence, "
4086                                                   "NULL AS reloftype, "
4087                                                   "d.refobjid AS owning_tab, "
4088                                                   "d.refobjsubid AS owning_col, "
4089                                                   "NULL AS reltablespace, "
4090                                                   "NULL AS reloptions, "
4091                                                   "NULL AS toast_reloptions "
4092                                                   "FROM pg_class c "
4093                                                   "LEFT JOIN pg_depend d ON "
4094                                                   "(c.relkind = '%c' AND "
4095                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4096                                                   "d.objsubid = 0 AND "
4097                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4098                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4099                                                   "ORDER BY c.oid",
4100                                                   username_subquery,
4101                                                   RELKIND_SEQUENCE,
4102                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4103                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4104         }
4105         else if (fout->remoteVersion >= 70200)
4106         {
4107                 appendPQExpBuffer(query,
4108                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4109                                                   "0::oid AS relnamespace, "
4110                                                   "(%s relowner) AS rolname, "
4111                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4112                                                   "relhasindex, relhasrules, relhasoids, "
4113                                                   "0 AS relfrozenxid, "
4114                                                   "0 AS toid, "
4115                                                   "0 AS tfrozenxid, "
4116                                                   "'p' AS relpersistence, "
4117                                                   "NULL AS reloftype, "
4118                                                   "NULL::oid AS owning_tab, "
4119                                                   "NULL::int4 AS owning_col, "
4120                                                   "NULL AS reltablespace, "
4121                                                   "NULL AS reloptions, "
4122                                                   "NULL AS toast_reloptions "
4123                                                   "FROM pg_class "
4124                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4125                                                   "ORDER BY oid",
4126                                                   username_subquery,
4127                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4128         }
4129         else if (fout->remoteVersion >= 70100)
4130         {
4131                 /* all tables have oids in 7.1 */
4132                 appendPQExpBuffer(query,
4133                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4134                                                   "0::oid AS relnamespace, "
4135                                                   "(%s relowner) AS rolname, "
4136                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4137                                                   "relhasindex, relhasrules, "
4138                                                   "'t'::bool AS relhasoids, "
4139                                                   "0 AS relfrozenxid, "
4140                                                   "0 AS toid, "
4141                                                   "0 AS tfrozenxid, "
4142                                                   "'p' AS relpersistence, "
4143                                                   "NULL AS reloftype, "
4144                                                   "NULL::oid AS owning_tab, "
4145                                                   "NULL::int4 AS owning_col, "
4146                                                   "NULL AS reltablespace, "
4147                                                   "NULL AS reloptions, "
4148                                                   "NULL AS toast_reloptions "
4149                                                   "FROM pg_class "
4150                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4151                                                   "ORDER BY oid",
4152                                                   username_subquery,
4153                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4154         }
4155         else
4156         {
4157                 /*
4158                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4159                  * have a view by looking for a rule in pg_rewrite.
4160                  */
4161                 appendPQExpBuffer(query,
4162                                                   "SELECT "
4163                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4164                                                   "oid, relname, relacl, "
4165                                                   "CASE WHEN relhasrules and relkind = 'r' "
4166                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4167                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4168                                                   "THEN '%c'::\"char\" "
4169                                                   "ELSE relkind END AS relkind,"
4170                                                   "0::oid AS relnamespace, "
4171                                                   "(%s relowner) AS rolname, "
4172                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4173                                                   "relhasindex, relhasrules, "
4174                                                   "'t'::bool AS relhasoids, "
4175                                                   "0 as relfrozenxid, "
4176                                                   "0 AS toid, "
4177                                                   "0 AS tfrozenxid, "
4178                                                   "'p' AS relpersistence, "
4179                                                   "NULL AS reloftype, "
4180                                                   "NULL::oid AS owning_tab, "
4181                                                   "NULL::int4 AS owning_col, "
4182                                                   "NULL AS reltablespace, "
4183                                                   "NULL AS reloptions, "
4184                                                   "NULL AS toast_reloptions "
4185                                                   "FROM pg_class c "
4186                                                   "WHERE relkind IN ('%c', '%c') "
4187                                                   "ORDER BY oid",
4188                                                   RELKIND_VIEW,
4189                                                   username_subquery,
4190                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4191         }
4192
4193         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4194
4195         ntups = PQntuples(res);
4196
4197         *numTables = ntups;
4198
4199         /*
4200          * Extract data from result and lock dumpable tables.  We do the locking
4201          * before anything else, to minimize the window wherein a table could
4202          * disappear under us.
4203          *
4204          * Note that we have to save info about all tables here, even when dumping
4205          * only one, because we don't yet know which tables might be inheritance
4206          * ancestors of the target table.
4207          */
4208         tblinfo = (TableInfo *) pg_calloc(ntups, sizeof(TableInfo));
4209
4210         i_reltableoid = PQfnumber(res, "tableoid");
4211         i_reloid = PQfnumber(res, "oid");
4212         i_relname = PQfnumber(res, "relname");
4213         i_relnamespace = PQfnumber(res, "relnamespace");
4214         i_relacl = PQfnumber(res, "relacl");
4215         i_relkind = PQfnumber(res, "relkind");
4216         i_rolname = PQfnumber(res, "rolname");
4217         i_relchecks = PQfnumber(res, "relchecks");
4218         i_relhastriggers = PQfnumber(res, "relhastriggers");
4219         i_relhasindex = PQfnumber(res, "relhasindex");
4220         i_relhasrules = PQfnumber(res, "relhasrules");
4221         i_relhasoids = PQfnumber(res, "relhasoids");
4222         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4223         i_toastoid = PQfnumber(res, "toid");
4224         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4225         i_relpersistence = PQfnumber(res, "relpersistence");
4226         i_owning_tab = PQfnumber(res, "owning_tab");
4227         i_owning_col = PQfnumber(res, "owning_col");
4228         i_reltablespace = PQfnumber(res, "reltablespace");
4229         i_reloptions = PQfnumber(res, "reloptions");
4230         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4231         i_reloftype = PQfnumber(res, "reloftype");
4232
4233         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4234         {
4235                 /*
4236                  * Arrange to fail instead of waiting forever for a table lock.
4237                  *
4238                  * NB: this coding assumes that the only queries issued within the
4239                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4240                  * applied to other things too.
4241                  */
4242                 resetPQExpBuffer(query);
4243                 appendPQExpBuffer(query, "SET statement_timeout = ");
4244                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4245                 ExecuteSqlStatement(fout, query->data);
4246         }
4247
4248         for (i = 0; i < ntups; i++)
4249         {
4250                 tblinfo[i].dobj.objType = DO_TABLE;
4251                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4252                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4253                 AssignDumpId(&tblinfo[i].dobj);
4254                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4255                 tblinfo[i].dobj.namespace =
4256                         findNamespace(fout,
4257                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4258                                                   tblinfo[i].dobj.catId.oid);
4259                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4260                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4261                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4262                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4263                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4264                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4265                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4266                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4267                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4268                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4269                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4270                 if (PQgetisnull(res, i, i_reloftype))
4271                         tblinfo[i].reloftype = NULL;
4272                 else
4273                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4274                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4275                 if (PQgetisnull(res, i, i_owning_tab))
4276                 {
4277                         tblinfo[i].owning_tab = InvalidOid;
4278                         tblinfo[i].owning_col = 0;
4279                 }
4280                 else
4281                 {
4282                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4283                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4284                 }
4285                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4286                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4287                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4288
4289                 /* other fields were zeroed above */
4290
4291                 /*
4292                  * Decide whether we want to dump this table.
4293                  */
4294                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4295                         tblinfo[i].dobj.dump = false;
4296                 else
4297                         selectDumpableTable(&tblinfo[i]);
4298                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4299
4300                 /*
4301                  * Read-lock target tables to make sure they aren't DROPPED or altered
4302                  * in schema before we get around to dumping them.
4303                  *
4304                  * Note that we don't explicitly lock parents of the target tables; we
4305                  * assume our lock on the child is enough to prevent schema
4306                  * alterations to parent tables.
4307                  *
4308                  * NOTE: it'd be kinda nice to lock other relations too, not only
4309                  * plain tables, but the backend doesn't presently allow that.
4310                  */
4311                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4312                 {
4313                         resetPQExpBuffer(query);
4314                         appendPQExpBuffer(query,
4315                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4316                                                           fmtQualifiedId(fout,
4317                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4318                                                                                          tblinfo[i].dobj.name));
4319                         ExecuteSqlStatement(fout, query->data);
4320                 }
4321
4322                 /* Emit notice if join for owner failed */
4323                 if (strlen(tblinfo[i].rolname) == 0)
4324                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4325                                           tblinfo[i].dobj.name);
4326         }
4327
4328         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4329         {
4330                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4331         }
4332
4333         PQclear(res);
4334
4335         destroyPQExpBuffer(query);
4336
4337         return tblinfo;
4338 }
4339
4340 /*
4341  * getOwnedSeqs
4342  *        identify owned sequences and mark them as dumpable if owning table is
4343  *
4344  * We used to do this in getTables(), but it's better to do it after the
4345  * index used by findTableByOid() has been set up.
4346  */
4347 void
4348 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4349 {
4350         int                     i;
4351
4352         /*
4353          * Force sequences that are "owned" by table columns to be dumped whenever
4354          * their owning table is being dumped.
4355          */
4356         for (i = 0; i < numTables; i++)
4357         {
4358                 TableInfo  *seqinfo = &tblinfo[i];
4359                 TableInfo  *owning_tab;
4360
4361                 if (!OidIsValid(seqinfo->owning_tab))
4362                         continue;                       /* not an owned sequence */
4363                 if (seqinfo->dobj.dump)
4364                         continue;                       /* no need to search */
4365                 owning_tab = findTableByOid(seqinfo->owning_tab);
4366                 if (owning_tab && owning_tab->dobj.dump)
4367                 {
4368                         seqinfo->interesting = true;
4369                         seqinfo->dobj.dump = true;
4370                 }
4371         }
4372 }
4373
4374 /*
4375  * getInherits
4376  *        read all the inheritance information
4377  * from the system catalogs return them in the InhInfo* structure
4378  *
4379  * numInherits is set to the number of pairs read in
4380  */
4381 InhInfo *
4382 getInherits(Archive *fout, int *numInherits)
4383 {
4384         PGresult   *res;
4385         int                     ntups;
4386         int                     i;
4387         PQExpBuffer query = createPQExpBuffer();
4388         InhInfo    *inhinfo;
4389
4390         int                     i_inhrelid;
4391         int                     i_inhparent;
4392
4393         /* Make sure we are in proper schema */
4394         selectSourceSchema(fout, "pg_catalog");
4395
4396         /* find all the inheritance information */
4397
4398         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4399
4400         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4401
4402         ntups = PQntuples(res);
4403
4404         *numInherits = ntups;
4405
4406         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4407
4408         i_inhrelid = PQfnumber(res, "inhrelid");
4409         i_inhparent = PQfnumber(res, "inhparent");
4410
4411         for (i = 0; i < ntups; i++)
4412         {
4413                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4414                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4415         }
4416
4417         PQclear(res);
4418
4419         destroyPQExpBuffer(query);
4420
4421         return inhinfo;
4422 }
4423
4424 /*
4425  * getIndexes
4426  *        get information about every index on a dumpable table
4427  *
4428  * Note: index data is not returned directly to the caller, but it
4429  * does get entered into the DumpableObject tables.
4430  */
4431 void
4432 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4433 {
4434         int                     i,
4435                                 j;
4436         PQExpBuffer query = createPQExpBuffer();
4437         PGresult   *res;
4438         IndxInfo   *indxinfo;
4439         ConstraintInfo *constrinfo;
4440         int                     i_tableoid,
4441                                 i_oid,
4442                                 i_indexname,
4443                                 i_indexdef,
4444                                 i_indnkeys,
4445                                 i_indkey,
4446                                 i_indisclustered,
4447                                 i_contype,
4448                                 i_conname,
4449                                 i_condeferrable,
4450                                 i_condeferred,
4451                                 i_contableoid,
4452                                 i_conoid,
4453                                 i_condef,
4454                                 i_tablespace,
4455                                 i_options;
4456         int                     ntups;
4457
4458         for (i = 0; i < numTables; i++)
4459         {
4460                 TableInfo  *tbinfo = &tblinfo[i];
4461
4462                 /* Only plain tables have indexes */
4463                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
4464                         continue;
4465
4466                 /* Ignore indexes of tables not to be dumped */
4467                 if (!tbinfo->dobj.dump)
4468                         continue;
4469
4470                 if (g_verbose)
4471                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4472                                           tbinfo->dobj.name);
4473
4474                 /* Make sure we are in proper schema so indexdef is right */
4475                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4476
4477                 /*
4478                  * The point of the messy-looking outer join is to find a constraint
4479                  * that is related by an internal dependency link to the index. If we
4480                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4481                  * assume an index won't have more than one internal dependency.
4482                  *
4483                  * As of 9.0 we don't need to look at pg_depend but can check for a
4484                  * match to pg_constraint.conindid.  The check on conrelid is
4485                  * redundant but useful because that column is indexed while conindid
4486                  * is not.
4487                  */
4488                 resetPQExpBuffer(query);
4489                 if (fout->remoteVersion >= 90000)
4490                 {
4491                         appendPQExpBuffer(query,
4492                                                           "SELECT t.tableoid, t.oid, "
4493                                                           "t.relname AS indexname, "
4494                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4495                                                           "t.relnatts AS indnkeys, "
4496                                                           "i.indkey, i.indisclustered, "
4497                                                           "c.contype, c.conname, "
4498                                                           "c.condeferrable, c.condeferred, "
4499                                                           "c.tableoid AS contableoid, "
4500                                                           "c.oid AS conoid, "
4501                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4502                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4503                                                         "array_to_string(t.reloptions, ', ') AS options "
4504                                                           "FROM pg_catalog.pg_index i "
4505                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4506                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4507                                                           "ON (i.indrelid = c.conrelid AND "
4508                                                           "i.indexrelid = c.conindid AND "
4509                                                           "c.contype IN ('p','u','x')) "
4510                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4511                                                           "ORDER BY indexname",
4512                                                           tbinfo->dobj.catId.oid);
4513                 }
4514                 else if (fout->remoteVersion >= 80200)
4515                 {
4516                         appendPQExpBuffer(query,
4517                                                           "SELECT t.tableoid, t.oid, "
4518                                                           "t.relname AS indexname, "
4519                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4520                                                           "t.relnatts AS indnkeys, "
4521                                                           "i.indkey, i.indisclustered, "
4522                                                           "c.contype, c.conname, "
4523                                                           "c.condeferrable, c.condeferred, "
4524                                                           "c.tableoid AS contableoid, "
4525                                                           "c.oid AS conoid, "
4526                                                           "null AS condef, "
4527                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4528                                                         "array_to_string(t.reloptions, ', ') AS options "
4529                                                           "FROM pg_catalog.pg_index i "
4530                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4531                                                           "LEFT JOIN pg_catalog.pg_depend d "
4532                                                           "ON (d.classid = t.tableoid "
4533                                                           "AND d.objid = t.oid "
4534                                                           "AND d.deptype = 'i') "
4535                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4536                                                           "ON (d.refclassid = c.tableoid "
4537                                                           "AND d.refobjid = c.oid) "
4538                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4539                                                           "ORDER BY indexname",
4540                                                           tbinfo->dobj.catId.oid);
4541                 }
4542                 else if (fout->remoteVersion >= 80000)
4543                 {
4544                         appendPQExpBuffer(query,
4545                                                           "SELECT t.tableoid, t.oid, "
4546                                                           "t.relname AS indexname, "
4547                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4548                                                           "t.relnatts AS indnkeys, "
4549                                                           "i.indkey, i.indisclustered, "
4550                                                           "c.contype, c.conname, "
4551                                                           "c.condeferrable, c.condeferred, "
4552                                                           "c.tableoid AS contableoid, "
4553                                                           "c.oid AS conoid, "
4554                                                           "null AS condef, "
4555                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4556                                                           "null AS options "
4557                                                           "FROM pg_catalog.pg_index i "
4558                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4559                                                           "LEFT JOIN pg_catalog.pg_depend d "
4560                                                           "ON (d.classid = t.tableoid "
4561                                                           "AND d.objid = t.oid "
4562                                                           "AND d.deptype = 'i') "
4563                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4564                                                           "ON (d.refclassid = c.tableoid "
4565                                                           "AND d.refobjid = c.oid) "
4566                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4567                                                           "ORDER BY indexname",
4568                                                           tbinfo->dobj.catId.oid);
4569                 }
4570                 else if (fout->remoteVersion >= 70300)
4571                 {
4572                         appendPQExpBuffer(query,
4573                                                           "SELECT t.tableoid, t.oid, "
4574                                                           "t.relname AS indexname, "
4575                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4576                                                           "t.relnatts AS indnkeys, "
4577                                                           "i.indkey, i.indisclustered, "
4578                                                           "c.contype, c.conname, "
4579                                                           "c.condeferrable, c.condeferred, "
4580                                                           "c.tableoid AS contableoid, "
4581                                                           "c.oid AS conoid, "
4582                                                           "null AS condef, "
4583                                                           "NULL AS tablespace, "
4584                                                           "null AS options "
4585                                                           "FROM pg_catalog.pg_index i "
4586                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4587                                                           "LEFT JOIN pg_catalog.pg_depend d "
4588                                                           "ON (d.classid = t.tableoid "
4589                                                           "AND d.objid = t.oid "
4590                                                           "AND d.deptype = 'i') "
4591                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4592                                                           "ON (d.refclassid = c.tableoid "
4593                                                           "AND d.refobjid = c.oid) "
4594                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4595                                                           "ORDER BY indexname",
4596                                                           tbinfo->dobj.catId.oid);
4597                 }
4598                 else if (fout->remoteVersion >= 70100)
4599                 {
4600                         appendPQExpBuffer(query,
4601                                                           "SELECT t.tableoid, t.oid, "
4602                                                           "t.relname AS indexname, "
4603                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4604                                                           "t.relnatts AS indnkeys, "
4605                                                           "i.indkey, false AS indisclustered, "
4606                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4607                                                           "ELSE '0'::char END AS contype, "
4608                                                           "t.relname AS conname, "
4609                                                           "false AS condeferrable, "
4610                                                           "false AS condeferred, "
4611                                                           "0::oid AS contableoid, "
4612                                                           "t.oid AS conoid, "
4613                                                           "null AS condef, "
4614                                                           "NULL AS tablespace, "
4615                                                           "null AS options "
4616                                                           "FROM pg_index i, pg_class t "
4617                                                           "WHERE t.oid = i.indexrelid "
4618                                                           "AND i.indrelid = '%u'::oid "
4619                                                           "ORDER BY indexname",
4620                                                           tbinfo->dobj.catId.oid);
4621                 }
4622                 else
4623                 {
4624                         appendPQExpBuffer(query,
4625                                                           "SELECT "
4626                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4627                                                           "t.oid, "
4628                                                           "t.relname AS indexname, "
4629                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4630                                                           "t.relnatts AS indnkeys, "
4631                                                           "i.indkey, false AS indisclustered, "
4632                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4633                                                           "ELSE '0'::char END AS contype, "
4634                                                           "t.relname AS conname, "
4635                                                           "false AS condeferrable, "
4636                                                           "false AS condeferred, "
4637                                                           "0::oid AS contableoid, "
4638                                                           "t.oid AS conoid, "
4639                                                           "null AS condef, "
4640                                                           "NULL AS tablespace, "
4641                                                           "null AS options "
4642                                                           "FROM pg_index i, pg_class t "
4643                                                           "WHERE t.oid = i.indexrelid "
4644                                                           "AND i.indrelid = '%u'::oid "
4645                                                           "ORDER BY indexname",
4646                                                           tbinfo->dobj.catId.oid);
4647                 }
4648
4649                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4650
4651                 ntups = PQntuples(res);
4652
4653                 i_tableoid = PQfnumber(res, "tableoid");
4654                 i_oid = PQfnumber(res, "oid");
4655                 i_indexname = PQfnumber(res, "indexname");
4656                 i_indexdef = PQfnumber(res, "indexdef");
4657                 i_indnkeys = PQfnumber(res, "indnkeys");
4658                 i_indkey = PQfnumber(res, "indkey");
4659                 i_indisclustered = PQfnumber(res, "indisclustered");
4660                 i_contype = PQfnumber(res, "contype");
4661                 i_conname = PQfnumber(res, "conname");
4662                 i_condeferrable = PQfnumber(res, "condeferrable");
4663                 i_condeferred = PQfnumber(res, "condeferred");
4664                 i_contableoid = PQfnumber(res, "contableoid");
4665                 i_conoid = PQfnumber(res, "conoid");
4666                 i_condef = PQfnumber(res, "condef");
4667                 i_tablespace = PQfnumber(res, "tablespace");
4668                 i_options = PQfnumber(res, "options");
4669
4670                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
4671                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4672
4673                 for (j = 0; j < ntups; j++)
4674                 {
4675                         char            contype;
4676
4677                         indxinfo[j].dobj.objType = DO_INDEX;
4678                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4679                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4680                         AssignDumpId(&indxinfo[j].dobj);
4681                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
4682                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4683                         indxinfo[j].indextable = tbinfo;
4684                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
4685                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
4686                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
4687                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
4688
4689                         /*
4690                          * In pre-7.4 releases, indkeys may contain more entries than
4691                          * indnkeys says (since indnkeys will be 1 for a functional
4692                          * index).      We don't actually care about this case since we don't
4693                          * examine indkeys except for indexes associated with PRIMARY and
4694                          * UNIQUE constraints, which are never functional indexes. But we
4695                          * have to allocate enough space to keep parseOidArray from
4696                          * complaining.
4697                          */
4698                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
4699                         parseOidArray(PQgetvalue(res, j, i_indkey),
4700                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
4701                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4702                         contype = *(PQgetvalue(res, j, i_contype));
4703
4704                         if (contype == 'p' || contype == 'u' || contype == 'x')
4705                         {
4706                                 /*
4707                                  * If we found a constraint matching the index, create an
4708                                  * entry for it.
4709                                  *
4710                                  * In a pre-7.3 database, we take this path iff the index was
4711                                  * marked indisprimary.
4712                                  */
4713                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
4714                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4715                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4716                                 AssignDumpId(&constrinfo[j].dobj);
4717                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4718                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4719                                 constrinfo[j].contable = tbinfo;
4720                                 constrinfo[j].condomain = NULL;
4721                                 constrinfo[j].contype = contype;
4722                                 if (contype == 'x')
4723                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4724                                 else
4725                                         constrinfo[j].condef = NULL;
4726                                 constrinfo[j].confrelid = InvalidOid;
4727                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
4728                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
4729                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
4730                                 constrinfo[j].conislocal = true;
4731                                 constrinfo[j].separate = true;
4732
4733                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
4734
4735                                 /* If pre-7.3 DB, better make sure table comes first */
4736                                 addObjectDependency(&constrinfo[j].dobj,
4737                                                                         tbinfo->dobj.dumpId);
4738                         }
4739                         else
4740                         {
4741                                 /* Plain secondary index */
4742                                 indxinfo[j].indexconstraint = 0;
4743                         }
4744                 }
4745
4746                 PQclear(res);
4747         }
4748
4749         destroyPQExpBuffer(query);
4750 }
4751
4752 /*
4753  * getConstraints
4754  *
4755  * Get info about constraints on dumpable tables.
4756  *
4757  * Currently handles foreign keys only.
4758  * Unique and primary key constraints are handled with indexes,
4759  * while check constraints are processed in getTableAttrs().
4760  */
4761 void
4762 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
4763 {
4764         int                     i,
4765                                 j;
4766         ConstraintInfo *constrinfo;
4767         PQExpBuffer query;
4768         PGresult   *res;
4769         int                     i_contableoid,
4770                                 i_conoid,
4771                                 i_conname,
4772                                 i_confrelid,
4773                                 i_condef;
4774         int                     ntups;
4775
4776         /* pg_constraint was created in 7.3, so nothing to do if older */
4777         if (fout->remoteVersion < 70300)
4778                 return;
4779
4780         query = createPQExpBuffer();
4781
4782         for (i = 0; i < numTables; i++)
4783         {
4784                 TableInfo  *tbinfo = &tblinfo[i];
4785
4786                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4787                         continue;
4788
4789                 if (g_verbose)
4790                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
4791                                           tbinfo->dobj.name);
4792
4793                 /*
4794                  * select table schema to ensure constraint expr is qualified if
4795                  * needed
4796                  */
4797                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4798
4799                 resetPQExpBuffer(query);
4800                 appendPQExpBuffer(query,
4801                                                   "SELECT tableoid, oid, conname, confrelid, "
4802                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
4803                                                   "FROM pg_catalog.pg_constraint "
4804                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4805                                                   "AND contype = 'f'",
4806                                                   tbinfo->dobj.catId.oid);
4807                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4808
4809                 ntups = PQntuples(res);
4810
4811                 i_contableoid = PQfnumber(res, "tableoid");
4812                 i_conoid = PQfnumber(res, "oid");
4813                 i_conname = PQfnumber(res, "conname");
4814                 i_confrelid = PQfnumber(res, "confrelid");
4815                 i_condef = PQfnumber(res, "condef");
4816
4817                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4818
4819                 for (j = 0; j < ntups; j++)
4820                 {
4821                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
4822                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4823                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4824                         AssignDumpId(&constrinfo[j].dobj);
4825                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4826                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4827                         constrinfo[j].contable = tbinfo;
4828                         constrinfo[j].condomain = NULL;
4829                         constrinfo[j].contype = 'f';
4830                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4831                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
4832                         constrinfo[j].conindex = 0;
4833                         constrinfo[j].condeferrable = false;
4834                         constrinfo[j].condeferred = false;
4835                         constrinfo[j].conislocal = true;
4836                         constrinfo[j].separate = true;
4837                 }
4838
4839                 PQclear(res);
4840         }
4841
4842         destroyPQExpBuffer(query);
4843 }
4844
4845 /*
4846  * getDomainConstraints
4847  *
4848  * Get info about constraints on a domain.
4849  */
4850 static void
4851 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
4852 {
4853         int                     i;
4854         ConstraintInfo *constrinfo;
4855         PQExpBuffer query;
4856         PGresult   *res;
4857         int                     i_tableoid,
4858                                 i_oid,
4859                                 i_conname,
4860                                 i_consrc;
4861         int                     ntups;
4862
4863         /* pg_constraint was created in 7.3, so nothing to do if older */
4864         if (fout->remoteVersion < 70300)
4865                 return;
4866
4867         /*
4868          * select appropriate schema to ensure names in constraint are properly
4869          * qualified
4870          */
4871         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
4872
4873         query = createPQExpBuffer();
4874
4875         if (fout->remoteVersion >= 90100)
4876                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4877                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4878                                                   "convalidated "
4879                                                   "FROM pg_catalog.pg_constraint "
4880                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4881                                                   "ORDER BY conname",
4882                                                   tyinfo->dobj.catId.oid);
4883
4884         else if (fout->remoteVersion >= 70400)
4885                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4886                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4887                                                   "true as convalidated "
4888                                                   "FROM pg_catalog.pg_constraint "
4889                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4890                                                   "ORDER BY conname",
4891                                                   tyinfo->dobj.catId.oid);
4892         else
4893                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4894                                                   "'CHECK (' || consrc || ')' AS consrc, "
4895                                                   "true as convalidated "
4896                                                   "FROM pg_catalog.pg_constraint "
4897                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4898                                                   "ORDER BY conname",
4899                                                   tyinfo->dobj.catId.oid);
4900
4901         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4902
4903         ntups = PQntuples(res);
4904
4905         i_tableoid = PQfnumber(res, "tableoid");
4906         i_oid = PQfnumber(res, "oid");
4907         i_conname = PQfnumber(res, "conname");
4908         i_consrc = PQfnumber(res, "consrc");
4909
4910         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4911
4912         tyinfo->nDomChecks = ntups;
4913         tyinfo->domChecks = constrinfo;
4914
4915         for (i = 0; i < ntups; i++)
4916         {
4917                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
4918
4919                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4920                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4921                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4922                 AssignDumpId(&constrinfo[i].dobj);
4923                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4924                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
4925                 constrinfo[i].contable = NULL;
4926                 constrinfo[i].condomain = tyinfo;
4927                 constrinfo[i].contype = 'c';
4928                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
4929                 constrinfo[i].confrelid = InvalidOid;
4930                 constrinfo[i].conindex = 0;
4931                 constrinfo[i].condeferrable = false;
4932                 constrinfo[i].condeferred = false;
4933                 constrinfo[i].conislocal = true;
4934
4935                 constrinfo[i].separate = !validated;
4936
4937                 /*
4938                  * Make the domain depend on the constraint, ensuring it won't be
4939                  * output till any constraint dependencies are OK.      If the constraint
4940                  * has not been validated, it's going to be dumped after the domain
4941                  * anyway, so this doesn't matter.
4942                  */
4943                 if (validated)
4944                         addObjectDependency(&tyinfo->dobj,
4945                                                                 constrinfo[i].dobj.dumpId);
4946         }
4947
4948         PQclear(res);
4949
4950         destroyPQExpBuffer(query);
4951 }
4952
4953 /*
4954  * getRules
4955  *        get basic information about every rule in the system
4956  *
4957  * numRules is set to the number of rules read in
4958  */
4959 RuleInfo *
4960 getRules(Archive *fout, int *numRules)
4961 {
4962         PGresult   *res;
4963         int                     ntups;
4964         int                     i;
4965         PQExpBuffer query = createPQExpBuffer();
4966         RuleInfo   *ruleinfo;
4967         int                     i_tableoid;
4968         int                     i_oid;
4969         int                     i_rulename;
4970         int                     i_ruletable;
4971         int                     i_ev_type;
4972         int                     i_is_instead;
4973         int                     i_ev_enabled;
4974
4975         /* Make sure we are in proper schema */
4976         selectSourceSchema(fout, "pg_catalog");
4977
4978         if (fout->remoteVersion >= 80300)
4979         {
4980                 appendPQExpBuffer(query, "SELECT "
4981                                                   "tableoid, oid, rulename, "
4982                                                   "ev_class AS ruletable, ev_type, is_instead, "
4983                                                   "ev_enabled "
4984                                                   "FROM pg_rewrite "
4985                                                   "ORDER BY oid");
4986         }
4987         else if (fout->remoteVersion >= 70100)
4988         {
4989                 appendPQExpBuffer(query, "SELECT "
4990                                                   "tableoid, oid, rulename, "
4991                                                   "ev_class AS ruletable, ev_type, is_instead, "
4992                                                   "'O'::char AS ev_enabled "
4993                                                   "FROM pg_rewrite "
4994                                                   "ORDER BY oid");
4995         }
4996         else
4997         {
4998                 appendPQExpBuffer(query, "SELECT "
4999                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5000                                                   "oid, rulename, "
5001                                                   "ev_class AS ruletable, ev_type, is_instead, "
5002                                                   "'O'::char AS ev_enabled "
5003                                                   "FROM pg_rewrite "
5004                                                   "ORDER BY oid");
5005         }
5006
5007         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5008
5009         ntups = PQntuples(res);
5010
5011         *numRules = ntups;
5012
5013         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5014
5015         i_tableoid = PQfnumber(res, "tableoid");
5016         i_oid = PQfnumber(res, "oid");
5017         i_rulename = PQfnumber(res, "rulename");
5018         i_ruletable = PQfnumber(res, "ruletable");
5019         i_ev_type = PQfnumber(res, "ev_type");
5020         i_is_instead = PQfnumber(res, "is_instead");
5021         i_ev_enabled = PQfnumber(res, "ev_enabled");
5022
5023         for (i = 0; i < ntups; i++)
5024         {
5025                 Oid                     ruletableoid;
5026
5027                 ruleinfo[i].dobj.objType = DO_RULE;
5028                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5029                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5030                 AssignDumpId(&ruleinfo[i].dobj);
5031                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5032                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5033                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5034                 if (ruleinfo[i].ruletable == NULL)
5035                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5036                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5037                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5038                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5039                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5040                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5041                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5042                 if (ruleinfo[i].ruletable)
5043                 {
5044                         /*
5045                          * If the table is a view, force its ON SELECT rule to be sorted
5046                          * before the view itself --- this ensures that any dependencies
5047                          * for the rule affect the table's positioning. Other rules are
5048                          * forced to appear after their table.
5049                          */
5050                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
5051                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5052                         {
5053                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5054                                                                         ruleinfo[i].dobj.dumpId);
5055                                 /* We'll merge the rule into CREATE VIEW, if possible */
5056                                 ruleinfo[i].separate = false;
5057                         }
5058                         else
5059                         {
5060                                 addObjectDependency(&ruleinfo[i].dobj,
5061                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5062                                 ruleinfo[i].separate = true;
5063                         }
5064                 }
5065                 else
5066                         ruleinfo[i].separate = true;
5067
5068                 /*
5069                  * If we're forced to break a dependency loop by dumping a view as a
5070                  * table and separate _RETURN rule, we'll move the view's reloptions
5071                  * to the rule.  (This is necessary because tables and views have
5072                  * different valid reloptions, so we can't apply the options until the
5073                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5074                  * NULL.
5075                  */
5076                 ruleinfo[i].reloptions = NULL;
5077         }
5078
5079         PQclear(res);
5080
5081         destroyPQExpBuffer(query);
5082
5083         return ruleinfo;
5084 }
5085
5086 /*
5087  * getTriggers
5088  *        get information about every trigger on a dumpable table
5089  *
5090  * Note: trigger data is not returned directly to the caller, but it
5091  * does get entered into the DumpableObject tables.
5092  */
5093 void
5094 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5095 {
5096         int                     i,
5097                                 j;
5098         PQExpBuffer query = createPQExpBuffer();
5099         PGresult   *res;
5100         TriggerInfo *tginfo;
5101         int                     i_tableoid,
5102                                 i_oid,
5103                                 i_tgname,
5104                                 i_tgfname,
5105                                 i_tgtype,
5106                                 i_tgnargs,
5107                                 i_tgargs,
5108                                 i_tgisconstraint,
5109                                 i_tgconstrname,
5110                                 i_tgconstrrelid,
5111                                 i_tgconstrrelname,
5112                                 i_tgenabled,
5113                                 i_tgdeferrable,
5114                                 i_tginitdeferred,
5115                                 i_tgdef;
5116         int                     ntups;
5117
5118         for (i = 0; i < numTables; i++)
5119         {
5120                 TableInfo  *tbinfo = &tblinfo[i];
5121
5122                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5123                         continue;
5124
5125                 if (g_verbose)
5126                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5127                                           tbinfo->dobj.name);
5128
5129                 /*
5130                  * select table schema to ensure regproc name is qualified if needed
5131                  */
5132                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5133
5134                 resetPQExpBuffer(query);
5135                 if (fout->remoteVersion >= 90000)
5136                 {
5137                         /*
5138                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5139                          * could result in non-forward-compatible dumps of WHEN clauses
5140                          * due to under-parenthesization.
5141                          */
5142                         appendPQExpBuffer(query,
5143                                                           "SELECT tgname, "
5144                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5145                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5146                                                           "tgenabled, tableoid, oid "
5147                                                           "FROM pg_catalog.pg_trigger t "
5148                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5149                                                           "AND NOT tgisinternal",
5150                                                           tbinfo->dobj.catId.oid);
5151                 }
5152                 else if (fout->remoteVersion >= 80300)
5153                 {
5154                         /*
5155                          * We ignore triggers that are tied to a foreign-key constraint
5156                          */
5157                         appendPQExpBuffer(query,
5158                                                           "SELECT tgname, "
5159                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5160                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5161                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5162                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5163                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5164                                                           "FROM pg_catalog.pg_trigger t "
5165                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5166                                                           "AND tgconstraint = 0",
5167                                                           tbinfo->dobj.catId.oid);
5168                 }
5169                 else if (fout->remoteVersion >= 70300)
5170                 {
5171                         /*
5172                          * We ignore triggers that are tied to a foreign-key constraint,
5173                          * but in these versions we have to grovel through pg_constraint
5174                          * to find out
5175                          */
5176                         appendPQExpBuffer(query,
5177                                                           "SELECT tgname, "
5178                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5179                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5180                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5181                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5182                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5183                                                           "FROM pg_catalog.pg_trigger t "
5184                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5185                                                           "AND (NOT tgisconstraint "
5186                                                           " OR NOT EXISTS"
5187                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5188                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5189                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5190                                                           tbinfo->dobj.catId.oid);
5191                 }
5192                 else if (fout->remoteVersion >= 70100)
5193                 {
5194                         appendPQExpBuffer(query,
5195                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5196                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5197                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5198                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5199                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5200                                                           "             AS tgconstrrelname "
5201                                                           "FROM pg_trigger "
5202                                                           "WHERE tgrelid = '%u'::oid",
5203                                                           tbinfo->dobj.catId.oid);
5204                 }
5205                 else
5206                 {
5207                         appendPQExpBuffer(query,
5208                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5209                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5210                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5211                                                           "tgconstrrelid, tginitdeferred, "
5212                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5213                                                           "oid, "
5214                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5215                                                           "             AS tgconstrrelname "
5216                                                           "FROM pg_trigger "
5217                                                           "WHERE tgrelid = '%u'::oid",
5218                                                           tbinfo->dobj.catId.oid);
5219                 }
5220                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5221
5222                 ntups = PQntuples(res);
5223
5224                 i_tableoid = PQfnumber(res, "tableoid");
5225                 i_oid = PQfnumber(res, "oid");
5226                 i_tgname = PQfnumber(res, "tgname");
5227                 i_tgfname = PQfnumber(res, "tgfname");
5228                 i_tgtype = PQfnumber(res, "tgtype");
5229                 i_tgnargs = PQfnumber(res, "tgnargs");
5230                 i_tgargs = PQfnumber(res, "tgargs");
5231                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5232                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5233                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5234                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5235                 i_tgenabled = PQfnumber(res, "tgenabled");
5236                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5237                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5238                 i_tgdef = PQfnumber(res, "tgdef");
5239
5240                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5241
5242                 for (j = 0; j < ntups; j++)
5243                 {
5244                         tginfo[j].dobj.objType = DO_TRIGGER;
5245                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5246                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5247                         AssignDumpId(&tginfo[j].dobj);
5248                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5249                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5250                         tginfo[j].tgtable = tbinfo;
5251                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5252                         if (i_tgdef >= 0)
5253                         {
5254                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5255
5256                                 /* remaining fields are not valid if we have tgdef */
5257                                 tginfo[j].tgfname = NULL;
5258                                 tginfo[j].tgtype = 0;
5259                                 tginfo[j].tgnargs = 0;
5260                                 tginfo[j].tgargs = NULL;
5261                                 tginfo[j].tgisconstraint = false;
5262                                 tginfo[j].tgdeferrable = false;
5263                                 tginfo[j].tginitdeferred = false;
5264                                 tginfo[j].tgconstrname = NULL;
5265                                 tginfo[j].tgconstrrelid = InvalidOid;
5266                                 tginfo[j].tgconstrrelname = NULL;
5267                         }
5268                         else
5269                         {
5270                                 tginfo[j].tgdef = NULL;
5271
5272                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5273                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5274                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5275                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5276                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5277                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5278                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5279
5280                                 if (tginfo[j].tgisconstraint)
5281                                 {
5282                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5283                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5284                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5285                                         {
5286                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5287                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5288                                                                                   tginfo[j].dobj.name,
5289                                                                                   tbinfo->dobj.name,
5290                                                                                   tginfo[j].tgconstrrelid);
5291                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5292                                         }
5293                                         else
5294                                                 tginfo[j].tgconstrrelname = NULL;
5295                                 }
5296                                 else
5297                                 {
5298                                         tginfo[j].tgconstrname = NULL;
5299                                         tginfo[j].tgconstrrelid = InvalidOid;
5300                                         tginfo[j].tgconstrrelname = NULL;
5301                                 }
5302                         }
5303                 }
5304
5305                 PQclear(res);
5306         }
5307
5308         destroyPQExpBuffer(query);
5309 }
5310
5311 /*
5312  * getEventTriggers
5313  *        get information about event triggers
5314  */
5315 EventTriggerInfo *
5316 getEventTriggers(Archive *fout, int *numEventTriggers)
5317 {
5318         int                     i;
5319         PQExpBuffer query = createPQExpBuffer();
5320         PGresult   *res;
5321         EventTriggerInfo *evtinfo;
5322         int                     i_tableoid,
5323                                 i_oid,
5324                                 i_evtname,
5325                                 i_evtevent,
5326                                 i_evtowner,
5327                                 i_evttags,
5328                                 i_evtfname,
5329                                 i_evtenabled;
5330         int                     ntups;
5331
5332         /* Before 9.3, there are no event triggers */
5333         if (fout->remoteVersion < 90300)
5334         {
5335                 *numEventTriggers = 0;
5336                 return NULL;
5337         }
5338
5339         /* Make sure we are in proper schema */
5340         selectSourceSchema(fout, "pg_catalog");
5341
5342         appendPQExpBuffer(query,
5343                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5344                                           "evtevent, (%s evtowner) AS evtowner, "
5345                                           "array_to_string(array("
5346                                           "select quote_literal(x) "
5347                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5348                                           "e.evtfoid::regproc as evtfname "
5349                                           "FROM pg_event_trigger e "
5350                                           "ORDER BY e.oid",
5351                                           username_subquery);
5352
5353         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5354
5355         ntups = PQntuples(res);
5356
5357         *numEventTriggers = ntups;
5358
5359         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5360
5361         i_tableoid = PQfnumber(res, "tableoid");
5362         i_oid = PQfnumber(res, "oid");
5363         i_evtname = PQfnumber(res, "evtname");
5364         i_evtevent = PQfnumber(res, "evtevent");
5365         i_evtowner = PQfnumber(res, "evtowner");
5366         i_evttags = PQfnumber(res, "evttags");
5367         i_evtfname = PQfnumber(res, "evtfname");
5368         i_evtenabled = PQfnumber(res, "evtenabled");
5369
5370         for (i = 0; i < ntups; i++)
5371         {
5372                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5373                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5374                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5375                 AssignDumpId(&evtinfo[i].dobj);
5376                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5377                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5378                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5379                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5380                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5381                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5382                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5383         }
5384
5385         PQclear(res);
5386
5387         destroyPQExpBuffer(query);
5388
5389         return evtinfo;
5390 }
5391
5392 /*
5393  * getProcLangs
5394  *        get basic information about every procedural language in the system
5395  *
5396  * numProcLangs is set to the number of langs read in
5397  *
5398  * NB: this must run after getFuncs() because we assume we can do
5399  * findFuncByOid().
5400  */
5401 ProcLangInfo *
5402 getProcLangs(Archive *fout, int *numProcLangs)
5403 {
5404         PGresult   *res;
5405         int                     ntups;
5406         int                     i;
5407         PQExpBuffer query = createPQExpBuffer();
5408         ProcLangInfo *planginfo;
5409         int                     i_tableoid;
5410         int                     i_oid;
5411         int                     i_lanname;
5412         int                     i_lanpltrusted;
5413         int                     i_lanplcallfoid;
5414         int                     i_laninline;
5415         int                     i_lanvalidator;
5416         int                     i_lanacl;
5417         int                     i_lanowner;
5418
5419         /* Make sure we are in proper schema */
5420         selectSourceSchema(fout, "pg_catalog");
5421
5422         if (fout->remoteVersion >= 90000)
5423         {
5424                 /* pg_language has a laninline column */
5425                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5426                                                   "lanname, lanpltrusted, lanplcallfoid, "
5427                                                   "laninline, lanvalidator,  lanacl, "
5428                                                   "(%s lanowner) AS lanowner "
5429                                                   "FROM pg_language "
5430                                                   "WHERE lanispl "
5431                                                   "ORDER BY oid",
5432                                                   username_subquery);
5433         }
5434         else if (fout->remoteVersion >= 80300)
5435         {
5436                 /* pg_language has a lanowner column */
5437                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5438                                                   "lanname, lanpltrusted, lanplcallfoid, "
5439                                                   "lanvalidator,  lanacl, "
5440                                                   "(%s lanowner) AS lanowner "
5441                                                   "FROM pg_language "
5442                                                   "WHERE lanispl "
5443                                                   "ORDER BY oid",
5444                                                   username_subquery);
5445         }
5446         else if (fout->remoteVersion >= 80100)
5447         {
5448                 /* Languages are owned by the bootstrap superuser, OID 10 */
5449                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5450                                                   "(%s '10') AS lanowner "
5451                                                   "FROM pg_language "
5452                                                   "WHERE lanispl "
5453                                                   "ORDER BY oid",
5454                                                   username_subquery);
5455         }
5456         else if (fout->remoteVersion >= 70400)
5457         {
5458                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5459                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5460                                                   "(%s '1') AS lanowner "
5461                                                   "FROM pg_language "
5462                                                   "WHERE lanispl "
5463                                                   "ORDER BY oid",
5464                                                   username_subquery);
5465         }
5466         else if (fout->remoteVersion >= 70100)
5467         {
5468                 /* No clear notion of an owner at all before 7.4 ... */
5469                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5470                                                   "WHERE lanispl "
5471                                                   "ORDER BY oid");
5472         }
5473         else
5474         {
5475                 appendPQExpBuffer(query, "SELECT "
5476                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5477                                                   "oid, * FROM pg_language "
5478                                                   "WHERE lanispl "
5479                                                   "ORDER BY oid");
5480         }
5481
5482         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5483
5484         ntups = PQntuples(res);
5485
5486         *numProcLangs = ntups;
5487
5488         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5489
5490         i_tableoid = PQfnumber(res, "tableoid");
5491         i_oid = PQfnumber(res, "oid");
5492         i_lanname = PQfnumber(res, "lanname");
5493         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5494         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5495         /* these may fail and return -1: */
5496         i_laninline = PQfnumber(res, "laninline");
5497         i_lanvalidator = PQfnumber(res, "lanvalidator");
5498         i_lanacl = PQfnumber(res, "lanacl");
5499         i_lanowner = PQfnumber(res, "lanowner");
5500
5501         for (i = 0; i < ntups; i++)
5502         {
5503                 planginfo[i].dobj.objType = DO_PROCLANG;
5504                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5505                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5506                 AssignDumpId(&planginfo[i].dobj);
5507
5508                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5509                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5510                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5511                 if (i_laninline >= 0)
5512                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5513                 else
5514                         planginfo[i].laninline = InvalidOid;
5515                 if (i_lanvalidator >= 0)
5516                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5517                 else
5518                         planginfo[i].lanvalidator = InvalidOid;
5519                 if (i_lanacl >= 0)
5520                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5521                 else
5522                         planginfo[i].lanacl = pg_strdup("{=U}");
5523                 if (i_lanowner >= 0)
5524                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5525                 else
5526                         planginfo[i].lanowner = pg_strdup("");
5527
5528                 if (fout->remoteVersion < 70300)
5529                 {
5530                         /*
5531                          * We need to make a dependency to ensure the function will be
5532                          * dumped first.  (In 7.3 and later the regular dependency
5533                          * mechanism will handle this for us.)
5534                          */
5535                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5536
5537                         if (funcInfo)
5538                                 addObjectDependency(&planginfo[i].dobj,
5539                                                                         funcInfo->dobj.dumpId);
5540                 }
5541         }
5542
5543         PQclear(res);
5544
5545         destroyPQExpBuffer(query);
5546
5547         return planginfo;
5548 }
5549
5550 /*
5551  * getCasts
5552  *        get basic information about every cast in the system
5553  *
5554  * numCasts is set to the number of casts read in
5555  */
5556 CastInfo *
5557 getCasts(Archive *fout, int *numCasts)
5558 {
5559         PGresult   *res;
5560         int                     ntups;
5561         int                     i;
5562         PQExpBuffer query = createPQExpBuffer();
5563         CastInfo   *castinfo;
5564         int                     i_tableoid;
5565         int                     i_oid;
5566         int                     i_castsource;
5567         int                     i_casttarget;
5568         int                     i_castfunc;
5569         int                     i_castcontext;
5570         int                     i_castmethod;
5571
5572         /* Make sure we are in proper schema */
5573         selectSourceSchema(fout, "pg_catalog");
5574
5575         if (fout->remoteVersion >= 80400)
5576         {
5577                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5578                                                   "castsource, casttarget, castfunc, castcontext, "
5579                                                   "castmethod "
5580                                                   "FROM pg_cast ORDER BY 3,4");
5581         }
5582         else if (fout->remoteVersion >= 70300)
5583         {
5584                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5585                                                   "castsource, casttarget, castfunc, castcontext, "
5586                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
5587                                                   "FROM pg_cast ORDER BY 3,4");
5588         }
5589         else
5590         {
5591                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
5592                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
5593                                                   "p.oid AS castfunc, 'e' AS castcontext, "
5594                                                   "'f' AS castmethod "
5595                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
5596                                                   "WHERE p.pronargs = 1 AND "
5597                                                   "p.proargtypes[0] = t1.oid AND "
5598                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
5599                                                   "ORDER BY 3,4");
5600         }
5601
5602         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5603
5604         ntups = PQntuples(res);
5605
5606         *numCasts = ntups;
5607
5608         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
5609
5610         i_tableoid = PQfnumber(res, "tableoid");
5611         i_oid = PQfnumber(res, "oid");
5612         i_castsource = PQfnumber(res, "castsource");
5613         i_casttarget = PQfnumber(res, "casttarget");
5614         i_castfunc = PQfnumber(res, "castfunc");
5615         i_castcontext = PQfnumber(res, "castcontext");
5616         i_castmethod = PQfnumber(res, "castmethod");
5617
5618         for (i = 0; i < ntups; i++)
5619         {
5620                 PQExpBufferData namebuf;
5621                 TypeInfo   *sTypeInfo;
5622                 TypeInfo   *tTypeInfo;
5623
5624                 castinfo[i].dobj.objType = DO_CAST;
5625                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5626                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5627                 AssignDumpId(&castinfo[i].dobj);
5628                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
5629                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
5630                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
5631                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
5632                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
5633
5634                 /*
5635                  * Try to name cast as concatenation of typnames.  This is only used
5636                  * for purposes of sorting.  If we fail to find either type, the name
5637                  * will be an empty string.
5638                  */
5639                 initPQExpBuffer(&namebuf);
5640                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
5641                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
5642                 if (sTypeInfo && tTypeInfo)
5643                         appendPQExpBuffer(&namebuf, "%s %s",
5644                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
5645                 castinfo[i].dobj.name = namebuf.data;
5646
5647                 if (OidIsValid(castinfo[i].castfunc))
5648                 {
5649                         /*
5650                          * We need to make a dependency to ensure the function will be
5651                          * dumped first.  (In 7.3 and later the regular dependency
5652                          * mechanism will handle this for us.)
5653                          */
5654                         FuncInfo   *funcInfo;
5655
5656                         funcInfo = findFuncByOid(castinfo[i].castfunc);
5657                         if (funcInfo)
5658                                 addObjectDependency(&castinfo[i].dobj,
5659                                                                         funcInfo->dobj.dumpId);
5660                 }
5661         }
5662
5663         PQclear(res);
5664
5665         destroyPQExpBuffer(query);
5666
5667         return castinfo;
5668 }
5669
5670 /*
5671  * getTableAttrs -
5672  *        for each interesting table, read info about its attributes
5673  *        (names, types, default values, CHECK constraints, etc)
5674  *
5675  * This is implemented in a very inefficient way right now, looping
5676  * through the tblinfo and doing a join per table to find the attrs and their
5677  * types.  However, because we want type names and so forth to be named
5678  * relative to the schema of each table, we couldn't do it in just one
5679  * query.  (Maybe one query per schema?)
5680  *
5681  *      modifies tblinfo
5682  */
5683 void
5684 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
5685 {
5686         int                     i,
5687                                 j;
5688         PQExpBuffer q = createPQExpBuffer();
5689         int                     i_attnum;
5690         int                     i_attname;
5691         int                     i_atttypname;
5692         int                     i_atttypmod;
5693         int                     i_attstattarget;
5694         int                     i_attstorage;
5695         int                     i_typstorage;
5696         int                     i_attnotnull;
5697         int                     i_atthasdef;
5698         int                     i_attisdropped;
5699         int                     i_attlen;
5700         int                     i_attalign;
5701         int                     i_attislocal;
5702         int                     i_attoptions;
5703         int                     i_attcollation;
5704         int                     i_attfdwoptions;
5705         PGresult   *res;
5706         int                     ntups;
5707         bool            hasdefaults;
5708
5709         for (i = 0; i < numTables; i++)
5710         {
5711                 TableInfo  *tbinfo = &tblinfo[i];
5712
5713                 /* Don't bother to collect info for sequences */
5714                 if (tbinfo->relkind == RELKIND_SEQUENCE)
5715                         continue;
5716
5717                 /* Don't bother with uninteresting tables, either */
5718                 if (!tbinfo->interesting)
5719                         continue;
5720
5721                 /*
5722                  * Make sure we are in proper schema for this table; this allows
5723                  * correct retrieval of formatted type names and default exprs
5724                  */
5725                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5726
5727                 /* find all the user attributes and their types */
5728
5729                 /*
5730                  * we must read the attribute names in attribute number order! because
5731                  * we will use the attnum to index into the attnames array later.  We
5732                  * actually ask to order by "attrelid, attnum" because (at least up to
5733                  * 7.3) the planner is not smart enough to realize it needn't re-sort
5734                  * the output of an indexscan on pg_attribute_relid_attnum_index.
5735                  */
5736                 if (g_verbose)
5737                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
5738                                           tbinfo->dobj.name);
5739
5740                 resetPQExpBuffer(q);
5741
5742                 if (fout->remoteVersion >= 90200)
5743                 {
5744                         /*
5745                          * attfdwoptions is new in 9.2.
5746                          */
5747                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5748                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5749                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5750                                                           "a.attlen, a.attalign, a.attislocal, "
5751                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5752                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5753                                                           "CASE WHEN a.attcollation <> t.typcollation "
5754                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
5755                                                           "pg_catalog.array_to_string(ARRAY("
5756                                                           "SELECT pg_catalog.quote_ident(option_name) || "
5757                                                           "' ' || pg_catalog.quote_literal(option_value) "
5758                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
5759                                                           "ORDER BY option_name"
5760                                                           "), E',\n    ') AS attfdwoptions "
5761                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5762                                                           "ON a.atttypid = t.oid "
5763                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5764                                                           "AND a.attnum > 0::pg_catalog.int2 "
5765                                                           "ORDER BY a.attrelid, a.attnum",
5766                                                           tbinfo->dobj.catId.oid);
5767                 }
5768                 else if (fout->remoteVersion >= 90100)
5769                 {
5770                         /*
5771                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
5772                          * clauses for attributes whose collation is different from their
5773                          * type's default, we use a CASE here to suppress uninteresting
5774                          * attcollations cheaply.
5775                          */
5776                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5777                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5778                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5779                                                           "a.attlen, a.attalign, a.attislocal, "
5780                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5781                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5782                                                           "CASE WHEN a.attcollation <> t.typcollation "
5783                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
5784                                                           "NULL AS attfdwoptions "
5785                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5786                                                           "ON a.atttypid = t.oid "
5787                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5788                                                           "AND a.attnum > 0::pg_catalog.int2 "
5789                                                           "ORDER BY a.attrelid, a.attnum",
5790                                                           tbinfo->dobj.catId.oid);
5791                 }
5792                 else if (fout->remoteVersion >= 90000)
5793                 {
5794                         /* attoptions is new in 9.0 */
5795                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5796                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5797                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5798                                                           "a.attlen, a.attalign, a.attislocal, "
5799                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5800                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5801                                                           "0 AS attcollation, "
5802                                                           "NULL AS attfdwoptions "
5803                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5804                                                           "ON a.atttypid = t.oid "
5805                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5806                                                           "AND a.attnum > 0::pg_catalog.int2 "
5807                                                           "ORDER BY a.attrelid, a.attnum",
5808                                                           tbinfo->dobj.catId.oid);
5809                 }
5810                 else if (fout->remoteVersion >= 70300)
5811                 {
5812                         /* need left join here to not fail on dropped columns ... */
5813                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5814                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5815                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5816                                                           "a.attlen, a.attalign, a.attislocal, "
5817                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5818                                                           "'' AS attoptions, 0 AS attcollation, "
5819                                                           "NULL AS attfdwoptions "
5820                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5821                                                           "ON a.atttypid = t.oid "
5822                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5823                                                           "AND a.attnum > 0::pg_catalog.int2 "
5824                                                           "ORDER BY a.attrelid, a.attnum",
5825                                                           tbinfo->dobj.catId.oid);
5826                 }
5827                 else if (fout->remoteVersion >= 70100)
5828                 {
5829                         /*
5830                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
5831                          * we don't dump it because we can't tell whether it's been
5832                          * explicitly set or was just a default.
5833                          *
5834                          * attislocal doesn't exist before 7.3, either; in older databases
5835                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
5836                          */
5837                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5838                                                           "-1 AS attstattarget, a.attstorage, "
5839                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
5840                                                           "false AS attisdropped, a.attlen, "
5841                                                           "a.attalign, true AS attislocal, "
5842                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
5843                                                           "'' AS attoptions, 0 AS attcollation, "
5844                                                           "NULL AS attfdwoptions "
5845                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
5846                                                           "ON a.atttypid = t.oid "
5847                                                           "WHERE a.attrelid = '%u'::oid "
5848                                                           "AND a.attnum > 0::int2 "
5849                                                           "ORDER BY a.attrelid, a.attnum",
5850                                                           tbinfo->dobj.catId.oid);
5851                 }
5852                 else
5853                 {
5854                         /* format_type not available before 7.1 */
5855                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
5856                                                           "-1 AS attstattarget, "
5857                                                           "attstorage, attstorage AS typstorage, "
5858                                                           "attnotnull, atthasdef, false AS attisdropped, "
5859                                                           "attlen, attalign, "
5860                                                           "true AS attislocal, "
5861                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
5862                                                           "'' AS attoptions, 0 AS attcollation, "
5863                                                           "NULL AS attfdwoptions "
5864                                                           "FROM pg_attribute a "
5865                                                           "WHERE attrelid = '%u'::oid "
5866                                                           "AND attnum > 0::int2 "
5867                                                           "ORDER BY attrelid, attnum",
5868                                                           tbinfo->dobj.catId.oid);
5869                 }
5870
5871                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
5872
5873                 ntups = PQntuples(res);
5874
5875                 i_attnum = PQfnumber(res, "attnum");
5876                 i_attname = PQfnumber(res, "attname");
5877                 i_atttypname = PQfnumber(res, "atttypname");
5878                 i_atttypmod = PQfnumber(res, "atttypmod");
5879                 i_attstattarget = PQfnumber(res, "attstattarget");
5880                 i_attstorage = PQfnumber(res, "attstorage");
5881                 i_typstorage = PQfnumber(res, "typstorage");
5882                 i_attnotnull = PQfnumber(res, "attnotnull");
5883                 i_atthasdef = PQfnumber(res, "atthasdef");
5884                 i_attisdropped = PQfnumber(res, "attisdropped");
5885                 i_attlen = PQfnumber(res, "attlen");
5886                 i_attalign = PQfnumber(res, "attalign");
5887                 i_attislocal = PQfnumber(res, "attislocal");
5888                 i_attoptions = PQfnumber(res, "attoptions");
5889                 i_attcollation = PQfnumber(res, "attcollation");
5890                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
5891
5892                 tbinfo->numatts = ntups;
5893                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
5894                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
5895                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
5896                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
5897                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
5898                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
5899                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
5900                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
5901                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
5902                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
5903                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
5904                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
5905                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
5906                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
5907                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
5908                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
5909                 hasdefaults = false;
5910
5911                 for (j = 0; j < ntups; j++)
5912                 {
5913                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
5914                                 exit_horribly(NULL,
5915                                                           "invalid column numbering in table \"%s\"\n",
5916                                                           tbinfo->dobj.name);
5917                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
5918                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
5919                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
5920                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
5921                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
5922                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
5923                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
5924                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
5925                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
5926                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
5927                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
5928                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
5929                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
5930                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
5931                         tbinfo->attrdefs[j] = NULL; /* fix below */
5932                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
5933                                 hasdefaults = true;
5934                         /* these flags will be set in flagInhAttrs() */
5935                         tbinfo->inhNotNull[j] = false;
5936                 }
5937
5938                 PQclear(res);
5939
5940                 /*
5941                  * Get info about column defaults
5942                  */
5943                 if (hasdefaults)
5944                 {
5945                         AttrDefInfo *attrdefs;
5946                         int                     numDefaults;
5947
5948                         if (g_verbose)
5949                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
5950                                                   tbinfo->dobj.name);
5951
5952                         resetPQExpBuffer(q);
5953                         if (fout->remoteVersion >= 70300)
5954                         {
5955                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
5956                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
5957                                                                   "FROM pg_catalog.pg_attrdef "
5958                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
5959                                                                   tbinfo->dobj.catId.oid);
5960                         }
5961                         else if (fout->remoteVersion >= 70200)
5962                         {
5963                                 /* 7.2 did not have OIDs in pg_attrdef */
5964                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
5965                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
5966                                                                   "FROM pg_attrdef "
5967                                                                   "WHERE adrelid = '%u'::oid",
5968                                                                   tbinfo->dobj.catId.oid);
5969                         }
5970                         else if (fout->remoteVersion >= 70100)
5971                         {
5972                                 /* no pg_get_expr, so must rely on adsrc */
5973                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
5974                                                                   "FROM pg_attrdef "
5975                                                                   "WHERE adrelid = '%u'::oid",
5976                                                                   tbinfo->dobj.catId.oid);
5977                         }
5978                         else
5979                         {
5980                                 /* no pg_get_expr, no tableoid either */
5981                                 appendPQExpBuffer(q, "SELECT "
5982                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
5983                                                                   "oid, adnum, adsrc "
5984                                                                   "FROM pg_attrdef "
5985                                                                   "WHERE adrelid = '%u'::oid",
5986                                                                   tbinfo->dobj.catId.oid);
5987                         }
5988                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
5989
5990                         numDefaults = PQntuples(res);
5991                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
5992
5993                         for (j = 0; j < numDefaults; j++)
5994                         {
5995                                 int                     adnum;
5996
5997                                 adnum = atoi(PQgetvalue(res, j, 2));
5998
5999                                 if (adnum <= 0 || adnum > ntups)
6000                                         exit_horribly(NULL,
6001                                                                   "invalid adnum value %d for table \"%s\"\n",
6002                                                                   adnum, tbinfo->dobj.name);
6003
6004                                 /*
6005                                  * dropped columns shouldn't have defaults, but just in case,
6006                                  * ignore 'em
6007                                  */
6008                                 if (tbinfo->attisdropped[adnum - 1])
6009                                         continue;
6010
6011                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6012                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6013                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6014                                 AssignDumpId(&attrdefs[j].dobj);
6015                                 attrdefs[j].adtable = tbinfo;
6016                                 attrdefs[j].adnum = adnum;
6017                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6018
6019                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6020                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6021
6022                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6023
6024                                 /*
6025                                  * Defaults on a VIEW must always be dumped as separate ALTER
6026                                  * TABLE commands.      Defaults on regular tables are dumped as
6027                                  * part of the CREATE TABLE if possible, which it won't be if
6028                                  * the column is not going to be emitted explicitly.
6029                                  */
6030                                 if (tbinfo->relkind == RELKIND_VIEW)
6031                                 {
6032                                         attrdefs[j].separate = true;
6033                                         /* needed in case pre-7.3 DB: */
6034                                         addObjectDependency(&attrdefs[j].dobj,
6035                                                                                 tbinfo->dobj.dumpId);
6036                                 }
6037                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6038                                 {
6039                                         /* column will be suppressed, print default separately */
6040                                         attrdefs[j].separate = true;
6041                                         /* needed in case pre-7.3 DB: */
6042                                         addObjectDependency(&attrdefs[j].dobj,
6043                                                                                 tbinfo->dobj.dumpId);
6044                                 }
6045                                 else
6046                                 {
6047                                         attrdefs[j].separate = false;
6048
6049                                         /*
6050                                          * Mark the default as needing to appear before the table,
6051                                          * so that any dependencies it has must be emitted before
6052                                          * the CREATE TABLE.  If this is not possible, we'll
6053                                          * change to "separate" mode while sorting dependencies.
6054                                          */
6055                                         addObjectDependency(&tbinfo->dobj,
6056                                                                                 attrdefs[j].dobj.dumpId);
6057                                 }
6058
6059                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6060                         }
6061                         PQclear(res);
6062                 }
6063
6064                 /*
6065                  * Get info about table CHECK constraints
6066                  */
6067                 if (tbinfo->ncheck > 0)
6068                 {
6069                         ConstraintInfo *constrs;
6070                         int                     numConstrs;
6071
6072                         if (g_verbose)
6073                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6074                                                   tbinfo->dobj.name);
6075
6076                         resetPQExpBuffer(q);
6077                         if (fout->remoteVersion >= 90200)
6078                         {
6079                                 /*
6080                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6081                                  * but it wasn't ever false for check constraints until 9.2).
6082                                  */
6083                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6084                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6085                                                                   "conislocal, convalidated "
6086                                                                   "FROM pg_catalog.pg_constraint "
6087                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6088                                                                   "   AND contype = 'c' "
6089                                                                   "ORDER BY conname",
6090                                                                   tbinfo->dobj.catId.oid);
6091                         }
6092                         else if (fout->remoteVersion >= 80400)
6093                         {
6094                                 /* conislocal is new in 8.4 */
6095                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6096                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6097                                                                   "conislocal, true AS convalidated "
6098                                                                   "FROM pg_catalog.pg_constraint "
6099                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6100                                                                   "   AND contype = 'c' "
6101                                                                   "ORDER BY conname",
6102                                                                   tbinfo->dobj.catId.oid);
6103                         }
6104                         else if (fout->remoteVersion >= 70400)
6105                         {
6106                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6107                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6108                                                                   "true AS conislocal, true AS convalidated "
6109                                                                   "FROM pg_catalog.pg_constraint "
6110                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6111                                                                   "   AND contype = 'c' "
6112                                                                   "ORDER BY conname",
6113                                                                   tbinfo->dobj.catId.oid);
6114                         }
6115                         else if (fout->remoteVersion >= 70300)
6116                         {
6117                                 /* no pg_get_constraintdef, must use consrc */
6118                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6119                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6120                                                                   "true AS conislocal, true AS convalidated "
6121                                                                   "FROM pg_catalog.pg_constraint "
6122                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6123                                                                   "   AND contype = 'c' "
6124                                                                   "ORDER BY conname",
6125                                                                   tbinfo->dobj.catId.oid);
6126                         }
6127                         else if (fout->remoteVersion >= 70200)
6128                         {
6129                                 /* 7.2 did not have OIDs in pg_relcheck */
6130                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6131                                                                   "rcname AS conname, "
6132                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6133                                                                   "true AS conislocal, true AS convalidated "
6134                                                                   "FROM pg_relcheck "
6135                                                                   "WHERE rcrelid = '%u'::oid "
6136                                                                   "ORDER BY rcname",
6137                                                                   tbinfo->dobj.catId.oid);
6138                         }
6139                         else if (fout->remoteVersion >= 70100)
6140                         {
6141                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6142                                                                   "rcname AS conname, "
6143                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6144                                                                   "true AS conislocal, true AS convalidated "
6145                                                                   "FROM pg_relcheck "
6146                                                                   "WHERE rcrelid = '%u'::oid "
6147                                                                   "ORDER BY rcname",
6148                                                                   tbinfo->dobj.catId.oid);
6149                         }
6150                         else
6151                         {
6152                                 /* no tableoid in 7.0 */
6153                                 appendPQExpBuffer(q, "SELECT "
6154                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6155                                                                   "oid, rcname AS conname, "
6156                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6157                                                                   "true AS conislocal, true AS convalidated "
6158                                                                   "FROM pg_relcheck "
6159                                                                   "WHERE rcrelid = '%u'::oid "
6160                                                                   "ORDER BY rcname",
6161                                                                   tbinfo->dobj.catId.oid);
6162                         }
6163                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6164
6165                         numConstrs = PQntuples(res);
6166                         if (numConstrs != tbinfo->ncheck)
6167                         {
6168                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6169                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6170                                                                                  tbinfo->ncheck),
6171                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6172                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6173                                 exit_nicely(1);
6174                         }
6175
6176                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6177                         tbinfo->checkexprs = constrs;
6178
6179                         for (j = 0; j < numConstrs; j++)
6180                         {
6181                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6182
6183                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6184                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6185                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6186                                 AssignDumpId(&constrs[j].dobj);
6187                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6188                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6189                                 constrs[j].contable = tbinfo;
6190                                 constrs[j].condomain = NULL;
6191                                 constrs[j].contype = 'c';
6192                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6193                                 constrs[j].confrelid = InvalidOid;
6194                                 constrs[j].conindex = 0;
6195                                 constrs[j].condeferrable = false;
6196                                 constrs[j].condeferred = false;
6197                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6198
6199                                 /*
6200                                  * An unvalidated constraint needs to be dumped separately, so
6201                                  * that potentially-violating existing data is loaded before
6202                                  * the constraint.
6203                                  */
6204                                 constrs[j].separate = !validated;
6205
6206                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6207
6208                                 /*
6209                                  * Mark the constraint as needing to appear before the table
6210                                  * --- this is so that any other dependencies of the
6211                                  * constraint will be emitted before we try to create the
6212                                  * table.  If the constraint is to be dumped separately, it
6213                                  * will be dumped after data is loaded anyway, so don't do it.
6214                                  * (There's an automatic dependency in the opposite direction
6215                                  * anyway, so don't need to add one manually here.)
6216                                  */
6217                                 if (!constrs[j].separate)
6218                                         addObjectDependency(&tbinfo->dobj,
6219                                                                                 constrs[j].dobj.dumpId);
6220
6221                                 /*
6222                                  * If the constraint is inherited, this will be detected later
6223                                  * (in pre-8.4 databases).      We also detect later if the
6224                                  * constraint must be split out from the table definition.
6225                                  */
6226                         }
6227                         PQclear(res);
6228                 }
6229         }
6230
6231         destroyPQExpBuffer(q);
6232 }
6233
6234 /*
6235  * Test whether a column should be printed as part of table's CREATE TABLE.
6236  * Column number is zero-based.
6237  *
6238  * Normally this is always true, but it's false for dropped columns, as well
6239  * as those that were inherited without any local definition.  (If we print
6240  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6241  * However, in binary_upgrade mode, we must print all such columns anyway and
6242  * fix the attislocal/attisdropped state later, so as to keep control of the
6243  * physical column order.
6244  *
6245  * This function exists because there are scattered nonobvious places that
6246  * must be kept in sync with this decision.
6247  */
6248 bool
6249 shouldPrintColumn(TableInfo *tbinfo, int colno)
6250 {
6251         if (binary_upgrade)
6252                 return true;
6253         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6254 }
6255
6256
6257 /*
6258  * getTSParsers:
6259  *        read all text search parsers in the system catalogs and return them
6260  *        in the TSParserInfo* structure
6261  *
6262  *      numTSParsers is set to the number of parsers read in
6263  */
6264 TSParserInfo *
6265 getTSParsers(Archive *fout, int *numTSParsers)
6266 {
6267         PGresult   *res;
6268         int                     ntups;
6269         int                     i;
6270         PQExpBuffer query;
6271         TSParserInfo *prsinfo;
6272         int                     i_tableoid;
6273         int                     i_oid;
6274         int                     i_prsname;
6275         int                     i_prsnamespace;
6276         int                     i_prsstart;
6277         int                     i_prstoken;
6278         int                     i_prsend;
6279         int                     i_prsheadline;
6280         int                     i_prslextype;
6281
6282         /* Before 8.3, there is no built-in text search support */
6283         if (fout->remoteVersion < 80300)
6284         {
6285                 *numTSParsers = 0;
6286                 return NULL;
6287         }
6288
6289         query = createPQExpBuffer();
6290
6291         /*
6292          * find all text search objects, including builtin ones; we filter out
6293          * system-defined objects at dump-out time.
6294          */
6295
6296         /* Make sure we are in proper schema */
6297         selectSourceSchema(fout, "pg_catalog");
6298
6299         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6300                                           "prsstart::oid, prstoken::oid, "
6301                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6302                                           "FROM pg_ts_parser");
6303
6304         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6305
6306         ntups = PQntuples(res);
6307         *numTSParsers = ntups;
6308
6309         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6310
6311         i_tableoid = PQfnumber(res, "tableoid");
6312         i_oid = PQfnumber(res, "oid");
6313         i_prsname = PQfnumber(res, "prsname");
6314         i_prsnamespace = PQfnumber(res, "prsnamespace");
6315         i_prsstart = PQfnumber(res, "prsstart");
6316         i_prstoken = PQfnumber(res, "prstoken");
6317         i_prsend = PQfnumber(res, "prsend");
6318         i_prsheadline = PQfnumber(res, "prsheadline");
6319         i_prslextype = PQfnumber(res, "prslextype");
6320
6321         for (i = 0; i < ntups; i++)
6322         {
6323                 prsinfo[i].dobj.objType = DO_TSPARSER;
6324                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6325                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6326                 AssignDumpId(&prsinfo[i].dobj);
6327                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6328                 prsinfo[i].dobj.namespace =
6329                         findNamespace(fout,
6330                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6331                                                   prsinfo[i].dobj.catId.oid);
6332                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6333                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6334                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6335                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6336                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6337
6338                 /* Decide whether we want to dump it */
6339                 selectDumpableObject(&(prsinfo[i].dobj));
6340         }
6341
6342         PQclear(res);
6343
6344         destroyPQExpBuffer(query);
6345
6346         return prsinfo;
6347 }
6348
6349 /*
6350  * getTSDictionaries:
6351  *        read all text search dictionaries in the system catalogs and return them
6352  *        in the TSDictInfo* structure
6353  *
6354  *      numTSDicts is set to the number of dictionaries read in
6355  */
6356 TSDictInfo *
6357 getTSDictionaries(Archive *fout, int *numTSDicts)
6358 {
6359         PGresult   *res;
6360         int                     ntups;
6361         int                     i;
6362         PQExpBuffer query;
6363         TSDictInfo *dictinfo;
6364         int                     i_tableoid;
6365         int                     i_oid;
6366         int                     i_dictname;
6367         int                     i_dictnamespace;
6368         int                     i_rolname;
6369         int                     i_dicttemplate;
6370         int                     i_dictinitoption;
6371
6372         /* Before 8.3, there is no built-in text search support */
6373         if (fout->remoteVersion < 80300)
6374         {
6375                 *numTSDicts = 0;
6376                 return NULL;
6377         }
6378
6379         query = createPQExpBuffer();
6380
6381         /* Make sure we are in proper schema */
6382         selectSourceSchema(fout, "pg_catalog");
6383
6384         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6385                                           "dictnamespace, (%s dictowner) AS rolname, "
6386                                           "dicttemplate, dictinitoption "
6387                                           "FROM pg_ts_dict",
6388                                           username_subquery);
6389
6390         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6391
6392         ntups = PQntuples(res);
6393         *numTSDicts = ntups;
6394
6395         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6396
6397         i_tableoid = PQfnumber(res, "tableoid");
6398         i_oid = PQfnumber(res, "oid");
6399         i_dictname = PQfnumber(res, "dictname");
6400         i_dictnamespace = PQfnumber(res, "dictnamespace");
6401         i_rolname = PQfnumber(res, "rolname");
6402         i_dictinitoption = PQfnumber(res, "dictinitoption");
6403         i_dicttemplate = PQfnumber(res, "dicttemplate");
6404
6405         for (i = 0; i < ntups; i++)
6406         {
6407                 dictinfo[i].dobj.objType = DO_TSDICT;
6408                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6409                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6410                 AssignDumpId(&dictinfo[i].dobj);
6411                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6412                 dictinfo[i].dobj.namespace =
6413                         findNamespace(fout,
6414                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6415                                                   dictinfo[i].dobj.catId.oid);
6416                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6417                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6418                 if (PQgetisnull(res, i, i_dictinitoption))
6419                         dictinfo[i].dictinitoption = NULL;
6420                 else
6421                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6422
6423                 /* Decide whether we want to dump it */
6424                 selectDumpableObject(&(dictinfo[i].dobj));
6425         }
6426
6427         PQclear(res);
6428
6429         destroyPQExpBuffer(query);
6430
6431         return dictinfo;
6432 }
6433
6434 /*
6435  * getTSTemplates:
6436  *        read all text search templates in the system catalogs and return them
6437  *        in the TSTemplateInfo* structure
6438  *
6439  *      numTSTemplates is set to the number of templates read in
6440  */
6441 TSTemplateInfo *
6442 getTSTemplates(Archive *fout, int *numTSTemplates)
6443 {
6444         PGresult   *res;
6445         int                     ntups;
6446         int                     i;
6447         PQExpBuffer query;
6448         TSTemplateInfo *tmplinfo;
6449         int                     i_tableoid;
6450         int                     i_oid;
6451         int                     i_tmplname;
6452         int                     i_tmplnamespace;
6453         int                     i_tmplinit;
6454         int                     i_tmpllexize;
6455
6456         /* Before 8.3, there is no built-in text search support */
6457         if (fout->remoteVersion < 80300)
6458         {
6459                 *numTSTemplates = 0;
6460                 return NULL;
6461         }
6462
6463         query = createPQExpBuffer();
6464
6465         /* Make sure we are in proper schema */
6466         selectSourceSchema(fout, "pg_catalog");
6467
6468         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6469                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6470                                           "FROM pg_ts_template");
6471
6472         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6473
6474         ntups = PQntuples(res);
6475         *numTSTemplates = ntups;
6476
6477         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6478
6479         i_tableoid = PQfnumber(res, "tableoid");
6480         i_oid = PQfnumber(res, "oid");
6481         i_tmplname = PQfnumber(res, "tmplname");
6482         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6483         i_tmplinit = PQfnumber(res, "tmplinit");
6484         i_tmpllexize = PQfnumber(res, "tmpllexize");
6485
6486         for (i = 0; i < ntups; i++)
6487         {
6488                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6489                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6490                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6491                 AssignDumpId(&tmplinfo[i].dobj);
6492                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6493                 tmplinfo[i].dobj.namespace =
6494                         findNamespace(fout,
6495                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
6496                                                   tmplinfo[i].dobj.catId.oid);
6497                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6498                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6499
6500                 /* Decide whether we want to dump it */
6501                 selectDumpableObject(&(tmplinfo[i].dobj));
6502         }
6503
6504         PQclear(res);
6505
6506         destroyPQExpBuffer(query);
6507
6508         return tmplinfo;
6509 }
6510
6511 /*
6512  * getTSConfigurations:
6513  *        read all text search configurations in the system catalogs and return
6514  *        them in the TSConfigInfo* structure
6515  *
6516  *      numTSConfigs is set to the number of configurations read in
6517  */
6518 TSConfigInfo *
6519 getTSConfigurations(Archive *fout, int *numTSConfigs)
6520 {
6521         PGresult   *res;
6522         int                     ntups;
6523         int                     i;
6524         PQExpBuffer query;
6525         TSConfigInfo *cfginfo;
6526         int                     i_tableoid;
6527         int                     i_oid;
6528         int                     i_cfgname;
6529         int                     i_cfgnamespace;
6530         int                     i_rolname;
6531         int                     i_cfgparser;
6532
6533         /* Before 8.3, there is no built-in text search support */
6534         if (fout->remoteVersion < 80300)
6535         {
6536                 *numTSConfigs = 0;
6537                 return NULL;
6538         }
6539
6540         query = createPQExpBuffer();
6541
6542         /* Make sure we are in proper schema */
6543         selectSourceSchema(fout, "pg_catalog");
6544
6545         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6546                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6547                                           "FROM pg_ts_config",
6548                                           username_subquery);
6549
6550         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6551
6552         ntups = PQntuples(res);
6553         *numTSConfigs = ntups;
6554
6555         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6556
6557         i_tableoid = PQfnumber(res, "tableoid");
6558         i_oid = PQfnumber(res, "oid");
6559         i_cfgname = PQfnumber(res, "cfgname");
6560         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6561         i_rolname = PQfnumber(res, "rolname");
6562         i_cfgparser = PQfnumber(res, "cfgparser");
6563
6564         for (i = 0; i < ntups; i++)
6565         {
6566                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6567                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6568                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6569                 AssignDumpId(&cfginfo[i].dobj);
6570                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
6571                 cfginfo[i].dobj.namespace =
6572                         findNamespace(fout,
6573                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
6574                                                   cfginfo[i].dobj.catId.oid);
6575                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6576                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
6577
6578                 /* Decide whether we want to dump it */
6579                 selectDumpableObject(&(cfginfo[i].dobj));
6580         }
6581
6582         PQclear(res);
6583
6584         destroyPQExpBuffer(query);
6585
6586         return cfginfo;
6587 }
6588
6589 /*
6590  * getForeignDataWrappers:
6591  *        read all foreign-data wrappers in the system catalogs and return
6592  *        them in the FdwInfo* structure
6593  *
6594  *      numForeignDataWrappers is set to the number of fdws read in
6595  */
6596 FdwInfo *
6597 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
6598 {
6599         PGresult   *res;
6600         int                     ntups;
6601         int                     i;
6602         PQExpBuffer query = createPQExpBuffer();
6603         FdwInfo    *fdwinfo;
6604         int                     i_tableoid;
6605         int                     i_oid;
6606         int                     i_fdwname;
6607         int                     i_rolname;
6608         int                     i_fdwhandler;
6609         int                     i_fdwvalidator;
6610         int                     i_fdwacl;
6611         int                     i_fdwoptions;
6612
6613         /* Before 8.4, there are no foreign-data wrappers */
6614         if (fout->remoteVersion < 80400)
6615         {
6616                 *numForeignDataWrappers = 0;
6617                 return NULL;
6618         }
6619
6620         /* Make sure we are in proper schema */
6621         selectSourceSchema(fout, "pg_catalog");
6622
6623         if (fout->remoteVersion >= 90100)
6624         {
6625                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6626                                                   "(%s fdwowner) AS rolname, "
6627                                                   "fdwhandler::pg_catalog.regproc, "
6628                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6629                                                   "array_to_string(ARRAY("
6630                                                   "SELECT quote_ident(option_name) || ' ' || "
6631                                                   "quote_literal(option_value) "
6632                                                   "FROM pg_options_to_table(fdwoptions) "
6633                                                   "ORDER BY option_name"
6634                                                   "), E',\n    ') AS fdwoptions "
6635                                                   "FROM pg_foreign_data_wrapper",
6636                                                   username_subquery);
6637         }
6638         else
6639         {
6640                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6641                                                   "(%s fdwowner) AS rolname, "
6642                                                   "'-' AS fdwhandler, "
6643                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6644                                                   "array_to_string(ARRAY("
6645                                                   "SELECT quote_ident(option_name) || ' ' || "
6646                                                   "quote_literal(option_value) "
6647                                                   "FROM pg_options_to_table(fdwoptions) "
6648                                                   "ORDER BY option_name"
6649                                                   "), E',\n    ') AS fdwoptions "
6650                                                   "FROM pg_foreign_data_wrapper",
6651                                                   username_subquery);
6652         }
6653
6654         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6655
6656         ntups = PQntuples(res);
6657         *numForeignDataWrappers = ntups;
6658
6659         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
6660
6661         i_tableoid = PQfnumber(res, "tableoid");
6662         i_oid = PQfnumber(res, "oid");
6663         i_fdwname = PQfnumber(res, "fdwname");
6664         i_rolname = PQfnumber(res, "rolname");
6665         i_fdwhandler = PQfnumber(res, "fdwhandler");
6666         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6667         i_fdwacl = PQfnumber(res, "fdwacl");
6668         i_fdwoptions = PQfnumber(res, "fdwoptions");
6669
6670         for (i = 0; i < ntups; i++)
6671         {
6672                 fdwinfo[i].dobj.objType = DO_FDW;
6673                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6674                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6675                 AssignDumpId(&fdwinfo[i].dobj);
6676                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6677                 fdwinfo[i].dobj.namespace = NULL;
6678                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6679                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
6680                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
6681                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
6682                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
6683
6684                 /* Decide whether we want to dump it */
6685                 selectDumpableObject(&(fdwinfo[i].dobj));
6686         }
6687
6688         PQclear(res);
6689
6690         destroyPQExpBuffer(query);
6691
6692         return fdwinfo;
6693 }
6694
6695 /*
6696  * getForeignServers:
6697  *        read all foreign servers in the system catalogs and return
6698  *        them in the ForeignServerInfo * structure
6699  *
6700  *      numForeignServers is set to the number of servers read in
6701  */
6702 ForeignServerInfo *
6703 getForeignServers(Archive *fout, int *numForeignServers)
6704 {
6705         PGresult   *res;
6706         int                     ntups;
6707         int                     i;
6708         PQExpBuffer query = createPQExpBuffer();
6709         ForeignServerInfo *srvinfo;
6710         int                     i_tableoid;
6711         int                     i_oid;
6712         int                     i_srvname;
6713         int                     i_rolname;
6714         int                     i_srvfdw;
6715         int                     i_srvtype;
6716         int                     i_srvversion;
6717         int                     i_srvacl;
6718         int                     i_srvoptions;
6719
6720         /* Before 8.4, there are no foreign servers */
6721         if (fout->remoteVersion < 80400)
6722         {
6723                 *numForeignServers = 0;
6724                 return NULL;
6725         }
6726
6727         /* Make sure we are in proper schema */
6728         selectSourceSchema(fout, "pg_catalog");
6729
6730         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
6731                                           "(%s srvowner) AS rolname, "
6732                                           "srvfdw, srvtype, srvversion, srvacl,"
6733                                           "array_to_string(ARRAY("
6734                                           "SELECT quote_ident(option_name) || ' ' || "
6735                                           "quote_literal(option_value) "
6736                                           "FROM pg_options_to_table(srvoptions) "
6737                                           "ORDER BY option_name"
6738                                           "), E',\n    ') AS srvoptions "
6739                                           "FROM pg_foreign_server",
6740                                           username_subquery);
6741
6742         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6743
6744         ntups = PQntuples(res);
6745         *numForeignServers = ntups;
6746
6747         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
6748
6749         i_tableoid = PQfnumber(res, "tableoid");
6750         i_oid = PQfnumber(res, "oid");
6751         i_srvname = PQfnumber(res, "srvname");
6752         i_rolname = PQfnumber(res, "rolname");
6753         i_srvfdw = PQfnumber(res, "srvfdw");
6754         i_srvtype = PQfnumber(res, "srvtype");
6755         i_srvversion = PQfnumber(res, "srvversion");
6756         i_srvacl = PQfnumber(res, "srvacl");
6757         i_srvoptions = PQfnumber(res, "srvoptions");
6758
6759         for (i = 0; i < ntups; i++)
6760         {
6761                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
6762                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6763                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6764                 AssignDumpId(&srvinfo[i].dobj);
6765                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6766                 srvinfo[i].dobj.namespace = NULL;
6767                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6768                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
6769                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
6770                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
6771                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
6772                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
6773
6774                 /* Decide whether we want to dump it */
6775                 selectDumpableObject(&(srvinfo[i].dobj));
6776         }
6777
6778         PQclear(res);
6779
6780         destroyPQExpBuffer(query);
6781
6782         return srvinfo;
6783 }
6784
6785 /*
6786  * getDefaultACLs:
6787  *        read all default ACL information in the system catalogs and return
6788  *        them in the DefaultACLInfo structure
6789  *
6790  *      numDefaultACLs is set to the number of ACLs read in
6791  */
6792 DefaultACLInfo *
6793 getDefaultACLs(Archive *fout, int *numDefaultACLs)
6794 {
6795         DefaultACLInfo *daclinfo;
6796         PQExpBuffer query;
6797         PGresult   *res;
6798         int                     i_oid;
6799         int                     i_tableoid;
6800         int                     i_defaclrole;
6801         int                     i_defaclnamespace;
6802         int                     i_defaclobjtype;
6803         int                     i_defaclacl;
6804         int                     i,
6805                                 ntups;
6806
6807         if (fout->remoteVersion < 90000)
6808         {
6809                 *numDefaultACLs = 0;
6810                 return NULL;
6811         }
6812
6813         query = createPQExpBuffer();
6814
6815         /* Make sure we are in proper schema */
6816         selectSourceSchema(fout, "pg_catalog");
6817
6818         appendPQExpBuffer(query, "SELECT oid, tableoid, "
6819                                           "(%s defaclrole) AS defaclrole, "
6820                                           "defaclnamespace, "
6821                                           "defaclobjtype, "
6822                                           "defaclacl "
6823                                           "FROM pg_default_acl",
6824                                           username_subquery);
6825
6826         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6827
6828         ntups = PQntuples(res);
6829         *numDefaultACLs = ntups;
6830
6831         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
6832
6833         i_oid = PQfnumber(res, "oid");
6834         i_tableoid = PQfnumber(res, "tableoid");
6835         i_defaclrole = PQfnumber(res, "defaclrole");
6836         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
6837         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
6838         i_defaclacl = PQfnumber(res, "defaclacl");
6839
6840         for (i = 0; i < ntups; i++)
6841         {
6842                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
6843
6844                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
6845                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6846                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6847                 AssignDumpId(&daclinfo[i].dobj);
6848                 /* cheesy ... is it worth coming up with a better object name? */
6849                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
6850
6851                 if (nspid != InvalidOid)
6852                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
6853                                                                                                  daclinfo[i].dobj.catId.oid);
6854                 else
6855                         daclinfo[i].dobj.namespace = NULL;
6856
6857                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
6858                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
6859                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
6860
6861                 /* Decide whether we want to dump it */
6862                 selectDumpableDefaultACL(&(daclinfo[i]));
6863         }
6864
6865         PQclear(res);
6866
6867         destroyPQExpBuffer(query);
6868
6869         return daclinfo;
6870 }
6871
6872 /*
6873  * dumpComment --
6874  *
6875  * This routine is used to dump any comments associated with the
6876  * object handed to this routine. The routine takes a constant character
6877  * string for the target part of the comment-creation command, plus
6878  * the namespace and owner of the object (for labeling the ArchiveEntry),
6879  * plus catalog ID and subid which are the lookup key for pg_description,
6880  * plus the dump ID for the object (for setting a dependency).
6881  * If a matching pg_description entry is found, it is dumped.
6882  *
6883  * Note: although this routine takes a dumpId for dependency purposes,
6884  * that purpose is just to mark the dependency in the emitted dump file
6885  * for possible future use by pg_restore.  We do NOT use it for determining
6886  * ordering of the comment in the dump file, because this routine is called
6887  * after dependency sorting occurs.  This routine should be called just after
6888  * calling ArchiveEntry() for the specified object.
6889  */
6890 static void
6891 dumpComment(Archive *fout, const char *target,
6892                         const char *namespace, const char *owner,
6893                         CatalogId catalogId, int subid, DumpId dumpId)
6894 {
6895         CommentItem *comments;
6896         int                     ncomments;
6897
6898         /* Comments are schema not data ... except blob comments are data */
6899         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
6900         {
6901                 if (dataOnly)
6902                         return;
6903         }
6904         else
6905         {
6906                 if (schemaOnly)
6907                         return;
6908         }
6909
6910         /* Search for comments associated with catalogId, using table */
6911         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
6912                                                          &comments);
6913
6914         /* Is there one matching the subid? */
6915         while (ncomments > 0)
6916         {
6917                 if (comments->objsubid == subid)
6918                         break;
6919                 comments++;
6920                 ncomments--;
6921         }
6922
6923         /* If a comment exists, build COMMENT ON statement */
6924         if (ncomments > 0)
6925         {
6926                 PQExpBuffer query = createPQExpBuffer();
6927
6928                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
6929                 appendStringLiteralAH(query, comments->descr, fout);
6930                 appendPQExpBuffer(query, ";\n");
6931
6932                 /*
6933                  * We mark comments as SECTION_NONE because they really belong in the
6934                  * same section as their parent, whether that is pre-data or
6935                  * post-data.
6936                  */
6937                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
6938                                          target, namespace, NULL, owner,
6939                                          false, "COMMENT", SECTION_NONE,
6940                                          query->data, "", NULL,
6941                                          &(dumpId), 1,
6942                                          NULL, NULL);
6943
6944                 destroyPQExpBuffer(query);
6945         }
6946 }
6947
6948 /*
6949  * dumpTableComment --
6950  *
6951  * As above, but dump comments for both the specified table (or view)
6952  * and its columns.
6953  */
6954 static void
6955 dumpTableComment(Archive *fout, TableInfo *tbinfo,
6956                                  const char *reltypename)
6957 {
6958         CommentItem *comments;
6959         int                     ncomments;
6960         PQExpBuffer query;
6961         PQExpBuffer target;
6962
6963         /* Comments are SCHEMA not data */
6964         if (dataOnly)
6965                 return;
6966
6967         /* Search for comments associated with relation, using table */
6968         ncomments = findComments(fout,
6969                                                          tbinfo->dobj.catId.tableoid,
6970                                                          tbinfo->dobj.catId.oid,
6971                                                          &comments);
6972
6973         /* If comments exist, build COMMENT ON statements */
6974         if (ncomments <= 0)
6975                 return;
6976
6977         query = createPQExpBuffer();
6978         target = createPQExpBuffer();
6979
6980         while (ncomments > 0)
6981         {
6982                 const char *descr = comments->descr;
6983                 int                     objsubid = comments->objsubid;
6984
6985                 if (objsubid == 0)
6986                 {
6987                         resetPQExpBuffer(target);
6988                         appendPQExpBuffer(target, "%s %s", reltypename,
6989                                                           fmtId(tbinfo->dobj.name));
6990
6991                         resetPQExpBuffer(query);
6992                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6993                         appendStringLiteralAH(query, descr, fout);
6994                         appendPQExpBuffer(query, ";\n");
6995
6996                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6997                                                  target->data,
6998                                                  tbinfo->dobj.namespace->dobj.name,
6999                                                  NULL, tbinfo->rolname,
7000                                                  false, "COMMENT", SECTION_NONE,
7001                                                  query->data, "", NULL,
7002                                                  &(tbinfo->dobj.dumpId), 1,
7003                                                  NULL, NULL);
7004                 }
7005                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7006                 {
7007                         resetPQExpBuffer(target);
7008                         appendPQExpBuffer(target, "COLUMN %s.",
7009                                                           fmtId(tbinfo->dobj.name));
7010                         appendPQExpBuffer(target, "%s",
7011                                                           fmtId(tbinfo->attnames[objsubid - 1]));
7012
7013                         resetPQExpBuffer(query);
7014                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7015                         appendStringLiteralAH(query, descr, fout);
7016                         appendPQExpBuffer(query, ";\n");
7017
7018                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7019                                                  target->data,
7020                                                  tbinfo->dobj.namespace->dobj.name,
7021                                                  NULL, tbinfo->rolname,
7022                                                  false, "COMMENT", SECTION_NONE,
7023                                                  query->data, "", NULL,
7024                                                  &(tbinfo->dobj.dumpId), 1,
7025                                                  NULL, NULL);
7026                 }
7027
7028                 comments++;
7029                 ncomments--;
7030         }
7031
7032         destroyPQExpBuffer(query);
7033         destroyPQExpBuffer(target);
7034 }
7035
7036 /*
7037  * findComments --
7038  *
7039  * Find the comment(s), if any, associated with the given object.  All the
7040  * objsubid values associated with the given classoid/objoid are found with
7041  * one search.
7042  */
7043 static int
7044 findComments(Archive *fout, Oid classoid, Oid objoid,
7045                          CommentItem **items)
7046 {
7047         /* static storage for table of comments */
7048         static CommentItem *comments = NULL;
7049         static int      ncomments = -1;
7050
7051         CommentItem *middle = NULL;
7052         CommentItem *low;
7053         CommentItem *high;
7054         int                     nmatch;
7055
7056         /* Get comments if we didn't already */
7057         if (ncomments < 0)
7058                 ncomments = collectComments(fout, &comments);
7059
7060         /*
7061          * Pre-7.2, pg_description does not contain classoid, so collectComments
7062          * just stores a zero.  If there's a collision on object OID, well, you
7063          * get duplicate comments.
7064          */
7065         if (fout->remoteVersion < 70200)
7066                 classoid = 0;
7067
7068         /*
7069          * Do binary search to find some item matching the object.
7070          */
7071         low = &comments[0];
7072         high = &comments[ncomments - 1];
7073         while (low <= high)
7074         {
7075                 middle = low + (high - low) / 2;
7076
7077                 if (classoid < middle->classoid)
7078                         high = middle - 1;
7079                 else if (classoid > middle->classoid)
7080                         low = middle + 1;
7081                 else if (objoid < middle->objoid)
7082                         high = middle - 1;
7083                 else if (objoid > middle->objoid)
7084                         low = middle + 1;
7085                 else
7086                         break;                          /* found a match */
7087         }
7088
7089         if (low > high)                         /* no matches */
7090         {
7091                 *items = NULL;
7092                 return 0;
7093         }
7094
7095         /*
7096          * Now determine how many items match the object.  The search loop
7097          * invariant still holds: only items between low and high inclusive could
7098          * match.
7099          */
7100         nmatch = 1;
7101         while (middle > low)
7102         {
7103                 if (classoid != middle[-1].classoid ||
7104                         objoid != middle[-1].objoid)
7105                         break;
7106                 middle--;
7107                 nmatch++;
7108         }
7109
7110         *items = middle;
7111
7112         middle += nmatch;
7113         while (middle <= high)
7114         {
7115                 if (classoid != middle->classoid ||
7116                         objoid != middle->objoid)
7117                         break;
7118                 middle++;
7119                 nmatch++;
7120         }
7121
7122         return nmatch;
7123 }
7124
7125 /*
7126  * collectComments --
7127  *
7128  * Construct a table of all comments available for database objects.
7129  * We used to do per-object queries for the comments, but it's much faster
7130  * to pull them all over at once, and on most databases the memory cost
7131  * isn't high.
7132  *
7133  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7134  */
7135 static int
7136 collectComments(Archive *fout, CommentItem **items)
7137 {
7138         PGresult   *res;
7139         PQExpBuffer query;
7140         int                     i_description;
7141         int                     i_classoid;
7142         int                     i_objoid;
7143         int                     i_objsubid;
7144         int                     ntups;
7145         int                     i;
7146         CommentItem *comments;
7147
7148         /*
7149          * Note we do NOT change source schema here; preserve the caller's
7150          * setting, instead.
7151          */
7152
7153         query = createPQExpBuffer();
7154
7155         if (fout->remoteVersion >= 70300)
7156         {
7157                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7158                                                   "FROM pg_catalog.pg_description "
7159                                                   "ORDER BY classoid, objoid, objsubid");
7160         }
7161         else if (fout->remoteVersion >= 70200)
7162         {
7163                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7164                                                   "FROM pg_description "
7165                                                   "ORDER BY classoid, objoid, objsubid");
7166         }
7167         else
7168         {
7169                 /* Note: this will fail to find attribute comments in pre-7.2... */
7170                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7171                                                   "FROM pg_description "
7172                                                   "ORDER BY objoid");
7173         }
7174
7175         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7176
7177         /* Construct lookup table containing OIDs in numeric form */
7178
7179         i_description = PQfnumber(res, "description");
7180         i_classoid = PQfnumber(res, "classoid");
7181         i_objoid = PQfnumber(res, "objoid");
7182         i_objsubid = PQfnumber(res, "objsubid");
7183
7184         ntups = PQntuples(res);
7185
7186         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7187
7188         for (i = 0; i < ntups; i++)
7189         {
7190                 comments[i].descr = PQgetvalue(res, i, i_description);
7191                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7192                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7193                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7194         }
7195
7196         /* Do NOT free the PGresult since we are keeping pointers into it */
7197         destroyPQExpBuffer(query);
7198
7199         *items = comments;
7200         return ntups;
7201 }
7202
7203 /*
7204  * dumpDumpableObject
7205  *
7206  * This routine and its subsidiaries are responsible for creating
7207  * ArchiveEntries (TOC objects) for each object to be dumped.
7208  */
7209 static void
7210 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7211 {
7212         switch (dobj->objType)
7213         {
7214                 case DO_NAMESPACE:
7215                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7216                         break;
7217                 case DO_EXTENSION:
7218                         dumpExtension(fout, (ExtensionInfo *) dobj);
7219                         break;
7220                 case DO_TYPE:
7221                         dumpType(fout, (TypeInfo *) dobj);
7222                         break;
7223                 case DO_SHELL_TYPE:
7224                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7225                         break;
7226                 case DO_FUNC:
7227                         dumpFunc(fout, (FuncInfo *) dobj);
7228                         break;
7229                 case DO_AGG:
7230                         dumpAgg(fout, (AggInfo *) dobj);
7231                         break;
7232                 case DO_OPERATOR:
7233                         dumpOpr(fout, (OprInfo *) dobj);
7234                         break;
7235                 case DO_OPCLASS:
7236                         dumpOpclass(fout, (OpclassInfo *) dobj);
7237                         break;
7238                 case DO_OPFAMILY:
7239                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7240                         break;
7241                 case DO_COLLATION:
7242                         dumpCollation(fout, (CollInfo *) dobj);
7243                         break;
7244                 case DO_CONVERSION:
7245                         dumpConversion(fout, (ConvInfo *) dobj);
7246                         break;
7247                 case DO_TABLE:
7248                         dumpTable(fout, (TableInfo *) dobj);
7249                         break;
7250                 case DO_ATTRDEF:
7251                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7252                         break;
7253                 case DO_INDEX:
7254                         dumpIndex(fout, (IndxInfo *) dobj);
7255                         break;
7256                 case DO_RULE:
7257                         dumpRule(fout, (RuleInfo *) dobj);
7258                         break;
7259                 case DO_TRIGGER:
7260                         dumpTrigger(fout, (TriggerInfo *) dobj);
7261                         break;
7262                 case DO_EVENT_TRIGGER:
7263                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7264                         break;
7265                 case DO_CONSTRAINT:
7266                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7267                         break;
7268                 case DO_FK_CONSTRAINT:
7269                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7270                         break;
7271                 case DO_PROCLANG:
7272                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7273                         break;
7274                 case DO_CAST:
7275                         dumpCast(fout, (CastInfo *) dobj);
7276                         break;
7277                 case DO_TABLE_DATA:
7278                         dumpTableData(fout, (TableDataInfo *) dobj);
7279                         break;
7280                 case DO_DUMMY_TYPE:
7281                         /* table rowtypes and array types are never dumped separately */
7282                         break;
7283                 case DO_TSPARSER:
7284                         dumpTSParser(fout, (TSParserInfo *) dobj);
7285                         break;
7286                 case DO_TSDICT:
7287                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7288                         break;
7289                 case DO_TSTEMPLATE:
7290                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7291                         break;
7292                 case DO_TSCONFIG:
7293                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7294                         break;
7295                 case DO_FDW:
7296                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7297                         break;
7298                 case DO_FOREIGN_SERVER:
7299                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7300                         break;
7301                 case DO_DEFAULT_ACL:
7302                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7303                         break;
7304                 case DO_BLOB:
7305                         dumpBlob(fout, (BlobInfo *) dobj);
7306                         break;
7307                 case DO_BLOB_DATA:
7308                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7309                                                  dobj->name, NULL, NULL, "",
7310                                                  false, "BLOBS", SECTION_DATA,
7311                                                  "", "", NULL,
7312                                                  NULL, 0,
7313                                                  dumpBlobs, NULL);
7314                         break;
7315                 case DO_PRE_DATA_BOUNDARY:
7316                 case DO_POST_DATA_BOUNDARY:
7317                         /* never dumped, nothing to do */
7318                         break;
7319         }
7320 }
7321
7322 /*
7323  * dumpNamespace
7324  *        writes out to fout the queries to recreate a user-defined namespace
7325  */
7326 static void
7327 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7328 {
7329         PQExpBuffer q;
7330         PQExpBuffer delq;
7331         PQExpBuffer labelq;
7332         char       *qnspname;
7333
7334         /* Skip if not to be dumped */
7335         if (!nspinfo->dobj.dump || dataOnly)
7336                 return;
7337
7338         /* don't dump dummy namespace from pre-7.3 source */
7339         if (strlen(nspinfo->dobj.name) == 0)
7340                 return;
7341
7342         q = createPQExpBuffer();
7343         delq = createPQExpBuffer();
7344         labelq = createPQExpBuffer();
7345
7346         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7347
7348         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7349
7350         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7351
7352         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7353
7354         if (binary_upgrade)
7355                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7356
7357         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7358                                  nspinfo->dobj.name,
7359                                  NULL, NULL,
7360                                  nspinfo->rolname,
7361                                  false, "SCHEMA", SECTION_PRE_DATA,
7362                                  q->data, delq->data, NULL,
7363                                  NULL, 0,
7364                                  NULL, NULL);
7365
7366         /* Dump Schema Comments and Security Labels */
7367         dumpComment(fout, labelq->data,
7368                                 NULL, nspinfo->rolname,
7369                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7370         dumpSecLabel(fout, labelq->data,
7371                                  NULL, nspinfo->rolname,
7372                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7373
7374         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7375                         qnspname, NULL, nspinfo->dobj.name, NULL,
7376                         nspinfo->rolname, nspinfo->nspacl);
7377
7378         free(qnspname);
7379
7380         destroyPQExpBuffer(q);
7381         destroyPQExpBuffer(delq);
7382         destroyPQExpBuffer(labelq);
7383 }
7384
7385 /*
7386  * dumpExtension
7387  *        writes out to fout the queries to recreate an extension
7388  */
7389 static void
7390 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7391 {
7392         PQExpBuffer q;
7393         PQExpBuffer delq;
7394         PQExpBuffer labelq;
7395         char       *qextname;
7396
7397         /* Skip if not to be dumped */
7398         if (!extinfo->dobj.dump || dataOnly)
7399                 return;
7400
7401         q = createPQExpBuffer();
7402         delq = createPQExpBuffer();
7403         labelq = createPQExpBuffer();
7404
7405         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7406
7407         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7408
7409         if (!binary_upgrade)
7410         {
7411                 /*
7412                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7413                  * problem if the extension already exists in the target database;
7414                  * this is essential for installed-by-default extensions such as
7415                  * plpgsql.
7416                  *
7417                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7418                  * built-in extensions based on their OIDs; see
7419                  * selectDumpableExtension.
7420                  */
7421                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7422                                                   qextname, fmtId(extinfo->namespace));
7423         }
7424         else
7425         {
7426                 int                     i;
7427                 int                     n;
7428
7429                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7430
7431                 /*
7432                  *      We unconditionally create the extension, so we must drop it if it
7433                  *      exists.  This could happen if the user deleted 'plpgsql' and then
7434                  *      readded it, causing its oid to be greater than FirstNormalObjectId.
7435                  *      The FirstNormalObjectId test was kept to avoid repeatedly dropping
7436                  *      and recreating extensions like 'plpgsql'.
7437                  */
7438                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
7439
7440                 appendPQExpBuffer(q,
7441                                                   "SELECT binary_upgrade.create_empty_extension(");
7442                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7443                 appendPQExpBuffer(q, ", ");
7444                 appendStringLiteralAH(q, extinfo->namespace, fout);
7445                 appendPQExpBuffer(q, ", ");
7446                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7447                 appendStringLiteralAH(q, extinfo->extversion, fout);
7448                 appendPQExpBuffer(q, ", ");
7449
7450                 /*
7451                  * Note that we're pushing extconfig (an OID array) back into
7452                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7453                  * preserved in binary upgrade.
7454                  */
7455                 if (strlen(extinfo->extconfig) > 2)
7456                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7457                 else
7458                         appendPQExpBuffer(q, "NULL");
7459                 appendPQExpBuffer(q, ", ");
7460                 if (strlen(extinfo->extcondition) > 2)
7461                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7462                 else
7463                         appendPQExpBuffer(q, "NULL");
7464                 appendPQExpBuffer(q, ", ");
7465                 appendPQExpBuffer(q, "ARRAY[");
7466                 n = 0;
7467                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7468                 {
7469                         DumpableObject *extobj;
7470
7471                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7472                         if (extobj && extobj->objType == DO_EXTENSION)
7473                         {
7474                                 if (n++ > 0)
7475                                         appendPQExpBuffer(q, ",");
7476                                 appendStringLiteralAH(q, extobj->name, fout);
7477                         }
7478                 }
7479                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7480                 appendPQExpBuffer(q, ");\n");
7481         }
7482
7483         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7484
7485         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7486                                  extinfo->dobj.name,
7487                                  NULL, NULL,
7488                                  "",
7489                                  false, "EXTENSION", SECTION_PRE_DATA,
7490                                  q->data, delq->data, NULL,
7491                                  NULL, 0,
7492                                  NULL, NULL);
7493
7494         /* Dump Extension Comments and Security Labels */
7495         dumpComment(fout, labelq->data,
7496                                 NULL, "",
7497                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7498         dumpSecLabel(fout, labelq->data,
7499                                  NULL, "",
7500                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7501
7502         free(qextname);
7503
7504         destroyPQExpBuffer(q);
7505         destroyPQExpBuffer(delq);
7506         destroyPQExpBuffer(labelq);
7507 }
7508
7509 /*
7510  * dumpType
7511  *        writes out to fout the queries to recreate a user-defined type
7512  */
7513 static void
7514 dumpType(Archive *fout, TypeInfo *tyinfo)
7515 {
7516         /* Skip if not to be dumped */
7517         if (!tyinfo->dobj.dump || dataOnly)
7518                 return;
7519
7520         /* Dump out in proper style */
7521         if (tyinfo->typtype == TYPTYPE_BASE)
7522                 dumpBaseType(fout, tyinfo);
7523         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7524                 dumpDomain(fout, tyinfo);
7525         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7526                 dumpCompositeType(fout, tyinfo);
7527         else if (tyinfo->typtype == TYPTYPE_ENUM)
7528                 dumpEnumType(fout, tyinfo);
7529         else if (tyinfo->typtype == TYPTYPE_RANGE)
7530                 dumpRangeType(fout, tyinfo);
7531         else
7532                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7533                                   tyinfo->dobj.name);
7534 }
7535
7536 /*
7537  * dumpEnumType
7538  *        writes out to fout the queries to recreate a user-defined enum type
7539  */
7540 static void
7541 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7542 {
7543         PQExpBuffer q = createPQExpBuffer();
7544         PQExpBuffer delq = createPQExpBuffer();
7545         PQExpBuffer labelq = createPQExpBuffer();
7546         PQExpBuffer query = createPQExpBuffer();
7547         PGresult   *res;
7548         int                     num,
7549                                 i;
7550         Oid                     enum_oid;
7551         char       *label;
7552
7553         /* Set proper schema search path */
7554         selectSourceSchema(fout, "pg_catalog");
7555
7556         if (fout->remoteVersion >= 90100)
7557                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7558                                                   "FROM pg_catalog.pg_enum "
7559                                                   "WHERE enumtypid = '%u'"
7560                                                   "ORDER BY enumsortorder",
7561                                                   tyinfo->dobj.catId.oid);
7562         else
7563                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7564                                                   "FROM pg_catalog.pg_enum "
7565                                                   "WHERE enumtypid = '%u'"
7566                                                   "ORDER BY oid",
7567                                                   tyinfo->dobj.catId.oid);
7568
7569         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7570
7571         num = PQntuples(res);
7572
7573         /*
7574          * DROP must be fully qualified in case same name appears in pg_catalog.
7575          * CASCADE shouldn't be required here as for normal types since the I/O
7576          * functions are generic and do not get dropped.
7577          */
7578         appendPQExpBuffer(delq, "DROP TYPE %s.",
7579                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7580         appendPQExpBuffer(delq, "%s;\n",
7581                                           fmtId(tyinfo->dobj.name));
7582
7583         if (binary_upgrade)
7584                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
7585                                                                                                  tyinfo->dobj.catId.oid);
7586
7587         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
7588                                           fmtId(tyinfo->dobj.name));
7589
7590         if (!binary_upgrade)
7591         {
7592                 /* Labels with server-assigned oids */
7593                 for (i = 0; i < num; i++)
7594                 {
7595                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7596                         if (i > 0)
7597                                 appendPQExpBuffer(q, ",");
7598                         appendPQExpBuffer(q, "\n    ");
7599                         appendStringLiteralAH(q, label, fout);
7600                 }
7601         }
7602
7603         appendPQExpBuffer(q, "\n);\n");
7604
7605         if (binary_upgrade)
7606         {
7607                 /* Labels with dump-assigned (preserved) oids */
7608                 for (i = 0; i < num; i++)
7609                 {
7610                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
7611                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7612
7613                         if (i == 0)
7614                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
7615                         appendPQExpBuffer(q,
7616                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
7617                                                           enum_oid);
7618                         appendPQExpBuffer(q, "ALTER TYPE %s.",
7619                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7620                         appendPQExpBuffer(q, "%s ADD VALUE ",
7621                                                           fmtId(tyinfo->dobj.name));
7622                         appendStringLiteralAH(q, label, fout);
7623                         appendPQExpBuffer(q, ";\n\n");
7624                 }
7625         }
7626
7627         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7628
7629         if (binary_upgrade)
7630                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7631
7632         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7633                                  tyinfo->dobj.name,
7634                                  tyinfo->dobj.namespace->dobj.name,
7635                                  NULL,
7636                                  tyinfo->rolname, false,
7637                                  "TYPE", SECTION_PRE_DATA,
7638                                  q->data, delq->data, NULL,
7639                                  NULL, 0,
7640                                  NULL, NULL);
7641
7642         /* Dump Type Comments and Security Labels */
7643         dumpComment(fout, labelq->data,
7644                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7645                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7646         dumpSecLabel(fout, labelq->data,
7647                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7648                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7649
7650         PQclear(res);
7651         destroyPQExpBuffer(q);
7652         destroyPQExpBuffer(delq);
7653         destroyPQExpBuffer(labelq);
7654         destroyPQExpBuffer(query);
7655 }
7656
7657 /*
7658  * dumpRangeType
7659  *        writes out to fout the queries to recreate a user-defined range type
7660  */
7661 static void
7662 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
7663 {
7664         PQExpBuffer q = createPQExpBuffer();
7665         PQExpBuffer delq = createPQExpBuffer();
7666         PQExpBuffer labelq = createPQExpBuffer();
7667         PQExpBuffer query = createPQExpBuffer();
7668         PGresult   *res;
7669         Oid                     collationOid;
7670         char       *procname;
7671
7672         /*
7673          * select appropriate schema to ensure names in CREATE are properly
7674          * qualified
7675          */
7676         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
7677
7678         appendPQExpBuffer(query,
7679                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
7680                                           "opc.opcname AS opcname, "
7681                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
7682                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
7683                                           "opc.opcdefault, "
7684                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
7685                                           "     ELSE rngcollation END AS collation, "
7686                                           "rngcanonical, rngsubdiff "
7687                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
7688                                           "     pg_catalog.pg_opclass opc "
7689                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
7690                                           "rngtypid = '%u'",
7691                                           tyinfo->dobj.catId.oid);
7692
7693         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7694
7695         /*
7696          * DROP must be fully qualified in case same name appears in pg_catalog.
7697          * CASCADE shouldn't be required here as for normal types since the I/O
7698          * functions are generic and do not get dropped.
7699          */
7700         appendPQExpBuffer(delq, "DROP TYPE %s.",
7701                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7702         appendPQExpBuffer(delq, "%s;\n",
7703                                           fmtId(tyinfo->dobj.name));
7704
7705         if (binary_upgrade)
7706                 binary_upgrade_set_type_oids_by_type_oid(fout,
7707                                                                                                  q, tyinfo->dobj.catId.oid);
7708
7709         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
7710                                           fmtId(tyinfo->dobj.name));
7711
7712         appendPQExpBuffer(q, "\n    subtype = %s",
7713                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
7714
7715         /* print subtype_opclass only if not default for subtype */
7716         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
7717         {
7718                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
7719                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
7720
7721                 /* always schema-qualify, don't try to be smart */
7722                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
7723                                                   fmtId(nspname));
7724                 appendPQExpBuffer(q, "%s", fmtId(opcname));
7725         }
7726
7727         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
7728         if (OidIsValid(collationOid))
7729         {
7730                 CollInfo   *coll = findCollationByOid(collationOid);
7731
7732                 if (coll)
7733                 {
7734                         /* always schema-qualify, don't try to be smart */
7735                         appendPQExpBuffer(q, ",\n    collation = %s.",
7736                                                           fmtId(coll->dobj.namespace->dobj.name));
7737                         appendPQExpBuffer(q, "%s",
7738                                                           fmtId(coll->dobj.name));
7739                 }
7740         }
7741
7742         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
7743         if (strcmp(procname, "-") != 0)
7744                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
7745
7746         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
7747         if (strcmp(procname, "-") != 0)
7748                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
7749
7750         appendPQExpBuffer(q, "\n);\n");
7751
7752         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7753
7754         if (binary_upgrade)
7755                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7756
7757         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7758                                  tyinfo->dobj.name,
7759                                  tyinfo->dobj.namespace->dobj.name,
7760                                  NULL,
7761                                  tyinfo->rolname, false,
7762                                  "TYPE", SECTION_PRE_DATA,
7763                                  q->data, delq->data, NULL,
7764                                  NULL, 0,
7765                                  NULL, NULL);
7766
7767         /* Dump Type Comments and Security Labels */
7768         dumpComment(fout, labelq->data,
7769                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7770                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7771         dumpSecLabel(fout, labelq->data,
7772                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7773                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7774
7775         PQclear(res);
7776         destroyPQExpBuffer(q);
7777         destroyPQExpBuffer(delq);
7778         destroyPQExpBuffer(labelq);
7779         destroyPQExpBuffer(query);
7780 }
7781
7782 /*
7783  * dumpBaseType
7784  *        writes out to fout the queries to recreate a user-defined base type
7785  */
7786 static void
7787 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
7788 {
7789         PQExpBuffer q = createPQExpBuffer();
7790         PQExpBuffer delq = createPQExpBuffer();
7791         PQExpBuffer labelq = createPQExpBuffer();
7792         PQExpBuffer query = createPQExpBuffer();
7793         PGresult   *res;
7794         char       *typlen;
7795         char       *typinput;
7796         char       *typoutput;
7797         char       *typreceive;
7798         char       *typsend;
7799         char       *typmodin;
7800         char       *typmodout;
7801         char       *typanalyze;
7802         Oid                     typreceiveoid;
7803         Oid                     typsendoid;
7804         Oid                     typmodinoid;
7805         Oid                     typmodoutoid;
7806         Oid                     typanalyzeoid;
7807         char       *typcategory;
7808         char       *typispreferred;
7809         char       *typdelim;
7810         char       *typbyval;
7811         char       *typalign;
7812         char       *typstorage;
7813         char       *typcollatable;
7814         char       *typdefault;
7815         bool            typdefault_is_literal = false;
7816
7817         /* Set proper schema search path so regproc references list correctly */
7818         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
7819
7820         /* Fetch type-specific details */
7821         if (fout->remoteVersion >= 90100)
7822         {
7823                 appendPQExpBuffer(query, "SELECT typlen, "
7824                                                   "typinput, typoutput, typreceive, typsend, "
7825                                                   "typmodin, typmodout, typanalyze, "
7826                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7827                                                   "typsend::pg_catalog.oid AS typsendoid, "
7828                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7829                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7830                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7831                                                   "typcategory, typispreferred, "
7832                                                   "typdelim, typbyval, typalign, typstorage, "
7833                                                   "(typcollation <> 0) AS typcollatable, "
7834                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7835                                                   "FROM pg_catalog.pg_type "
7836                                                   "WHERE oid = '%u'::pg_catalog.oid",
7837                                                   tyinfo->dobj.catId.oid);
7838         }
7839         else if (fout->remoteVersion >= 80400)
7840         {
7841                 appendPQExpBuffer(query, "SELECT typlen, "
7842                                                   "typinput, typoutput, typreceive, typsend, "
7843                                                   "typmodin, typmodout, typanalyze, "
7844                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7845                                                   "typsend::pg_catalog.oid AS typsendoid, "
7846                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7847                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7848                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7849                                                   "typcategory, typispreferred, "
7850                                                   "typdelim, typbyval, typalign, typstorage, "
7851                                                   "false AS typcollatable, "
7852                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7853                                                   "FROM pg_catalog.pg_type "
7854                                                   "WHERE oid = '%u'::pg_catalog.oid",
7855                                                   tyinfo->dobj.catId.oid);
7856         }
7857         else if (fout->remoteVersion >= 80300)
7858         {
7859                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
7860                 appendPQExpBuffer(query, "SELECT typlen, "
7861                                                   "typinput, typoutput, typreceive, typsend, "
7862                                                   "typmodin, typmodout, typanalyze, "
7863                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7864                                                   "typsend::pg_catalog.oid AS typsendoid, "
7865                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7866                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7867                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7868                                                   "'U' AS typcategory, false AS typispreferred, "
7869                                                   "typdelim, typbyval, typalign, typstorage, "
7870                                                   "false AS typcollatable, "
7871                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7872                                                   "FROM pg_catalog.pg_type "
7873                                                   "WHERE oid = '%u'::pg_catalog.oid",
7874                                                   tyinfo->dobj.catId.oid);
7875         }
7876         else if (fout->remoteVersion >= 80000)
7877         {
7878                 appendPQExpBuffer(query, "SELECT typlen, "
7879                                                   "typinput, typoutput, typreceive, typsend, "
7880                                                   "'-' AS typmodin, '-' AS typmodout, "
7881                                                   "typanalyze, "
7882                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7883                                                   "typsend::pg_catalog.oid AS typsendoid, "
7884                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7885                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7886                                                   "'U' AS typcategory, false AS typispreferred, "
7887                                                   "typdelim, typbyval, typalign, typstorage, "
7888                                                   "false AS typcollatable, "
7889                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7890                                                   "FROM pg_catalog.pg_type "
7891                                                   "WHERE oid = '%u'::pg_catalog.oid",
7892                                                   tyinfo->dobj.catId.oid);
7893         }
7894         else if (fout->remoteVersion >= 70400)
7895         {
7896                 appendPQExpBuffer(query, "SELECT typlen, "
7897                                                   "typinput, typoutput, typreceive, typsend, "
7898                                                   "'-' AS typmodin, '-' AS typmodout, "
7899                                                   "'-' AS typanalyze, "
7900                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7901                                                   "typsend::pg_catalog.oid AS typsendoid, "
7902                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7903                                                   "0 AS typanalyzeoid, "
7904                                                   "'U' AS typcategory, false AS typispreferred, "
7905                                                   "typdelim, typbyval, typalign, typstorage, "
7906                                                   "false AS typcollatable, "
7907                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7908                                                   "FROM pg_catalog.pg_type "
7909                                                   "WHERE oid = '%u'::pg_catalog.oid",
7910                                                   tyinfo->dobj.catId.oid);
7911         }
7912         else if (fout->remoteVersion >= 70300)
7913         {
7914                 appendPQExpBuffer(query, "SELECT typlen, "
7915                                                   "typinput, typoutput, "
7916                                                   "'-' AS typreceive, '-' AS typsend, "
7917                                                   "'-' AS typmodin, '-' AS typmodout, "
7918                                                   "'-' AS typanalyze, "
7919                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7920                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7921                                                   "0 AS typanalyzeoid, "
7922                                                   "'U' AS typcategory, false AS typispreferred, "
7923                                                   "typdelim, typbyval, typalign, typstorage, "
7924                                                   "false AS typcollatable, "
7925                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7926                                                   "FROM pg_catalog.pg_type "
7927                                                   "WHERE oid = '%u'::pg_catalog.oid",
7928                                                   tyinfo->dobj.catId.oid);
7929         }
7930         else if (fout->remoteVersion >= 70200)
7931         {
7932                 /*
7933                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
7934                  * ignore them because they are not right.
7935                  */
7936                 appendPQExpBuffer(query, "SELECT typlen, "
7937                                                   "typinput, typoutput, "
7938                                                   "'-' AS typreceive, '-' AS typsend, "
7939                                                   "'-' AS typmodin, '-' AS typmodout, "
7940                                                   "'-' AS typanalyze, "
7941                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7942                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7943                                                   "0 AS typanalyzeoid, "
7944                                                   "'U' AS typcategory, false AS typispreferred, "
7945                                                   "typdelim, typbyval, typalign, typstorage, "
7946                                                   "false AS typcollatable, "
7947                                                   "NULL AS typdefaultbin, typdefault "
7948                                                   "FROM pg_type "
7949                                                   "WHERE oid = '%u'::oid",
7950                                                   tyinfo->dobj.catId.oid);
7951         }
7952         else if (fout->remoteVersion >= 70100)
7953         {
7954                 /*
7955                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
7956                  * representation.
7957                  */
7958                 appendPQExpBuffer(query, "SELECT typlen, "
7959                                                   "typinput, typoutput, "
7960                                                   "'-' AS typreceive, '-' AS typsend, "
7961                                                   "'-' AS typmodin, '-' AS typmodout, "
7962                                                   "'-' AS typanalyze, "
7963                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7964                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7965                                                   "0 AS typanalyzeoid, "
7966                                                   "'U' AS typcategory, false AS typispreferred, "
7967                                                   "typdelim, typbyval, typalign, typstorage, "
7968                                                   "false AS typcollatable, "
7969                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7970                                                   "FROM pg_type "
7971                                                   "WHERE oid = '%u'::oid",
7972                                                   tyinfo->dobj.catId.oid);
7973         }
7974         else
7975         {
7976                 appendPQExpBuffer(query, "SELECT typlen, "
7977                                                   "typinput, typoutput, "
7978                                                   "'-' AS typreceive, '-' AS typsend, "
7979                                                   "'-' AS typmodin, '-' AS typmodout, "
7980                                                   "'-' AS typanalyze, "
7981                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7982                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7983                                                   "0 AS typanalyzeoid, "
7984                                                   "'U' AS typcategory, false AS typispreferred, "
7985                                                   "typdelim, typbyval, typalign, "
7986                                                   "'p'::char AS typstorage, "
7987                                                   "false AS typcollatable, "
7988                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7989                                                   "FROM pg_type "
7990                                                   "WHERE oid = '%u'::oid",
7991                                                   tyinfo->dobj.catId.oid);
7992         }
7993
7994         res = ExecuteSqlQueryForSingleRow(fout, query->data);
7995
7996         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
7997         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
7998         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7999         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8000         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8001         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8002         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8003         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8004         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8005         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8006         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8007         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8008         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8009         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8010         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8011         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8012         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8013         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8014         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8015         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8016         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8017                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8018         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8019         {
8020                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8021                 typdefault_is_literal = true;   /* it needs quotes */
8022         }
8023         else
8024                 typdefault = NULL;
8025
8026         /*
8027          * DROP must be fully qualified in case same name appears in pg_catalog.
8028          * The reason we include CASCADE is that the circular dependency between
8029          * the type and its I/O functions makes it impossible to drop the type any
8030          * other way.
8031          */
8032         appendPQExpBuffer(delq, "DROP TYPE %s.",
8033                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8034         appendPQExpBuffer(delq, "%s CASCADE;\n",
8035                                           fmtId(tyinfo->dobj.name));
8036
8037         /* We might already have a shell type, but setting pg_type_oid is harmless */
8038         if (binary_upgrade)
8039                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8040                                                                                                  tyinfo->dobj.catId.oid);
8041
8042         appendPQExpBuffer(q,
8043                                           "CREATE TYPE %s (\n"
8044                                           "    INTERNALLENGTH = %s",
8045                                           fmtId(tyinfo->dobj.name),
8046                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8047
8048         if (fout->remoteVersion >= 70300)
8049         {
8050                 /* regproc result is correctly quoted as of 7.3 */
8051                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8052                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8053                 if (OidIsValid(typreceiveoid))
8054                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8055                 if (OidIsValid(typsendoid))
8056                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8057                 if (OidIsValid(typmodinoid))
8058                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8059                 if (OidIsValid(typmodoutoid))
8060                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8061                 if (OidIsValid(typanalyzeoid))
8062                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8063         }
8064         else
8065         {
8066                 /* regproc delivers an unquoted name before 7.3 */
8067                 /* cannot combine these because fmtId uses static result area */
8068                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8069                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8070                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8071         }
8072
8073         if (strcmp(typcollatable, "t") == 0)
8074                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8075
8076         if (typdefault != NULL)
8077         {
8078                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8079                 if (typdefault_is_literal)
8080                         appendStringLiteralAH(q, typdefault, fout);
8081                 else
8082                         appendPQExpBufferStr(q, typdefault);
8083         }
8084
8085         if (OidIsValid(tyinfo->typelem))
8086         {
8087                 char       *elemType;
8088
8089                 /* reselect schema in case changed by function dump */
8090                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8091                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8092                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8093                 free(elemType);
8094         }
8095
8096         if (strcmp(typcategory, "U") != 0)
8097         {
8098                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8099                 appendStringLiteralAH(q, typcategory, fout);
8100         }
8101
8102         if (strcmp(typispreferred, "t") == 0)
8103                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8104
8105         if (typdelim && strcmp(typdelim, ",") != 0)
8106         {
8107                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8108                 appendStringLiteralAH(q, typdelim, fout);
8109         }
8110
8111         if (strcmp(typalign, "c") == 0)
8112                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8113         else if (strcmp(typalign, "s") == 0)
8114                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8115         else if (strcmp(typalign, "i") == 0)
8116                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8117         else if (strcmp(typalign, "d") == 0)
8118                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8119
8120         if (strcmp(typstorage, "p") == 0)
8121                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8122         else if (strcmp(typstorage, "e") == 0)
8123                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8124         else if (strcmp(typstorage, "x") == 0)
8125                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8126         else if (strcmp(typstorage, "m") == 0)
8127                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8128
8129         if (strcmp(typbyval, "t") == 0)
8130                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8131
8132         appendPQExpBuffer(q, "\n);\n");
8133
8134         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8135
8136         if (binary_upgrade)
8137                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8138
8139         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8140                                  tyinfo->dobj.name,
8141                                  tyinfo->dobj.namespace->dobj.name,
8142                                  NULL,
8143                                  tyinfo->rolname, false,
8144                                  "TYPE", SECTION_PRE_DATA,
8145                                  q->data, delq->data, NULL,
8146                                  NULL, 0,
8147                                  NULL, NULL);
8148
8149         /* Dump Type Comments and Security Labels */
8150         dumpComment(fout, labelq->data,
8151                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8152                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8153         dumpSecLabel(fout, labelq->data,
8154                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8155                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8156
8157         PQclear(res);
8158         destroyPQExpBuffer(q);
8159         destroyPQExpBuffer(delq);
8160         destroyPQExpBuffer(labelq);
8161         destroyPQExpBuffer(query);
8162 }
8163
8164 /*
8165  * dumpDomain
8166  *        writes out to fout the queries to recreate a user-defined domain
8167  */
8168 static void
8169 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8170 {
8171         PQExpBuffer q = createPQExpBuffer();
8172         PQExpBuffer delq = createPQExpBuffer();
8173         PQExpBuffer labelq = createPQExpBuffer();
8174         PQExpBuffer query = createPQExpBuffer();
8175         PGresult   *res;
8176         int                     i;
8177         char       *typnotnull;
8178         char       *typdefn;
8179         char       *typdefault;
8180         Oid                     typcollation;
8181         bool            typdefault_is_literal = false;
8182
8183         /* Set proper schema search path so type references list correctly */
8184         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8185
8186         /* Fetch domain specific details */
8187         if (fout->remoteVersion >= 90100)
8188         {
8189                 /* typcollation is new in 9.1 */
8190                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8191                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8192                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8193                                                   "t.typdefault, "
8194                                                   "CASE WHEN t.typcollation <> u.typcollation "
8195                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8196                                                   "FROM pg_catalog.pg_type t "
8197                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8198                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8199                                                   tyinfo->dobj.catId.oid);
8200         }
8201         else
8202         {
8203                 /* We assume here that remoteVersion must be at least 70300 */
8204                 appendPQExpBuffer(query, "SELECT typnotnull, "
8205                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8206                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8207                                                   "typdefault, 0 AS typcollation "
8208                                                   "FROM pg_catalog.pg_type "
8209                                                   "WHERE oid = '%u'::pg_catalog.oid",
8210                                                   tyinfo->dobj.catId.oid);
8211         }
8212
8213         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8214
8215         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8216         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8217         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8218                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8219         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8220         {
8221                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8222                 typdefault_is_literal = true;   /* it needs quotes */
8223         }
8224         else
8225                 typdefault = NULL;
8226         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8227
8228         if (binary_upgrade)
8229                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8230                                                                                                  tyinfo->dobj.catId.oid);
8231
8232         appendPQExpBuffer(q,
8233                                           "CREATE DOMAIN %s AS %s",
8234                                           fmtId(tyinfo->dobj.name),
8235                                           typdefn);
8236
8237         /* Print collation only if different from base type's collation */
8238         if (OidIsValid(typcollation))
8239         {
8240                 CollInfo   *coll;
8241
8242                 coll = findCollationByOid(typcollation);
8243                 if (coll)
8244                 {
8245                         /* always schema-qualify, don't try to be smart */
8246                         appendPQExpBuffer(q, " COLLATE %s.",
8247                                                           fmtId(coll->dobj.namespace->dobj.name));
8248                         appendPQExpBuffer(q, "%s",
8249                                                           fmtId(coll->dobj.name));
8250                 }
8251         }
8252
8253         if (typnotnull[0] == 't')
8254                 appendPQExpBuffer(q, " NOT NULL");
8255
8256         if (typdefault != NULL)
8257         {
8258                 appendPQExpBuffer(q, " DEFAULT ");
8259                 if (typdefault_is_literal)
8260                         appendStringLiteralAH(q, typdefault, fout);
8261                 else
8262                         appendPQExpBufferStr(q, typdefault);
8263         }
8264
8265         PQclear(res);
8266
8267         /*
8268          * Add any CHECK constraints for the domain
8269          */
8270         for (i = 0; i < tyinfo->nDomChecks; i++)
8271         {
8272                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8273
8274                 if (!domcheck->separate)
8275                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8276                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8277         }
8278
8279         appendPQExpBuffer(q, ";\n");
8280
8281         /*
8282          * DROP must be fully qualified in case same name appears in pg_catalog
8283          */
8284         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8285                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8286         appendPQExpBuffer(delq, "%s;\n",
8287                                           fmtId(tyinfo->dobj.name));
8288
8289         appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
8290
8291         if (binary_upgrade)
8292                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8293
8294         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8295                                  tyinfo->dobj.name,
8296                                  tyinfo->dobj.namespace->dobj.name,
8297                                  NULL,
8298                                  tyinfo->rolname, false,
8299                                  "DOMAIN", SECTION_PRE_DATA,
8300                                  q->data, delq->data, NULL,
8301                                  NULL, 0,
8302                                  NULL, NULL);
8303
8304         /* Dump Domain Comments and Security Labels */
8305         dumpComment(fout, labelq->data,
8306                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8307                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8308         dumpSecLabel(fout, labelq->data,
8309                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8310                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8311
8312         destroyPQExpBuffer(q);
8313         destroyPQExpBuffer(delq);
8314         destroyPQExpBuffer(labelq);
8315         destroyPQExpBuffer(query);
8316 }
8317
8318 /*
8319  * dumpCompositeType
8320  *        writes out to fout the queries to recreate a user-defined stand-alone
8321  *        composite type
8322  */
8323 static void
8324 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8325 {
8326         PQExpBuffer q = createPQExpBuffer();
8327         PQExpBuffer dropped = createPQExpBuffer();
8328         PQExpBuffer delq = createPQExpBuffer();
8329         PQExpBuffer labelq = createPQExpBuffer();
8330         PQExpBuffer query = createPQExpBuffer();
8331         PGresult   *res;
8332         int                     ntups;
8333         int                     i_attname;
8334         int                     i_atttypdefn;
8335         int                     i_attlen;
8336         int                     i_attalign;
8337         int                     i_attisdropped;
8338         int                     i_attcollation;
8339         int                     i_typrelid;
8340         int                     i;
8341         int                     actual_atts;
8342
8343         /* Set proper schema search path so type references list correctly */
8344         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8345
8346         /* Fetch type specific details */
8347         if (fout->remoteVersion >= 90100)
8348         {
8349                 /*
8350                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8351                  * clauses for attributes whose collation is different from their
8352                  * type's default, we use a CASE here to suppress uninteresting
8353                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8354                  * collation does not matter for those.
8355                  */
8356                 appendPQExpBuffer(query, "SELECT a.attname, "
8357                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8358                                                   "a.attlen, a.attalign, a.attisdropped, "
8359                                                   "CASE WHEN a.attcollation <> at.typcollation "
8360                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8361                                                   "ct.typrelid "
8362                                                   "FROM pg_catalog.pg_type ct "
8363                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8364                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8365                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8366                                                   "ORDER BY a.attnum ",
8367                                                   tyinfo->dobj.catId.oid);
8368         }
8369         else
8370         {
8371                 /*
8372                  * We assume here that remoteVersion must be at least 70300.  Since
8373                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8374                  * always be false.
8375                  */
8376                 appendPQExpBuffer(query, "SELECT a.attname, "
8377                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8378                                                   "a.attlen, a.attalign, a.attisdropped, "
8379                                                   "0 AS attcollation, "
8380                                                   "ct.typrelid "
8381                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8382                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8383                                                   "AND a.attrelid = ct.typrelid "
8384                                                   "ORDER BY a.attnum ",
8385                                                   tyinfo->dobj.catId.oid);
8386         }
8387
8388         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8389
8390         ntups = PQntuples(res);
8391
8392         i_attname = PQfnumber(res, "attname");
8393         i_atttypdefn = PQfnumber(res, "atttypdefn");
8394         i_attlen = PQfnumber(res, "attlen");
8395         i_attalign = PQfnumber(res, "attalign");
8396         i_attisdropped = PQfnumber(res, "attisdropped");
8397         i_attcollation = PQfnumber(res, "attcollation");
8398         i_typrelid = PQfnumber(res, "typrelid");
8399
8400         if (binary_upgrade)
8401         {
8402                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8403
8404                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8405                                                                                                  tyinfo->dobj.catId.oid);
8406                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8407         }
8408
8409         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8410                                           fmtId(tyinfo->dobj.name));
8411
8412         actual_atts = 0;
8413         for (i = 0; i < ntups; i++)
8414         {
8415                 char       *attname;
8416                 char       *atttypdefn;
8417                 char       *attlen;
8418                 char       *attalign;
8419                 bool            attisdropped;
8420                 Oid                     attcollation;
8421
8422                 attname = PQgetvalue(res, i, i_attname);
8423                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8424                 attlen = PQgetvalue(res, i, i_attlen);
8425                 attalign = PQgetvalue(res, i, i_attalign);
8426                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8427                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8428
8429                 if (attisdropped && !binary_upgrade)
8430                         continue;
8431
8432                 /* Format properly if not first attr */
8433                 if (actual_atts++ > 0)
8434                         appendPQExpBuffer(q, ",");
8435                 appendPQExpBuffer(q, "\n\t");
8436
8437                 if (!attisdropped)
8438                 {
8439                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8440
8441                         /* Add collation if not default for the column type */
8442                         if (OidIsValid(attcollation))
8443                         {
8444                                 CollInfo   *coll;
8445
8446                                 coll = findCollationByOid(attcollation);
8447                                 if (coll)
8448                                 {
8449                                         /* always schema-qualify, don't try to be smart */
8450                                         appendPQExpBuffer(q, " COLLATE %s.",
8451                                                                           fmtId(coll->dobj.namespace->dobj.name));
8452                                         appendPQExpBuffer(q, "%s",
8453                                                                           fmtId(coll->dobj.name));
8454                                 }
8455                         }
8456                 }
8457                 else
8458                 {
8459                         /*
8460                          * This is a dropped attribute and we're in binary_upgrade mode.
8461                          * Insert a placeholder for it in the CREATE TYPE command, and set
8462                          * length and alignment with direct UPDATE to the catalogs
8463                          * afterwards. See similar code in dumpTableSchema().
8464                          */
8465                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8466
8467                         /* stash separately for insertion after the CREATE TYPE */
8468                         appendPQExpBuffer(dropped,
8469                                           "\n-- For binary upgrade, recreate dropped column.\n");
8470                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8471                                                           "SET attlen = %s, "
8472                                                           "attalign = '%s', attbyval = false\n"
8473                                                           "WHERE attname = ", attlen, attalign);
8474                         appendStringLiteralAH(dropped, attname, fout);
8475                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8476                         appendStringLiteralAH(dropped, fmtId(tyinfo->dobj.name), fout);
8477                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8478
8479                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8480                                                           fmtId(tyinfo->dobj.name));
8481                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8482                                                           fmtId(attname));
8483                 }
8484         }
8485         appendPQExpBuffer(q, "\n);\n");
8486         appendPQExpBufferStr(q, dropped->data);
8487
8488         /*
8489          * DROP must be fully qualified in case same name appears in pg_catalog
8490          */
8491         appendPQExpBuffer(delq, "DROP TYPE %s.",
8492                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8493         appendPQExpBuffer(delq, "%s;\n",
8494                                           fmtId(tyinfo->dobj.name));
8495
8496         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8497
8498         if (binary_upgrade)
8499                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8500
8501         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8502                                  tyinfo->dobj.name,
8503                                  tyinfo->dobj.namespace->dobj.name,
8504                                  NULL,
8505                                  tyinfo->rolname, false,
8506                                  "TYPE", SECTION_PRE_DATA,
8507                                  q->data, delq->data, NULL,
8508                                  NULL, 0,
8509                                  NULL, NULL);
8510
8511
8512         /* Dump Type Comments and Security Labels */
8513         dumpComment(fout, labelq->data,
8514                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8515                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8516         dumpSecLabel(fout, labelq->data,
8517                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8518                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8519
8520         PQclear(res);
8521         destroyPQExpBuffer(q);
8522         destroyPQExpBuffer(dropped);
8523         destroyPQExpBuffer(delq);
8524         destroyPQExpBuffer(labelq);
8525         destroyPQExpBuffer(query);
8526
8527         /* Dump any per-column comments */
8528         dumpCompositeTypeColComments(fout, tyinfo);
8529 }
8530
8531 /*
8532  * dumpCompositeTypeColComments
8533  *        writes out to fout the queries to recreate comments on the columns of
8534  *        a user-defined stand-alone composite type
8535  */
8536 static void
8537 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
8538 {
8539         CommentItem *comments;
8540         int                     ncomments;
8541         PGresult   *res;
8542         PQExpBuffer query;
8543         PQExpBuffer target;
8544         Oid                     pgClassOid;
8545         int                     i;
8546         int                     ntups;
8547         int                     i_attname;
8548         int                     i_attnum;
8549
8550         query = createPQExpBuffer();
8551
8552         /* We assume here that remoteVersion must be at least 70300 */
8553         appendPQExpBuffer(query,
8554                                           "SELECT c.tableoid, a.attname, a.attnum "
8555                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
8556                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
8557                                           "  AND NOT a.attisdropped "
8558                                           "ORDER BY a.attnum ",
8559                                           tyinfo->typrelid);
8560
8561         /* Fetch column attnames */
8562         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8563
8564         ntups = PQntuples(res);
8565         if (ntups < 1)
8566         {
8567                 PQclear(res);
8568                 destroyPQExpBuffer(query);
8569                 return;
8570         }
8571
8572         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
8573
8574         /* Search for comments associated with type's pg_class OID */
8575         ncomments = findComments(fout,
8576                                                          pgClassOid,
8577                                                          tyinfo->typrelid,
8578                                                          &comments);
8579
8580         /* If no comments exist, we're done */
8581         if (ncomments <= 0)
8582         {
8583                 PQclear(res);
8584                 destroyPQExpBuffer(query);
8585                 return;
8586         }
8587
8588         /* Build COMMENT ON statements */
8589         target = createPQExpBuffer();
8590
8591         i_attnum = PQfnumber(res, "attnum");
8592         i_attname = PQfnumber(res, "attname");
8593         while (ncomments > 0)
8594         {
8595                 const char *attname;
8596
8597                 attname = NULL;
8598                 for (i = 0; i < ntups; i++)
8599                 {
8600                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
8601                         {
8602                                 attname = PQgetvalue(res, i, i_attname);
8603                                 break;
8604                         }
8605                 }
8606                 if (attname)                    /* just in case we don't find it */
8607                 {
8608                         const char *descr = comments->descr;
8609
8610                         resetPQExpBuffer(target);
8611                         appendPQExpBuffer(target, "COLUMN %s.",
8612                                                           fmtId(tyinfo->dobj.name));
8613                         appendPQExpBuffer(target, "%s",
8614                                                           fmtId(attname));
8615
8616                         resetPQExpBuffer(query);
8617                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
8618                         appendStringLiteralAH(query, descr, fout);
8619                         appendPQExpBuffer(query, ";\n");
8620
8621                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
8622                                                  target->data,
8623                                                  tyinfo->dobj.namespace->dobj.name,
8624                                                  NULL, tyinfo->rolname,
8625                                                  false, "COMMENT", SECTION_NONE,
8626                                                  query->data, "", NULL,
8627                                                  &(tyinfo->dobj.dumpId), 1,
8628                                                  NULL, NULL);
8629                 }
8630
8631                 comments++;
8632                 ncomments--;
8633         }
8634
8635         PQclear(res);
8636         destroyPQExpBuffer(query);
8637         destroyPQExpBuffer(target);
8638 }
8639
8640 /*
8641  * dumpShellType
8642  *        writes out to fout the queries to create a shell type
8643  *
8644  * We dump a shell definition in advance of the I/O functions for the type.
8645  */
8646 static void
8647 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
8648 {
8649         PQExpBuffer q;
8650
8651         /* Skip if not to be dumped */
8652         if (!stinfo->dobj.dump || dataOnly)
8653                 return;
8654
8655         q = createPQExpBuffer();
8656
8657         /*
8658          * Note the lack of a DROP command for the shell type; any required DROP
8659          * is driven off the base type entry, instead.  This interacts with
8660          * _printTocEntry()'s use of the presence of a DROP command to decide
8661          * whether an entry needs an ALTER OWNER command.  We don't want to alter
8662          * the shell type's owner immediately on creation; that should happen only
8663          * after it's filled in, otherwise the backend complains.
8664          */
8665
8666         if (binary_upgrade)
8667                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8668                                                                                    stinfo->baseType->dobj.catId.oid);
8669
8670         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
8671                                           fmtId(stinfo->dobj.name));
8672
8673         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
8674                                  stinfo->dobj.name,
8675                                  stinfo->dobj.namespace->dobj.name,
8676                                  NULL,
8677                                  stinfo->baseType->rolname, false,
8678                                  "SHELL TYPE", SECTION_PRE_DATA,
8679                                  q->data, "", NULL,
8680                                  NULL, 0,
8681                                  NULL, NULL);
8682
8683         destroyPQExpBuffer(q);
8684 }
8685
8686 /*
8687  * Determine whether we want to dump definitions for procedural languages.
8688  * Since the languages themselves don't have schemas, we can't rely on
8689  * the normal schema-based selection mechanism.  We choose to dump them
8690  * whenever neither --schema nor --table was given.  (Before 8.1, we used
8691  * the dump flag of the PL's call handler function, but in 8.1 this will
8692  * probably always be false since call handlers are created in pg_catalog.)
8693  *
8694  * For some backwards compatibility with the older behavior, we forcibly
8695  * dump a PL if its handler function (and validator if any) are in a
8696  * dumpable namespace.  That case is not checked here.
8697  *
8698  * Also, if the PL belongs to an extension, we do not use this heuristic.
8699  * That case isn't checked here either.
8700  */
8701 static bool
8702 shouldDumpProcLangs(void)
8703 {
8704         if (!include_everything)
8705                 return false;
8706         /* And they're schema not data */
8707         if (dataOnly)
8708                 return false;
8709         return true;
8710 }
8711
8712 /*
8713  * dumpProcLang
8714  *                writes out to fout the queries to recreate a user-defined
8715  *                procedural language
8716  */
8717 static void
8718 dumpProcLang(Archive *fout, ProcLangInfo *plang)
8719 {
8720         PQExpBuffer defqry;
8721         PQExpBuffer delqry;
8722         PQExpBuffer labelq;
8723         bool            useParams;
8724         char       *qlanname;
8725         char       *lanschema;
8726         FuncInfo   *funcInfo;
8727         FuncInfo   *inlineInfo = NULL;
8728         FuncInfo   *validatorInfo = NULL;
8729
8730         /* Skip if not to be dumped */
8731         if (!plang->dobj.dump || dataOnly)
8732                 return;
8733
8734         /*
8735          * Try to find the support function(s).  It is not an error if we don't
8736          * find them --- if the functions are in the pg_catalog schema, as is
8737          * standard in 8.1 and up, then we won't have loaded them. (In this case
8738          * we will emit a parameterless CREATE LANGUAGE command, which will
8739          * require PL template knowledge in the backend to reload.)
8740          */
8741
8742         funcInfo = findFuncByOid(plang->lanplcallfoid);
8743         if (funcInfo != NULL && !funcInfo->dobj.dump)
8744                 funcInfo = NULL;                /* treat not-dumped same as not-found */
8745
8746         if (OidIsValid(plang->laninline))
8747         {
8748                 inlineInfo = findFuncByOid(plang->laninline);
8749                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
8750                         inlineInfo = NULL;
8751         }
8752
8753         if (OidIsValid(plang->lanvalidator))
8754         {
8755                 validatorInfo = findFuncByOid(plang->lanvalidator);
8756                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
8757                         validatorInfo = NULL;
8758         }
8759
8760         /*
8761          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
8762          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
8763          * dump it.
8764          *
8765          * However, for a language that belongs to an extension, we must not use
8766          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
8767          * told to (via dobj.dump).  Generally the support functions will belong
8768          * to the same extension and so have the same dump flags ... if they
8769          * don't, this might not work terribly nicely.
8770          */
8771         useParams = (funcInfo != NULL &&
8772                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
8773                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
8774
8775         if (!plang->dobj.ext_member)
8776         {
8777                 if (!useParams && !shouldDumpProcLangs())
8778                         return;
8779         }
8780
8781         defqry = createPQExpBuffer();
8782         delqry = createPQExpBuffer();
8783         labelq = createPQExpBuffer();
8784
8785         qlanname = pg_strdup(fmtId(plang->dobj.name));
8786
8787         /*
8788          * If dumping a HANDLER clause, treat the language as being in the handler
8789          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
8790          * it doesn't really have a schema.
8791          */
8792         if (useParams)
8793                 lanschema = funcInfo->dobj.namespace->dobj.name;
8794         else
8795                 lanschema = NULL;
8796
8797         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
8798                                           qlanname);
8799
8800         if (useParams)
8801         {
8802                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
8803                                                   plang->lanpltrusted ? "TRUSTED " : "",
8804                                                   qlanname);
8805                 appendPQExpBuffer(defqry, " HANDLER %s",
8806                                                   fmtId(funcInfo->dobj.name));
8807                 if (OidIsValid(plang->laninline))
8808                 {
8809                         appendPQExpBuffer(defqry, " INLINE ");
8810                         /* Cope with possibility that inline is in different schema */
8811                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
8812                                 appendPQExpBuffer(defqry, "%s.",
8813                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
8814                         appendPQExpBuffer(defqry, "%s",
8815                                                           fmtId(inlineInfo->dobj.name));
8816                 }
8817                 if (OidIsValid(plang->lanvalidator))
8818                 {
8819                         appendPQExpBuffer(defqry, " VALIDATOR ");
8820                         /* Cope with possibility that validator is in different schema */
8821                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
8822                                 appendPQExpBuffer(defqry, "%s.",
8823                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
8824                         appendPQExpBuffer(defqry, "%s",
8825                                                           fmtId(validatorInfo->dobj.name));
8826                 }
8827         }
8828         else
8829         {
8830                 /*
8831                  * If not dumping parameters, then use CREATE OR REPLACE so that the
8832                  * command will not fail if the language is preinstalled in the target
8833                  * database.  We restrict the use of REPLACE to this case so as to
8834                  * eliminate the risk of replacing a language with incompatible
8835                  * parameter settings: this command will only succeed at all if there
8836                  * is a pg_pltemplate entry, and if there is one, the existing entry
8837                  * must match it too.
8838                  */
8839                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
8840                                                   qlanname);
8841         }
8842         appendPQExpBuffer(defqry, ";\n");
8843
8844         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
8845
8846         if (binary_upgrade)
8847                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
8848
8849         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
8850                                  plang->dobj.name,
8851                                  lanschema, NULL, plang->lanowner,
8852                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
8853                                  defqry->data, delqry->data, NULL,
8854                                  NULL, 0,
8855                                  NULL, NULL);
8856
8857         /* Dump Proc Lang Comments and Security Labels */
8858         dumpComment(fout, labelq->data,
8859                                 NULL, "",
8860                                 plang->dobj.catId, 0, plang->dobj.dumpId);
8861         dumpSecLabel(fout, labelq->data,
8862                                  NULL, "",
8863                                  plang->dobj.catId, 0, plang->dobj.dumpId);
8864
8865         if (plang->lanpltrusted)
8866                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
8867                                 qlanname, NULL, plang->dobj.name,
8868                                 lanschema,
8869                                 plang->lanowner, plang->lanacl);
8870
8871         free(qlanname);
8872
8873         destroyPQExpBuffer(defqry);
8874         destroyPQExpBuffer(delqry);
8875         destroyPQExpBuffer(labelq);
8876 }
8877
8878 /*
8879  * format_function_arguments: generate function name and argument list
8880  *
8881  * This is used when we can rely on pg_get_function_arguments to format
8882  * the argument list.
8883  */
8884 static char *
8885 format_function_arguments(FuncInfo *finfo, char *funcargs)
8886 {
8887         PQExpBufferData fn;
8888
8889         initPQExpBuffer(&fn);
8890         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
8891         return fn.data;
8892 }
8893
8894 /*
8895  * format_function_arguments_old: generate function name and argument list
8896  *
8897  * The argument type names are qualified if needed.  The function name
8898  * is never qualified.
8899  *
8900  * This is used only with pre-8.4 servers, so we aren't expecting to see
8901  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
8902  *
8903  * Any or all of allargtypes, argmodes, argnames may be NULL.
8904  */
8905 static char *
8906 format_function_arguments_old(Archive *fout,
8907                                                           FuncInfo *finfo, int nallargs,
8908                                                           char **allargtypes,
8909                                                           char **argmodes,
8910                                                           char **argnames)
8911 {
8912         PQExpBufferData fn;
8913         int                     j;
8914
8915         initPQExpBuffer(&fn);
8916         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8917         for (j = 0; j < nallargs; j++)
8918         {
8919                 Oid                     typid;
8920                 char       *typname;
8921                 const char *argmode;
8922                 const char *argname;
8923
8924                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
8925                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
8926
8927                 if (argmodes)
8928                 {
8929                         switch (argmodes[j][0])
8930                         {
8931                                 case PROARGMODE_IN:
8932                                         argmode = "";
8933                                         break;
8934                                 case PROARGMODE_OUT:
8935                                         argmode = "OUT ";
8936                                         break;
8937                                 case PROARGMODE_INOUT:
8938                                         argmode = "INOUT ";
8939                                         break;
8940                                 default:
8941                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
8942                                         argmode = "";
8943                                         break;
8944                         }
8945                 }
8946                 else
8947                         argmode = "";
8948
8949                 argname = argnames ? argnames[j] : (char *) NULL;
8950                 if (argname && argname[0] == '\0')
8951                         argname = NULL;
8952
8953                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
8954                                                   (j > 0) ? ", " : "",
8955                                                   argmode,
8956                                                   argname ? fmtId(argname) : "",
8957                                                   argname ? " " : "",
8958                                                   typname);
8959                 free(typname);
8960         }
8961         appendPQExpBuffer(&fn, ")");
8962         return fn.data;
8963 }
8964
8965 /*
8966  * format_function_signature: generate function name and argument list
8967  *
8968  * This is like format_function_arguments_old except that only a minimal
8969  * list of input argument types is generated; this is sufficient to
8970  * reference the function, but not to define it.
8971  *
8972  * If honor_quotes is false then the function name is never quoted.
8973  * This is appropriate for use in TOC tags, but not in SQL commands.
8974  */
8975 static char *
8976 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
8977 {
8978         PQExpBufferData fn;
8979         int                     j;
8980
8981         initPQExpBuffer(&fn);
8982         if (honor_quotes)
8983                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8984         else
8985                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
8986         for (j = 0; j < finfo->nargs; j++)
8987         {
8988                 char       *typname;
8989
8990                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
8991                                                                            zeroAsOpaque);
8992
8993                 appendPQExpBuffer(&fn, "%s%s",
8994                                                   (j > 0) ? ", " : "",
8995                                                   typname);
8996                 free(typname);
8997         }
8998         appendPQExpBuffer(&fn, ")");
8999         return fn.data;
9000 }
9001
9002
9003 /*
9004  * dumpFunc:
9005  *        dump out one function
9006  */
9007 static void
9008 dumpFunc(Archive *fout, FuncInfo *finfo)
9009 {
9010         PQExpBuffer query;
9011         PQExpBuffer q;
9012         PQExpBuffer delqry;
9013         PQExpBuffer labelq;
9014         PQExpBuffer asPart;
9015         PGresult   *res;
9016         char       *funcsig;            /* identity signature */
9017         char       *funcfullsig;        /* full signature */
9018         char       *funcsig_tag;
9019         char       *proretset;
9020         char       *prosrc;
9021         char       *probin;
9022         char       *funcargs;
9023         char       *funciargs;
9024         char       *funcresult;
9025         char       *proallargtypes;
9026         char       *proargmodes;
9027         char       *proargnames;
9028         char       *proiswindow;
9029         char       *provolatile;
9030         char       *proisstrict;
9031         char       *prosecdef;
9032         char       *proleakproof;
9033         char       *proconfig;
9034         char       *procost;
9035         char       *prorows;
9036         char       *lanname;
9037         char       *rettypename;
9038         int                     nallargs;
9039         char      **allargtypes = NULL;
9040         char      **argmodes = NULL;
9041         char      **argnames = NULL;
9042         char      **configitems = NULL;
9043         int                     nconfigitems = 0;
9044         int                     i;
9045
9046         /* Skip if not to be dumped */
9047         if (!finfo->dobj.dump || dataOnly)
9048                 return;
9049
9050         query = createPQExpBuffer();
9051         q = createPQExpBuffer();
9052         delqry = createPQExpBuffer();
9053         labelq = createPQExpBuffer();
9054         asPart = createPQExpBuffer();
9055
9056         /* Set proper schema search path so type references list correctly */
9057         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9058
9059         /* Fetch function-specific details */
9060         if (fout->remoteVersion >= 90200)
9061         {
9062                 /*
9063                  * proleakproof was added at v9.2
9064                  */
9065                 appendPQExpBuffer(query,
9066                                                   "SELECT proretset, prosrc, probin, "
9067                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9068                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9069                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9070                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9071                                                   "proleakproof, proconfig, procost, prorows, "
9072                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9073                                                   "FROM pg_catalog.pg_proc "
9074                                                   "WHERE oid = '%u'::pg_catalog.oid",
9075                                                   finfo->dobj.catId.oid);
9076         }
9077         else if (fout->remoteVersion >= 80400)
9078         {
9079                 /*
9080                  * In 8.4 and up we rely on pg_get_function_arguments and
9081                  * pg_get_function_result instead of examining proallargtypes etc.
9082                  */
9083                 appendPQExpBuffer(query,
9084                                                   "SELECT proretset, prosrc, probin, "
9085                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9086                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9087                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9088                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9089                                                   "false AS proleakproof, "
9090                                                   " proconfig, procost, prorows, "
9091                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9092                                                   "FROM pg_catalog.pg_proc "
9093                                                   "WHERE oid = '%u'::pg_catalog.oid",
9094                                                   finfo->dobj.catId.oid);
9095         }
9096         else if (fout->remoteVersion >= 80300)
9097         {
9098                 appendPQExpBuffer(query,
9099                                                   "SELECT proretset, prosrc, probin, "
9100                                                   "proallargtypes, proargmodes, proargnames, "
9101                                                   "false AS proiswindow, "
9102                                                   "provolatile, proisstrict, prosecdef, "
9103                                                   "false AS proleakproof, "
9104                                                   "proconfig, procost, prorows, "
9105                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9106                                                   "FROM pg_catalog.pg_proc "
9107                                                   "WHERE oid = '%u'::pg_catalog.oid",
9108                                                   finfo->dobj.catId.oid);
9109         }
9110         else if (fout->remoteVersion >= 80100)
9111         {
9112                 appendPQExpBuffer(query,
9113                                                   "SELECT proretset, prosrc, probin, "
9114                                                   "proallargtypes, proargmodes, proargnames, "
9115                                                   "false AS proiswindow, "
9116                                                   "provolatile, proisstrict, prosecdef, "
9117                                                   "false AS proleakproof, "
9118                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9119                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9120                                                   "FROM pg_catalog.pg_proc "
9121                                                   "WHERE oid = '%u'::pg_catalog.oid",
9122                                                   finfo->dobj.catId.oid);
9123         }
9124         else if (fout->remoteVersion >= 80000)
9125         {
9126                 appendPQExpBuffer(query,
9127                                                   "SELECT proretset, prosrc, probin, "
9128                                                   "null AS proallargtypes, "
9129                                                   "null AS proargmodes, "
9130                                                   "proargnames, "
9131                                                   "false AS proiswindow, "
9132                                                   "provolatile, proisstrict, prosecdef, "
9133                                                   "false AS proleakproof, "
9134                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9135                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9136                                                   "FROM pg_catalog.pg_proc "
9137                                                   "WHERE oid = '%u'::pg_catalog.oid",
9138                                                   finfo->dobj.catId.oid);
9139         }
9140         else if (fout->remoteVersion >= 70300)
9141         {
9142                 appendPQExpBuffer(query,
9143                                                   "SELECT proretset, prosrc, probin, "
9144                                                   "null AS proallargtypes, "
9145                                                   "null AS proargmodes, "
9146                                                   "null AS proargnames, "
9147                                                   "false AS proiswindow, "
9148                                                   "provolatile, proisstrict, prosecdef, "
9149                                                   "false AS proleakproof, "
9150                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9151                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9152                                                   "FROM pg_catalog.pg_proc "
9153                                                   "WHERE oid = '%u'::pg_catalog.oid",
9154                                                   finfo->dobj.catId.oid);
9155         }
9156         else if (fout->remoteVersion >= 70100)
9157         {
9158                 appendPQExpBuffer(query,
9159                                                   "SELECT proretset, prosrc, probin, "
9160                                                   "null AS proallargtypes, "
9161                                                   "null AS proargmodes, "
9162                                                   "null AS proargnames, "
9163                                                   "false AS proiswindow, "
9164                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9165                                                   "proisstrict, "
9166                                                   "false AS prosecdef, "
9167                                                   "false AS proleakproof, "
9168                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9169                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9170                                                   "FROM pg_proc "
9171                                                   "WHERE oid = '%u'::oid",
9172                                                   finfo->dobj.catId.oid);
9173         }
9174         else
9175         {
9176                 appendPQExpBuffer(query,
9177                                                   "SELECT proretset, prosrc, probin, "
9178                                                   "null AS proallargtypes, "
9179                                                   "null AS proargmodes, "
9180                                                   "null AS proargnames, "
9181                                                   "false AS proiswindow, "
9182                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9183                                                   "false AS proisstrict, "
9184                                                   "false AS prosecdef, "
9185                                                   "false AS proleakproof, "
9186                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9187                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9188                                                   "FROM pg_proc "
9189                                                   "WHERE oid = '%u'::oid",
9190                                                   finfo->dobj.catId.oid);
9191         }
9192
9193         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9194
9195         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9196         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9197         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9198         if (fout->remoteVersion >= 80400)
9199         {
9200                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9201                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9202                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9203                 proallargtypes = proargmodes = proargnames = NULL;
9204         }
9205         else
9206         {
9207                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9208                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9209                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9210                 funcargs = funciargs = funcresult = NULL;
9211         }
9212         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9213         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9214         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9215         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9216         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9217         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9218         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9219         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9220         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9221
9222         /*
9223          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9224          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9225          * versions would set it to "-".  There are no known cases in which prosrc
9226          * is unused, so the tests below for "-" are probably useless.
9227          */
9228         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9229         {
9230                 appendPQExpBuffer(asPart, "AS ");
9231                 appendStringLiteralAH(asPart, probin, fout);
9232                 if (strcmp(prosrc, "-") != 0)
9233                 {
9234                         appendPQExpBuffer(asPart, ", ");
9235
9236                         /*
9237                          * where we have bin, use dollar quoting if allowed and src
9238                          * contains quote or backslash; else use regular quoting.
9239                          */
9240                         if (disable_dollar_quoting ||
9241                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9242                                 appendStringLiteralAH(asPart, prosrc, fout);
9243                         else
9244                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9245                 }
9246         }
9247         else
9248         {
9249                 if (strcmp(prosrc, "-") != 0)
9250                 {
9251                         appendPQExpBuffer(asPart, "AS ");
9252                         /* with no bin, dollar quote src unconditionally if allowed */
9253                         if (disable_dollar_quoting)
9254                                 appendStringLiteralAH(asPart, prosrc, fout);
9255                         else
9256                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9257                 }
9258         }
9259
9260         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9261
9262         if (proallargtypes && *proallargtypes)
9263         {
9264                 int                     nitems = 0;
9265
9266                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9267                         nitems < finfo->nargs)
9268                 {
9269                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9270                         if (allargtypes)
9271                                 free(allargtypes);
9272                         allargtypes = NULL;
9273                 }
9274                 else
9275                         nallargs = nitems;
9276         }
9277
9278         if (proargmodes && *proargmodes)
9279         {
9280                 int                     nitems = 0;
9281
9282                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9283                         nitems != nallargs)
9284                 {
9285                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9286                         if (argmodes)
9287                                 free(argmodes);
9288                         argmodes = NULL;
9289                 }
9290         }
9291
9292         if (proargnames && *proargnames)
9293         {
9294                 int                     nitems = 0;
9295
9296                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9297                         nitems != nallargs)
9298                 {
9299                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9300                         if (argnames)
9301                                 free(argnames);
9302                         argnames = NULL;
9303                 }
9304         }
9305
9306         if (proconfig && *proconfig)
9307         {
9308                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9309                 {
9310                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9311                         if (configitems)
9312                                 free(configitems);
9313                         configitems = NULL;
9314                         nconfigitems = 0;
9315                 }
9316         }
9317
9318         if (funcargs)
9319         {
9320                 /* 8.4 or later; we rely on server-side code for most of the work */
9321                 funcfullsig = format_function_arguments(finfo, funcargs);
9322                 funcsig = format_function_arguments(finfo, funciargs);
9323         }
9324         else
9325         {
9326                 /* pre-8.4, do it ourselves */
9327                 funcsig = format_function_arguments_old(fout,
9328                                                                                                 finfo, nallargs, allargtypes,
9329                                                                                                 argmodes, argnames);
9330                 funcfullsig = funcsig;
9331         }
9332
9333         funcsig_tag = format_function_signature(fout, finfo, false);
9334
9335         /*
9336          * DROP must be fully qualified in case same name appears in pg_catalog
9337          */
9338         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9339                                           fmtId(finfo->dobj.namespace->dobj.name),
9340                                           funcsig);
9341
9342         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9343         if (funcresult)
9344                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9345         else
9346         {
9347                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9348                                                                                    zeroAsOpaque);
9349                 appendPQExpBuffer(q, "RETURNS %s%s",
9350                                                   (proretset[0] == 't') ? "SETOF " : "",
9351                                                   rettypename);
9352                 free(rettypename);
9353         }
9354
9355         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9356
9357         if (proiswindow[0] == 't')
9358                 appendPQExpBuffer(q, " WINDOW");
9359
9360         if (provolatile[0] != PROVOLATILE_VOLATILE)
9361         {
9362                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9363                         appendPQExpBuffer(q, " IMMUTABLE");
9364                 else if (provolatile[0] == PROVOLATILE_STABLE)
9365                         appendPQExpBuffer(q, " STABLE");
9366                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9367                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9368                                                   finfo->dobj.name);
9369         }
9370
9371         if (proisstrict[0] == 't')
9372                 appendPQExpBuffer(q, " STRICT");
9373
9374         if (prosecdef[0] == 't')
9375                 appendPQExpBuffer(q, " SECURITY DEFINER");
9376
9377         if (proleakproof[0] == 't')
9378                 appendPQExpBuffer(q, " LEAKPROOF");
9379
9380         /*
9381          * COST and ROWS are emitted only if present and not default, so as not to
9382          * break backwards-compatibility of the dump without need.      Keep this code
9383          * in sync with the defaults in functioncmds.c.
9384          */
9385         if (strcmp(procost, "0") != 0)
9386         {
9387                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9388                 {
9389                         /* default cost is 1 */
9390                         if (strcmp(procost, "1") != 0)
9391                                 appendPQExpBuffer(q, " COST %s", procost);
9392                 }
9393                 else
9394                 {
9395                         /* default cost is 100 */
9396                         if (strcmp(procost, "100") != 0)
9397                                 appendPQExpBuffer(q, " COST %s", procost);
9398                 }
9399         }
9400         if (proretset[0] == 't' &&
9401                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9402                 appendPQExpBuffer(q, " ROWS %s", prorows);
9403
9404         for (i = 0; i < nconfigitems; i++)
9405         {
9406                 /* we feel free to scribble on configitems[] here */
9407                 char       *configitem = configitems[i];
9408                 char       *pos;
9409
9410                 pos = strchr(configitem, '=');
9411                 if (pos == NULL)
9412                         continue;
9413                 *pos++ = '\0';
9414                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9415
9416                 /*
9417                  * Some GUC variable names are 'LIST' type and hence must not be
9418                  * quoted.
9419                  */
9420                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9421                         || pg_strcasecmp(configitem, "search_path") == 0)
9422                         appendPQExpBuffer(q, "%s", pos);
9423                 else
9424                         appendStringLiteralAH(q, pos, fout);
9425         }
9426
9427         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9428
9429         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9430
9431         if (binary_upgrade)
9432                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9433
9434         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9435                                  funcsig_tag,
9436                                  finfo->dobj.namespace->dobj.name,
9437                                  NULL,
9438                                  finfo->rolname, false,
9439                                  "FUNCTION", SECTION_PRE_DATA,
9440                                  q->data, delqry->data, NULL,
9441                                  NULL, 0,
9442                                  NULL, NULL);
9443
9444         /* Dump Function Comments and Security Labels */
9445         dumpComment(fout, labelq->data,
9446                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9447                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9448         dumpSecLabel(fout, labelq->data,
9449                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9450                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9451
9452         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9453                         funcsig, NULL, funcsig_tag,
9454                         finfo->dobj.namespace->dobj.name,
9455                         finfo->rolname, finfo->proacl);
9456
9457         PQclear(res);
9458
9459         destroyPQExpBuffer(query);
9460         destroyPQExpBuffer(q);
9461         destroyPQExpBuffer(delqry);
9462         destroyPQExpBuffer(labelq);
9463         destroyPQExpBuffer(asPart);
9464         free(funcsig);
9465         free(funcsig_tag);
9466         if (allargtypes)
9467                 free(allargtypes);
9468         if (argmodes)
9469                 free(argmodes);
9470         if (argnames)
9471                 free(argnames);
9472         if (configitems)
9473                 free(configitems);
9474 }
9475
9476
9477 /*
9478  * Dump a user-defined cast
9479  */
9480 static void
9481 dumpCast(Archive *fout, CastInfo *cast)
9482 {
9483         PQExpBuffer defqry;
9484         PQExpBuffer delqry;
9485         PQExpBuffer labelq;
9486         FuncInfo   *funcInfo = NULL;
9487
9488         /* Skip if not to be dumped */
9489         if (!cast->dobj.dump || dataOnly)
9490                 return;
9491
9492         /* Cannot dump if we don't have the cast function's info */
9493         if (OidIsValid(cast->castfunc))
9494         {
9495                 funcInfo = findFuncByOid(cast->castfunc);
9496                 if (funcInfo == NULL)
9497                         return;
9498         }
9499
9500         /*
9501          * As per discussion we dump casts if one or more of the underlying
9502          * objects (the conversion function and the two data types) are not
9503          * builtin AND if all of the non-builtin objects are included in the dump.
9504          * Builtin meaning, the namespace name does not start with "pg_".
9505          *
9506          * However, for a cast that belongs to an extension, we must not use this
9507          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9508          */
9509         if (!cast->dobj.ext_member)
9510         {
9511                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9512                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9513
9514                 if (sourceInfo == NULL || targetInfo == NULL)
9515                         return;
9516
9517                 /*
9518                  * Skip this cast if all objects are from pg_
9519                  */
9520                 if ((funcInfo == NULL ||
9521                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9522                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
9523                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
9524                         return;
9525
9526                 /*
9527                  * Skip cast if function isn't from pg_ and is not to be dumped.
9528                  */
9529                 if (funcInfo &&
9530                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9531                         !funcInfo->dobj.dump)
9532                         return;
9533
9534                 /*
9535                  * Same for the source type
9536                  */
9537                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9538                         !sourceInfo->dobj.dump)
9539                         return;
9540
9541                 /*
9542                  * and the target type.
9543                  */
9544                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9545                         !targetInfo->dobj.dump)
9546                         return;
9547         }
9548
9549         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
9550         selectSourceSchema(fout, "pg_catalog");
9551
9552         defqry = createPQExpBuffer();
9553         delqry = createPQExpBuffer();
9554         labelq = createPQExpBuffer();
9555
9556         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
9557                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9558                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9559
9560         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
9561                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9562                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9563
9564         switch (cast->castmethod)
9565         {
9566                 case COERCION_METHOD_BINARY:
9567                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
9568                         break;
9569                 case COERCION_METHOD_INOUT:
9570                         appendPQExpBuffer(defqry, "WITH INOUT");
9571                         break;
9572                 case COERCION_METHOD_FUNCTION:
9573                         if (funcInfo)
9574                         {
9575                                 char       *fsig = format_function_signature(fout, funcInfo, true);
9576
9577                                 /*
9578                                  * Always qualify the function name, in case it is not in
9579                                  * pg_catalog schema (format_function_signature won't qualify
9580                                  * it).
9581                                  */
9582                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
9583                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
9584                                 free(fsig);
9585                         }
9586                         else
9587                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
9588                         break;
9589                 default:
9590                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
9591         }
9592
9593         if (cast->castcontext == 'a')
9594                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
9595         else if (cast->castcontext == 'i')
9596                 appendPQExpBuffer(defqry, " AS IMPLICIT");
9597         appendPQExpBuffer(defqry, ";\n");
9598
9599         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
9600                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9601                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9602
9603         if (binary_upgrade)
9604                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
9605
9606         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
9607                                  labelq->data,
9608                                  "pg_catalog", NULL, "",
9609                                  false, "CAST", SECTION_PRE_DATA,
9610                                  defqry->data, delqry->data, NULL,
9611                                  NULL, 0,
9612                                  NULL, NULL);
9613
9614         /* Dump Cast Comments */
9615         dumpComment(fout, labelq->data,
9616                                 NULL, "",
9617                                 cast->dobj.catId, 0, cast->dobj.dumpId);
9618
9619         destroyPQExpBuffer(defqry);
9620         destroyPQExpBuffer(delqry);
9621         destroyPQExpBuffer(labelq);
9622 }
9623
9624 /*
9625  * dumpOpr
9626  *        write out a single operator definition
9627  */
9628 static void
9629 dumpOpr(Archive *fout, OprInfo *oprinfo)
9630 {
9631         PQExpBuffer query;
9632         PQExpBuffer q;
9633         PQExpBuffer delq;
9634         PQExpBuffer labelq;
9635         PQExpBuffer oprid;
9636         PQExpBuffer details;
9637         const char *name;
9638         PGresult   *res;
9639         int                     i_oprkind;
9640         int                     i_oprcode;
9641         int                     i_oprleft;
9642         int                     i_oprright;
9643         int                     i_oprcom;
9644         int                     i_oprnegate;
9645         int                     i_oprrest;
9646         int                     i_oprjoin;
9647         int                     i_oprcanmerge;
9648         int                     i_oprcanhash;
9649         char       *oprkind;
9650         char       *oprcode;
9651         char       *oprleft;
9652         char       *oprright;
9653         char       *oprcom;
9654         char       *oprnegate;
9655         char       *oprrest;
9656         char       *oprjoin;
9657         char       *oprcanmerge;
9658         char       *oprcanhash;
9659
9660         /* Skip if not to be dumped */
9661         if (!oprinfo->dobj.dump || dataOnly)
9662                 return;
9663
9664         /*
9665          * some operators are invalid because they were the result of user
9666          * defining operators before commutators exist
9667          */
9668         if (!OidIsValid(oprinfo->oprcode))
9669                 return;
9670
9671         query = createPQExpBuffer();
9672         q = createPQExpBuffer();
9673         delq = createPQExpBuffer();
9674         labelq = createPQExpBuffer();
9675         oprid = createPQExpBuffer();
9676         details = createPQExpBuffer();
9677
9678         /* Make sure we are in proper schema so regoperator works correctly */
9679         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
9680
9681         if (fout->remoteVersion >= 80300)
9682         {
9683                 appendPQExpBuffer(query, "SELECT oprkind, "
9684                                                   "oprcode::pg_catalog.regprocedure, "
9685                                                   "oprleft::pg_catalog.regtype, "
9686                                                   "oprright::pg_catalog.regtype, "
9687                                                   "oprcom::pg_catalog.regoperator, "
9688                                                   "oprnegate::pg_catalog.regoperator, "
9689                                                   "oprrest::pg_catalog.regprocedure, "
9690                                                   "oprjoin::pg_catalog.regprocedure, "
9691                                                   "oprcanmerge, oprcanhash "
9692                                                   "FROM pg_catalog.pg_operator "
9693                                                   "WHERE oid = '%u'::pg_catalog.oid",
9694                                                   oprinfo->dobj.catId.oid);
9695         }
9696         else if (fout->remoteVersion >= 70300)
9697         {
9698                 appendPQExpBuffer(query, "SELECT oprkind, "
9699                                                   "oprcode::pg_catalog.regprocedure, "
9700                                                   "oprleft::pg_catalog.regtype, "
9701                                                   "oprright::pg_catalog.regtype, "
9702                                                   "oprcom::pg_catalog.regoperator, "
9703                                                   "oprnegate::pg_catalog.regoperator, "
9704                                                   "oprrest::pg_catalog.regprocedure, "
9705                                                   "oprjoin::pg_catalog.regprocedure, "
9706                                                   "(oprlsortop != 0) AS oprcanmerge, "
9707                                                   "oprcanhash "
9708                                                   "FROM pg_catalog.pg_operator "
9709                                                   "WHERE oid = '%u'::pg_catalog.oid",
9710                                                   oprinfo->dobj.catId.oid);
9711         }
9712         else if (fout->remoteVersion >= 70100)
9713         {
9714                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9715                                                   "CASE WHEN oprleft = 0 THEN '-' "
9716                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
9717                                                   "CASE WHEN oprright = 0 THEN '-' "
9718                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
9719                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9720                                                   "(oprlsortop != 0) AS oprcanmerge, "
9721                                                   "oprcanhash "
9722                                                   "FROM pg_operator "
9723                                                   "WHERE oid = '%u'::oid",
9724                                                   oprinfo->dobj.catId.oid);
9725         }
9726         else
9727         {
9728                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9729                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
9730                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
9731                                                   "CASE WHEN oprright = 0 THEN '-'::name "
9732                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
9733                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9734                                                   "(oprlsortop != 0) AS oprcanmerge, "
9735                                                   "oprcanhash "
9736                                                   "FROM pg_operator "
9737                                                   "WHERE oid = '%u'::oid",
9738                                                   oprinfo->dobj.catId.oid);
9739         }
9740
9741         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9742
9743         i_oprkind = PQfnumber(res, "oprkind");
9744         i_oprcode = PQfnumber(res, "oprcode");
9745         i_oprleft = PQfnumber(res, "oprleft");
9746         i_oprright = PQfnumber(res, "oprright");
9747         i_oprcom = PQfnumber(res, "oprcom");
9748         i_oprnegate = PQfnumber(res, "oprnegate");
9749         i_oprrest = PQfnumber(res, "oprrest");
9750         i_oprjoin = PQfnumber(res, "oprjoin");
9751         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
9752         i_oprcanhash = PQfnumber(res, "oprcanhash");
9753
9754         oprkind = PQgetvalue(res, 0, i_oprkind);
9755         oprcode = PQgetvalue(res, 0, i_oprcode);
9756         oprleft = PQgetvalue(res, 0, i_oprleft);
9757         oprright = PQgetvalue(res, 0, i_oprright);
9758         oprcom = PQgetvalue(res, 0, i_oprcom);
9759         oprnegate = PQgetvalue(res, 0, i_oprnegate);
9760         oprrest = PQgetvalue(res, 0, i_oprrest);
9761         oprjoin = PQgetvalue(res, 0, i_oprjoin);
9762         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
9763         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
9764
9765         appendPQExpBuffer(details, "    PROCEDURE = %s",
9766                                           convertRegProcReference(fout, oprcode));
9767
9768         appendPQExpBuffer(oprid, "%s (",
9769                                           oprinfo->dobj.name);
9770
9771         /*
9772          * right unary means there's a left arg and left unary means there's a
9773          * right arg
9774          */
9775         if (strcmp(oprkind, "r") == 0 ||
9776                 strcmp(oprkind, "b") == 0)
9777         {
9778                 if (fout->remoteVersion >= 70100)
9779                         name = oprleft;
9780                 else
9781                         name = fmtId(oprleft);
9782                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
9783                 appendPQExpBuffer(oprid, "%s", name);
9784         }
9785         else
9786                 appendPQExpBuffer(oprid, "NONE");
9787
9788         if (strcmp(oprkind, "l") == 0 ||
9789                 strcmp(oprkind, "b") == 0)
9790         {
9791                 if (fout->remoteVersion >= 70100)
9792                         name = oprright;
9793                 else
9794                         name = fmtId(oprright);
9795                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
9796                 appendPQExpBuffer(oprid, ", %s)", name);
9797         }
9798         else
9799                 appendPQExpBuffer(oprid, ", NONE)");
9800
9801         name = convertOperatorReference(fout, oprcom);
9802         if (name)
9803                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
9804
9805         name = convertOperatorReference(fout, oprnegate);
9806         if (name)
9807                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
9808
9809         if (strcmp(oprcanmerge, "t") == 0)
9810                 appendPQExpBuffer(details, ",\n    MERGES");
9811
9812         if (strcmp(oprcanhash, "t") == 0)
9813                 appendPQExpBuffer(details, ",\n    HASHES");
9814
9815         name = convertRegProcReference(fout, oprrest);
9816         if (name)
9817                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
9818
9819         name = convertRegProcReference(fout, oprjoin);
9820         if (name)
9821                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
9822
9823         /*
9824          * DROP must be fully qualified in case same name appears in pg_catalog
9825          */
9826         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
9827                                           fmtId(oprinfo->dobj.namespace->dobj.name),
9828                                           oprid->data);
9829
9830         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
9831                                           oprinfo->dobj.name, details->data);
9832
9833         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
9834
9835         if (binary_upgrade)
9836                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
9837
9838         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
9839                                  oprinfo->dobj.name,
9840                                  oprinfo->dobj.namespace->dobj.name,
9841                                  NULL,
9842                                  oprinfo->rolname,
9843                                  false, "OPERATOR", SECTION_PRE_DATA,
9844                                  q->data, delq->data, NULL,
9845                                  NULL, 0,
9846                                  NULL, NULL);
9847
9848         /* Dump Operator Comments */
9849         dumpComment(fout, labelq->data,
9850                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
9851                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
9852
9853         PQclear(res);
9854
9855         destroyPQExpBuffer(query);
9856         destroyPQExpBuffer(q);
9857         destroyPQExpBuffer(delq);
9858         destroyPQExpBuffer(labelq);
9859         destroyPQExpBuffer(oprid);
9860         destroyPQExpBuffer(details);
9861 }
9862
9863 /*
9864  * Convert a function reference obtained from pg_operator
9865  *
9866  * Returns what to print, or NULL if function references is InvalidOid
9867  *
9868  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
9869  * argument-types part.  In prior versions, the input is a REGPROC display.
9870  */
9871 static const char *
9872 convertRegProcReference(Archive *fout, const char *proc)
9873 {
9874         /* In all cases "-" means a null reference */
9875         if (strcmp(proc, "-") == 0)
9876                 return NULL;
9877
9878         if (fout->remoteVersion >= 70300)
9879         {
9880                 char       *name;
9881                 char       *paren;
9882                 bool            inquote;
9883
9884                 name = pg_strdup(proc);
9885                 /* find non-double-quoted left paren */
9886                 inquote = false;
9887                 for (paren = name; *paren; paren++)
9888                 {
9889                         if (*paren == '(' && !inquote)
9890                         {
9891                                 *paren = '\0';
9892                                 break;
9893                         }
9894                         if (*paren == '"')
9895                                 inquote = !inquote;
9896                 }
9897                 return name;
9898         }
9899
9900         /* REGPROC before 7.3 does not quote its result */
9901         return fmtId(proc);
9902 }
9903
9904 /*
9905  * Convert an operator cross-reference obtained from pg_operator
9906  *
9907  * Returns what to print, or NULL to print nothing
9908  *
9909  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
9910  * argument-types part, and add OPERATOR() decoration if the name is
9911  * schema-qualified.  In older versions, the input is just a numeric OID,
9912  * which we search our operator list for.
9913  */
9914 static const char *
9915 convertOperatorReference(Archive *fout, const char *opr)
9916 {
9917         OprInfo    *oprInfo;
9918
9919         /* In all cases "0" means a null reference */
9920         if (strcmp(opr, "0") == 0)
9921                 return NULL;
9922
9923         if (fout->remoteVersion >= 70300)
9924         {
9925                 char       *name;
9926                 char       *oname;
9927                 char       *ptr;
9928                 bool            inquote;
9929                 bool            sawdot;
9930
9931                 name = pg_strdup(opr);
9932                 /* find non-double-quoted left paren, and check for non-quoted dot */
9933                 inquote = false;
9934                 sawdot = false;
9935                 for (ptr = name; *ptr; ptr++)
9936                 {
9937                         if (*ptr == '"')
9938                                 inquote = !inquote;
9939                         else if (*ptr == '.' && !inquote)
9940                                 sawdot = true;
9941                         else if (*ptr == '(' && !inquote)
9942                         {
9943                                 *ptr = '\0';
9944                                 break;
9945                         }
9946                 }
9947                 /* If not schema-qualified, don't need to add OPERATOR() */
9948                 if (!sawdot)
9949                         return name;
9950                 oname = pg_malloc(strlen(name) + 11);
9951                 sprintf(oname, "OPERATOR(%s)", name);
9952                 free(name);
9953                 return oname;
9954         }
9955
9956         oprInfo = findOprByOid(atooid(opr));
9957         if (oprInfo == NULL)
9958         {
9959                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
9960                                   opr);
9961                 return NULL;
9962         }
9963         return oprInfo->dobj.name;
9964 }
9965
9966 /*
9967  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
9968  *
9969  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
9970  * argument lists of these functions are predetermined.  Note that the
9971  * caller should ensure we are in the proper schema, because the results
9972  * are search path dependent!
9973  */
9974 static const char *
9975 convertTSFunction(Archive *fout, Oid funcOid)
9976 {
9977         char       *result;
9978         char            query[128];
9979         PGresult   *res;
9980
9981         snprintf(query, sizeof(query),
9982                          "SELECT '%u'::pg_catalog.regproc", funcOid);
9983         res = ExecuteSqlQueryForSingleRow(fout, query);
9984
9985         result = pg_strdup(PQgetvalue(res, 0, 0));
9986
9987         PQclear(res);
9988
9989         return result;
9990 }
9991
9992
9993 /*
9994  * dumpOpclass
9995  *        write out a single operator class definition
9996  */
9997 static void
9998 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
9999 {
10000         PQExpBuffer query;
10001         PQExpBuffer q;
10002         PQExpBuffer delq;
10003         PQExpBuffer labelq;
10004         PGresult   *res;
10005         int                     ntups;
10006         int                     i_opcintype;
10007         int                     i_opckeytype;
10008         int                     i_opcdefault;
10009         int                     i_opcfamily;
10010         int                     i_opcfamilyname;
10011         int                     i_opcfamilynsp;
10012         int                     i_amname;
10013         int                     i_amopstrategy;
10014         int                     i_amopreqcheck;
10015         int                     i_amopopr;
10016         int                     i_sortfamily;
10017         int                     i_sortfamilynsp;
10018         int                     i_amprocnum;
10019         int                     i_amproc;
10020         int                     i_amproclefttype;
10021         int                     i_amprocrighttype;
10022         char       *opcintype;
10023         char       *opckeytype;
10024         char       *opcdefault;
10025         char       *opcfamily;
10026         char       *opcfamilyname;
10027         char       *opcfamilynsp;
10028         char       *amname;
10029         char       *amopstrategy;
10030         char       *amopreqcheck;
10031         char       *amopopr;
10032         char       *sortfamily;
10033         char       *sortfamilynsp;
10034         char       *amprocnum;
10035         char       *amproc;
10036         char       *amproclefttype;
10037         char       *amprocrighttype;
10038         bool            needComma;
10039         int                     i;
10040
10041         /* Skip if not to be dumped */
10042         if (!opcinfo->dobj.dump || dataOnly)
10043                 return;
10044
10045         /*
10046          * XXX currently we do not implement dumping of operator classes from
10047          * pre-7.3 databases.  This could be done but it seems not worth the
10048          * trouble.
10049          */
10050         if (fout->remoteVersion < 70300)
10051                 return;
10052
10053         query = createPQExpBuffer();
10054         q = createPQExpBuffer();
10055         delq = createPQExpBuffer();
10056         labelq = createPQExpBuffer();
10057
10058         /* Make sure we are in proper schema so regoperator works correctly */
10059         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10060
10061         /* Get additional fields from the pg_opclass row */
10062         if (fout->remoteVersion >= 80300)
10063         {
10064                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10065                                                   "opckeytype::pg_catalog.regtype, "
10066                                                   "opcdefault, opcfamily, "
10067                                                   "opfname AS opcfamilyname, "
10068                                                   "nspname AS opcfamilynsp, "
10069                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10070                                                   "FROM pg_catalog.pg_opclass c "
10071                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10072                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10073                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10074                                                   opcinfo->dobj.catId.oid);
10075         }
10076         else
10077         {
10078                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10079                                                   "opckeytype::pg_catalog.regtype, "
10080                                                   "opcdefault, NULL AS opcfamily, "
10081                                                   "NULL AS opcfamilyname, "
10082                                                   "NULL AS opcfamilynsp, "
10083                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10084                                                   "FROM pg_catalog.pg_opclass "
10085                                                   "WHERE oid = '%u'::pg_catalog.oid",
10086                                                   opcinfo->dobj.catId.oid);
10087         }
10088
10089         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10090
10091         i_opcintype = PQfnumber(res, "opcintype");
10092         i_opckeytype = PQfnumber(res, "opckeytype");
10093         i_opcdefault = PQfnumber(res, "opcdefault");
10094         i_opcfamily = PQfnumber(res, "opcfamily");
10095         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10096         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10097         i_amname = PQfnumber(res, "amname");
10098
10099         opcintype = PQgetvalue(res, 0, i_opcintype);
10100         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10101         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10102         /* opcfamily will still be needed after we PQclear res */
10103         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10104         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10105         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10106         /* amname will still be needed after we PQclear res */
10107         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10108
10109         /*
10110          * DROP must be fully qualified in case same name appears in pg_catalog
10111          */
10112         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10113                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10114         appendPQExpBuffer(delq, ".%s",
10115                                           fmtId(opcinfo->dobj.name));
10116         appendPQExpBuffer(delq, " USING %s;\n",
10117                                           fmtId(amname));
10118
10119         /* Build the fixed portion of the CREATE command */
10120         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10121                                           fmtId(opcinfo->dobj.name));
10122         if (strcmp(opcdefault, "t") == 0)
10123                 appendPQExpBuffer(q, "DEFAULT ");
10124         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10125                                           opcintype,
10126                                           fmtId(amname));
10127         if (strlen(opcfamilyname) > 0 &&
10128                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10129                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10130         {
10131                 appendPQExpBuffer(q, " FAMILY ");
10132                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10133                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10134                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10135         }
10136         appendPQExpBuffer(q, " AS\n    ");
10137
10138         needComma = false;
10139
10140         if (strcmp(opckeytype, "-") != 0)
10141         {
10142                 appendPQExpBuffer(q, "STORAGE %s",
10143                                                   opckeytype);
10144                 needComma = true;
10145         }
10146
10147         PQclear(res);
10148
10149         /*
10150          * Now fetch and print the OPERATOR entries (pg_amop rows).
10151          *
10152          * Print only those opfamily members that are tied to the opclass by
10153          * pg_depend entries.
10154          *
10155          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10156          * older server's opclass in which it is used.  This is to avoid
10157          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10158          * older server and then reload into that old version.  This can go away
10159          * once 8.3 is so old as to not be of interest to anyone.
10160          */
10161         resetPQExpBuffer(query);
10162
10163         if (fout->remoteVersion >= 90100)
10164         {
10165                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10166                                                   "amopopr::pg_catalog.regoperator, "
10167                                                   "opfname AS sortfamily, "
10168                                                   "nspname AS sortfamilynsp "
10169                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10170                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10171                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10172                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10173                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10174                                                   "AND refobjid = '%u'::pg_catalog.oid "
10175                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10176                                                   "ORDER BY amopstrategy",
10177                                                   opcinfo->dobj.catId.oid,
10178                                                   opcfamily);
10179         }
10180         else if (fout->remoteVersion >= 80400)
10181         {
10182                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10183                                                   "amopopr::pg_catalog.regoperator, "
10184                                                   "NULL AS sortfamily, "
10185                                                   "NULL AS sortfamilynsp "
10186                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10187                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10188                                                   "AND refobjid = '%u'::pg_catalog.oid "
10189                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10190                                                   "AND objid = ao.oid "
10191                                                   "ORDER BY amopstrategy",
10192                                                   opcinfo->dobj.catId.oid);
10193         }
10194         else if (fout->remoteVersion >= 80300)
10195         {
10196                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10197                                                   "amopopr::pg_catalog.regoperator, "
10198                                                   "NULL AS sortfamily, "
10199                                                   "NULL AS sortfamilynsp "
10200                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10201                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10202                                                   "AND refobjid = '%u'::pg_catalog.oid "
10203                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10204                                                   "AND objid = ao.oid "
10205                                                   "ORDER BY amopstrategy",
10206                                                   opcinfo->dobj.catId.oid);
10207         }
10208         else
10209         {
10210                 /*
10211                  * Here, we print all entries since there are no opfamilies and hence
10212                  * no loose operators to worry about.
10213                  */
10214                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10215                                                   "amopopr::pg_catalog.regoperator, "
10216                                                   "NULL AS sortfamily, "
10217                                                   "NULL AS sortfamilynsp "
10218                                                   "FROM pg_catalog.pg_amop "
10219                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10220                                                   "ORDER BY amopstrategy",
10221                                                   opcinfo->dobj.catId.oid);
10222         }
10223
10224         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10225
10226         ntups = PQntuples(res);
10227
10228         i_amopstrategy = PQfnumber(res, "amopstrategy");
10229         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10230         i_amopopr = PQfnumber(res, "amopopr");
10231         i_sortfamily = PQfnumber(res, "sortfamily");
10232         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10233
10234         for (i = 0; i < ntups; i++)
10235         {
10236                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10237                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10238                 amopopr = PQgetvalue(res, i, i_amopopr);
10239                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10240                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10241
10242                 if (needComma)
10243                         appendPQExpBuffer(q, " ,\n    ");
10244
10245                 appendPQExpBuffer(q, "OPERATOR %s %s",
10246                                                   amopstrategy, amopopr);
10247
10248                 if (strlen(sortfamily) > 0)
10249                 {
10250                         appendPQExpBuffer(q, " FOR ORDER BY ");
10251                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10252                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10253                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10254                 }
10255
10256                 if (strcmp(amopreqcheck, "t") == 0)
10257                         appendPQExpBuffer(q, " RECHECK");
10258
10259                 needComma = true;
10260         }
10261
10262         PQclear(res);
10263
10264         /*
10265          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10266          *
10267          * Print only those opfamily members that are tied to the opclass by
10268          * pg_depend entries.
10269          *
10270          * We print the amproclefttype/amprocrighttype even though in most cases
10271          * the backend could deduce the right values, because of the corner case
10272          * of a btree sort support function for a cross-type comparison.  That's
10273          * only allowed in 9.2 and later, but for simplicity print them in all
10274          * versions that have the columns.
10275          */
10276         resetPQExpBuffer(query);
10277
10278         if (fout->remoteVersion >= 80300)
10279         {
10280                 appendPQExpBuffer(query, "SELECT amprocnum, "
10281                                                   "amproc::pg_catalog.regprocedure, "
10282                                                   "amproclefttype::pg_catalog.regtype, "
10283                                                   "amprocrighttype::pg_catalog.regtype "
10284                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10285                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10286                                                   "AND refobjid = '%u'::pg_catalog.oid "
10287                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10288                                                   "AND objid = ap.oid "
10289                                                   "ORDER BY amprocnum",
10290                                                   opcinfo->dobj.catId.oid);
10291         }
10292         else
10293         {
10294                 appendPQExpBuffer(query, "SELECT amprocnum, "
10295                                                   "amproc::pg_catalog.regprocedure, "
10296                                                   "'' AS amproclefttype, "
10297                                                   "'' AS amprocrighttype "
10298                                                   "FROM pg_catalog.pg_amproc "
10299                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10300                                                   "ORDER BY amprocnum",
10301                                                   opcinfo->dobj.catId.oid);
10302         }
10303
10304         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10305
10306         ntups = PQntuples(res);
10307
10308         i_amprocnum = PQfnumber(res, "amprocnum");
10309         i_amproc = PQfnumber(res, "amproc");
10310         i_amproclefttype = PQfnumber(res, "amproclefttype");
10311         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10312
10313         for (i = 0; i < ntups; i++)
10314         {
10315                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10316                 amproc = PQgetvalue(res, i, i_amproc);
10317                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10318                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10319
10320                 if (needComma)
10321                         appendPQExpBuffer(q, " ,\n    ");
10322
10323                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10324
10325                 if (*amproclefttype && *amprocrighttype)
10326                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10327
10328                 appendPQExpBuffer(q, " %s", amproc);
10329
10330                 needComma = true;
10331         }
10332
10333         PQclear(res);
10334
10335         appendPQExpBuffer(q, ";\n");
10336
10337         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10338                                           fmtId(opcinfo->dobj.name));
10339         appendPQExpBuffer(labelq, " USING %s",
10340                                           fmtId(amname));
10341
10342         if (binary_upgrade)
10343                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10344
10345         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10346                                  opcinfo->dobj.name,
10347                                  opcinfo->dobj.namespace->dobj.name,
10348                                  NULL,
10349                                  opcinfo->rolname,
10350                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10351                                  q->data, delq->data, NULL,
10352                                  NULL, 0,
10353                                  NULL, NULL);
10354
10355         /* Dump Operator Class Comments */
10356         dumpComment(fout, labelq->data,
10357                                 NULL, opcinfo->rolname,
10358                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10359
10360         free(amname);
10361         destroyPQExpBuffer(query);
10362         destroyPQExpBuffer(q);
10363         destroyPQExpBuffer(delq);
10364         destroyPQExpBuffer(labelq);
10365 }
10366
10367 /*
10368  * dumpOpfamily
10369  *        write out a single operator family definition
10370  *
10371  * Note: this also dumps any "loose" operator members that aren't bound to a
10372  * specific opclass within the opfamily.
10373  */
10374 static void
10375 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10376 {
10377         PQExpBuffer query;
10378         PQExpBuffer q;
10379         PQExpBuffer delq;
10380         PQExpBuffer labelq;
10381         PGresult   *res;
10382         PGresult   *res_ops;
10383         PGresult   *res_procs;
10384         int                     ntups;
10385         int                     i_amname;
10386         int                     i_amopstrategy;
10387         int                     i_amopreqcheck;
10388         int                     i_amopopr;
10389         int                     i_sortfamily;
10390         int                     i_sortfamilynsp;
10391         int                     i_amprocnum;
10392         int                     i_amproc;
10393         int                     i_amproclefttype;
10394         int                     i_amprocrighttype;
10395         char       *amname;
10396         char       *amopstrategy;
10397         char       *amopreqcheck;
10398         char       *amopopr;
10399         char       *sortfamily;
10400         char       *sortfamilynsp;
10401         char       *amprocnum;
10402         char       *amproc;
10403         char       *amproclefttype;
10404         char       *amprocrighttype;
10405         bool            needComma;
10406         int                     i;
10407
10408         /* Skip if not to be dumped */
10409         if (!opfinfo->dobj.dump || dataOnly)
10410                 return;
10411
10412         /*
10413          * We want to dump the opfamily only if (1) it contains "loose" operators
10414          * or functions, or (2) it contains an opclass with a different name or
10415          * owner.  Otherwise it's sufficient to let it be created during creation
10416          * of the contained opclass, and not dumping it improves portability of
10417          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10418          * that first.
10419          */
10420
10421         query = createPQExpBuffer();
10422         q = createPQExpBuffer();
10423         delq = createPQExpBuffer();
10424         labelq = createPQExpBuffer();
10425
10426         /* Make sure we are in proper schema so regoperator works correctly */
10427         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10428
10429         /*
10430          * Fetch only those opfamily members that are tied directly to the
10431          * opfamily by pg_depend entries.
10432          *
10433          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10434          * older server's opclass in which it is used.  This is to avoid
10435          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10436          * older server and then reload into that old version.  This can go away
10437          * once 8.3 is so old as to not be of interest to anyone.
10438          */
10439         if (fout->remoteVersion >= 90100)
10440         {
10441                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10442                                                   "amopopr::pg_catalog.regoperator, "
10443                                                   "opfname AS sortfamily, "
10444                                                   "nspname AS sortfamilynsp "
10445                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10446                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10447                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10448                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10449                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10450                                                   "AND refobjid = '%u'::pg_catalog.oid "
10451                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10452                                                   "ORDER BY amopstrategy",
10453                                                   opfinfo->dobj.catId.oid,
10454                                                   opfinfo->dobj.catId.oid);
10455         }
10456         else if (fout->remoteVersion >= 80400)
10457         {
10458                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10459                                                   "amopopr::pg_catalog.regoperator, "
10460                                                   "NULL AS sortfamily, "
10461                                                   "NULL AS sortfamilynsp "
10462                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10463                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10464                                                   "AND refobjid = '%u'::pg_catalog.oid "
10465                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10466                                                   "AND objid = ao.oid "
10467                                                   "ORDER BY amopstrategy",
10468                                                   opfinfo->dobj.catId.oid);
10469         }
10470         else
10471         {
10472                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10473                                                   "amopopr::pg_catalog.regoperator, "
10474                                                   "NULL AS sortfamily, "
10475                                                   "NULL AS sortfamilynsp "
10476                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10477                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10478                                                   "AND refobjid = '%u'::pg_catalog.oid "
10479                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10480                                                   "AND objid = ao.oid "
10481                                                   "ORDER BY amopstrategy",
10482                                                   opfinfo->dobj.catId.oid);
10483         }
10484
10485         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10486
10487         resetPQExpBuffer(query);
10488
10489         appendPQExpBuffer(query, "SELECT amprocnum, "
10490                                           "amproc::pg_catalog.regprocedure, "
10491                                           "amproclefttype::pg_catalog.regtype, "
10492                                           "amprocrighttype::pg_catalog.regtype "
10493                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10494                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10495                                           "AND refobjid = '%u'::pg_catalog.oid "
10496                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10497                                           "AND objid = ap.oid "
10498                                           "ORDER BY amprocnum",
10499                                           opfinfo->dobj.catId.oid);
10500
10501         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10502
10503         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10504         {
10505                 /* No loose members, so check contained opclasses */
10506                 resetPQExpBuffer(query);
10507
10508                 appendPQExpBuffer(query, "SELECT 1 "
10509                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10510                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10511                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10512                                                   "AND refobjid = f.oid "
10513                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10514                                                   "AND objid = c.oid "
10515                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10516                                                   "LIMIT 1",
10517                                                   opfinfo->dobj.catId.oid);
10518
10519                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10520
10521                 if (PQntuples(res) == 0)
10522                 {
10523                         /* no need to dump it, so bail out */
10524                         PQclear(res);
10525                         PQclear(res_ops);
10526                         PQclear(res_procs);
10527                         destroyPQExpBuffer(query);
10528                         destroyPQExpBuffer(q);
10529                         destroyPQExpBuffer(delq);
10530                         destroyPQExpBuffer(labelq);
10531                         return;
10532                 }
10533
10534                 PQclear(res);
10535         }
10536
10537         /* Get additional fields from the pg_opfamily row */
10538         resetPQExpBuffer(query);
10539
10540         appendPQExpBuffer(query, "SELECT "
10541          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
10542                                           "FROM pg_catalog.pg_opfamily "
10543                                           "WHERE oid = '%u'::pg_catalog.oid",
10544                                           opfinfo->dobj.catId.oid);
10545
10546         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10547
10548         i_amname = PQfnumber(res, "amname");
10549
10550         /* amname will still be needed after we PQclear res */
10551         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10552
10553         /*
10554          * DROP must be fully qualified in case same name appears in pg_catalog
10555          */
10556         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
10557                                           fmtId(opfinfo->dobj.namespace->dobj.name));
10558         appendPQExpBuffer(delq, ".%s",
10559                                           fmtId(opfinfo->dobj.name));
10560         appendPQExpBuffer(delq, " USING %s;\n",
10561                                           fmtId(amname));
10562
10563         /* Build the fixed portion of the CREATE command */
10564         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
10565                                           fmtId(opfinfo->dobj.name));
10566         appendPQExpBuffer(q, " USING %s;\n",
10567                                           fmtId(amname));
10568
10569         PQclear(res);
10570
10571         /* Do we need an ALTER to add loose members? */
10572         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
10573         {
10574                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
10575                                                   fmtId(opfinfo->dobj.name));
10576                 appendPQExpBuffer(q, " USING %s ADD\n    ",
10577                                                   fmtId(amname));
10578
10579                 needComma = false;
10580
10581                 /*
10582                  * Now fetch and print the OPERATOR entries (pg_amop rows).
10583                  */
10584                 ntups = PQntuples(res_ops);
10585
10586                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
10587                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
10588                 i_amopopr = PQfnumber(res_ops, "amopopr");
10589                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
10590                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
10591
10592                 for (i = 0; i < ntups; i++)
10593                 {
10594                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
10595                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
10596                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
10597                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
10598                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
10599
10600                         if (needComma)
10601                                 appendPQExpBuffer(q, " ,\n    ");
10602
10603                         appendPQExpBuffer(q, "OPERATOR %s %s",
10604                                                           amopstrategy, amopopr);
10605
10606                         if (strlen(sortfamily) > 0)
10607                         {
10608                                 appendPQExpBuffer(q, " FOR ORDER BY ");
10609                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
10610                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10611                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10612                         }
10613
10614                         if (strcmp(amopreqcheck, "t") == 0)
10615                                 appendPQExpBuffer(q, " RECHECK");
10616
10617                         needComma = true;
10618                 }
10619
10620                 /*
10621                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
10622                  */
10623                 ntups = PQntuples(res_procs);
10624
10625                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
10626                 i_amproc = PQfnumber(res_procs, "amproc");
10627                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
10628                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
10629
10630                 for (i = 0; i < ntups; i++)
10631                 {
10632                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
10633                         amproc = PQgetvalue(res_procs, i, i_amproc);
10634                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
10635                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
10636
10637                         if (needComma)
10638                                 appendPQExpBuffer(q, " ,\n    ");
10639
10640                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
10641                                                           amprocnum, amproclefttype, amprocrighttype,
10642                                                           amproc);
10643
10644                         needComma = true;
10645                 }
10646
10647                 appendPQExpBuffer(q, ";\n");
10648         }
10649
10650         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
10651                                           fmtId(opfinfo->dobj.name));
10652         appendPQExpBuffer(labelq, " USING %s",
10653                                           fmtId(amname));
10654
10655         if (binary_upgrade)
10656                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
10657
10658         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
10659                                  opfinfo->dobj.name,
10660                                  opfinfo->dobj.namespace->dobj.name,
10661                                  NULL,
10662                                  opfinfo->rolname,
10663                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
10664                                  q->data, delq->data, NULL,
10665                                  NULL, 0,
10666                                  NULL, NULL);
10667
10668         /* Dump Operator Family Comments */
10669         dumpComment(fout, labelq->data,
10670                                 NULL, opfinfo->rolname,
10671                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
10672
10673         free(amname);
10674         PQclear(res_ops);
10675         PQclear(res_procs);
10676         destroyPQExpBuffer(query);
10677         destroyPQExpBuffer(q);
10678         destroyPQExpBuffer(delq);
10679         destroyPQExpBuffer(labelq);
10680 }
10681
10682 /*
10683  * dumpCollation
10684  *        write out a single collation definition
10685  */
10686 static void
10687 dumpCollation(Archive *fout, CollInfo *collinfo)
10688 {
10689         PQExpBuffer query;
10690         PQExpBuffer q;
10691         PQExpBuffer delq;
10692         PQExpBuffer labelq;
10693         PGresult   *res;
10694         int                     i_collcollate;
10695         int                     i_collctype;
10696         const char *collcollate;
10697         const char *collctype;
10698
10699         /* Skip if not to be dumped */
10700         if (!collinfo->dobj.dump || dataOnly)
10701                 return;
10702
10703         query = createPQExpBuffer();
10704         q = createPQExpBuffer();
10705         delq = createPQExpBuffer();
10706         labelq = createPQExpBuffer();
10707
10708         /* Make sure we are in proper schema */
10709         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
10710
10711         /* Get conversion-specific details */
10712         appendPQExpBuffer(query, "SELECT "
10713                                           "collcollate, "
10714                                           "collctype "
10715                                           "FROM pg_catalog.pg_collation c "
10716                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10717                                           collinfo->dobj.catId.oid);
10718
10719         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10720
10721         i_collcollate = PQfnumber(res, "collcollate");
10722         i_collctype = PQfnumber(res, "collctype");
10723
10724         collcollate = PQgetvalue(res, 0, i_collcollate);
10725         collctype = PQgetvalue(res, 0, i_collctype);
10726
10727         /*
10728          * DROP must be fully qualified in case same name appears in pg_catalog
10729          */
10730         appendPQExpBuffer(delq, "DROP COLLATION %s",
10731                                           fmtId(collinfo->dobj.namespace->dobj.name));
10732         appendPQExpBuffer(delq, ".%s;\n",
10733                                           fmtId(collinfo->dobj.name));
10734
10735         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
10736                                           fmtId(collinfo->dobj.name));
10737         appendStringLiteralAH(q, collcollate, fout);
10738         appendPQExpBuffer(q, ", lc_ctype = ");
10739         appendStringLiteralAH(q, collctype, fout);
10740         appendPQExpBuffer(q, ");\n");
10741
10742         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
10743
10744         if (binary_upgrade)
10745                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
10746
10747         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
10748                                  collinfo->dobj.name,
10749                                  collinfo->dobj.namespace->dobj.name,
10750                                  NULL,
10751                                  collinfo->rolname,
10752                                  false, "COLLATION", SECTION_PRE_DATA,
10753                                  q->data, delq->data, NULL,
10754                                  NULL, 0,
10755                                  NULL, NULL);
10756
10757         /* Dump Collation Comments */
10758         dumpComment(fout, labelq->data,
10759                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
10760                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
10761
10762         PQclear(res);
10763
10764         destroyPQExpBuffer(query);
10765         destroyPQExpBuffer(q);
10766         destroyPQExpBuffer(delq);
10767         destroyPQExpBuffer(labelq);
10768 }
10769
10770 /*
10771  * dumpConversion
10772  *        write out a single conversion definition
10773  */
10774 static void
10775 dumpConversion(Archive *fout, ConvInfo *convinfo)
10776 {
10777         PQExpBuffer query;
10778         PQExpBuffer q;
10779         PQExpBuffer delq;
10780         PQExpBuffer labelq;
10781         PGresult   *res;
10782         int                     i_conforencoding;
10783         int                     i_contoencoding;
10784         int                     i_conproc;
10785         int                     i_condefault;
10786         const char *conforencoding;
10787         const char *contoencoding;
10788         const char *conproc;
10789         bool            condefault;
10790
10791         /* Skip if not to be dumped */
10792         if (!convinfo->dobj.dump || dataOnly)
10793                 return;
10794
10795         query = createPQExpBuffer();
10796         q = createPQExpBuffer();
10797         delq = createPQExpBuffer();
10798         labelq = createPQExpBuffer();
10799
10800         /* Make sure we are in proper schema */
10801         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
10802
10803         /* Get conversion-specific details */
10804         appendPQExpBuffer(query, "SELECT "
10805                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
10806                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
10807                                           "conproc, condefault "
10808                                           "FROM pg_catalog.pg_conversion c "
10809                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10810                                           convinfo->dobj.catId.oid);
10811
10812         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10813
10814         i_conforencoding = PQfnumber(res, "conforencoding");
10815         i_contoencoding = PQfnumber(res, "contoencoding");
10816         i_conproc = PQfnumber(res, "conproc");
10817         i_condefault = PQfnumber(res, "condefault");
10818
10819         conforencoding = PQgetvalue(res, 0, i_conforencoding);
10820         contoencoding = PQgetvalue(res, 0, i_contoencoding);
10821         conproc = PQgetvalue(res, 0, i_conproc);
10822         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
10823
10824         /*
10825          * DROP must be fully qualified in case same name appears in pg_catalog
10826          */
10827         appendPQExpBuffer(delq, "DROP CONVERSION %s",
10828                                           fmtId(convinfo->dobj.namespace->dobj.name));
10829         appendPQExpBuffer(delq, ".%s;\n",
10830                                           fmtId(convinfo->dobj.name));
10831
10832         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
10833                                           (condefault) ? "DEFAULT " : "",
10834                                           fmtId(convinfo->dobj.name));
10835         appendStringLiteralAH(q, conforencoding, fout);
10836         appendPQExpBuffer(q, " TO ");
10837         appendStringLiteralAH(q, contoencoding, fout);
10838         /* regproc is automatically quoted in 7.3 and above */
10839         appendPQExpBuffer(q, " FROM %s;\n", conproc);
10840
10841         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
10842
10843         if (binary_upgrade)
10844                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
10845
10846         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
10847                                  convinfo->dobj.name,
10848                                  convinfo->dobj.namespace->dobj.name,
10849                                  NULL,
10850                                  convinfo->rolname,
10851                                  false, "CONVERSION", SECTION_PRE_DATA,
10852                                  q->data, delq->data, NULL,
10853                                  NULL, 0,
10854                                  NULL, NULL);
10855
10856         /* Dump Conversion Comments */
10857         dumpComment(fout, labelq->data,
10858                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
10859                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
10860
10861         PQclear(res);
10862
10863         destroyPQExpBuffer(query);
10864         destroyPQExpBuffer(q);
10865         destroyPQExpBuffer(delq);
10866         destroyPQExpBuffer(labelq);
10867 }
10868
10869 /*
10870  * format_aggregate_signature: generate aggregate name and argument list
10871  *
10872  * The argument type names are qualified if needed.  The aggregate name
10873  * is never qualified.
10874  */
10875 static char *
10876 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
10877 {
10878         PQExpBufferData buf;
10879         int                     j;
10880
10881         initPQExpBuffer(&buf);
10882         if (honor_quotes)
10883                 appendPQExpBuffer(&buf, "%s",
10884                                                   fmtId(agginfo->aggfn.dobj.name));
10885         else
10886                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
10887
10888         if (agginfo->aggfn.nargs == 0)
10889                 appendPQExpBuffer(&buf, "(*)");
10890         else
10891         {
10892                 appendPQExpBuffer(&buf, "(");
10893                 for (j = 0; j < agginfo->aggfn.nargs; j++)
10894                 {
10895                         char       *typname;
10896
10897                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
10898                                                                                    zeroAsOpaque);
10899
10900                         appendPQExpBuffer(&buf, "%s%s",
10901                                                           (j > 0) ? ", " : "",
10902                                                           typname);
10903                         free(typname);
10904                 }
10905                 appendPQExpBuffer(&buf, ")");
10906         }
10907         return buf.data;
10908 }
10909
10910 /*
10911  * dumpAgg
10912  *        write out a single aggregate definition
10913  */
10914 static void
10915 dumpAgg(Archive *fout, AggInfo *agginfo)
10916 {
10917         PQExpBuffer query;
10918         PQExpBuffer q;
10919         PQExpBuffer delq;
10920         PQExpBuffer labelq;
10921         PQExpBuffer details;
10922         char       *aggsig;
10923         char       *aggsig_tag;
10924         PGresult   *res;
10925         int                     i_aggtransfn;
10926         int                     i_aggfinalfn;
10927         int                     i_aggsortop;
10928         int                     i_aggtranstype;
10929         int                     i_agginitval;
10930         int                     i_convertok;
10931         const char *aggtransfn;
10932         const char *aggfinalfn;
10933         const char *aggsortop;
10934         const char *aggtranstype;
10935         const char *agginitval;
10936         bool            convertok;
10937
10938         /* Skip if not to be dumped */
10939         if (!agginfo->aggfn.dobj.dump || dataOnly)
10940                 return;
10941
10942         query = createPQExpBuffer();
10943         q = createPQExpBuffer();
10944         delq = createPQExpBuffer();
10945         labelq = createPQExpBuffer();
10946         details = createPQExpBuffer();
10947
10948         /* Make sure we are in proper schema */
10949         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
10950
10951         /* Get aggregate-specific details */
10952         if (fout->remoteVersion >= 80100)
10953         {
10954                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10955                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10956                                                   "aggsortop::pg_catalog.regoperator, "
10957                                                   "agginitval, "
10958                                                   "'t'::boolean AS convertok "
10959                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10960                                                   "WHERE a.aggfnoid = p.oid "
10961                                                   "AND p.oid = '%u'::pg_catalog.oid",
10962                                                   agginfo->aggfn.dobj.catId.oid);
10963         }
10964         else if (fout->remoteVersion >= 70300)
10965         {
10966                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10967                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10968                                                   "0 AS aggsortop, "
10969                                                   "agginitval, "
10970                                                   "'t'::boolean AS convertok "
10971                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10972                                                   "WHERE a.aggfnoid = p.oid "
10973                                                   "AND p.oid = '%u'::pg_catalog.oid",
10974                                                   agginfo->aggfn.dobj.catId.oid);
10975         }
10976         else if (fout->remoteVersion >= 70100)
10977         {
10978                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
10979                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
10980                                                   "0 AS aggsortop, "
10981                                                   "agginitval, "
10982                                                   "'t'::boolean AS convertok "
10983                                                   "FROM pg_aggregate "
10984                                                   "WHERE oid = '%u'::oid",
10985                                                   agginfo->aggfn.dobj.catId.oid);
10986         }
10987         else
10988         {
10989                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
10990                                                   "aggfinalfn, "
10991                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
10992                                                   "0 AS aggsortop, "
10993                                                   "agginitval1 AS agginitval, "
10994                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
10995                                                   "FROM pg_aggregate "
10996                                                   "WHERE oid = '%u'::oid",
10997                                                   agginfo->aggfn.dobj.catId.oid);
10998         }
10999
11000         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11001
11002         i_aggtransfn = PQfnumber(res, "aggtransfn");
11003         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11004         i_aggsortop = PQfnumber(res, "aggsortop");
11005         i_aggtranstype = PQfnumber(res, "aggtranstype");
11006         i_agginitval = PQfnumber(res, "agginitval");
11007         i_convertok = PQfnumber(res, "convertok");
11008
11009         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11010         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11011         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11012         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11013         agginitval = PQgetvalue(res, 0, i_agginitval);
11014         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11015
11016         aggsig = format_aggregate_signature(agginfo, fout, true);
11017         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11018
11019         if (!convertok)
11020         {
11021                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11022                                   aggsig);
11023                 return;
11024         }
11025
11026         if (fout->remoteVersion >= 70300)
11027         {
11028                 /* If using 7.3's regproc or regtype, data is already quoted */
11029                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11030                                                   aggtransfn,
11031                                                   aggtranstype);
11032         }
11033         else if (fout->remoteVersion >= 70100)
11034         {
11035                 /* format_type quotes, regproc does not */
11036                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11037                                                   fmtId(aggtransfn),
11038                                                   aggtranstype);
11039         }
11040         else
11041         {
11042                 /* need quotes all around */
11043                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11044                                                   fmtId(aggtransfn));
11045                 appendPQExpBuffer(details, "    STYPE = %s",
11046                                                   fmtId(aggtranstype));
11047         }
11048
11049         if (!PQgetisnull(res, 0, i_agginitval))
11050         {
11051                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11052                 appendStringLiteralAH(details, agginitval, fout);
11053         }
11054
11055         if (strcmp(aggfinalfn, "-") != 0)
11056         {
11057                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11058                                                   aggfinalfn);
11059         }
11060
11061         aggsortop = convertOperatorReference(fout, aggsortop);
11062         if (aggsortop)
11063         {
11064                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11065                                                   aggsortop);
11066         }
11067
11068         /*
11069          * DROP must be fully qualified in case same name appears in pg_catalog
11070          */
11071         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11072                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11073                                           aggsig);
11074
11075         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11076                                           aggsig, details->data);
11077
11078         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11079
11080         if (binary_upgrade)
11081                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11082
11083         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11084                                  aggsig_tag,
11085                                  agginfo->aggfn.dobj.namespace->dobj.name,
11086                                  NULL,
11087                                  agginfo->aggfn.rolname,
11088                                  false, "AGGREGATE", SECTION_PRE_DATA,
11089                                  q->data, delq->data, NULL,
11090                                  NULL, 0,
11091                                  NULL, NULL);
11092
11093         /* Dump Aggregate Comments */
11094         dumpComment(fout, labelq->data,
11095                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11096                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11097         dumpSecLabel(fout, labelq->data,
11098                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11099                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11100
11101         /*
11102          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11103          * command look like a function's GRANT; in particular this affects the
11104          * syntax for zero-argument aggregates.
11105          */
11106         free(aggsig);
11107         free(aggsig_tag);
11108
11109         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11110         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11111
11112         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11113                         "FUNCTION",
11114                         aggsig, NULL, aggsig_tag,
11115                         agginfo->aggfn.dobj.namespace->dobj.name,
11116                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11117
11118         free(aggsig);
11119         free(aggsig_tag);
11120
11121         PQclear(res);
11122
11123         destroyPQExpBuffer(query);
11124         destroyPQExpBuffer(q);
11125         destroyPQExpBuffer(delq);
11126         destroyPQExpBuffer(labelq);
11127         destroyPQExpBuffer(details);
11128 }
11129
11130 /*
11131  * dumpTSParser
11132  *        write out a single text search parser
11133  */
11134 static void
11135 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11136 {
11137         PQExpBuffer q;
11138         PQExpBuffer delq;
11139         PQExpBuffer labelq;
11140
11141         /* Skip if not to be dumped */
11142         if (!prsinfo->dobj.dump || dataOnly)
11143                 return;
11144
11145         q = createPQExpBuffer();
11146         delq = createPQExpBuffer();
11147         labelq = createPQExpBuffer();
11148
11149         /* Make sure we are in proper schema */
11150         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11151
11152         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11153                                           fmtId(prsinfo->dobj.name));
11154
11155         appendPQExpBuffer(q, "    START = %s,\n",
11156                                           convertTSFunction(fout, prsinfo->prsstart));
11157         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11158                                           convertTSFunction(fout, prsinfo->prstoken));
11159         appendPQExpBuffer(q, "    END = %s,\n",
11160                                           convertTSFunction(fout, prsinfo->prsend));
11161         if (prsinfo->prsheadline != InvalidOid)
11162                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11163                                                   convertTSFunction(fout, prsinfo->prsheadline));
11164         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11165                                           convertTSFunction(fout, prsinfo->prslextype));
11166
11167         /*
11168          * DROP must be fully qualified in case same name appears in pg_catalog
11169          */
11170         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11171                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11172         appendPQExpBuffer(delq, ".%s;\n",
11173                                           fmtId(prsinfo->dobj.name));
11174
11175         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11176                                           fmtId(prsinfo->dobj.name));
11177
11178         if (binary_upgrade)
11179                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11180
11181         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11182                                  prsinfo->dobj.name,
11183                                  prsinfo->dobj.namespace->dobj.name,
11184                                  NULL,
11185                                  "",
11186                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11187                                  q->data, delq->data, NULL,
11188                                  NULL, 0,
11189                                  NULL, NULL);
11190
11191         /* Dump Parser Comments */
11192         dumpComment(fout, labelq->data,
11193                                 NULL, "",
11194                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11195
11196         destroyPQExpBuffer(q);
11197         destroyPQExpBuffer(delq);
11198         destroyPQExpBuffer(labelq);
11199 }
11200
11201 /*
11202  * dumpTSDictionary
11203  *        write out a single text search dictionary
11204  */
11205 static void
11206 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11207 {
11208         PQExpBuffer q;
11209         PQExpBuffer delq;
11210         PQExpBuffer labelq;
11211         PQExpBuffer query;
11212         PGresult   *res;
11213         char       *nspname;
11214         char       *tmplname;
11215
11216         /* Skip if not to be dumped */
11217         if (!dictinfo->dobj.dump || dataOnly)
11218                 return;
11219
11220         q = createPQExpBuffer();
11221         delq = createPQExpBuffer();
11222         labelq = createPQExpBuffer();
11223         query = createPQExpBuffer();
11224
11225         /* Fetch name and namespace of the dictionary's template */
11226         selectSourceSchema(fout, "pg_catalog");
11227         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11228                                           "FROM pg_ts_template p, pg_namespace n "
11229                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11230                                           dictinfo->dicttemplate);
11231         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11232         nspname = PQgetvalue(res, 0, 0);
11233         tmplname = PQgetvalue(res, 0, 1);
11234
11235         /* Make sure we are in proper schema */
11236         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11237
11238         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11239                                           fmtId(dictinfo->dobj.name));
11240
11241         appendPQExpBuffer(q, "    TEMPLATE = ");
11242         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11243                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11244         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11245
11246         PQclear(res);
11247
11248         /* the dictinitoption can be dumped straight into the command */
11249         if (dictinfo->dictinitoption)
11250                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11251
11252         appendPQExpBuffer(q, " );\n");
11253
11254         /*
11255          * DROP must be fully qualified in case same name appears in pg_catalog
11256          */
11257         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11258                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11259         appendPQExpBuffer(delq, ".%s;\n",
11260                                           fmtId(dictinfo->dobj.name));
11261
11262         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11263                                           fmtId(dictinfo->dobj.name));
11264
11265         if (binary_upgrade)
11266                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11267
11268         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11269                                  dictinfo->dobj.name,
11270                                  dictinfo->dobj.namespace->dobj.name,
11271                                  NULL,
11272                                  dictinfo->rolname,
11273                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11274                                  q->data, delq->data, NULL,
11275                                  NULL, 0,
11276                                  NULL, NULL);
11277
11278         /* Dump Dictionary Comments */
11279         dumpComment(fout, labelq->data,
11280                                 NULL, dictinfo->rolname,
11281                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11282
11283         destroyPQExpBuffer(q);
11284         destroyPQExpBuffer(delq);
11285         destroyPQExpBuffer(labelq);
11286         destroyPQExpBuffer(query);
11287 }
11288
11289 /*
11290  * dumpTSTemplate
11291  *        write out a single text search template
11292  */
11293 static void
11294 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11295 {
11296         PQExpBuffer q;
11297         PQExpBuffer delq;
11298         PQExpBuffer labelq;
11299
11300         /* Skip if not to be dumped */
11301         if (!tmplinfo->dobj.dump || dataOnly)
11302                 return;
11303
11304         q = createPQExpBuffer();
11305         delq = createPQExpBuffer();
11306         labelq = createPQExpBuffer();
11307
11308         /* Make sure we are in proper schema */
11309         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11310
11311         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11312                                           fmtId(tmplinfo->dobj.name));
11313
11314         if (tmplinfo->tmplinit != InvalidOid)
11315                 appendPQExpBuffer(q, "    INIT = %s,\n",
11316                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11317         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11318                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11319
11320         /*
11321          * DROP must be fully qualified in case same name appears in pg_catalog
11322          */
11323         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11324                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11325         appendPQExpBuffer(delq, ".%s;\n",
11326                                           fmtId(tmplinfo->dobj.name));
11327
11328         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11329                                           fmtId(tmplinfo->dobj.name));
11330
11331         if (binary_upgrade)
11332                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11333
11334         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11335                                  tmplinfo->dobj.name,
11336                                  tmplinfo->dobj.namespace->dobj.name,
11337                                  NULL,
11338                                  "",
11339                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11340                                  q->data, delq->data, NULL,
11341                                  NULL, 0,
11342                                  NULL, NULL);
11343
11344         /* Dump Template Comments */
11345         dumpComment(fout, labelq->data,
11346                                 NULL, "",
11347                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11348
11349         destroyPQExpBuffer(q);
11350         destroyPQExpBuffer(delq);
11351         destroyPQExpBuffer(labelq);
11352 }
11353
11354 /*
11355  * dumpTSConfig
11356  *        write out a single text search configuration
11357  */
11358 static void
11359 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11360 {
11361         PQExpBuffer q;
11362         PQExpBuffer delq;
11363         PQExpBuffer labelq;
11364         PQExpBuffer query;
11365         PGresult   *res;
11366         char       *nspname;
11367         char       *prsname;
11368         int                     ntups,
11369                                 i;
11370         int                     i_tokenname;
11371         int                     i_dictname;
11372
11373         /* Skip if not to be dumped */
11374         if (!cfginfo->dobj.dump || dataOnly)
11375                 return;
11376
11377         q = createPQExpBuffer();
11378         delq = createPQExpBuffer();
11379         labelq = createPQExpBuffer();
11380         query = createPQExpBuffer();
11381
11382         /* Fetch name and namespace of the config's parser */
11383         selectSourceSchema(fout, "pg_catalog");
11384         appendPQExpBuffer(query, "SELECT nspname, prsname "
11385                                           "FROM pg_ts_parser p, pg_namespace n "
11386                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11387                                           cfginfo->cfgparser);
11388         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11389         nspname = PQgetvalue(res, 0, 0);
11390         prsname = PQgetvalue(res, 0, 1);
11391
11392         /* Make sure we are in proper schema */
11393         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11394
11395         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11396                                           fmtId(cfginfo->dobj.name));
11397
11398         appendPQExpBuffer(q, "    PARSER = ");
11399         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11400                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11401         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11402
11403         PQclear(res);
11404
11405         resetPQExpBuffer(query);
11406         appendPQExpBuffer(query,
11407                                           "SELECT \n"
11408                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11409                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11410                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11411                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11412                                           "WHERE m.mapcfg = '%u' \n"
11413                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11414                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11415
11416         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11417         ntups = PQntuples(res);
11418
11419         i_tokenname = PQfnumber(res, "tokenname");
11420         i_dictname = PQfnumber(res, "dictname");
11421
11422         for (i = 0; i < ntups; i++)
11423         {
11424                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11425                 char       *dictname = PQgetvalue(res, i, i_dictname);
11426
11427                 if (i == 0 ||
11428                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11429                 {
11430                         /* starting a new token type, so start a new command */
11431                         if (i > 0)
11432                                 appendPQExpBuffer(q, ";\n");
11433                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11434                                                           fmtId(cfginfo->dobj.name));
11435                         /* tokenname needs quoting, dictname does NOT */
11436                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11437                                                           fmtId(tokenname), dictname);
11438                 }
11439                 else
11440                         appendPQExpBuffer(q, ", %s", dictname);
11441         }
11442
11443         if (ntups > 0)
11444                 appendPQExpBuffer(q, ";\n");
11445
11446         PQclear(res);
11447
11448         /*
11449          * DROP must be fully qualified in case same name appears in pg_catalog
11450          */
11451         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11452                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11453         appendPQExpBuffer(delq, ".%s;\n",
11454                                           fmtId(cfginfo->dobj.name));
11455
11456         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11457                                           fmtId(cfginfo->dobj.name));
11458
11459         if (binary_upgrade)
11460                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11461
11462         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11463                                  cfginfo->dobj.name,
11464                                  cfginfo->dobj.namespace->dobj.name,
11465                                  NULL,
11466                                  cfginfo->rolname,
11467                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11468                                  q->data, delq->data, NULL,
11469                                  NULL, 0,
11470                                  NULL, NULL);
11471
11472         /* Dump Configuration Comments */
11473         dumpComment(fout, labelq->data,
11474                                 NULL, cfginfo->rolname,
11475                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11476
11477         destroyPQExpBuffer(q);
11478         destroyPQExpBuffer(delq);
11479         destroyPQExpBuffer(labelq);
11480         destroyPQExpBuffer(query);
11481 }
11482
11483 /*
11484  * dumpForeignDataWrapper
11485  *        write out a single foreign-data wrapper definition
11486  */
11487 static void
11488 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11489 {
11490         PQExpBuffer q;
11491         PQExpBuffer delq;
11492         PQExpBuffer labelq;
11493         char       *qfdwname;
11494
11495         /* Skip if not to be dumped */
11496         if (!fdwinfo->dobj.dump || dataOnly)
11497                 return;
11498
11499         /*
11500          * FDWs that belong to an extension are dumped based on their "dump"
11501          * field. Otherwise omit them if we are only dumping some specific object.
11502          */
11503         if (!fdwinfo->dobj.ext_member)
11504                 if (!include_everything)
11505                         return;
11506
11507         q = createPQExpBuffer();
11508         delq = createPQExpBuffer();
11509         labelq = createPQExpBuffer();
11510
11511         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11512
11513         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11514                                           qfdwname);
11515
11516         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11517                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11518
11519         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11520                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11521
11522         if (strlen(fdwinfo->fdwoptions) > 0)
11523                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
11524
11525         appendPQExpBuffer(q, ";\n");
11526
11527         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
11528                                           qfdwname);
11529
11530         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
11531                                           qfdwname);
11532
11533         if (binary_upgrade)
11534                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
11535
11536         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11537                                  fdwinfo->dobj.name,
11538                                  NULL,
11539                                  NULL,
11540                                  fdwinfo->rolname,
11541                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
11542                                  q->data, delq->data, NULL,
11543                                  NULL, 0,
11544                                  NULL, NULL);
11545
11546         /* Handle the ACL */
11547         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11548                         "FOREIGN DATA WRAPPER",
11549                         qfdwname, NULL, fdwinfo->dobj.name,
11550                         NULL, fdwinfo->rolname,
11551                         fdwinfo->fdwacl);
11552
11553         /* Dump Foreign Data Wrapper Comments */
11554         dumpComment(fout, labelq->data,
11555                                 NULL, fdwinfo->rolname,
11556                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
11557
11558         free(qfdwname);
11559
11560         destroyPQExpBuffer(q);
11561         destroyPQExpBuffer(delq);
11562         destroyPQExpBuffer(labelq);
11563 }
11564
11565 /*
11566  * dumpForeignServer
11567  *        write out a foreign server definition
11568  */
11569 static void
11570 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
11571 {
11572         PQExpBuffer q;
11573         PQExpBuffer delq;
11574         PQExpBuffer labelq;
11575         PQExpBuffer query;
11576         PGresult   *res;
11577         char       *qsrvname;
11578         char       *fdwname;
11579
11580         /* Skip if not to be dumped */
11581         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
11582                 return;
11583
11584         q = createPQExpBuffer();
11585         delq = createPQExpBuffer();
11586         labelq = createPQExpBuffer();
11587         query = createPQExpBuffer();
11588
11589         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
11590
11591         /* look up the foreign-data wrapper */
11592         selectSourceSchema(fout, "pg_catalog");
11593         appendPQExpBuffer(query, "SELECT fdwname "
11594                                           "FROM pg_foreign_data_wrapper w "
11595                                           "WHERE w.oid = '%u'",
11596                                           srvinfo->srvfdw);
11597         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11598         fdwname = PQgetvalue(res, 0, 0);
11599
11600         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
11601         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
11602         {
11603                 appendPQExpBuffer(q, " TYPE ");
11604                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
11605         }
11606         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
11607         {
11608                 appendPQExpBuffer(q, " VERSION ");
11609                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
11610         }
11611
11612         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
11613         appendPQExpBuffer(q, "%s", fmtId(fdwname));
11614
11615         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
11616                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
11617
11618         appendPQExpBuffer(q, ";\n");
11619
11620         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
11621                                           qsrvname);
11622
11623         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
11624
11625         if (binary_upgrade)
11626                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
11627
11628         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11629                                  srvinfo->dobj.name,
11630                                  NULL,
11631                                  NULL,
11632                                  srvinfo->rolname,
11633                                  false, "SERVER", SECTION_PRE_DATA,
11634                                  q->data, delq->data, NULL,
11635                                  NULL, 0,
11636                                  NULL, NULL);
11637
11638         /* Handle the ACL */
11639         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11640                         "FOREIGN SERVER",
11641                         qsrvname, NULL, srvinfo->dobj.name,
11642                         NULL, srvinfo->rolname,
11643                         srvinfo->srvacl);
11644
11645         /* Dump user mappings */
11646         dumpUserMappings(fout,
11647                                          srvinfo->dobj.name, NULL,
11648                                          srvinfo->rolname,
11649                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
11650
11651         /* Dump Foreign Server Comments */
11652         dumpComment(fout, labelq->data,
11653                                 NULL, srvinfo->rolname,
11654                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
11655
11656         free(qsrvname);
11657
11658         destroyPQExpBuffer(q);
11659         destroyPQExpBuffer(delq);
11660         destroyPQExpBuffer(labelq);
11661 }
11662
11663 /*
11664  * dumpUserMappings
11665  *
11666  * This routine is used to dump any user mappings associated with the
11667  * server handed to this routine. Should be called after ArchiveEntry()
11668  * for the server.
11669  */
11670 static void
11671 dumpUserMappings(Archive *fout,
11672                                  const char *servername, const char *namespace,
11673                                  const char *owner,
11674                                  CatalogId catalogId, DumpId dumpId)
11675 {
11676         PQExpBuffer q;
11677         PQExpBuffer delq;
11678         PQExpBuffer query;
11679         PQExpBuffer tag;
11680         PGresult   *res;
11681         int                     ntups;
11682         int                     i_usename;
11683         int                     i_umoptions;
11684         int                     i;
11685
11686         q = createPQExpBuffer();
11687         tag = createPQExpBuffer();
11688         delq = createPQExpBuffer();
11689         query = createPQExpBuffer();
11690
11691         /*
11692          * We read from the publicly accessible view pg_user_mappings, so as not
11693          * to fail if run by a non-superuser.  Note that the view will show
11694          * umoptions as null if the user hasn't got privileges for the associated
11695          * server; this means that pg_dump will dump such a mapping, but with no
11696          * OPTIONS clause.      A possible alternative is to skip such mappings
11697          * altogether, but it's not clear that that's an improvement.
11698          */
11699         selectSourceSchema(fout, "pg_catalog");
11700
11701         appendPQExpBuffer(query,
11702                                           "SELECT usename, "
11703                                           "array_to_string(ARRAY("
11704                                           "SELECT quote_ident(option_name) || ' ' || "
11705                                           "quote_literal(option_value) "
11706                                           "FROM pg_options_to_table(umoptions) "
11707                                           "ORDER BY option_name"
11708                                           "), E',\n    ') AS umoptions "
11709                                           "FROM pg_user_mappings "
11710                                           "WHERE srvid = '%u' "
11711                                           "ORDER BY usename",
11712                                           catalogId.oid);
11713
11714         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11715
11716         ntups = PQntuples(res);
11717         i_usename = PQfnumber(res, "usename");
11718         i_umoptions = PQfnumber(res, "umoptions");
11719
11720         for (i = 0; i < ntups; i++)
11721         {
11722                 char       *usename;
11723                 char       *umoptions;
11724
11725                 usename = PQgetvalue(res, i, i_usename);
11726                 umoptions = PQgetvalue(res, i, i_umoptions);
11727
11728                 resetPQExpBuffer(q);
11729                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
11730                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
11731
11732                 if (umoptions && strlen(umoptions) > 0)
11733                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
11734
11735                 appendPQExpBuffer(q, ";\n");
11736
11737                 resetPQExpBuffer(delq);
11738                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
11739                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
11740
11741                 resetPQExpBuffer(tag);
11742                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
11743                                                   usename, servername);
11744
11745                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11746                                          tag->data,
11747                                          namespace,
11748                                          NULL,
11749                                          owner, false,
11750                                          "USER MAPPING", SECTION_PRE_DATA,
11751                                          q->data, delq->data, NULL,
11752                                          &dumpId, 1,
11753                                          NULL, NULL);
11754         }
11755
11756         PQclear(res);
11757
11758         destroyPQExpBuffer(query);
11759         destroyPQExpBuffer(delq);
11760         destroyPQExpBuffer(q);
11761 }
11762
11763 /*
11764  * Write out default privileges information
11765  */
11766 static void
11767 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
11768 {
11769         PQExpBuffer q;
11770         PQExpBuffer tag;
11771         const char *type;
11772
11773         /* Skip if not to be dumped */
11774         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
11775                 return;
11776
11777         q = createPQExpBuffer();
11778         tag = createPQExpBuffer();
11779
11780         switch (daclinfo->defaclobjtype)
11781         {
11782                 case DEFACLOBJ_RELATION:
11783                         type = "TABLES";
11784                         break;
11785                 case DEFACLOBJ_SEQUENCE:
11786                         type = "SEQUENCES";
11787                         break;
11788                 case DEFACLOBJ_FUNCTION:
11789                         type = "FUNCTIONS";
11790                         break;
11791                 default:
11792                         /* shouldn't get here */
11793                         exit_horribly(NULL,
11794                                                   "unknown object type (%d) in default privileges\n",
11795                                                   (int) daclinfo->defaclobjtype);
11796                         type = "";                      /* keep compiler quiet */
11797         }
11798
11799         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
11800
11801         /* build the actual command(s) for this tuple */
11802         if (!buildDefaultACLCommands(type,
11803                                                                  daclinfo->dobj.namespace != NULL ?
11804                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
11805                                                                  daclinfo->defaclacl,
11806                                                                  daclinfo->defaclrole,
11807                                                                  fout->remoteVersion,
11808                                                                  q))
11809                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
11810                                           daclinfo->defaclacl);
11811
11812         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
11813                                  tag->data,
11814            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
11815                                  NULL,
11816                                  daclinfo->defaclrole,
11817                                  false, "DEFAULT ACL", SECTION_POST_DATA,
11818                                  q->data, "", NULL,
11819                                  NULL, 0,
11820                                  NULL, NULL);
11821
11822         destroyPQExpBuffer(tag);
11823         destroyPQExpBuffer(q);
11824 }
11825
11826 /*----------
11827  * Write out grant/revoke information
11828  *
11829  * 'objCatId' is the catalog ID of the underlying object.
11830  * 'objDumpId' is the dump ID of the underlying object.
11831  * 'type' must be one of
11832  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
11833  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
11834  * 'name' is the formatted name of the object.  Must be quoted etc. already.
11835  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
11836  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
11837  * 'nspname' is the namespace the object is in (NULL if none).
11838  * 'owner' is the owner, NULL if there is no owner (for languages).
11839  * 'acls' is the string read out of the fooacl system catalog field;
11840  *              it will be parsed here.
11841  *----------
11842  */
11843 static void
11844 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
11845                 const char *type, const char *name, const char *subname,
11846                 const char *tag, const char *nspname, const char *owner,
11847                 const char *acls)
11848 {
11849         PQExpBuffer sql;
11850
11851         /* Do nothing if ACL dump is not enabled */
11852         if (aclsSkip)
11853                 return;
11854
11855         /* --data-only skips ACLs *except* BLOB ACLs */
11856         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
11857                 return;
11858
11859         sql = createPQExpBuffer();
11860
11861         if (!buildACLCommands(name, subname, type, acls, owner,
11862                                                   "", fout->remoteVersion, sql))
11863                 exit_horribly(NULL,
11864                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
11865                                           acls, name, type);
11866
11867         if (sql->len > 0)
11868                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11869                                          tag, nspname,
11870                                          NULL,
11871                                          owner ? owner : "",
11872                                          false, "ACL", SECTION_NONE,
11873                                          sql->data, "", NULL,
11874                                          &(objDumpId), 1,
11875                                          NULL, NULL);
11876
11877         destroyPQExpBuffer(sql);
11878 }
11879
11880 /*
11881  * dumpSecLabel
11882  *
11883  * This routine is used to dump any security labels associated with the
11884  * object handed to this routine. The routine takes a constant character
11885  * string for the target part of the security-label command, plus
11886  * the namespace and owner of the object (for labeling the ArchiveEntry),
11887  * plus catalog ID and subid which are the lookup key for pg_seclabel,
11888  * plus the dump ID for the object (for setting a dependency).
11889  * If a matching pg_seclabel entry is found, it is dumped.
11890  *
11891  * Note: although this routine takes a dumpId for dependency purposes,
11892  * that purpose is just to mark the dependency in the emitted dump file
11893  * for possible future use by pg_restore.  We do NOT use it for determining
11894  * ordering of the label in the dump file, because this routine is called
11895  * after dependency sorting occurs.  This routine should be called just after
11896  * calling ArchiveEntry() for the specified object.
11897  */
11898 static void
11899 dumpSecLabel(Archive *fout, const char *target,
11900                          const char *namespace, const char *owner,
11901                          CatalogId catalogId, int subid, DumpId dumpId)
11902 {
11903         SecLabelItem *labels;
11904         int                     nlabels;
11905         int                     i;
11906         PQExpBuffer query;
11907
11908         /* do nothing, if --no-security-labels is supplied */
11909         if (no_security_labels)
11910                 return;
11911
11912         /* Comments are schema not data ... except blob comments are data */
11913         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
11914         {
11915                 if (dataOnly)
11916                         return;
11917         }
11918         else
11919         {
11920                 if (schemaOnly)
11921                         return;
11922         }
11923
11924         /* Search for security labels associated with catalogId, using table */
11925         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
11926
11927         query = createPQExpBuffer();
11928
11929         for (i = 0; i < nlabels; i++)
11930         {
11931                 /*
11932                  * Ignore label entries for which the subid doesn't match.
11933                  */
11934                 if (labels[i].objsubid != subid)
11935                         continue;
11936
11937                 appendPQExpBuffer(query,
11938                                                   "SECURITY LABEL FOR %s ON %s IS ",
11939                                                   fmtId(labels[i].provider), target);
11940                 appendStringLiteralAH(query, labels[i].label, fout);
11941                 appendPQExpBuffer(query, ";\n");
11942         }
11943
11944         if (query->len > 0)
11945         {
11946                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11947                                          target, namespace, NULL, owner,
11948                                          false, "SECURITY LABEL", SECTION_NONE,
11949                                          query->data, "", NULL,
11950                                          &(dumpId), 1,
11951                                          NULL, NULL);
11952         }
11953         destroyPQExpBuffer(query);
11954 }
11955
11956 /*
11957  * dumpTableSecLabel
11958  *
11959  * As above, but dump security label for both the specified table (or view)
11960  * and its columns.
11961  */
11962 static void
11963 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
11964 {
11965         SecLabelItem *labels;
11966         int                     nlabels;
11967         int                     i;
11968         PQExpBuffer query;
11969         PQExpBuffer target;
11970
11971         /* do nothing, if --no-security-labels is supplied */
11972         if (no_security_labels)
11973                 return;
11974
11975         /* SecLabel are SCHEMA not data */
11976         if (dataOnly)
11977                 return;
11978
11979         /* Search for comments associated with relation, using table */
11980         nlabels = findSecLabels(fout,
11981                                                         tbinfo->dobj.catId.tableoid,
11982                                                         tbinfo->dobj.catId.oid,
11983                                                         &labels);
11984
11985         /* If security labels exist, build SECURITY LABEL statements */
11986         if (nlabels <= 0)
11987                 return;
11988
11989         query = createPQExpBuffer();
11990         target = createPQExpBuffer();
11991
11992         for (i = 0; i < nlabels; i++)
11993         {
11994                 const char *colname;
11995                 const char *provider = labels[i].provider;
11996                 const char *label = labels[i].label;
11997                 int                     objsubid = labels[i].objsubid;
11998
11999                 resetPQExpBuffer(target);
12000                 if (objsubid == 0)
12001                 {
12002                         appendPQExpBuffer(target, "%s %s", reltypename,
12003                                                           fmtId(tbinfo->dobj.name));
12004                 }
12005                 else
12006                 {
12007                         colname = getAttrName(objsubid, tbinfo);
12008                         /* first fmtId result must be consumed before calling it again */
12009                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12010                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12011                 }
12012                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12013                                                   fmtId(provider), target->data);
12014                 appendStringLiteralAH(query, label, fout);
12015                 appendPQExpBuffer(query, ";\n");
12016         }
12017         if (query->len > 0)
12018         {
12019                 resetPQExpBuffer(target);
12020                 appendPQExpBuffer(target, "%s %s", reltypename,
12021                                                   fmtId(tbinfo->dobj.name));
12022                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12023                                          target->data,
12024                                          tbinfo->dobj.namespace->dobj.name,
12025                                          NULL, tbinfo->rolname,
12026                                          false, "SECURITY LABEL", SECTION_NONE,
12027                                          query->data, "", NULL,
12028                                          &(tbinfo->dobj.dumpId), 1,
12029                                          NULL, NULL);
12030         }
12031         destroyPQExpBuffer(query);
12032         destroyPQExpBuffer(target);
12033 }
12034
12035 /*
12036  * findSecLabels
12037  *
12038  * Find the security label(s), if any, associated with the given object.
12039  * All the objsubid values associated with the given classoid/objoid are
12040  * found with one search.
12041  */
12042 static int
12043 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12044 {
12045         /* static storage for table of security labels */
12046         static SecLabelItem *labels = NULL;
12047         static int      nlabels = -1;
12048
12049         SecLabelItem *middle = NULL;
12050         SecLabelItem *low;
12051         SecLabelItem *high;
12052         int                     nmatch;
12053
12054         /* Get security labels if we didn't already */
12055         if (nlabels < 0)
12056                 nlabels = collectSecLabels(fout, &labels);
12057
12058         if (nlabels <= 0)                       /* no labels, so no match is possible */
12059         {
12060                 *items = NULL;
12061                 return 0;
12062         }
12063
12064         /*
12065          * Do binary search to find some item matching the object.
12066          */
12067         low = &labels[0];
12068         high = &labels[nlabels - 1];
12069         while (low <= high)
12070         {
12071                 middle = low + (high - low) / 2;
12072
12073                 if (classoid < middle->classoid)
12074                         high = middle - 1;
12075                 else if (classoid > middle->classoid)
12076                         low = middle + 1;
12077                 else if (objoid < middle->objoid)
12078                         high = middle - 1;
12079                 else if (objoid > middle->objoid)
12080                         low = middle + 1;
12081                 else
12082                         break;                          /* found a match */
12083         }
12084
12085         if (low > high)                         /* no matches */
12086         {
12087                 *items = NULL;
12088                 return 0;
12089         }
12090
12091         /*
12092          * Now determine how many items match the object.  The search loop
12093          * invariant still holds: only items between low and high inclusive could
12094          * match.
12095          */
12096         nmatch = 1;
12097         while (middle > low)
12098         {
12099                 if (classoid != middle[-1].classoid ||
12100                         objoid != middle[-1].objoid)
12101                         break;
12102                 middle--;
12103                 nmatch++;
12104         }
12105
12106         *items = middle;
12107
12108         middle += nmatch;
12109         while (middle <= high)
12110         {
12111                 if (classoid != middle->classoid ||
12112                         objoid != middle->objoid)
12113                         break;
12114                 middle++;
12115                 nmatch++;
12116         }
12117
12118         return nmatch;
12119 }
12120
12121 /*
12122  * collectSecLabels
12123  *
12124  * Construct a table of all security labels available for database objects.
12125  * It's much faster to pull them all at once.
12126  *
12127  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12128  */
12129 static int
12130 collectSecLabels(Archive *fout, SecLabelItem **items)
12131 {
12132         PGresult   *res;
12133         PQExpBuffer query;
12134         int                     i_label;
12135         int                     i_provider;
12136         int                     i_classoid;
12137         int                     i_objoid;
12138         int                     i_objsubid;
12139         int                     ntups;
12140         int                     i;
12141         SecLabelItem *labels;
12142
12143         query = createPQExpBuffer();
12144
12145         appendPQExpBuffer(query,
12146                                           "SELECT label, provider, classoid, objoid, objsubid "
12147                                           "FROM pg_catalog.pg_seclabel "
12148                                           "ORDER BY classoid, objoid, objsubid");
12149
12150         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12151
12152         /* Construct lookup table containing OIDs in numeric form */
12153         i_label = PQfnumber(res, "label");
12154         i_provider = PQfnumber(res, "provider");
12155         i_classoid = PQfnumber(res, "classoid");
12156         i_objoid = PQfnumber(res, "objoid");
12157         i_objsubid = PQfnumber(res, "objsubid");
12158
12159         ntups = PQntuples(res);
12160
12161         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12162
12163         for (i = 0; i < ntups; i++)
12164         {
12165                 labels[i].label = PQgetvalue(res, i, i_label);
12166                 labels[i].provider = PQgetvalue(res, i, i_provider);
12167                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12168                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12169                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12170         }
12171
12172         /* Do NOT free the PGresult since we are keeping pointers into it */
12173         destroyPQExpBuffer(query);
12174
12175         *items = labels;
12176         return ntups;
12177 }
12178
12179 /*
12180  * dumpTable
12181  *        write out to fout the declarations (not data) of a user-defined table
12182  */
12183 static void
12184 dumpTable(Archive *fout, TableInfo *tbinfo)
12185 {
12186         if (tbinfo->dobj.dump)
12187         {
12188                 char       *namecopy;
12189
12190                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12191                         dumpSequence(fout, tbinfo);
12192                 else if (!dataOnly)
12193                         dumpTableSchema(fout, tbinfo);
12194
12195                 /* Handle the ACL here */
12196                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12197                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12198                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12199                                 "TABLE",
12200                                 namecopy, NULL, tbinfo->dobj.name,
12201                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12202                                 tbinfo->relacl);
12203
12204                 /*
12205                  * Handle column ACLs, if any.  Note: we pull these with a separate
12206                  * query rather than trying to fetch them during getTableAttrs, so
12207                  * that we won't miss ACLs on system columns.
12208                  */
12209                 if (fout->remoteVersion >= 80400)
12210                 {
12211                         PQExpBuffer query = createPQExpBuffer();
12212                         PGresult   *res;
12213                         int                     i;
12214
12215                         appendPQExpBuffer(query,
12216                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12217                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12218                                                           "ORDER BY attnum",
12219                                                           tbinfo->dobj.catId.oid);
12220                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12221
12222                         for (i = 0; i < PQntuples(res); i++)
12223                         {
12224                                 char       *attname = PQgetvalue(res, i, 0);
12225                                 char       *attacl = PQgetvalue(res, i, 1);
12226                                 char       *attnamecopy;
12227                                 char       *acltag;
12228
12229                                 attnamecopy = pg_strdup(fmtId(attname));
12230                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12231                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12232                                 /* Column's GRANT type is always TABLE */
12233                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12234                                                 namecopy, attnamecopy, acltag,
12235                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12236                                                 attacl);
12237                                 free(attnamecopy);
12238                                 free(acltag);
12239                         }
12240                         PQclear(res);
12241                         destroyPQExpBuffer(query);
12242                 }
12243
12244                 free(namecopy);
12245         }
12246 }
12247
12248 /*
12249  * dumpTableSchema
12250  *        write the declaration (not data) of one user-defined table or view
12251  */
12252 static void
12253 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12254 {
12255         PQExpBuffer query = createPQExpBuffer();
12256         PQExpBuffer q = createPQExpBuffer();
12257         PQExpBuffer delq = createPQExpBuffer();
12258         PQExpBuffer labelq = createPQExpBuffer();
12259         PGresult   *res;
12260         int                     numParents;
12261         TableInfo **parents;
12262         int                     actual_atts;    /* number of attrs in this CREATE statement */
12263         const char *reltypename;
12264         char       *storage;
12265         char       *srvname;
12266         char       *ftoptions;
12267         int                     j,
12268                                 k;
12269
12270         /* Make sure we are in proper schema */
12271         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12272
12273         if (binary_upgrade)
12274                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12275                                                                                                 tbinfo->dobj.catId.oid);
12276
12277         /* Is it a table or a view? */
12278         if (tbinfo->relkind == RELKIND_VIEW)
12279         {
12280                 char       *viewdef;
12281
12282                 reltypename = "VIEW";
12283
12284                 /* Fetch the view definition */
12285                 if (fout->remoteVersion >= 70300)
12286                 {
12287                         /* Beginning in 7.3, viewname is not unique; rely on OID */
12288                         appendPQExpBuffer(query,
12289                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12290                                                           tbinfo->dobj.catId.oid);
12291                 }
12292                 else
12293                 {
12294                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
12295                                                           "FROM pg_views WHERE viewname = ");
12296                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12297                         appendPQExpBuffer(query, ";");
12298                 }
12299
12300                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12301
12302                 if (PQntuples(res) != 1)
12303                 {
12304                         if (PQntuples(res) < 1)
12305                                 exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12306                                                           tbinfo->dobj.name);
12307                         else
12308                                 exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12309                                                           tbinfo->dobj.name);
12310                 }
12311
12312                 viewdef = PQgetvalue(res, 0, 0);
12313
12314                 if (strlen(viewdef) == 0)
12315                         exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12316                                                   tbinfo->dobj.name);
12317
12318                 /*
12319                  * DROP must be fully qualified in case same name appears in
12320                  * pg_catalog
12321                  */
12322                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12323                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12324                 appendPQExpBuffer(delq, "%s;\n",
12325                                                   fmtId(tbinfo->dobj.name));
12326
12327                 if (binary_upgrade)
12328                         binary_upgrade_set_pg_class_oids(fout, q,
12329                                                                                          tbinfo->dobj.catId.oid, false);
12330
12331                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12332                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12333                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12334                 appendPQExpBuffer(q, " AS\n    %s\n", viewdef);
12335
12336                 appendPQExpBuffer(labelq, "VIEW %s",
12337                                                   fmtId(tbinfo->dobj.name));
12338
12339                 PQclear(res);
12340         }
12341         else
12342         {
12343                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12344                 {
12345                         int                     i_srvname;
12346                         int                     i_ftoptions;
12347
12348                         reltypename = "FOREIGN TABLE";
12349
12350                         /* retrieve name of foreign server and generic options */
12351                         appendPQExpBuffer(query,
12352                                                           "SELECT fs.srvname, "
12353                                                           "pg_catalog.array_to_string(ARRAY("
12354                                                           "SELECT pg_catalog.quote_ident(option_name) || "
12355                                                           "' ' || pg_catalog.quote_literal(option_value) "
12356                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
12357                                                           "ORDER BY option_name"
12358                                                           "), E',\n    ') AS ftoptions "
12359                                                           "FROM pg_catalog.pg_foreign_table ft "
12360                                                           "JOIN pg_catalog.pg_foreign_server fs "
12361                                                           "ON (fs.oid = ft.ftserver) "
12362                                                           "WHERE ft.ftrelid = '%u'",
12363                                                           tbinfo->dobj.catId.oid);
12364                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12365                         i_srvname = PQfnumber(res, "srvname");
12366                         i_ftoptions = PQfnumber(res, "ftoptions");
12367                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12368                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12369                         PQclear(res);
12370                 }
12371                 else
12372                 {
12373                         reltypename = "TABLE";
12374                         srvname = NULL;
12375                         ftoptions = NULL;
12376                 }
12377                 numParents = tbinfo->numParents;
12378                 parents = tbinfo->parents;
12379
12380                 /*
12381                  * DROP must be fully qualified in case same name appears in
12382                  * pg_catalog
12383                  */
12384                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12385                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12386                 appendPQExpBuffer(delq, "%s;\n",
12387                                                   fmtId(tbinfo->dobj.name));
12388
12389                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12390                                                   fmtId(tbinfo->dobj.name));
12391
12392                 if (binary_upgrade)
12393                         binary_upgrade_set_pg_class_oids(fout, q,
12394                                                                                          tbinfo->dobj.catId.oid, false);
12395
12396                 appendPQExpBuffer(q, "CREATE %s%s %s",
12397                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12398                                                   "UNLOGGED " : "",
12399                                                   reltypename,
12400                                                   fmtId(tbinfo->dobj.name));
12401
12402                 /*
12403                  * Attach to type, if reloftype; except in case of a binary upgrade,
12404                  * we dump the table normally and attach it to the type afterward.
12405                  */
12406                 if (tbinfo->reloftype && !binary_upgrade)
12407                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12408
12409                 /* Dump the attributes */
12410                 actual_atts = 0;
12411                 for (j = 0; j < tbinfo->numatts; j++)
12412                 {
12413                         /*
12414                          * Normally, dump if it's locally defined in this table, and not
12415                          * dropped.  But for binary upgrade, we'll dump all the columns,
12416                          * and then fix up the dropped and nonlocal cases below.
12417                          */
12418                         if (shouldPrintColumn(tbinfo, j))
12419                         {
12420                                 /*
12421                                  * Default value --- suppress if to be printed separately.
12422                                  */
12423                                 bool            has_default = (tbinfo->attrdefs[j] != NULL &&
12424                                                                                    !tbinfo->attrdefs[j]->separate);
12425
12426                                 /*
12427                                  * Not Null constraint --- suppress if inherited, except in
12428                                  * binary-upgrade case where that won't work.
12429                                  */
12430                                 bool            has_notnull = (tbinfo->notnull[j] &&
12431                                                                                    (!tbinfo->inhNotNull[j] ||
12432                                                                                         binary_upgrade));
12433
12434                                 /* Skip column if fully defined by reloftype */
12435                                 if (tbinfo->reloftype &&
12436                                         !has_default && !has_notnull && !binary_upgrade)
12437                                         continue;
12438
12439                                 /* Format properly if not first attr */
12440                                 if (actual_atts == 0)
12441                                         appendPQExpBuffer(q, " (");
12442                                 else
12443                                         appendPQExpBuffer(q, ",");
12444                                 appendPQExpBuffer(q, "\n    ");
12445                                 actual_atts++;
12446
12447                                 /* Attribute name */
12448                                 appendPQExpBuffer(q, "%s ",
12449                                                                   fmtId(tbinfo->attnames[j]));
12450
12451                                 if (tbinfo->attisdropped[j])
12452                                 {
12453                                         /*
12454                                          * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
12455                                          * so we will not have gotten a valid type name; insert
12456                                          * INTEGER as a stopgap.  We'll clean things up later.
12457                                          */
12458                                         appendPQExpBuffer(q, "INTEGER /* dummy */");
12459                                         /* Skip all the rest, too */
12460                                         continue;
12461                                 }
12462
12463                                 /* Attribute type */
12464                                 if (tbinfo->reloftype && !binary_upgrade)
12465                                 {
12466                                         appendPQExpBuffer(q, "WITH OPTIONS");
12467                                 }
12468                                 else if (fout->remoteVersion >= 70100)
12469                                 {
12470                                         appendPQExpBuffer(q, "%s",
12471                                                                           tbinfo->atttypnames[j]);
12472                                 }
12473                                 else
12474                                 {
12475                                         /* If no format_type, fake it */
12476                                         appendPQExpBuffer(q, "%s",
12477                                                                           myFormatType(tbinfo->atttypnames[j],
12478                                                                                                    tbinfo->atttypmod[j]));
12479                                 }
12480
12481                                 /* Add collation if not default for the type */
12482                                 if (OidIsValid(tbinfo->attcollation[j]))
12483                                 {
12484                                         CollInfo   *coll;
12485
12486                                         coll = findCollationByOid(tbinfo->attcollation[j]);
12487                                         if (coll)
12488                                         {
12489                                                 /* always schema-qualify, don't try to be smart */
12490                                                 appendPQExpBuffer(q, " COLLATE %s.",
12491                                                                          fmtId(coll->dobj.namespace->dobj.name));
12492                                                 appendPQExpBuffer(q, "%s",
12493                                                                                   fmtId(coll->dobj.name));
12494                                         }
12495                                 }
12496
12497                                 if (has_default)
12498                                         appendPQExpBuffer(q, " DEFAULT %s",
12499                                                                           tbinfo->attrdefs[j]->adef_expr);
12500
12501                                 if (has_notnull)
12502                                         appendPQExpBuffer(q, " NOT NULL");
12503                         }
12504                 }
12505
12506                 /*
12507                  * Add non-inherited CHECK constraints, if any.
12508                  */
12509                 for (j = 0; j < tbinfo->ncheck; j++)
12510                 {
12511                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12512
12513                         if (constr->separate || !constr->conislocal)
12514                                 continue;
12515
12516                         if (actual_atts == 0)
12517                                 appendPQExpBuffer(q, " (\n    ");
12518                         else
12519                                 appendPQExpBuffer(q, ",\n    ");
12520
12521                         appendPQExpBuffer(q, "CONSTRAINT %s ",
12522                                                           fmtId(constr->dobj.name));
12523                         appendPQExpBuffer(q, "%s", constr->condef);
12524
12525                         actual_atts++;
12526                 }
12527
12528                 if (actual_atts)
12529                         appendPQExpBuffer(q, "\n)");
12530                 else if (!(tbinfo->reloftype && !binary_upgrade))
12531                 {
12532                         /*
12533                          * We must have a parenthesized attribute list, even though empty,
12534                          * when not using the OF TYPE syntax.
12535                          */
12536                         appendPQExpBuffer(q, " (\n)");
12537                 }
12538
12539                 if (numParents > 0 && !binary_upgrade)
12540                 {
12541                         appendPQExpBuffer(q, "\nINHERITS (");
12542                         for (k = 0; k < numParents; k++)
12543                         {
12544                                 TableInfo  *parentRel = parents[k];
12545
12546                                 if (k > 0)
12547                                         appendPQExpBuffer(q, ", ");
12548                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12549                                         appendPQExpBuffer(q, "%s.",
12550                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12551                                 appendPQExpBuffer(q, "%s",
12552                                                                   fmtId(parentRel->dobj.name));
12553                         }
12554                         appendPQExpBuffer(q, ")");
12555                 }
12556
12557                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12558                         appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
12559
12560                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
12561                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
12562                 {
12563                         bool            addcomma = false;
12564
12565                         appendPQExpBuffer(q, "\nWITH (");
12566                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12567                         {
12568                                 addcomma = true;
12569                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
12570                         }
12571                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
12572                         {
12573                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
12574                                                                   tbinfo->toast_reloptions);
12575                         }
12576                         appendPQExpBuffer(q, ")");
12577                 }
12578
12579                 /* Dump generic options if any */
12580                 if (ftoptions && ftoptions[0])
12581                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
12582
12583                 appendPQExpBuffer(q, ";\n");
12584
12585                 /*
12586                  * To create binary-compatible heap files, we have to ensure the same
12587                  * physical column order, including dropped columns, as in the
12588                  * original.  Therefore, we create dropped columns above and drop them
12589                  * here, also updating their attlen/attalign values so that the
12590                  * dropped column can be skipped properly.      (We do not bother with
12591                  * restoring the original attbyval setting.)  Also, inheritance
12592                  * relationships are set up by doing ALTER INHERIT rather than using
12593                  * an INHERITS clause --- the latter would possibly mess up the column
12594                  * order.  That also means we have to take care about setting
12595                  * attislocal correctly, plus fix up any inherited CHECK constraints.
12596                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
12597                  */
12598                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
12599                 {
12600                         for (j = 0; j < tbinfo->numatts; j++)
12601                         {
12602                                 if (tbinfo->attisdropped[j])
12603                                 {
12604                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
12605                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12606                                                                           "SET attlen = %d, "
12607                                                                           "attalign = '%c', attbyval = false\n"
12608                                                                           "WHERE attname = ",
12609                                                                           tbinfo->attlen[j],
12610                                                                           tbinfo->attalign[j]);
12611                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12612                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12613                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12614                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12615
12616                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12617                                                                           fmtId(tbinfo->dobj.name));
12618                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
12619                                                                           fmtId(tbinfo->attnames[j]));
12620                                 }
12621                                 else if (!tbinfo->attislocal[j])
12622                                 {
12623                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
12624                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12625                                                                           "SET attislocal = false\n"
12626                                                                           "WHERE attname = ");
12627                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12628                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12629                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12630                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12631                                 }
12632                         }
12633
12634                         for (k = 0; k < tbinfo->ncheck; k++)
12635                         {
12636                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
12637
12638                                 if (constr->separate || constr->conislocal)
12639                                         continue;
12640
12641                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
12642                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12643                                                                   fmtId(tbinfo->dobj.name));
12644                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
12645                                                                   fmtId(constr->dobj.name));
12646                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
12647                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
12648                                                                   "SET conislocal = false\n"
12649                                                                   "WHERE contype = 'c' AND conname = ");
12650                                 appendStringLiteralAH(q, constr->dobj.name, fout);
12651                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
12652                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12653                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12654                         }
12655
12656                         if (numParents > 0)
12657                         {
12658                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
12659                                 for (k = 0; k < numParents; k++)
12660                                 {
12661                                         TableInfo  *parentRel = parents[k];
12662
12663                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
12664                                                                           fmtId(tbinfo->dobj.name));
12665                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12666                                                 appendPQExpBuffer(q, "%s.",
12667                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12668                                         appendPQExpBuffer(q, "%s;\n",
12669                                                                           fmtId(parentRel->dobj.name));
12670                                 }
12671                         }
12672
12673                         if (tbinfo->reloftype)
12674                         {
12675                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
12676                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
12677                                                                   fmtId(tbinfo->dobj.name),
12678                                                                   tbinfo->reloftype);
12679                         }
12680
12681                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
12682                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12683                                                           "SET relfrozenxid = '%u'\n"
12684                                                           "WHERE oid = ",
12685                                                           tbinfo->frozenxid);
12686                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12687                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12688
12689                         if (tbinfo->toast_oid)
12690                         {
12691                                 /* We preserve the toast oids, so we can use it during restore */
12692                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
12693                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12694                                                                   "SET relfrozenxid = '%u'\n"
12695                                                                   "WHERE oid = '%u';\n",
12696                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
12697                         }
12698                 }
12699
12700                 /*
12701                  * Dump additional per-column properties that we can't handle in the
12702                  * main CREATE TABLE command.
12703                  */
12704                 for (j = 0; j < tbinfo->numatts; j++)
12705                 {
12706                         /* None of this applies to dropped columns */
12707                         if (tbinfo->attisdropped[j])
12708                                 continue;
12709
12710                         /*
12711                          * If we didn't dump the column definition explicitly above, and
12712                          * it is NOT NULL and did not inherit that property from a parent,
12713                          * we have to mark it separately.
12714                          */
12715                         if (!shouldPrintColumn(tbinfo, j) &&
12716                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
12717                         {
12718                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12719                                                                   fmtId(tbinfo->dobj.name));
12720                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
12721                                                                   fmtId(tbinfo->attnames[j]));
12722                         }
12723
12724                         /*
12725                          * Dump per-column statistics information. We only issue an ALTER
12726                          * TABLE statement if the attstattarget entry for this column is
12727                          * non-negative (i.e. it's not the default value)
12728                          */
12729                         if (tbinfo->attstattarget[j] >= 0)
12730                         {
12731                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12732                                                                   fmtId(tbinfo->dobj.name));
12733                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12734                                                                   fmtId(tbinfo->attnames[j]));
12735                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
12736                                                                   tbinfo->attstattarget[j]);
12737                         }
12738
12739                         /*
12740                          * Dump per-column storage information.  The statement is only
12741                          * dumped if the storage has been changed from the type's default.
12742                          */
12743                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
12744                         {
12745                                 switch (tbinfo->attstorage[j])
12746                                 {
12747                                         case 'p':
12748                                                 storage = "PLAIN";
12749                                                 break;
12750                                         case 'e':
12751                                                 storage = "EXTERNAL";
12752                                                 break;
12753                                         case 'm':
12754                                                 storage = "MAIN";
12755                                                 break;
12756                                         case 'x':
12757                                                 storage = "EXTENDED";
12758                                                 break;
12759                                         default:
12760                                                 storage = NULL;
12761                                 }
12762
12763                                 /*
12764                                  * Only dump the statement if it's a storage type we recognize
12765                                  */
12766                                 if (storage != NULL)
12767                                 {
12768                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12769                                                                           fmtId(tbinfo->dobj.name));
12770                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
12771                                                                           fmtId(tbinfo->attnames[j]));
12772                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
12773                                                                           storage);
12774                                 }
12775                         }
12776
12777                         /*
12778                          * Dump per-column attributes.
12779                          */
12780                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
12781                         {
12782                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12783                                                                   fmtId(tbinfo->dobj.name));
12784                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12785                                                                   fmtId(tbinfo->attnames[j]));
12786                                 appendPQExpBuffer(q, "SET (%s);\n",
12787                                                                   tbinfo->attoptions[j]);
12788                         }
12789
12790                         /*
12791                          * Dump per-column fdw options.
12792                          */
12793                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
12794                                 tbinfo->attfdwoptions[j] &&
12795                                 tbinfo->attfdwoptions[j][0] != '\0')
12796                         {
12797                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
12798                                                                   fmtId(tbinfo->dobj.name));
12799                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12800                                                                   fmtId(tbinfo->attnames[j]));
12801                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
12802                                                                   tbinfo->attfdwoptions[j]);
12803                         }
12804                 }
12805         }
12806
12807         if (binary_upgrade)
12808                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
12809
12810         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12811                                  tbinfo->dobj.name,
12812                                  tbinfo->dobj.namespace->dobj.name,
12813                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
12814                                  tbinfo->rolname,
12815                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
12816                                  reltypename, SECTION_PRE_DATA,
12817                                  q->data, delq->data, NULL,
12818                                  NULL, 0,
12819                                  NULL, NULL);
12820
12821
12822         /* Dump Table Comments */
12823         dumpTableComment(fout, tbinfo, reltypename);
12824
12825         /* Dump Table Security Labels */
12826         dumpTableSecLabel(fout, tbinfo, reltypename);
12827
12828         /* Dump comments on inlined table constraints */
12829         for (j = 0; j < tbinfo->ncheck; j++)
12830         {
12831                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12832
12833                 if (constr->separate || !constr->conislocal)
12834                         continue;
12835
12836                 dumpTableConstraintComment(fout, constr);
12837         }
12838
12839         destroyPQExpBuffer(query);
12840         destroyPQExpBuffer(q);
12841         destroyPQExpBuffer(delq);
12842         destroyPQExpBuffer(labelq);
12843 }
12844
12845 /*
12846  * dumpAttrDef --- dump an attribute's default-value declaration
12847  */
12848 static void
12849 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
12850 {
12851         TableInfo  *tbinfo = adinfo->adtable;
12852         int                     adnum = adinfo->adnum;
12853         PQExpBuffer q;
12854         PQExpBuffer delq;
12855
12856         /* Skip if table definition not to be dumped */
12857         if (!tbinfo->dobj.dump || dataOnly)
12858                 return;
12859
12860         /* Skip if not "separate"; it was dumped in the table's definition */
12861         if (!adinfo->separate)
12862                 return;
12863
12864         q = createPQExpBuffer();
12865         delq = createPQExpBuffer();
12866
12867         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12868                                           fmtId(tbinfo->dobj.name));
12869         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
12870                                           fmtId(tbinfo->attnames[adnum - 1]),
12871                                           adinfo->adef_expr);
12872
12873         /*
12874          * DROP must be fully qualified in case same name appears in pg_catalog
12875          */
12876         appendPQExpBuffer(delq, "ALTER TABLE %s.",
12877                                           fmtId(tbinfo->dobj.namespace->dobj.name));
12878         appendPQExpBuffer(delq, "%s ",
12879                                           fmtId(tbinfo->dobj.name));
12880         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
12881                                           fmtId(tbinfo->attnames[adnum - 1]));
12882
12883         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
12884                                  tbinfo->attnames[adnum - 1],
12885                                  tbinfo->dobj.namespace->dobj.name,
12886                                  NULL,
12887                                  tbinfo->rolname,
12888                                  false, "DEFAULT", SECTION_PRE_DATA,
12889                                  q->data, delq->data, NULL,
12890                                  NULL, 0,
12891                                  NULL, NULL);
12892
12893         destroyPQExpBuffer(q);
12894         destroyPQExpBuffer(delq);
12895 }
12896
12897 /*
12898  * getAttrName: extract the correct name for an attribute
12899  *
12900  * The array tblInfo->attnames[] only provides names of user attributes;
12901  * if a system attribute number is supplied, we have to fake it.
12902  * We also do a little bit of bounds checking for safety's sake.
12903  */
12904 static const char *
12905 getAttrName(int attrnum, TableInfo *tblInfo)
12906 {
12907         if (attrnum > 0 && attrnum <= tblInfo->numatts)
12908                 return tblInfo->attnames[attrnum - 1];
12909         switch (attrnum)
12910         {
12911                 case SelfItemPointerAttributeNumber:
12912                         return "ctid";
12913                 case ObjectIdAttributeNumber:
12914                         return "oid";
12915                 case MinTransactionIdAttributeNumber:
12916                         return "xmin";
12917                 case MinCommandIdAttributeNumber:
12918                         return "cmin";
12919                 case MaxTransactionIdAttributeNumber:
12920                         return "xmax";
12921                 case MaxCommandIdAttributeNumber:
12922                         return "cmax";
12923                 case TableOidAttributeNumber:
12924                         return "tableoid";
12925         }
12926         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
12927                                   attrnum, tblInfo->dobj.name);
12928         return NULL;                            /* keep compiler quiet */
12929 }
12930
12931 /*
12932  * dumpIndex
12933  *        write out to fout a user-defined index
12934  */
12935 static void
12936 dumpIndex(Archive *fout, IndxInfo *indxinfo)
12937 {
12938         TableInfo  *tbinfo = indxinfo->indextable;
12939         PQExpBuffer q;
12940         PQExpBuffer delq;
12941         PQExpBuffer labelq;
12942
12943         if (dataOnly)
12944                 return;
12945
12946         q = createPQExpBuffer();
12947         delq = createPQExpBuffer();
12948         labelq = createPQExpBuffer();
12949
12950         appendPQExpBuffer(labelq, "INDEX %s",
12951                                           fmtId(indxinfo->dobj.name));
12952
12953         /*
12954          * If there's an associated constraint, don't dump the index per se, but
12955          * do dump any comment for it.  (This is safe because dependency ordering
12956          * will have ensured the constraint is emitted first.)
12957          */
12958         if (indxinfo->indexconstraint == 0)
12959         {
12960                 if (binary_upgrade)
12961                         binary_upgrade_set_pg_class_oids(fout, q,
12962                                                                                          indxinfo->dobj.catId.oid, true);
12963
12964                 /* Plain secondary index */
12965                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
12966
12967                 /* If the index is clustered, we need to record that. */
12968                 if (indxinfo->indisclustered)
12969                 {
12970                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
12971                                                           fmtId(tbinfo->dobj.name));
12972                         appendPQExpBuffer(q, " ON %s;\n",
12973                                                           fmtId(indxinfo->dobj.name));
12974                 }
12975
12976                 /*
12977                  * DROP must be fully qualified in case same name appears in
12978                  * pg_catalog
12979                  */
12980                 appendPQExpBuffer(delq, "DROP INDEX %s.",
12981                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12982                 appendPQExpBuffer(delq, "%s;\n",
12983                                                   fmtId(indxinfo->dobj.name));
12984
12985                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
12986                                          indxinfo->dobj.name,
12987                                          tbinfo->dobj.namespace->dobj.name,
12988                                          indxinfo->tablespace,
12989                                          tbinfo->rolname, false,
12990                                          "INDEX", SECTION_POST_DATA,
12991                                          q->data, delq->data, NULL,
12992                                          NULL, 0,
12993                                          NULL, NULL);
12994         }
12995
12996         /* Dump Index Comments */
12997         dumpComment(fout, labelq->data,
12998                                 tbinfo->dobj.namespace->dobj.name,
12999                                 tbinfo->rolname,
13000                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13001
13002         destroyPQExpBuffer(q);
13003         destroyPQExpBuffer(delq);
13004         destroyPQExpBuffer(labelq);
13005 }
13006
13007 /*
13008  * dumpConstraint
13009  *        write out to fout a user-defined constraint
13010  */
13011 static void
13012 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13013 {
13014         TableInfo  *tbinfo = coninfo->contable;
13015         PQExpBuffer q;
13016         PQExpBuffer delq;
13017
13018         /* Skip if not to be dumped */
13019         if (!coninfo->dobj.dump || dataOnly)
13020                 return;
13021
13022         q = createPQExpBuffer();
13023         delq = createPQExpBuffer();
13024
13025         if (coninfo->contype == 'p' ||
13026                 coninfo->contype == 'u' ||
13027                 coninfo->contype == 'x')
13028         {
13029                 /* Index-related constraint */
13030                 IndxInfo   *indxinfo;
13031                 int                     k;
13032
13033                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13034
13035                 if (indxinfo == NULL)
13036                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13037                                                   coninfo->dobj.name);
13038
13039                 if (binary_upgrade)
13040                         binary_upgrade_set_pg_class_oids(fout, q,
13041                                                                                          indxinfo->dobj.catId.oid, true);
13042
13043                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13044                                                   fmtId(tbinfo->dobj.name));
13045                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13046                                                   fmtId(coninfo->dobj.name));
13047
13048                 if (coninfo->condef)
13049                 {
13050                         /* pg_get_constraintdef should have provided everything */
13051                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13052                 }
13053                 else
13054                 {
13055                         appendPQExpBuffer(q, "%s (",
13056                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13057                         for (k = 0; k < indxinfo->indnkeys; k++)
13058                         {
13059                                 int                     indkey = (int) indxinfo->indkeys[k];
13060                                 const char *attname;
13061
13062                                 if (indkey == InvalidAttrNumber)
13063                                         break;
13064                                 attname = getAttrName(indkey, tbinfo);
13065
13066                                 appendPQExpBuffer(q, "%s%s",
13067                                                                   (k == 0) ? "" : ", ",
13068                                                                   fmtId(attname));
13069                         }
13070
13071                         appendPQExpBuffer(q, ")");
13072
13073                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13074                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13075
13076                         if (coninfo->condeferrable)
13077                         {
13078                                 appendPQExpBuffer(q, " DEFERRABLE");
13079                                 if (coninfo->condeferred)
13080                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13081                         }
13082
13083                         appendPQExpBuffer(q, ";\n");
13084                 }
13085
13086                 /* If the index is clustered, we need to record that. */
13087                 if (indxinfo->indisclustered)
13088                 {
13089                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13090                                                           fmtId(tbinfo->dobj.name));
13091                         appendPQExpBuffer(q, " ON %s;\n",
13092                                                           fmtId(indxinfo->dobj.name));
13093                 }
13094
13095                 /*
13096                  * DROP must be fully qualified in case same name appears in
13097                  * pg_catalog
13098                  */
13099                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13100                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13101                 appendPQExpBuffer(delq, "%s ",
13102                                                   fmtId(tbinfo->dobj.name));
13103                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13104                                                   fmtId(coninfo->dobj.name));
13105
13106                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13107                                          coninfo->dobj.name,
13108                                          tbinfo->dobj.namespace->dobj.name,
13109                                          indxinfo->tablespace,
13110                                          tbinfo->rolname, false,
13111                                          "CONSTRAINT", SECTION_POST_DATA,
13112                                          q->data, delq->data, NULL,
13113                                          NULL, 0,
13114                                          NULL, NULL);
13115         }
13116         else if (coninfo->contype == 'f')
13117         {
13118                 /*
13119                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13120                  * current table data is not processed
13121                  */
13122                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13123                                                   fmtId(tbinfo->dobj.name));
13124                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13125                                                   fmtId(coninfo->dobj.name),
13126                                                   coninfo->condef);
13127
13128                 /*
13129                  * DROP must be fully qualified in case same name appears in
13130                  * pg_catalog
13131                  */
13132                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13133                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13134                 appendPQExpBuffer(delq, "%s ",
13135                                                   fmtId(tbinfo->dobj.name));
13136                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13137                                                   fmtId(coninfo->dobj.name));
13138
13139                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13140                                          coninfo->dobj.name,
13141                                          tbinfo->dobj.namespace->dobj.name,
13142                                          NULL,
13143                                          tbinfo->rolname, false,
13144                                          "FK CONSTRAINT", SECTION_POST_DATA,
13145                                          q->data, delq->data, NULL,
13146                                          NULL, 0,
13147                                          NULL, NULL);
13148         }
13149         else if (coninfo->contype == 'c' && tbinfo)
13150         {
13151                 /* CHECK constraint on a table */
13152
13153                 /* Ignore if not to be dumped separately */
13154                 if (coninfo->separate)
13155                 {
13156                         /* not ONLY since we want it to propagate to children */
13157                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13158                                                           fmtId(tbinfo->dobj.name));
13159                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13160                                                           fmtId(coninfo->dobj.name),
13161                                                           coninfo->condef);
13162
13163                         /*
13164                          * DROP must be fully qualified in case same name appears in
13165                          * pg_catalog
13166                          */
13167                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13168                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13169                         appendPQExpBuffer(delq, "%s ",
13170                                                           fmtId(tbinfo->dobj.name));
13171                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13172                                                           fmtId(coninfo->dobj.name));
13173
13174                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13175                                                  coninfo->dobj.name,
13176                                                  tbinfo->dobj.namespace->dobj.name,
13177                                                  NULL,
13178                                                  tbinfo->rolname, false,
13179                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13180                                                  q->data, delq->data, NULL,
13181                                                  NULL, 0,
13182                                                  NULL, NULL);
13183                 }
13184         }
13185         else if (coninfo->contype == 'c' && tbinfo == NULL)
13186         {
13187                 /* CHECK constraint on a domain */
13188                 TypeInfo   *tyinfo = coninfo->condomain;
13189
13190                 /* Ignore if not to be dumped separately */
13191                 if (coninfo->separate)
13192                 {
13193                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13194                                                           fmtId(tyinfo->dobj.name));
13195                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13196                                                           fmtId(coninfo->dobj.name),
13197                                                           coninfo->condef);
13198
13199                         /*
13200                          * DROP must be fully qualified in case same name appears in
13201                          * pg_catalog
13202                          */
13203                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13204                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13205                         appendPQExpBuffer(delq, "%s ",
13206                                                           fmtId(tyinfo->dobj.name));
13207                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13208                                                           fmtId(coninfo->dobj.name));
13209
13210                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13211                                                  coninfo->dobj.name,
13212                                                  tyinfo->dobj.namespace->dobj.name,
13213                                                  NULL,
13214                                                  tyinfo->rolname, false,
13215                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13216                                                  q->data, delq->data, NULL,
13217                                                  NULL, 0,
13218                                                  NULL, NULL);
13219                 }
13220         }
13221         else
13222         {
13223                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
13224                                           coninfo->contype);
13225         }
13226
13227         /* Dump Constraint Comments --- only works for table constraints */
13228         if (tbinfo && coninfo->separate)
13229                 dumpTableConstraintComment(fout, coninfo);
13230
13231         destroyPQExpBuffer(q);
13232         destroyPQExpBuffer(delq);
13233 }
13234
13235 /*
13236  * dumpTableConstraintComment --- dump a constraint's comment if any
13237  *
13238  * This is split out because we need the function in two different places
13239  * depending on whether the constraint is dumped as part of CREATE TABLE
13240  * or as a separate ALTER command.
13241  */
13242 static void
13243 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13244 {
13245         TableInfo  *tbinfo = coninfo->contable;
13246         PQExpBuffer labelq = createPQExpBuffer();
13247
13248         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13249                                           fmtId(coninfo->dobj.name));
13250         appendPQExpBuffer(labelq, "ON %s",
13251                                           fmtId(tbinfo->dobj.name));
13252         dumpComment(fout, labelq->data,
13253                                 tbinfo->dobj.namespace->dobj.name,
13254                                 tbinfo->rolname,
13255                                 coninfo->dobj.catId, 0,
13256                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13257
13258         destroyPQExpBuffer(labelq);
13259 }
13260
13261 /*
13262  * findLastBuiltInOid -
13263  * find the last built in oid
13264  *
13265  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13266  * pg_database entry for the current database
13267  */
13268 static Oid
13269 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13270 {
13271         PGresult   *res;
13272         Oid                     last_oid;
13273         PQExpBuffer query = createPQExpBuffer();
13274
13275         resetPQExpBuffer(query);
13276         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13277         appendStringLiteralAH(query, dbname, fout);
13278
13279         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13280         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13281         PQclear(res);
13282         destroyPQExpBuffer(query);
13283         return last_oid;
13284 }
13285
13286 /*
13287  * findLastBuiltInOid -
13288  * find the last built in oid
13289  *
13290  * For 7.0, we do this by assuming that the last thing that initdb does is to
13291  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13292  * initdb won't be changing anymore, it'll do.
13293  */
13294 static Oid
13295 findLastBuiltinOid_V70(Archive *fout)
13296 {
13297         PGresult   *res;
13298         int                     last_oid;
13299
13300         res = ExecuteSqlQueryForSingleRow(fout,
13301                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13302         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13303         PQclear(res);
13304         return last_oid;
13305 }
13306
13307 static void
13308 dumpSequence(Archive *fout, TableInfo *tbinfo)
13309 {
13310         PGresult   *res;
13311         char       *startv,
13312                            *last,
13313                            *incby,
13314                            *maxv = NULL,
13315                            *minv = NULL,
13316                            *cache;
13317         char            bufm[100],
13318                                 bufx[100];
13319         bool            cycled,
13320                                 called;
13321         PQExpBuffer query = createPQExpBuffer();
13322         PQExpBuffer delqry = createPQExpBuffer();
13323         PQExpBuffer labelq = createPQExpBuffer();
13324
13325         /* Make sure we are in proper schema */
13326         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13327
13328         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13329         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13330
13331         if (fout->remoteVersion >= 80400)
13332         {
13333                 appendPQExpBuffer(query,
13334                                                   "SELECT sequence_name, "
13335                                                   "start_value, last_value, increment_by, "
13336                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13337                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13338                                                   "     ELSE max_value "
13339                                                   "END AS max_value, "
13340                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13341                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13342                                                   "     ELSE min_value "
13343                                                   "END AS min_value, "
13344                                                   "cache_value, is_cycled, is_called from %s",
13345                                                   bufx, bufm,
13346                                                   fmtId(tbinfo->dobj.name));
13347         }
13348         else
13349         {
13350                 appendPQExpBuffer(query,
13351                                                   "SELECT sequence_name, "
13352                                                   "0 AS start_value, last_value, increment_by, "
13353                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13354                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13355                                                   "     ELSE max_value "
13356                                                   "END AS max_value, "
13357                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13358                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13359                                                   "     ELSE min_value "
13360                                                   "END AS min_value, "
13361                                                   "cache_value, is_cycled, is_called from %s",
13362                                                   bufx, bufm,
13363                                                   fmtId(tbinfo->dobj.name));
13364         }
13365
13366         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13367
13368         if (PQntuples(res) != 1)
13369         {
13370                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13371                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13372                                                                  PQntuples(res)),
13373                                   tbinfo->dobj.name, PQntuples(res));
13374                 exit_nicely(1);
13375         }
13376
13377         /* Disable this check: it fails if sequence has been renamed */
13378 #ifdef NOT_USED
13379         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13380         {
13381                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13382                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13383                 exit_nicely(1);
13384         }
13385 #endif
13386
13387         startv = PQgetvalue(res, 0, 1);
13388         last = PQgetvalue(res, 0, 2);
13389         incby = PQgetvalue(res, 0, 3);
13390         if (!PQgetisnull(res, 0, 4))
13391                 maxv = PQgetvalue(res, 0, 4);
13392         if (!PQgetisnull(res, 0, 5))
13393                 minv = PQgetvalue(res, 0, 5);
13394         cache = PQgetvalue(res, 0, 6);
13395         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
13396         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
13397
13398         /*
13399          * The logic we use for restoring sequences is as follows:
13400          *
13401          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
13402          * last_val for start if called is false, else use min_val for start_val).
13403          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
13404          * BY command for it.
13405          *
13406          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
13407          */
13408         if (!dataOnly)
13409         {
13410                 /*
13411                  * DROP must be fully qualified in case same name appears in
13412                  * pg_catalog
13413                  */
13414                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13415                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13416                 appendPQExpBuffer(delqry, "%s;\n",
13417                                                   fmtId(tbinfo->dobj.name));
13418
13419                 resetPQExpBuffer(query);
13420
13421                 if (binary_upgrade)
13422                 {
13423                         binary_upgrade_set_pg_class_oids(fout, query,
13424                                                                                          tbinfo->dobj.catId.oid, false);
13425                         binary_upgrade_set_type_oids_by_rel_oid(fout, query,
13426                                                                                                         tbinfo->dobj.catId.oid);
13427                 }
13428
13429                 appendPQExpBuffer(query,
13430                                                   "CREATE SEQUENCE %s\n",
13431                                                   fmtId(tbinfo->dobj.name));
13432
13433                 if (fout->remoteVersion >= 80400)
13434                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
13435                 else
13436                 {
13437                         /*
13438                          * Versions before 8.4 did not remember the true start value.  If
13439                          * is_called is false then the sequence has never been incremented
13440                          * so we can use last_val.      Otherwise punt and let it default.
13441                          */
13442                         if (!called)
13443                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
13444                 }
13445
13446                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13447
13448                 if (minv)
13449                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13450                 else
13451                         appendPQExpBuffer(query, "    NO MINVALUE\n");
13452
13453                 if (maxv)
13454                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13455                 else
13456                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
13457
13458                 appendPQExpBuffer(query,
13459                                                   "    CACHE %s%s",
13460                                                   cache, (cycled ? "\n    CYCLE" : ""));
13461
13462                 appendPQExpBuffer(query, ";\n");
13463
13464                 appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13465
13466                 /* binary_upgrade:      no need to clear TOAST table oid */
13467
13468                 if (binary_upgrade)
13469                         binary_upgrade_extension_member(query, &tbinfo->dobj,
13470                                                                                         labelq->data);
13471
13472                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13473                                          tbinfo->dobj.name,
13474                                          tbinfo->dobj.namespace->dobj.name,
13475                                          NULL,
13476                                          tbinfo->rolname,
13477                                          false, "SEQUENCE", SECTION_PRE_DATA,
13478                                          query->data, delqry->data, NULL,
13479                                          NULL, 0,
13480                                          NULL, NULL);
13481
13482                 /*
13483                  * If the sequence is owned by a table column, emit the ALTER for it
13484                  * as a separate TOC entry immediately following the sequence's own
13485                  * entry.  It's OK to do this rather than using full sorting logic,
13486                  * because the dependency that tells us it's owned will have forced
13487                  * the table to be created first.  We can't just include the ALTER in
13488                  * the TOC entry because it will fail if we haven't reassigned the
13489                  * sequence owner to match the table's owner.
13490                  *
13491                  * We need not schema-qualify the table reference because both
13492                  * sequence and table must be in the same schema.
13493                  */
13494                 if (OidIsValid(tbinfo->owning_tab))
13495                 {
13496                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
13497
13498                         if (owning_tab && owning_tab->dobj.dump)
13499                         {
13500                                 resetPQExpBuffer(query);
13501                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
13502                                                                   fmtId(tbinfo->dobj.name));
13503                                 appendPQExpBuffer(query, " OWNED BY %s",
13504                                                                   fmtId(owning_tab->dobj.name));
13505                                 appendPQExpBuffer(query, ".%s;\n",
13506                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
13507
13508                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13509                                                          tbinfo->dobj.name,
13510                                                          tbinfo->dobj.namespace->dobj.name,
13511                                                          NULL,
13512                                                          tbinfo->rolname,
13513                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
13514                                                          query->data, "", NULL,
13515                                                          &(tbinfo->dobj.dumpId), 1,
13516                                                          NULL, NULL);
13517                         }
13518                 }
13519
13520                 /* Dump Sequence Comments and Security Labels */
13521                 dumpComment(fout, labelq->data,
13522                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13523                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13524                 dumpSecLabel(fout, labelq->data,
13525                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13526                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13527         }
13528
13529         if (!schemaOnly)
13530         {
13531                 resetPQExpBuffer(query);
13532                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
13533                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
13534                 appendPQExpBuffer(query, ", %s, %s);\n",
13535                                                   last, (called ? "true" : "false"));
13536
13537                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13538                                          tbinfo->dobj.name,
13539                                          tbinfo->dobj.namespace->dobj.name,
13540                                          NULL,
13541                                          tbinfo->rolname,
13542                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
13543                                          query->data, "", NULL,
13544                                          &(tbinfo->dobj.dumpId), 1,
13545                                          NULL, NULL);
13546         }
13547
13548         PQclear(res);
13549
13550         destroyPQExpBuffer(query);
13551         destroyPQExpBuffer(delqry);
13552         destroyPQExpBuffer(labelq);
13553 }
13554
13555 static void
13556 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
13557 {
13558         TableInfo  *tbinfo = tginfo->tgtable;
13559         PQExpBuffer query;
13560         PQExpBuffer delqry;
13561         PQExpBuffer labelq;
13562         char       *tgargs;
13563         size_t          lentgargs;
13564         const char *p;
13565         int                     findx;
13566
13567         if (dataOnly)
13568                 return;
13569
13570         query = createPQExpBuffer();
13571         delqry = createPQExpBuffer();
13572         labelq = createPQExpBuffer();
13573
13574         /*
13575          * DROP must be fully qualified in case same name appears in pg_catalog
13576          */
13577         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
13578                                           fmtId(tginfo->dobj.name));
13579         appendPQExpBuffer(delqry, "ON %s.",
13580                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13581         appendPQExpBuffer(delqry, "%s;\n",
13582                                           fmtId(tbinfo->dobj.name));
13583
13584         if (tginfo->tgdef)
13585         {
13586                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
13587         }
13588         else
13589         {
13590                 if (tginfo->tgisconstraint)
13591                 {
13592                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
13593                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
13594                 }
13595                 else
13596                 {
13597                         appendPQExpBuffer(query, "CREATE TRIGGER ");
13598                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
13599                 }
13600                 appendPQExpBuffer(query, "\n    ");
13601
13602                 /* Trigger type */
13603                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
13604                         appendPQExpBuffer(query, "BEFORE");
13605                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
13606                         appendPQExpBuffer(query, "AFTER");
13607                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
13608                         appendPQExpBuffer(query, "INSTEAD OF");
13609                 else
13610                 {
13611                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
13612                         exit_nicely(1);
13613                 }
13614
13615                 findx = 0;
13616                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
13617                 {
13618                         appendPQExpBuffer(query, " INSERT");
13619                         findx++;
13620                 }
13621                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
13622                 {
13623                         if (findx > 0)
13624                                 appendPQExpBuffer(query, " OR DELETE");
13625                         else
13626                                 appendPQExpBuffer(query, " DELETE");
13627                         findx++;
13628                 }
13629                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
13630                 {
13631                         if (findx > 0)
13632                                 appendPQExpBuffer(query, " OR UPDATE");
13633                         else
13634                                 appendPQExpBuffer(query, " UPDATE");
13635                         findx++;
13636                 }
13637                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
13638                 {
13639                         if (findx > 0)
13640                                 appendPQExpBuffer(query, " OR TRUNCATE");
13641                         else
13642                                 appendPQExpBuffer(query, " TRUNCATE");
13643                         findx++;
13644                 }
13645                 appendPQExpBuffer(query, " ON %s\n",
13646                                                   fmtId(tbinfo->dobj.name));
13647
13648                 if (tginfo->tgisconstraint)
13649                 {
13650                         if (OidIsValid(tginfo->tgconstrrelid))
13651                         {
13652                                 /* If we are using regclass, name is already quoted */
13653                                 if (fout->remoteVersion >= 70300)
13654                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13655                                                                           tginfo->tgconstrrelname);
13656                                 else
13657                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13658                                                                           fmtId(tginfo->tgconstrrelname));
13659                         }
13660                         if (!tginfo->tgdeferrable)
13661                                 appendPQExpBuffer(query, "NOT ");
13662                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
13663                         if (tginfo->tginitdeferred)
13664                                 appendPQExpBuffer(query, "DEFERRED\n");
13665                         else
13666                                 appendPQExpBuffer(query, "IMMEDIATE\n");
13667                 }
13668
13669                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
13670                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
13671                 else
13672                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
13673
13674                 /* In 7.3, result of regproc is already quoted */
13675                 if (fout->remoteVersion >= 70300)
13676                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13677                                                           tginfo->tgfname);
13678                 else
13679                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13680                                                           fmtId(tginfo->tgfname));
13681
13682                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
13683                                                                                   &lentgargs);
13684                 p = tgargs;
13685                 for (findx = 0; findx < tginfo->tgnargs; findx++)
13686                 {
13687                         /* find the embedded null that terminates this trigger argument */
13688                         size_t          tlen = strlen(p);
13689
13690                         if (p + tlen >= tgargs + lentgargs)
13691                         {
13692                                 /* hm, not found before end of bytea value... */
13693                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
13694                                                   tginfo->tgargs,
13695                                                   tginfo->dobj.name,
13696                                                   tbinfo->dobj.name);
13697                                 exit_nicely(1);
13698                         }
13699
13700                         if (findx > 0)
13701                                 appendPQExpBuffer(query, ", ");
13702                         appendStringLiteralAH(query, p, fout);
13703                         p += tlen + 1;
13704                 }
13705                 free(tgargs);
13706                 appendPQExpBuffer(query, ");\n");
13707         }
13708
13709         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
13710         {
13711                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
13712                                                   fmtId(tbinfo->dobj.name));
13713                 switch (tginfo->tgenabled)
13714                 {
13715                         case 'D':
13716                         case 'f':
13717                                 appendPQExpBuffer(query, "DISABLE");
13718                                 break;
13719                         case 'A':
13720                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
13721                                 break;
13722                         case 'R':
13723                                 appendPQExpBuffer(query, "ENABLE REPLICA");
13724                                 break;
13725                         default:
13726                                 appendPQExpBuffer(query, "ENABLE");
13727                                 break;
13728                 }
13729                 appendPQExpBuffer(query, " TRIGGER %s;\n",
13730                                                   fmtId(tginfo->dobj.name));
13731         }
13732
13733         appendPQExpBuffer(labelq, "TRIGGER %s ",
13734                                           fmtId(tginfo->dobj.name));
13735         appendPQExpBuffer(labelq, "ON %s",
13736                                           fmtId(tbinfo->dobj.name));
13737
13738         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
13739                                  tginfo->dobj.name,
13740                                  tbinfo->dobj.namespace->dobj.name,
13741                                  NULL,
13742                                  tbinfo->rolname, false,
13743                                  "TRIGGER", SECTION_POST_DATA,
13744                                  query->data, delqry->data, NULL,
13745                                  NULL, 0,
13746                                  NULL, NULL);
13747
13748         dumpComment(fout, labelq->data,
13749                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13750                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
13751
13752         destroyPQExpBuffer(query);
13753         destroyPQExpBuffer(delqry);
13754         destroyPQExpBuffer(labelq);
13755 }
13756
13757 static void
13758 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
13759 {
13760         PQExpBuffer query;
13761         PQExpBuffer labelq;
13762
13763         query = createPQExpBuffer();
13764         labelq = createPQExpBuffer();
13765
13766         appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
13767         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
13768         appendPQExpBuffer(query, " ON ");
13769         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
13770         appendPQExpBufferStr(query, " ");
13771
13772         if (strcmp("", evtinfo->evttags) != 0)
13773         {
13774                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
13775                 appendPQExpBufferStr(query, evtinfo->evttags);
13776                 appendPQExpBufferStr(query, ") ");
13777         }
13778
13779         appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
13780         appendPQExpBufferStr(query, evtinfo->evtfname);
13781         appendPQExpBuffer(query, "();\n");
13782
13783         if (evtinfo->evtenabled != 'O')
13784         {
13785                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
13786                                                   fmtId(evtinfo->dobj.name));
13787                 switch (evtinfo->evtenabled)
13788                 {
13789                         case 'D':
13790                                 appendPQExpBuffer(query, "DISABLE");
13791                                 break;
13792                         case 'A':
13793                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
13794                                 break;
13795                         case 'R':
13796                                 appendPQExpBuffer(query, "ENABLE REPLICA");
13797                                 break;
13798                         default:
13799                                 appendPQExpBuffer(query, "ENABLE");
13800                                 break;
13801                 }
13802                 appendPQExpBuffer(query, ";\n");
13803         }
13804         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
13805                                           fmtId(evtinfo->dobj.name));
13806
13807         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
13808                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
13809                                  "EVENT TRIGGER", SECTION_POST_DATA,
13810                                  query->data, "", NULL, NULL, 0, NULL, NULL);
13811
13812         dumpComment(fout, labelq->data,
13813                                 NULL, NULL,
13814                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
13815
13816         destroyPQExpBuffer(query);
13817         destroyPQExpBuffer(labelq);
13818 }
13819
13820 /*
13821  * dumpRule
13822  *              Dump a rule
13823  */
13824 static void
13825 dumpRule(Archive *fout, RuleInfo *rinfo)
13826 {
13827         TableInfo  *tbinfo = rinfo->ruletable;
13828         PQExpBuffer query;
13829         PQExpBuffer cmd;
13830         PQExpBuffer delcmd;
13831         PQExpBuffer labelq;
13832         PGresult   *res;
13833
13834         /* Skip if not to be dumped */
13835         if (!rinfo->dobj.dump || dataOnly)
13836                 return;
13837
13838         /*
13839          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
13840          * we do not want to dump it as a separate object.
13841          */
13842         if (!rinfo->separate)
13843                 return;
13844
13845         /*
13846          * Make sure we are in proper schema.
13847          */
13848         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13849
13850         query = createPQExpBuffer();
13851         cmd = createPQExpBuffer();
13852         delcmd = createPQExpBuffer();
13853         labelq = createPQExpBuffer();
13854
13855         if (fout->remoteVersion >= 70300)
13856         {
13857                 appendPQExpBuffer(query,
13858                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
13859                                                   rinfo->dobj.catId.oid);
13860         }
13861         else
13862         {
13863                 /* Rule name was unique before 7.3 ... */
13864                 appendPQExpBuffer(query,
13865                                                   "SELECT pg_get_ruledef('%s') AS definition",
13866                                                   rinfo->dobj.name);
13867         }
13868
13869         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13870
13871         if (PQntuples(res) != 1)
13872         {
13873                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
13874                                   rinfo->dobj.name, tbinfo->dobj.name);
13875                 exit_nicely(1);
13876         }
13877
13878         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
13879
13880         /*
13881          * Add the command to alter the rules replication firing semantics if it
13882          * differs from the default.
13883          */
13884         if (rinfo->ev_enabled != 'O')
13885         {
13886                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
13887                 switch (rinfo->ev_enabled)
13888                 {
13889                         case 'A':
13890                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
13891                                                                   fmtId(rinfo->dobj.name));
13892                                 break;
13893                         case 'R':
13894                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
13895                                                                   fmtId(rinfo->dobj.name));
13896                                 break;
13897                         case 'D':
13898                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
13899                                                                   fmtId(rinfo->dobj.name));
13900                                 break;
13901                 }
13902         }
13903
13904         /*
13905          * Apply view's reloptions when its ON SELECT rule is separate.
13906          */
13907         if (rinfo->reloptions)
13908         {
13909                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
13910                                                   fmtId(tbinfo->dobj.name),
13911                                                   rinfo->reloptions);
13912         }
13913
13914         /*
13915          * DROP must be fully qualified in case same name appears in pg_catalog
13916          */
13917         appendPQExpBuffer(delcmd, "DROP RULE %s ",
13918                                           fmtId(rinfo->dobj.name));
13919         appendPQExpBuffer(delcmd, "ON %s.",
13920                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13921         appendPQExpBuffer(delcmd, "%s;\n",
13922                                           fmtId(tbinfo->dobj.name));
13923
13924         appendPQExpBuffer(labelq, "RULE %s",
13925                                           fmtId(rinfo->dobj.name));
13926         appendPQExpBuffer(labelq, " ON %s",
13927                                           fmtId(tbinfo->dobj.name));
13928
13929         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
13930                                  rinfo->dobj.name,
13931                                  tbinfo->dobj.namespace->dobj.name,
13932                                  NULL,
13933                                  tbinfo->rolname, false,
13934                                  "RULE", SECTION_POST_DATA,
13935                                  cmd->data, delcmd->data, NULL,
13936                                  NULL, 0,
13937                                  NULL, NULL);
13938
13939         /* Dump rule comments */
13940         dumpComment(fout, labelq->data,
13941                                 tbinfo->dobj.namespace->dobj.name,
13942                                 tbinfo->rolname,
13943                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
13944
13945         PQclear(res);
13946
13947         destroyPQExpBuffer(query);
13948         destroyPQExpBuffer(cmd);
13949         destroyPQExpBuffer(delcmd);
13950         destroyPQExpBuffer(labelq);
13951 }
13952
13953 /*
13954  * getExtensionMembership --- obtain extension membership data
13955  */
13956 void
13957 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
13958                                            int numExtensions)
13959 {
13960         PQExpBuffer query;
13961         PGresult   *res;
13962         int                     ntups,
13963                                 i;
13964         int                     i_classid,
13965                                 i_objid,
13966                                 i_refclassid,
13967                                 i_refobjid;
13968         DumpableObject *dobj,
13969                            *refdobj;
13970
13971         /* Nothing to do if no extensions */
13972         if (numExtensions == 0)
13973                 return;
13974
13975         /* Make sure we are in proper schema */
13976         selectSourceSchema(fout, "pg_catalog");
13977
13978         query = createPQExpBuffer();
13979
13980         /* refclassid constraint is redundant but may speed the search */
13981         appendPQExpBuffer(query, "SELECT "
13982                                           "classid, objid, refclassid, refobjid "
13983                                           "FROM pg_depend "
13984                                           "WHERE refclassid = 'pg_extension'::regclass "
13985                                           "AND deptype = 'e' "
13986                                           "ORDER BY 3,4");
13987
13988         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13989
13990         ntups = PQntuples(res);
13991
13992         i_classid = PQfnumber(res, "classid");
13993         i_objid = PQfnumber(res, "objid");
13994         i_refclassid = PQfnumber(res, "refclassid");
13995         i_refobjid = PQfnumber(res, "refobjid");
13996
13997         /*
13998          * Since we ordered the SELECT by referenced ID, we can expect that
13999          * multiple entries for the same extension will appear together; this
14000          * saves on searches.
14001          */
14002         refdobj = NULL;
14003
14004         for (i = 0; i < ntups; i++)
14005         {
14006                 CatalogId       objId;
14007                 CatalogId       refobjId;
14008
14009                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14010                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14011                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14012                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14013
14014                 if (refdobj == NULL ||
14015                         refdobj->catId.tableoid != refobjId.tableoid ||
14016                         refdobj->catId.oid != refobjId.oid)
14017                         refdobj = findObjectByCatalogId(refobjId);
14018
14019                 /*
14020                  * Failure to find objects mentioned in pg_depend is not unexpected,
14021                  * since for example we don't collect info about TOAST tables.
14022                  */
14023                 if (refdobj == NULL)
14024                 {
14025 #ifdef NOT_USED
14026                         fprintf(stderr, "no referenced object %u %u\n",
14027                                         refobjId.tableoid, refobjId.oid);
14028 #endif
14029                         continue;
14030                 }
14031
14032                 dobj = findObjectByCatalogId(objId);
14033
14034                 if (dobj == NULL)
14035                 {
14036 #ifdef NOT_USED
14037                         fprintf(stderr, "no referencing object %u %u\n",
14038                                         objId.tableoid, objId.oid);
14039 #endif
14040                         continue;
14041                 }
14042
14043                 /* Record dependency so that getDependencies needn't repeat this */
14044                 addObjectDependency(dobj, refdobj->dumpId);
14045
14046                 dobj->ext_member = true;
14047
14048                 /*
14049                  * Normally, mark the member object as not to be dumped.  But in
14050                  * binary upgrades, we still dump the members individually, since the
14051                  * idea is to exactly reproduce the database contents rather than
14052                  * replace the extension contents with something different.
14053                  */
14054                 if (!binary_upgrade)
14055                         dobj->dump = false;
14056                 else
14057                         dobj->dump = refdobj->dump;
14058         }
14059
14060         PQclear(res);
14061
14062         /*
14063          * Now identify extension configuration tables and create TableDataInfo
14064          * objects for them, ensuring their data will be dumped even though the
14065          * tables themselves won't be.
14066          *
14067          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14068          * user data in a configuration table is treated like schema data. This
14069          * seems appropriate since system data in a config table would get
14070          * reloaded by CREATE EXTENSION.
14071          */
14072         for (i = 0; i < numExtensions; i++)
14073         {
14074                 ExtensionInfo *curext = &(extinfo[i]);
14075                 char       *extconfig = curext->extconfig;
14076                 char       *extcondition = curext->extcondition;
14077                 char      **extconfigarray = NULL;
14078                 char      **extconditionarray = NULL;
14079                 int                     nconfigitems;
14080                 int                     nconditionitems;
14081
14082                 /* Tables of not-to-be-dumped extensions shouldn't be dumped */
14083                 if (!curext->dobj.dump)
14084                         continue;
14085
14086                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14087                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14088                         nconfigitems == nconditionitems)
14089                 {
14090                         int                     j;
14091
14092                         for (j = 0; j < nconfigitems; j++)
14093                         {
14094                                 TableInfo  *configtbl;
14095
14096                                 configtbl = findTableByOid(atooid(extconfigarray[j]));
14097                                 if (configtbl == NULL)
14098                                         continue;
14099
14100                                 /*
14101                                  * Note: config tables are dumped without OIDs regardless of
14102                                  * the --oids setting.  This is because row filtering
14103                                  * conditions aren't compatible with dumping OIDs.
14104                                  */
14105                                 makeTableDataInfo(configtbl, false);
14106                                 if (configtbl->dataObj != NULL)
14107                                 {
14108                                         if (strlen(extconditionarray[j]) > 0)
14109                                                 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14110                                 }
14111                         }
14112                 }
14113                 if (extconfigarray)
14114                         free(extconfigarray);
14115                 if (extconditionarray)
14116                         free(extconditionarray);
14117         }
14118
14119         destroyPQExpBuffer(query);
14120 }
14121
14122 /*
14123  * getDependencies --- obtain available dependency data
14124  */
14125 static void
14126 getDependencies(Archive *fout)
14127 {
14128         PQExpBuffer query;
14129         PGresult   *res;
14130         int                     ntups,
14131                                 i;
14132         int                     i_classid,
14133                                 i_objid,
14134                                 i_refclassid,
14135                                 i_refobjid,
14136                                 i_deptype;
14137         DumpableObject *dobj,
14138                            *refdobj;
14139
14140         /* No dependency info available before 7.3 */
14141         if (fout->remoteVersion < 70300)
14142                 return;
14143
14144         if (g_verbose)
14145                 write_msg(NULL, "reading dependency data\n");
14146
14147         /* Make sure we are in proper schema */
14148         selectSourceSchema(fout, "pg_catalog");
14149
14150         query = createPQExpBuffer();
14151
14152         /*
14153          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14154          * already processed by getExtensionMembership.
14155          */
14156         appendPQExpBuffer(query, "SELECT "
14157                                           "classid, objid, refclassid, refobjid, deptype "
14158                                           "FROM pg_depend "
14159                                           "WHERE deptype != 'p' AND deptype != 'e' "
14160                                           "ORDER BY 1,2");
14161
14162         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14163
14164         ntups = PQntuples(res);
14165
14166         i_classid = PQfnumber(res, "classid");
14167         i_objid = PQfnumber(res, "objid");
14168         i_refclassid = PQfnumber(res, "refclassid");
14169         i_refobjid = PQfnumber(res, "refobjid");
14170         i_deptype = PQfnumber(res, "deptype");
14171
14172         /*
14173          * Since we ordered the SELECT by referencing ID, we can expect that
14174          * multiple entries for the same object will appear together; this saves
14175          * on searches.
14176          */
14177         dobj = NULL;
14178
14179         for (i = 0; i < ntups; i++)
14180         {
14181                 CatalogId       objId;
14182                 CatalogId       refobjId;
14183                 char            deptype;
14184
14185                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14186                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14187                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14188                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14189                 deptype = *(PQgetvalue(res, i, i_deptype));
14190
14191                 if (dobj == NULL ||
14192                         dobj->catId.tableoid != objId.tableoid ||
14193                         dobj->catId.oid != objId.oid)
14194                         dobj = findObjectByCatalogId(objId);
14195
14196                 /*
14197                  * Failure to find objects mentioned in pg_depend is not unexpected,
14198                  * since for example we don't collect info about TOAST tables.
14199                  */
14200                 if (dobj == NULL)
14201                 {
14202 #ifdef NOT_USED
14203                         fprintf(stderr, "no referencing object %u %u\n",
14204                                         objId.tableoid, objId.oid);
14205 #endif
14206                         continue;
14207                 }
14208
14209                 refdobj = findObjectByCatalogId(refobjId);
14210
14211                 if (refdobj == NULL)
14212                 {
14213 #ifdef NOT_USED
14214                         fprintf(stderr, "no referenced object %u %u\n",
14215                                         refobjId.tableoid, refobjId.oid);
14216 #endif
14217                         continue;
14218                 }
14219
14220                 /*
14221                  * Ordinarily, table rowtypes have implicit dependencies on their
14222                  * tables.      However, for a composite type the implicit dependency goes
14223                  * the other way in pg_depend; which is the right thing for DROP but
14224                  * it doesn't produce the dependency ordering we need. So in that one
14225                  * case, we reverse the direction of the dependency.
14226                  */
14227                 if (deptype == 'i' &&
14228                         dobj->objType == DO_TABLE &&
14229                         refdobj->objType == DO_TYPE)
14230                         addObjectDependency(refdobj, dobj->dumpId);
14231                 else
14232                         /* normal case */
14233                         addObjectDependency(dobj, refdobj->dumpId);
14234         }
14235
14236         PQclear(res);
14237
14238         destroyPQExpBuffer(query);
14239 }
14240
14241
14242 /*
14243  * createBoundaryObjects - create dummy DumpableObjects to represent
14244  * dump section boundaries.
14245  */
14246 static DumpableObject *
14247 createBoundaryObjects(void)
14248 {
14249         DumpableObject *dobjs;
14250
14251         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
14252
14253         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
14254         dobjs[0].catId = nilCatalogId;
14255         AssignDumpId(dobjs + 0);
14256         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
14257
14258         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
14259         dobjs[1].catId = nilCatalogId;
14260         AssignDumpId(dobjs + 1);
14261         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
14262
14263         return dobjs;
14264 }
14265
14266 /*
14267  * addBoundaryDependencies - add dependencies as needed to enforce the dump
14268  * section boundaries.
14269  */
14270 static void
14271 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
14272                                                 DumpableObject *boundaryObjs)
14273 {
14274         DumpableObject *preDataBound = boundaryObjs + 0;
14275         DumpableObject *postDataBound = boundaryObjs + 1;
14276         int                     i;
14277
14278         for (i = 0; i < numObjs; i++)
14279         {
14280                 DumpableObject *dobj = dobjs[i];
14281
14282                 /*
14283                  * The classification of object types here must match the SECTION_xxx
14284                  * values assigned during subsequent ArchiveEntry calls!
14285                  */
14286                 switch (dobj->objType)
14287                 {
14288                         case DO_NAMESPACE:
14289                         case DO_EXTENSION:
14290                         case DO_TYPE:
14291                         case DO_SHELL_TYPE:
14292                         case DO_FUNC:
14293                         case DO_AGG:
14294                         case DO_OPERATOR:
14295                         case DO_OPCLASS:
14296                         case DO_OPFAMILY:
14297                         case DO_COLLATION:
14298                         case DO_CONVERSION:
14299                         case DO_TABLE:
14300                         case DO_ATTRDEF:
14301                         case DO_PROCLANG:
14302                         case DO_CAST:
14303                         case DO_DUMMY_TYPE:
14304                         case DO_TSPARSER:
14305                         case DO_TSDICT:
14306                         case DO_TSTEMPLATE:
14307                         case DO_TSCONFIG:
14308                         case DO_FDW:
14309                         case DO_FOREIGN_SERVER:
14310                         case DO_BLOB:
14311                                 /* Pre-data objects: must come before the pre-data boundary */
14312                                 addObjectDependency(preDataBound, dobj->dumpId);
14313                                 break;
14314                         case DO_TABLE_DATA:
14315                         case DO_BLOB_DATA:
14316                                 /* Data objects: must come between the boundaries */
14317                                 addObjectDependency(dobj, preDataBound->dumpId);
14318                                 addObjectDependency(postDataBound, dobj->dumpId);
14319                                 break;
14320                         case DO_INDEX:
14321                         case DO_TRIGGER:
14322                         case DO_EVENT_TRIGGER:
14323                         case DO_DEFAULT_ACL:
14324                                 /* Post-data objects: must come after the post-data boundary */
14325                                 addObjectDependency(dobj, postDataBound->dumpId);
14326                                 break;
14327                         case DO_RULE:
14328                                 /* Rules are post-data, but only if dumped separately */
14329                                 if (((RuleInfo *) dobj)->separate)
14330                                         addObjectDependency(dobj, postDataBound->dumpId);
14331                                 break;
14332                         case DO_CONSTRAINT:
14333                         case DO_FK_CONSTRAINT:
14334                                 /* Constraints are post-data, but only if dumped separately */
14335                                 if (((ConstraintInfo *) dobj)->separate)
14336                                         addObjectDependency(dobj, postDataBound->dumpId);
14337                                 break;
14338                         case DO_PRE_DATA_BOUNDARY:
14339                                 /* nothing to do */
14340                                 break;
14341                         case DO_POST_DATA_BOUNDARY:
14342                                 /* must come after the pre-data boundary */
14343                                 addObjectDependency(dobj, preDataBound->dumpId);
14344                                 break;
14345                 }
14346         }
14347 }
14348
14349
14350 /*
14351  * BuildArchiveDependencies - create dependency data for archive TOC entries
14352  *
14353  * The raw dependency data obtained by getDependencies() is not terribly
14354  * useful in an archive dump, because in many cases there are dependency
14355  * chains linking through objects that don't appear explicitly in the dump.
14356  * For example, a view will depend on its _RETURN rule while the _RETURN rule
14357  * will depend on other objects --- but the rule will not appear as a separate
14358  * object in the dump.  We need to adjust the view's dependencies to include
14359  * whatever the rule depends on that is included in the dump.
14360  *
14361  * Just to make things more complicated, there are also "special" dependencies
14362  * such as the dependency of a TABLE DATA item on its TABLE, which we must
14363  * not rearrange because pg_restore knows that TABLE DATA only depends on
14364  * its table.  In these cases we must leave the dependencies strictly as-is
14365  * even if they refer to not-to-be-dumped objects.
14366  *
14367  * To handle this, the convention is that "special" dependencies are created
14368  * during ArchiveEntry calls, and an archive TOC item that has any such
14369  * entries will not be touched here.  Otherwise, we recursively search the
14370  * DumpableObject data structures to build the correct dependencies for each
14371  * archive TOC item.
14372  */
14373 static void
14374 BuildArchiveDependencies(Archive *fout)
14375 {
14376         ArchiveHandle *AH = (ArchiveHandle *) fout;
14377         TocEntry   *te;
14378
14379         /* Scan all TOC entries in the archive */
14380         for (te = AH->toc->next; te != AH->toc; te = te->next)
14381         {
14382                 DumpableObject *dobj;
14383                 DumpId     *dependencies;
14384                 int                     nDeps;
14385                 int                     allocDeps;
14386
14387                 /* No need to process entries that will not be dumped */
14388                 if (te->reqs == 0)
14389                         continue;
14390                 /* Ignore entries that already have "special" dependencies */
14391                 if (te->nDeps > 0)
14392                         continue;
14393                 /* Otherwise, look up the item's original DumpableObject, if any */
14394                 dobj = findObjectByDumpId(te->dumpId);
14395                 if (dobj == NULL)
14396                         continue;
14397                 /* No work if it has no dependencies */
14398                 if (dobj->nDeps <= 0)
14399                         continue;
14400                 /* Set up work array */
14401                 allocDeps = 64;
14402                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
14403                 nDeps = 0;
14404                 /* Recursively find all dumpable dependencies */
14405                 findDumpableDependencies(AH, dobj,
14406                                                                  &dependencies, &nDeps, &allocDeps);
14407                 /* And save 'em ... */
14408                 if (nDeps > 0)
14409                 {
14410                         dependencies = (DumpId *) pg_realloc(dependencies,
14411                                                                                                  nDeps * sizeof(DumpId));
14412                         te->dependencies = dependencies;
14413                         te->nDeps = nDeps;
14414                 }
14415                 else
14416                         free(dependencies);
14417         }
14418 }
14419
14420 /* Recursive search subroutine for BuildArchiveDependencies */
14421 static void
14422 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
14423                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
14424 {
14425         int                     i;
14426
14427         /*
14428          * Ignore section boundary objects: if we search through them, we'll
14429          * report lots of bogus dependencies.
14430          */
14431         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
14432                 dobj->objType == DO_POST_DATA_BOUNDARY)
14433                 return;
14434
14435         for (i = 0; i < dobj->nDeps; i++)
14436         {
14437                 DumpId          depid = dobj->dependencies[i];
14438
14439                 if (TocIDRequired(AH, depid) != 0)
14440                 {
14441                         /* Object will be dumped, so just reference it as a dependency */
14442                         if (*nDeps >= *allocDeps)
14443                         {
14444                                 *allocDeps *= 2;
14445                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
14446                                                                                           *allocDeps * sizeof(DumpId));
14447                         }
14448                         (*dependencies)[*nDeps] = depid;
14449                         (*nDeps)++;
14450                 }
14451                 else
14452                 {
14453                         /*
14454                          * Object will not be dumped, so recursively consider its deps.
14455                          * We rely on the assumption that sortDumpableObjects already
14456                          * broke any dependency loops, else we might recurse infinitely.
14457                          */
14458                         DumpableObject *otherdobj = findObjectByDumpId(depid);
14459
14460                         if (otherdobj)
14461                                 findDumpableDependencies(AH, otherdobj,
14462                                                                                  dependencies, nDeps, allocDeps);
14463                 }
14464         }
14465 }
14466
14467
14468 /*
14469  * selectSourceSchema - make the specified schema the active search path
14470  * in the source database.
14471  *
14472  * NB: pg_catalog is explicitly searched after the specified schema;
14473  * so user names are only qualified if they are cross-schema references,
14474  * and system names are only qualified if they conflict with a user name
14475  * in the current schema.
14476  *
14477  * Whenever the selected schema is not pg_catalog, be careful to qualify
14478  * references to system catalogs and types in our emitted commands!
14479  */
14480 static void
14481 selectSourceSchema(Archive *fout, const char *schemaName)
14482 {
14483         static char *curSchemaName = NULL;
14484         PQExpBuffer query;
14485
14486         /* Not relevant if fetching from pre-7.3 DB */
14487         if (fout->remoteVersion < 70300)
14488                 return;
14489         /* Ignore null schema names */
14490         if (schemaName == NULL || *schemaName == '\0')
14491                 return;
14492         /* Optimize away repeated selection of same schema */
14493         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
14494                 return;
14495
14496         query = createPQExpBuffer();
14497         appendPQExpBuffer(query, "SET search_path = %s",
14498                                           fmtId(schemaName));
14499         if (strcmp(schemaName, "pg_catalog") != 0)
14500                 appendPQExpBuffer(query, ", pg_catalog");
14501
14502         ExecuteSqlStatement(fout, query->data);
14503
14504         destroyPQExpBuffer(query);
14505         if (curSchemaName)
14506                 free(curSchemaName);
14507         curSchemaName = pg_strdup(schemaName);
14508 }
14509
14510 /*
14511  * getFormattedTypeName - retrieve a nicely-formatted type name for the
14512  * given type name.
14513  *
14514  * NB: in 7.3 and up the result may depend on the currently-selected
14515  * schema; this is why we don't try to cache the names.
14516  */
14517 static char *
14518 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
14519 {
14520         char       *result;
14521         PQExpBuffer query;
14522         PGresult   *res;
14523
14524         if (oid == 0)
14525         {
14526                 if ((opts & zeroAsOpaque) != 0)
14527                         return pg_strdup(g_opaque_type);
14528                 else if ((opts & zeroAsAny) != 0)
14529                         return pg_strdup("'any'");
14530                 else if ((opts & zeroAsStar) != 0)
14531                         return pg_strdup("*");
14532                 else if ((opts & zeroAsNone) != 0)
14533                         return pg_strdup("NONE");
14534         }
14535
14536         query = createPQExpBuffer();
14537         if (fout->remoteVersion >= 70300)
14538         {
14539                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
14540                                                   oid);
14541         }
14542         else if (fout->remoteVersion >= 70100)
14543         {
14544                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
14545                                                   oid);
14546         }
14547         else
14548         {
14549                 appendPQExpBuffer(query, "SELECT typname "
14550                                                   "FROM pg_type "
14551                                                   "WHERE oid = '%u'::oid",
14552                                                   oid);
14553         }
14554
14555         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14556
14557         if (fout->remoteVersion >= 70100)
14558         {
14559                 /* already quoted */
14560                 result = pg_strdup(PQgetvalue(res, 0, 0));
14561         }
14562         else
14563         {
14564                 /* may need to quote it */
14565                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
14566         }
14567
14568         PQclear(res);
14569         destroyPQExpBuffer(query);
14570
14571         return result;
14572 }
14573
14574 /*
14575  * myFormatType --- local implementation of format_type for use with 7.0.
14576  */
14577 static char *
14578 myFormatType(const char *typname, int32 typmod)
14579 {
14580         char       *result;
14581         bool            isarray = false;
14582         PQExpBuffer buf = createPQExpBuffer();
14583
14584         /* Handle array types */
14585         if (typname[0] == '_')
14586         {
14587                 isarray = true;
14588                 typname++;
14589         }
14590
14591         /* Show lengths on bpchar and varchar */
14592         if (strcmp(typname, "bpchar") == 0)
14593         {
14594                 int                     len = (typmod - VARHDRSZ);
14595
14596                 appendPQExpBuffer(buf, "character");
14597                 if (len > 1)
14598                         appendPQExpBuffer(buf, "(%d)",
14599                                                           typmod - VARHDRSZ);
14600         }
14601         else if (strcmp(typname, "varchar") == 0)
14602         {
14603                 appendPQExpBuffer(buf, "character varying");
14604                 if (typmod != -1)
14605                         appendPQExpBuffer(buf, "(%d)",
14606                                                           typmod - VARHDRSZ);
14607         }
14608         else if (strcmp(typname, "numeric") == 0)
14609         {
14610                 appendPQExpBuffer(buf, "numeric");
14611                 if (typmod != -1)
14612                 {
14613                         int32           tmp_typmod;
14614                         int                     precision;
14615                         int                     scale;
14616
14617                         tmp_typmod = typmod - VARHDRSZ;
14618                         precision = (tmp_typmod >> 16) & 0xffff;
14619                         scale = tmp_typmod & 0xffff;
14620                         appendPQExpBuffer(buf, "(%d,%d)",
14621                                                           precision, scale);
14622                 }
14623         }
14624
14625         /*
14626          * char is an internal single-byte data type; Let's make sure we force it
14627          * through with quotes. - thomas 1998-12-13
14628          */
14629         else if (strcmp(typname, "char") == 0)
14630                 appendPQExpBuffer(buf, "\"char\"");
14631         else
14632                 appendPQExpBuffer(buf, "%s", fmtId(typname));
14633
14634         /* Append array qualifier for array types */
14635         if (isarray)
14636                 appendPQExpBuffer(buf, "[]");
14637
14638         result = pg_strdup(buf->data);
14639         destroyPQExpBuffer(buf);
14640
14641         return result;
14642 }
14643
14644 /*
14645  * fmtQualifiedId - convert a qualified name to the proper format for
14646  * the source database.
14647  *
14648  * Like fmtId, use the result before calling again.
14649  */
14650 static const char *
14651 fmtQualifiedId(Archive *fout, const char *schema, const char *id)
14652 {
14653         static PQExpBuffer id_return = NULL;
14654
14655         if (id_return)                          /* first time through? */
14656                 resetPQExpBuffer(id_return);
14657         else
14658                 id_return = createPQExpBuffer();
14659
14660         /* Suppress schema name if fetching from pre-7.3 DB */
14661         if (fout->remoteVersion >= 70300 && schema && *schema)
14662         {
14663                 appendPQExpBuffer(id_return, "%s.",
14664                                                   fmtId(schema));
14665         }
14666         appendPQExpBuffer(id_return, "%s",
14667                                           fmtId(id));
14668
14669         return id_return->data;
14670 }
14671
14672 /*
14673  * Return a column list clause for the given relation.
14674  *
14675  * Special case: if there are no undropped columns in the relation, return
14676  * "", not an invalid "()" column list.
14677  */
14678 static const char *
14679 fmtCopyColumnList(const TableInfo *ti)
14680 {
14681         static PQExpBuffer q = NULL;
14682         int                     numatts = ti->numatts;
14683         char      **attnames = ti->attnames;
14684         bool       *attisdropped = ti->attisdropped;
14685         bool            needComma;
14686         int                     i;
14687
14688         if (q)                                          /* first time through? */
14689                 resetPQExpBuffer(q);
14690         else
14691                 q = createPQExpBuffer();
14692
14693         appendPQExpBuffer(q, "(");
14694         needComma = false;
14695         for (i = 0; i < numatts; i++)
14696         {
14697                 if (attisdropped[i])
14698                         continue;
14699                 if (needComma)
14700                         appendPQExpBuffer(q, ", ");
14701                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
14702                 needComma = true;
14703         }
14704
14705         if (!needComma)
14706                 return "";                              /* no undropped columns */
14707
14708         appendPQExpBuffer(q, ")");
14709         return q->data;
14710 }
14711
14712 /*
14713  * Execute an SQL query and verify that we got exactly one row back.
14714  */
14715 static PGresult *
14716 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
14717 {
14718         PGresult   *res;
14719         int                     ntups;
14720
14721         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
14722
14723         /* Expecting a single result only */
14724         ntups = PQntuples(res);
14725         if (ntups != 1)
14726                 exit_horribly(NULL,
14727                                           ngettext("query returned %d row instead of one: %s\n",
14728                                                            "query returned %d rows instead of one: %s\n",
14729                                                            ntups),
14730                                           ntups, query);
14731
14732         return res;
14733 }