]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
pg_dump: Dump foreign options in prettier format
[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_largeobject.h"
53 #include "catalog/pg_largeobject_metadata.h"
54 #include "catalog/pg_proc.h"
55 #include "catalog/pg_trigger.h"
56 #include "catalog/pg_type.h"
57 #include "libpq/libpq-fs.h"
58
59 #include "pg_backup_archiver.h"
60 #include "dumpmem.h"
61 #include "dumputils.h"
62
63 extern char *optarg;
64 extern int      optind,
65                         opterr;
66
67
68 typedef struct
69 {
70         const char *descr;                      /* comment for an object */
71         Oid                     classoid;               /* object class (catalog OID) */
72         Oid                     objoid;                 /* object OID */
73         int                     objsubid;               /* subobject (table column #) */
74 } CommentItem;
75
76 typedef struct
77 {
78         const char *provider;           /* label provider of this security label */
79         const char *label;                      /* security label for an object */
80         Oid                     classoid;               /* object class (catalog OID) */
81         Oid                     objoid;                 /* object OID */
82         int                     objsubid;               /* subobject (table column #) */
83 } SecLabelItem;
84
85 /* global decls */
86 bool            g_verbose;                      /* User wants verbose narration of our
87                                                                  * activities. */
88 Archive    *g_fout;                             /* the script file */
89 PGconn     *g_conn;                             /* the database connection */
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 /* these are to avoid passing around info for findNamespace() */
134 static NamespaceInfo *g_namespaces;
135 static int      g_numNamespaces;
136
137 /* flags for various command-line long options */
138 static int      binary_upgrade = 0;
139 static int      disable_dollar_quoting = 0;
140 static int      dump_inserts = 0;
141 static int      column_inserts = 0;
142 static int      no_security_labels = 0;
143 static int      no_unlogged_table_data = 0;
144 static int      serializable_deferrable = 0;
145
146
147 static void help(const char *progname);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(SimpleStringList *patterns,
150                                                         SimpleOidList *oids);
151 static void expand_table_name_patterns(SimpleStringList *patterns,
152                                                    SimpleOidList *oids);
153 static NamespaceInfo *findNamespace(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 dumpTable(Archive *fout, TableInfo *tbinfo);
191 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
192 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
193 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
194 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
195 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
196 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
197 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
198 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
199 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
200 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
201 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
202 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
203 static void dumpUserMappings(Archive *fout,
204                                  const char *servername, const char *namespace,
205                                  const char *owner, CatalogId catalogId, DumpId dumpId);
206 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
207
208 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
209                 const char *type, const char *name, const char *subname,
210                 const char *tag, const char *nspname, const char *owner,
211                 const char *acls);
212
213 static void getDependencies(void);
214 static void getDomainConstraints(TypeInfo *tyinfo);
215 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
216 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
217 static void getTableDataFKConstraints(void);
218 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
219 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
220                                                           char **allargtypes,
221                                                           char **argmodes,
222                                                           char **argnames);
223 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
224 static const char *convertRegProcReference(const char *proc);
225 static const char *convertOperatorReference(const char *opr);
226 static const char *convertTSFunction(Oid funcOid);
227 static Oid      findLastBuiltinOid_V71(const char *);
228 static Oid      findLastBuiltinOid_V70(void);
229 static void selectSourceSchema(const char *schemaName);
230 static char *getFormattedTypeName(Oid oid, OidOptions opts);
231 static char *myFormatType(const char *typname, int32 typmod);
232 static const char *fmtQualifiedId(const char *schema, const char *id);
233 static void getBlobs(Archive *AH);
234 static void dumpBlob(Archive *AH, BlobInfo *binfo);
235 static int      dumpBlobs(Archive *AH, void *arg);
236 static void dumpDatabase(Archive *AH);
237 static void dumpEncoding(Archive *AH);
238 static void dumpStdStrings(Archive *AH);
239 static void binary_upgrade_set_type_oids_by_type_oid(
240                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
241 static bool binary_upgrade_set_type_oids_by_rel_oid(
242                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
243 static void binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer,
244                                                                  Oid pg_class_oid, bool is_index);
245 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
246                                                                 DumpableObject *dobj,
247                                                                 const char *objlabel);
248 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
249 static const char *fmtCopyColumnList(const TableInfo *ti);
250 static void do_sql_command(PGconn *conn, const char *query);
251 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
252                                  ExecStatusType expected);
253
254 int
255 main(int argc, char **argv)
256 {
257         int                     c;
258         const char *filename = NULL;
259         const char *format = "p";
260         const char *dbname = NULL;
261         const char *pghost = NULL;
262         const char *pgport = NULL;
263         const char *username = NULL;
264         const char *dumpencoding = NULL;
265         const char *std_strings;
266         bool            oids = false;
267         TableInfo  *tblinfo;
268         int                     numTables;
269         DumpableObject **dobjs;
270         int                     numObjs;
271         int                     i;
272         enum trivalue prompt_password = TRI_DEFAULT;
273         int                     compressLevel = -1;
274         int                     plainText = 0;
275         int                     outputClean = 0;
276         int                     outputCreateDB = 0;
277         bool            outputBlobs = false;
278         int                     outputNoOwner = 0;
279         char       *outputSuperuser = NULL;
280         char       *use_role = NULL;
281         int                     my_version;
282         int                     optindex;
283         RestoreOptions *ropt;
284         ArchiveFormat archiveFormat = archUnknown;
285         ArchiveMode archiveMode;
286
287         static int      disable_triggers = 0;
288         static int      outputNoTablespaces = 0;
289         static int      use_setsessauth = 0;
290
291         static struct option long_options[] = {
292                 {"data-only", no_argument, NULL, 'a'},
293                 {"blobs", no_argument, NULL, 'b'},
294                 {"clean", no_argument, NULL, 'c'},
295                 {"create", no_argument, NULL, 'C'},
296                 {"file", required_argument, NULL, 'f'},
297                 {"format", required_argument, NULL, 'F'},
298                 {"host", required_argument, NULL, 'h'},
299                 {"ignore-version", no_argument, NULL, 'i'},
300                 {"no-reconnect", no_argument, NULL, 'R'},
301                 {"oids", no_argument, NULL, 'o'},
302                 {"no-owner", no_argument, NULL, 'O'},
303                 {"port", required_argument, NULL, 'p'},
304                 {"schema", required_argument, NULL, 'n'},
305                 {"exclude-schema", required_argument, NULL, 'N'},
306                 {"schema-only", no_argument, NULL, 's'},
307                 {"superuser", required_argument, NULL, 'S'},
308                 {"table", required_argument, NULL, 't'},
309                 {"exclude-table", required_argument, NULL, 'T'},
310                 {"no-password", no_argument, NULL, 'w'},
311                 {"password", no_argument, NULL, 'W'},
312                 {"username", required_argument, NULL, 'U'},
313                 {"verbose", no_argument, NULL, 'v'},
314                 {"no-privileges", no_argument, NULL, 'x'},
315                 {"no-acl", no_argument, NULL, 'x'},
316                 {"compress", required_argument, NULL, 'Z'},
317                 {"encoding", required_argument, NULL, 'E'},
318                 {"help", no_argument, NULL, '?'},
319                 {"version", no_argument, NULL, 'V'},
320
321                 /*
322                  * the following options don't have an equivalent short option letter
323                  */
324                 {"attribute-inserts", no_argument, &column_inserts, 1},
325                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
326                 {"column-inserts", no_argument, &column_inserts, 1},
327                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
328                 {"disable-triggers", no_argument, &disable_triggers, 1},
329                 {"exclude-table-data", required_argument, NULL, 4},
330                 {"inserts", no_argument, &dump_inserts, 1},
331                 {"lock-wait-timeout", required_argument, NULL, 2},
332                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
333                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
334                 {"role", required_argument, NULL, 3},
335                 {"section", required_argument, NULL, 5},
336                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
337                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
338                 {"no-security-labels", no_argument, &no_security_labels, 1},
339                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
340
341                 {NULL, 0, NULL, 0}
342         };
343
344         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
345
346         g_verbose = false;
347
348         strcpy(g_comment_start, "-- ");
349         g_comment_end[0] = '\0';
350         strcpy(g_opaque_type, "opaque");
351
352         dataOnly = schemaOnly = false;
353         dumpSections = DUMP_UNSECTIONED;
354         lockWaitTimeout = NULL;
355
356         progname = get_progname(argv[0]);
357
358         /* Set default options based on progname */
359         if (strcmp(progname, "pg_backup") == 0)
360                 format = "c";
361
362         if (argc > 1)
363         {
364                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
365                 {
366                         help(progname);
367                         exit(0);
368                 }
369                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
370                 {
371                         puts("pg_dump (PostgreSQL) " PG_VERSION);
372                         exit(0);
373                 }
374         }
375
376         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
377                                                         long_options, &optindex)) != -1)
378         {
379                 switch (c)
380                 {
381                         case 'a':                       /* Dump data only */
382                                 dataOnly = true;
383                                 break;
384
385                         case 'b':                       /* Dump blobs */
386                                 outputBlobs = true;
387                                 break;
388
389                         case 'c':                       /* clean (i.e., drop) schema prior to create */
390                                 outputClean = 1;
391                                 break;
392
393                         case 'C':                       /* Create DB */
394                                 outputCreateDB = 1;
395                                 break;
396
397                         case 'E':                       /* Dump encoding */
398                                 dumpencoding = optarg;
399                                 break;
400
401                         case 'f':
402                                 filename = optarg;
403                                 break;
404
405                         case 'F':
406                                 format = optarg;
407                                 break;
408
409                         case 'h':                       /* server host */
410                                 pghost = optarg;
411                                 break;
412
413                         case 'i':
414                                 /* ignored, deprecated option */
415                                 break;
416
417                         case 'n':                       /* include schema(s) */
418                                 simple_string_list_append(&schema_include_patterns, optarg);
419                                 include_everything = false;
420                                 break;
421
422                         case 'N':                       /* exclude schema(s) */
423                                 simple_string_list_append(&schema_exclude_patterns, optarg);
424                                 break;
425
426                         case 'o':                       /* Dump oids */
427                                 oids = true;
428                                 break;
429
430                         case 'O':                       /* Don't reconnect to match owner */
431                                 outputNoOwner = 1;
432                                 break;
433
434                         case 'p':                       /* server port */
435                                 pgport = optarg;
436                                 break;
437
438                         case 'R':
439                                 /* no-op, still accepted for backwards compatibility */
440                                 break;
441
442                         case 's':                       /* dump schema only */
443                                 schemaOnly = true;
444                                 break;
445
446                         case 'S':                       /* Username for superuser in plain text output */
447                                 outputSuperuser = pg_strdup(optarg);
448                                 break;
449
450                         case 't':                       /* include table(s) */
451                                 simple_string_list_append(&table_include_patterns, optarg);
452                                 include_everything = false;
453                                 break;
454
455                         case 'T':                       /* exclude table(s) */
456                                 simple_string_list_append(&table_exclude_patterns, optarg);
457                                 break;
458
459                         case 'U':
460                                 username = optarg;
461                                 break;
462
463                         case 'v':                       /* verbose */
464                                 g_verbose = true;
465                                 break;
466
467                         case 'w':
468                                 prompt_password = TRI_NO;
469                                 break;
470
471                         case 'W':
472                                 prompt_password = TRI_YES;
473                                 break;
474
475                         case 'x':                       /* skip ACL dump */
476                                 aclsSkip = true;
477                                 break;
478
479                         case 'Z':                       /* Compression Level */
480                                 compressLevel = atoi(optarg);
481                                 break;
482
483                         case 0:
484                                 /* This covers the long options. */
485                                 break;
486
487                         case 2:                         /* lock-wait-timeout */
488                                 lockWaitTimeout = optarg;
489                                 break;
490
491                         case 3:                         /* SET ROLE */
492                                 use_role = optarg;
493                                 break;
494
495                         case 4:                 /* exclude table(s) data */
496                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
497                                 break;
498
499                         case 5:                         /* section */
500                                 set_section(optarg, &dumpSections);
501                                 break;
502
503                         default:
504                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
505                                 exit(1);
506                 }
507         }
508
509         /* Get database name from command line */
510         if (optind < argc)
511                 dbname = argv[optind++];
512
513         /* Complain if any arguments remain */
514         if (optind < argc)
515         {
516                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
517                                 progname, argv[optind]);
518                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
519                                 progname);
520                 exit(1);
521         }
522
523         /* --column-inserts implies --inserts */
524         if (column_inserts)
525                 dump_inserts = 1;
526
527         if (dataOnly && schemaOnly)
528         {
529                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
530                 exit(1);
531         }
532
533         if ((dataOnly || schemaOnly) && dumpSections != DUMP_UNSECTIONED)
534         {
535                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used with --section\n");
536                 exit(1);
537         }
538
539         if (dataOnly)
540                 dumpSections = DUMP_DATA;
541         else if (schemaOnly)
542                 dumpSections = DUMP_PRE_DATA | DUMP_POST_DATA;
543         else if ( dumpSections != DUMP_UNSECTIONED)
544         {
545                 dataOnly = dumpSections == DUMP_DATA;
546                 schemaOnly = !(dumpSections & DUMP_DATA);
547         }
548
549         if (dataOnly && outputClean)
550         {
551                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
552                 exit(1);
553         }
554
555         if (dump_inserts && oids)
556         {
557                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
558                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
559                 exit(1);
560         }
561
562         /* Identify archive format to emit */
563         archiveFormat = parseArchiveFormat(format, &archiveMode);
564
565         /* archiveFormat specific setup */
566         if (archiveFormat == archNull)
567                 plainText = 1;
568
569         /* Custom and directory formats are compressed by default, others not */
570         if (compressLevel == -1)
571         {
572                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
573                         compressLevel = Z_DEFAULT_COMPRESSION;
574                 else
575                         compressLevel = 0;
576         }
577
578         /* Open the output file */
579         g_fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
580
581         if (g_fout == NULL)
582         {
583                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
584                 exit(1);
585         }
586
587         /* Let the archiver know how noisy to be */
588         g_fout->verbose = g_verbose;
589
590         my_version = parse_version(PG_VERSION);
591         if (my_version < 0)
592         {
593                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
594                 exit(1);
595         }
596
597         /*
598          * We allow the server to be back to 7.0, and up to any minor release of
599          * our own major version.  (See also version check in pg_dumpall.c.)
600          */
601         g_fout->minRemoteVersion = 70000;
602         g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
603
604         /*
605          * Open the database using the Archiver, so it knows about it. Errors mean
606          * death.
607          */
608         g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
609                                                          username, prompt_password);
610
611         /* Set the client encoding if requested */
612         if (dumpencoding)
613         {
614                 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
615                 {
616                         write_msg(NULL, "invalid client encoding \"%s\" specified\n",
617                                           dumpencoding);
618                         exit(1);
619                 }
620         }
621
622         /*
623          * Get the active encoding and the standard_conforming_strings setting, so
624          * we know how to escape strings.
625          */
626         g_fout->encoding = PQclientEncoding(g_conn);
627
628         std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
629         g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
630
631         /* Set the role if requested */
632         if (use_role && g_fout->remoteVersion >= 80100)
633         {
634                 PQExpBuffer query = createPQExpBuffer();
635
636                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
637                 do_sql_command(g_conn, query->data);
638                 destroyPQExpBuffer(query);
639         }
640
641         /* Set the datestyle to ISO to ensure the dump's portability */
642         do_sql_command(g_conn, "SET DATESTYLE = ISO");
643
644         /* Likewise, avoid using sql_standard intervalstyle */
645         if (g_fout->remoteVersion >= 80400)
646                 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
647
648         /*
649          * If supported, set extra_float_digits so that we can dump float data
650          * exactly (given correctly implemented float I/O code, anyway)
651          */
652         if (g_fout->remoteVersion >= 90000)
653                 do_sql_command(g_conn, "SET extra_float_digits TO 3");
654         else if (g_fout->remoteVersion >= 70400)
655                 do_sql_command(g_conn, "SET extra_float_digits TO 2");
656
657         /*
658          * If synchronized scanning is supported, disable it, to prevent
659          * unpredictable changes in row ordering across a dump and reload.
660          */
661         if (g_fout->remoteVersion >= 80300)
662                 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
663
664         /*
665          * Disable timeouts if supported.
666          */
667         if (g_fout->remoteVersion >= 70300)
668                 do_sql_command(g_conn, "SET statement_timeout = 0");
669
670         /*
671          * Quote all identifiers, if requested.
672          */
673         if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
674                 do_sql_command(g_conn, "SET quote_all_identifiers = true");
675
676         /*
677          * Disable security label support if server version < v9.1.x (prevents
678          * access to nonexistent pg_seclabel catalog)
679          */
680         if (g_fout->remoteVersion < 90100)
681                 no_security_labels = 1;
682
683         /*
684          * Start transaction-snapshot mode transaction to dump consistent data.
685          */
686         do_sql_command(g_conn, "BEGIN");
687         if (g_fout->remoteVersion >= 90100)
688         {
689                 if (serializable_deferrable)
690                         do_sql_command(g_conn,
691                                                    "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, "
692                                                    "READ ONLY, DEFERRABLE");
693                 else
694                         do_sql_command(g_conn,
695                                                    "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
696         }
697         else
698                 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
699
700         /* Select the appropriate subquery to convert user IDs to names */
701         if (g_fout->remoteVersion >= 80100)
702                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
703         else if (g_fout->remoteVersion >= 70300)
704                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
705         else
706                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
707
708         /* Find the last built-in OID, if needed */
709         if (g_fout->remoteVersion < 70300)
710         {
711                 if (g_fout->remoteVersion >= 70100)
712                         g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
713                 else
714                         g_last_builtin_oid = findLastBuiltinOid_V70();
715                 if (g_verbose)
716                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
717         }
718
719         /* Expand schema selection patterns into OID lists */
720         if (schema_include_patterns.head != NULL)
721         {
722                 expand_schema_name_patterns(&schema_include_patterns,
723                                                                         &schema_include_oids);
724                 if (schema_include_oids.head == NULL)
725                 {
726                         write_msg(NULL, "No matching schemas were found\n");
727                         exit_nicely();
728                 }
729         }
730         expand_schema_name_patterns(&schema_exclude_patterns,
731                                                                 &schema_exclude_oids);
732         /* non-matching exclusion patterns aren't an error */
733
734         /* Expand table selection patterns into OID lists */
735         if (table_include_patterns.head != NULL)
736         {
737                 expand_table_name_patterns(&table_include_patterns,
738                                                                    &table_include_oids);
739                 if (table_include_oids.head == NULL)
740                 {
741                         write_msg(NULL, "No matching tables were found\n");
742                         exit_nicely();
743                 }
744         }
745         expand_table_name_patterns(&table_exclude_patterns,
746                                                            &table_exclude_oids);
747
748         expand_table_name_patterns(&tabledata_exclude_patterns,
749                                                            &tabledata_exclude_oids);
750
751         /* non-matching exclusion patterns aren't an error */
752
753         /*
754          * Dumping blobs is now default unless we saw an inclusion switch or -s
755          * ... but even if we did see one of these, -b turns it back on.
756          */
757         if (include_everything && !schemaOnly)
758                 outputBlobs = true;
759
760         /*
761          * Now scan the database and create DumpableObject structs for all the
762          * objects we intend to dump.
763          */
764         tblinfo = getSchemaData(&numTables);
765
766         if (g_fout->remoteVersion < 80400)
767                 guessConstraintInheritance(tblinfo, numTables);
768
769         if (!schemaOnly)
770         {
771                 getTableData(tblinfo, numTables, oids);
772                 if (dataOnly)
773                         getTableDataFKConstraints();
774         }
775
776         if (outputBlobs)
777                 getBlobs(g_fout);
778
779         /*
780          * Collect dependency data to assist in ordering the objects.
781          */
782         getDependencies();
783
784         /*
785          * Sort the objects into a safe dump order (no forward references).
786          *
787          * In 7.3 or later, we can rely on dependency information to help us
788          * determine a safe order, so the initial sort is mostly for cosmetic
789          * purposes: we sort by name to ensure that logically identical schemas
790          * will dump identically.  Before 7.3 we don't have dependencies and we
791          * use OID ordering as an (unreliable) guide to creation order.
792          */
793         getDumpableObjects(&dobjs, &numObjs);
794
795         if (g_fout->remoteVersion >= 70300)
796                 sortDumpableObjectsByTypeName(dobjs, numObjs);
797         else
798                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
799
800         sortDumpableObjects(dobjs, numObjs);
801
802         /*
803          * Create archive TOC entries for all the objects to be dumped, in a safe
804          * order.
805          */
806
807         /* First the special ENCODING and STDSTRINGS entries. */
808         dumpEncoding(g_fout);
809         dumpStdStrings(g_fout);
810
811         /* The database item is always next, unless we don't want it at all */
812         if (include_everything && !dataOnly)
813                 dumpDatabase(g_fout);
814
815         /* Now the rearrangeable objects. */
816         for (i = 0; i < numObjs; i++)
817                 dumpDumpableObject(g_fout, dobjs[i]);
818
819         /*
820          * And finally we can do the actual output.
821          */
822         if (plainText)
823         {
824                 ropt = NewRestoreOptions();
825                 ropt->filename = (char *) filename;
826                 ropt->dropSchema = outputClean;
827                 ropt->aclsSkip = aclsSkip;
828                 ropt->superuser = outputSuperuser;
829                 ropt->createDB = outputCreateDB;
830                 ropt->noOwner = outputNoOwner;
831                 ropt->noTablespace = outputNoTablespaces;
832                 ropt->disable_triggers = disable_triggers;
833                 ropt->use_setsessauth = use_setsessauth;
834                 ropt->dataOnly = dataOnly;
835
836                 if (compressLevel == -1)
837                         ropt->compression = 0;
838                 else
839                         ropt->compression = compressLevel;
840
841                 ropt->suppressDumpWarnings = true;              /* We've already shown them */
842
843                 RestoreArchive(g_fout, ropt);
844         }
845
846         CloseArchive(g_fout);
847
848         PQfinish(g_conn);
849
850         exit(0);
851 }
852
853
854 static void
855 help(const char *progname)
856 {
857         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
858         printf(_("Usage:\n"));
859         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
860
861         printf(_("\nGeneral options:\n"));
862         printf(_("  -f, --file=FILENAME         output file or directory name\n"));
863         printf(_("  -F, --format=c|d|t|p        output file format (custom, directory, tar,\n"
864                          "                              plain text (default))\n"));
865         printf(_("  -v, --verbose               verbose mode\n"));
866         printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
867         printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
868         printf(_("  --help                      show this help, then exit\n"));
869         printf(_("  --version                   output version information, then exit\n"));
870
871         printf(_("\nOptions controlling the output content:\n"));
872         printf(_("  -a, --data-only             dump only the data, not the schema\n"));
873         printf(_("  -b, --blobs                 include large objects in dump\n"));
874         printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
875         printf(_("  -C, --create                include commands to create database in dump\n"));
876         printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
877         printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
878         printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
879         printf(_("  -o, --oids                  include OIDs in dump\n"));
880         printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
881                          "                              plain-text format\n"));
882         printf(_("  -s, --schema-only           dump only the schema, no data\n"));
883         printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
884         printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
885         printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
886         printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
887         printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
888         printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
889         printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
890         printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
891         printf(_("  --exclude-table-data=TABLE  do NOT dump data for the named table(s)\n"));
892         printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
893         printf(_("  --no-security-labels        do not dump security label assignments\n"));
894         printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
895         printf(_("  --no-unlogged-table-data    do not dump unlogged table data\n"));
896         printf(_("  --quote-all-identifiers     quote all identifiers, even if not key words\n"));
897         printf(_("  --section=SECTION           dump named section (pre-data, data or post-data)\n"));
898         printf(_("  --serializable-deferrable   wait until the dump can run without anomalies\n"));
899         printf(_("  --use-set-session-authorization\n"
900                          "                              use SET SESSION AUTHORIZATION commands instead of\n"
901         "                              ALTER OWNER commands to set ownership\n"));
902
903         printf(_("\nConnection options:\n"));
904         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
905         printf(_("  -p, --port=PORT          database server port number\n"));
906         printf(_("  -U, --username=NAME      connect as specified database user\n"));
907         printf(_("  -w, --no-password        never prompt for password\n"));
908         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
909         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
910
911         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
912                          "variable value is used.\n\n"));
913         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
914 }
915
916 void
917 exit_nicely(void)
918 {
919         PQfinish(g_conn);
920         if (g_verbose)
921                 write_msg(NULL, "*** aborted because of error\n");
922         exit(1);
923 }
924
925 static ArchiveFormat
926 parseArchiveFormat(const char *format, ArchiveMode *mode)
927 {
928         ArchiveFormat archiveFormat;
929
930         *mode = archModeWrite;
931
932         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
933         {
934                 /* This is used by pg_dumpall, and is not documented */
935                 archiveFormat = archNull;
936                 *mode = archModeAppend;
937         }
938         else if (pg_strcasecmp(format, "c") == 0)
939                 archiveFormat = archCustom;
940         else if (pg_strcasecmp(format, "custom") == 0)
941                 archiveFormat = archCustom;
942         else if (pg_strcasecmp(format, "d") == 0)
943                 archiveFormat = archDirectory;
944         else if (pg_strcasecmp(format, "directory") == 0)
945                 archiveFormat = archDirectory;
946         else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
947
948                 /*
949                  * Dump files into the current directory; for demonstration only, not
950                  * documented.
951                  */
952                 archiveFormat = archFiles;
953         else if (pg_strcasecmp(format, "p") == 0)
954                 archiveFormat = archNull;
955         else if (pg_strcasecmp(format, "plain") == 0)
956                 archiveFormat = archNull;
957         else if (pg_strcasecmp(format, "t") == 0)
958                 archiveFormat = archTar;
959         else if (pg_strcasecmp(format, "tar") == 0)
960                 archiveFormat = archTar;
961         else
962         {
963                 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
964                 exit(1);
965         }
966         return archiveFormat;
967 }
968
969 /*
970  * Find the OIDs of all schemas matching the given list of patterns,
971  * and append them to the given OID list.
972  */
973 static void
974 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
975 {
976         PQExpBuffer query;
977         PGresult   *res;
978         SimpleStringListCell *cell;
979         int                     i;
980
981         if (patterns->head == NULL)
982                 return;                                 /* nothing to do */
983
984         if (g_fout->remoteVersion < 70300)
985         {
986                 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
987                 exit_nicely();
988         }
989
990         query = createPQExpBuffer();
991
992         /*
993          * We use UNION ALL rather than UNION; this might sometimes result in
994          * duplicate entries in the OID list, but we don't care.
995          */
996
997         for (cell = patterns->head; cell; cell = cell->next)
998         {
999                 if (cell != patterns->head)
1000                         appendPQExpBuffer(query, "UNION ALL\n");
1001                 appendPQExpBuffer(query,
1002                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1003                 processSQLNamePattern(g_conn, query, cell->val, false, false,
1004                                                           NULL, "n.nspname", NULL,
1005                                                           NULL);
1006         }
1007
1008         res = PQexec(g_conn, query->data);
1009         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1010
1011         for (i = 0; i < PQntuples(res); i++)
1012         {
1013                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1014         }
1015
1016         PQclear(res);
1017         destroyPQExpBuffer(query);
1018 }
1019
1020 /*
1021  * Find the OIDs of all tables matching the given list of patterns,
1022  * and append them to the given OID list.
1023  */
1024 static void
1025 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
1026 {
1027         PQExpBuffer query;
1028         PGresult   *res;
1029         SimpleStringListCell *cell;
1030         int                     i;
1031
1032         if (patterns->head == NULL)
1033                 return;                                 /* nothing to do */
1034
1035         query = createPQExpBuffer();
1036
1037         /*
1038          * We use UNION ALL rather than UNION; this might sometimes result in
1039          * duplicate entries in the OID list, but we don't care.
1040          */
1041
1042         for (cell = patterns->head; cell; cell = cell->next)
1043         {
1044                 if (cell != patterns->head)
1045                         appendPQExpBuffer(query, "UNION ALL\n");
1046                 appendPQExpBuffer(query,
1047                                                   "SELECT c.oid"
1048                                                   "\nFROM pg_catalog.pg_class c"
1049                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1050                                                   "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
1051                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1052                                                   RELKIND_FOREIGN_TABLE);
1053                 processSQLNamePattern(g_conn, query, cell->val, true, false,
1054                                                           "n.nspname", "c.relname", NULL,
1055                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1056         }
1057
1058         res = PQexec(g_conn, query->data);
1059         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1060
1061         for (i = 0; i < PQntuples(res); i++)
1062         {
1063                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1064         }
1065
1066         PQclear(res);
1067         destroyPQExpBuffer(query);
1068 }
1069
1070 /*
1071  * selectDumpableNamespace: policy-setting subroutine
1072  *              Mark a namespace as to be dumped or not
1073  */
1074 static void
1075 selectDumpableNamespace(NamespaceInfo *nsinfo)
1076 {
1077         /*
1078          * If specific tables are being dumped, do not dump any complete
1079          * namespaces. If specific namespaces are being dumped, dump just those
1080          * namespaces. Otherwise, dump all non-system namespaces.
1081          */
1082         if (table_include_oids.head != NULL)
1083                 nsinfo->dobj.dump = false;
1084         else if (schema_include_oids.head != NULL)
1085                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1086                                                                                                    nsinfo->dobj.catId.oid);
1087         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1088                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1089                 nsinfo->dobj.dump = false;
1090         else
1091                 nsinfo->dobj.dump = true;
1092
1093         /*
1094          * In any case, a namespace can be excluded by an exclusion switch
1095          */
1096         if (nsinfo->dobj.dump &&
1097                 simple_oid_list_member(&schema_exclude_oids,
1098                                                            nsinfo->dobj.catId.oid))
1099                 nsinfo->dobj.dump = false;
1100 }
1101
1102 /*
1103  * selectDumpableTable: policy-setting subroutine
1104  *              Mark a table as to be dumped or not
1105  */
1106 static void
1107 selectDumpableTable(TableInfo *tbinfo)
1108 {
1109         /*
1110          * If specific tables are being dumped, dump just those tables; else, dump
1111          * according to the parent namespace's dump flag.
1112          */
1113         if (table_include_oids.head != NULL)
1114                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1115                                                                                                    tbinfo->dobj.catId.oid);
1116         else
1117                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1118
1119         /*
1120          * In any case, a table can be excluded by an exclusion switch
1121          */
1122         if (tbinfo->dobj.dump &&
1123                 simple_oid_list_member(&table_exclude_oids,
1124                                                            tbinfo->dobj.catId.oid))
1125                 tbinfo->dobj.dump = false;
1126
1127         /* If table is to be dumped, check that the data is not excluded */
1128         if (tbinfo->dobj.dump && !
1129                 simple_oid_list_member(&tabledata_exclude_oids,
1130                                                            tbinfo->dobj.catId.oid))
1131                 tbinfo->dobj.dumpdata = true;
1132         else
1133                 tbinfo->dobj.dumpdata = false;
1134
1135 }
1136
1137 /*
1138  * selectDumpableType: policy-setting subroutine
1139  *              Mark a type as to be dumped or not
1140  *
1141  * If it's a table's rowtype or an autogenerated array type, we also apply a
1142  * special type code to facilitate sorting into the desired order.      (We don't
1143  * want to consider those to be ordinary types because that would bring tables
1144  * up into the datatype part of the dump order.)  We still set the object's
1145  * dump flag; that's not going to cause the dummy type to be dumped, but we
1146  * need it so that casts involving such types will be dumped correctly -- see
1147  * dumpCast.  This means the flag should be set the same as for the underlying
1148  * object (the table or base type).
1149  */
1150 static void
1151 selectDumpableType(TypeInfo *tyinfo)
1152 {
1153         /* skip complex types, except for standalone composite types */
1154         if (OidIsValid(tyinfo->typrelid) &&
1155                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1156         {
1157                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1158
1159                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1160                 if (tytable != NULL)
1161                         tyinfo->dobj.dump = tytable->dobj.dump;
1162                 else
1163                         tyinfo->dobj.dump = false;
1164                 return;
1165         }
1166
1167         /* skip auto-generated array types */
1168         if (tyinfo->isArray)
1169         {
1170                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1171                 /*
1172                  * Fall through to set the dump flag; we assume that the subsequent
1173                  * rules will do the same thing as they would for the array's base
1174                  * type.  (We cannot reliably look up the base type here, since
1175                  * getTypes may not have processed it yet.)
1176                  */
1177         }
1178
1179         /* dump only types in dumpable namespaces */
1180         if (!tyinfo->dobj.namespace->dobj.dump)
1181                 tyinfo->dobj.dump = false;
1182
1183         /* skip undefined placeholder types */
1184         else if (!tyinfo->isDefined)
1185                 tyinfo->dobj.dump = false;
1186
1187         else
1188                 tyinfo->dobj.dump = true;
1189 }
1190
1191 /*
1192  * selectDumpableDefaultACL: policy-setting subroutine
1193  *              Mark a default ACL as to be dumped or not
1194  *
1195  * For per-schema default ACLs, dump if the schema is to be dumped.
1196  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1197  * and aclsSkip are checked separately.
1198  */
1199 static void
1200 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1201 {
1202         if (dinfo->dobj.namespace)
1203                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1204         else
1205                 dinfo->dobj.dump = include_everything;
1206 }
1207
1208 /*
1209  * selectDumpableExtension: policy-setting subroutine
1210  *              Mark an extension as to be dumped or not
1211  *
1212  * Normally, we dump all extensions, or none of them if include_everything
1213  * is false (i.e., a --schema or --table switch was given).  However, in
1214  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1215  * assume those will already be installed in the target database.  We identify
1216  * such extensions by their having OIDs in the range reserved for initdb.
1217  */
1218 static void
1219 selectDumpableExtension(ExtensionInfo *extinfo)
1220 {
1221         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1222                 extinfo->dobj.dump = false;
1223         else
1224                 extinfo->dobj.dump = include_everything;
1225 }
1226
1227 /*
1228  * selectDumpableObject: policy-setting subroutine
1229  *              Mark a generic dumpable object as to be dumped or not
1230  *
1231  * Use this only for object types without a special-case routine above.
1232  */
1233 static void
1234 selectDumpableObject(DumpableObject *dobj)
1235 {
1236         /*
1237          * Default policy is to dump if parent namespace is dumpable, or always
1238          * for non-namespace-associated items.
1239          */
1240         if (dobj->namespace)
1241                 dobj->dump = dobj->namespace->dobj.dump;
1242         else
1243                 dobj->dump = true;
1244 }
1245
1246 /*
1247  *      Dump a table's contents for loading using the COPY command
1248  *      - this routine is called by the Archiver when it wants the table
1249  *        to be dumped.
1250  */
1251
1252 static int
1253 dumpTableData_copy(Archive *fout, void *dcontext)
1254 {
1255         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1256         TableInfo  *tbinfo = tdinfo->tdtable;
1257         const char *classname = tbinfo->dobj.name;
1258         const bool      hasoids = tbinfo->hasoids;
1259         const bool      oids = tdinfo->oids;
1260         PQExpBuffer q = createPQExpBuffer();
1261         PGresult   *res;
1262         int                     ret;
1263         char       *copybuf;
1264         const char *column_list;
1265
1266         if (g_verbose)
1267                 write_msg(NULL, "dumping contents of table %s\n", classname);
1268
1269         /*
1270          * Make sure we are in proper schema.  We will qualify the table name
1271          * below anyway (in case its name conflicts with a pg_catalog table); but
1272          * this ensures reproducible results in case the table contains regproc,
1273          * regclass, etc columns.
1274          */
1275         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1276
1277         /*
1278          * If possible, specify the column list explicitly so that we have no
1279          * possibility of retrieving data in the wrong column order.  (The default
1280          * column ordering of COPY will not be what we want in certain corner
1281          * cases involving ADD COLUMN and inheritance.)
1282          */
1283         if (g_fout->remoteVersion >= 70300)
1284                 column_list = fmtCopyColumnList(tbinfo);
1285         else
1286                 column_list = "";               /* can't select columns in COPY */
1287
1288         if (oids && hasoids)
1289         {
1290                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1291                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1292                                                                                  classname),
1293                                                   column_list);
1294         }
1295         else if (tdinfo->filtercond)
1296         {
1297                 /* Note: this syntax is only supported in 8.2 and up */
1298                 appendPQExpBufferStr(q, "COPY (SELECT ");
1299                 /* klugery to get rid of parens in column list */
1300                 if (strlen(column_list) > 2)
1301                 {
1302                         appendPQExpBufferStr(q, column_list + 1);
1303                         q->data[q->len - 1] = ' ';
1304                 }
1305                 else
1306                         appendPQExpBufferStr(q, "* ");
1307                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1308                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1309                                                                                  classname),
1310                                                   tdinfo->filtercond);
1311         }
1312         else
1313         {
1314                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1315                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1316                                                                                  classname),
1317                                                   column_list);
1318         }
1319         res = PQexec(g_conn, q->data);
1320         check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1321         PQclear(res);
1322
1323         for (;;)
1324         {
1325                 ret = PQgetCopyData(g_conn, &copybuf, 0);
1326
1327                 if (ret < 0)
1328                         break;                          /* done or error */
1329
1330                 if (copybuf)
1331                 {
1332                         WriteData(fout, copybuf, ret);
1333                         PQfreemem(copybuf);
1334                 }
1335
1336                 /* ----------
1337                  * THROTTLE:
1338                  *
1339                  * There was considerable discussion in late July, 2000 regarding
1340                  * slowing down pg_dump when backing up large tables. Users with both
1341                  * slow & fast (multi-processor) machines experienced performance
1342                  * degradation when doing a backup.
1343                  *
1344                  * Initial attempts based on sleeping for a number of ms for each ms
1345                  * of work were deemed too complex, then a simple 'sleep in each loop'
1346                  * implementation was suggested. The latter failed because the loop
1347                  * was too tight. Finally, the following was implemented:
1348                  *
1349                  * If throttle is non-zero, then
1350                  *              See how long since the last sleep.
1351                  *              Work out how long to sleep (based on ratio).
1352                  *              If sleep is more than 100ms, then
1353                  *                      sleep
1354                  *                      reset timer
1355                  *              EndIf
1356                  * EndIf
1357                  *
1358                  * where the throttle value was the number of ms to sleep per ms of
1359                  * work. The calculation was done in each loop.
1360                  *
1361                  * Most of the hard work is done in the backend, and this solution
1362                  * still did not work particularly well: on slow machines, the ratio
1363                  * was 50:1, and on medium paced machines, 1:1, and on fast
1364                  * multi-processor machines, it had little or no effect, for reasons
1365                  * that were unclear.
1366                  *
1367                  * Further discussion ensued, and the proposal was dropped.
1368                  *
1369                  * For those people who want this feature, it can be implemented using
1370                  * gettimeofday in each loop, calculating the time since last sleep,
1371                  * multiplying that by the sleep ratio, then if the result is more
1372                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1373                  * function to sleep for a subsecond period ie.
1374                  *
1375                  * select(0, NULL, NULL, NULL, &tvi);
1376                  *
1377                  * This will return after the interval specified in the structure tvi.
1378                  * Finally, call gettimeofday again to save the 'last sleep time'.
1379                  * ----------
1380                  */
1381         }
1382         archprintf(fout, "\\.\n\n\n");
1383
1384         if (ret == -2)
1385         {
1386                 /* copy data transfer failed */
1387                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1388                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1389                 write_msg(NULL, "The command was: %s\n", q->data);
1390                 exit_nicely();
1391         }
1392
1393         /* Check command status and return to normal libpq state */
1394         res = PQgetResult(g_conn);
1395         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1396         PQclear(res);
1397
1398         destroyPQExpBuffer(q);
1399         return 1;
1400 }
1401
1402 static int
1403 dumpTableData_insert(Archive *fout, void *dcontext)
1404 {
1405         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1406         TableInfo  *tbinfo = tdinfo->tdtable;
1407         const char *classname = tbinfo->dobj.name;
1408         PQExpBuffer q = createPQExpBuffer();
1409         PGresult   *res;
1410         int                     tuple;
1411         int                     nfields;
1412         int                     field;
1413
1414         /*
1415          * Make sure we are in proper schema.  We will qualify the table name
1416          * below anyway (in case its name conflicts with a pg_catalog table); but
1417          * this ensures reproducible results in case the table contains regproc,
1418          * regclass, etc columns.
1419          */
1420         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1421
1422         if (fout->remoteVersion >= 70100)
1423         {
1424                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1425                                                   "SELECT * FROM ONLY %s",
1426                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1427                                                                                  classname));
1428         }
1429         else
1430         {
1431                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1432                                                   "SELECT * FROM %s",
1433                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1434                                                                                  classname));
1435         }
1436         if (tdinfo->filtercond)
1437                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1438
1439         res = PQexec(g_conn, q->data);
1440         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1441
1442         do
1443         {
1444                 PQclear(res);
1445
1446                 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1447                 check_sql_result(res, g_conn, "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         } while (PQntuples(res) > 0);
1540
1541         PQclear(res);
1542
1543         archprintf(fout, "\n\n");
1544
1545         do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1546
1547         destroyPQExpBuffer(q);
1548         return 1;
1549 }
1550
1551
1552 /*
1553  * dumpTableData -
1554  *        dump the contents of a single table
1555  *
1556  * Actually, this just makes an ArchiveEntry for the table contents.
1557  */
1558 static void
1559 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1560 {
1561         TableInfo  *tbinfo = tdinfo->tdtable;
1562         PQExpBuffer copyBuf = createPQExpBuffer();
1563         DataDumperPtr dumpFn;
1564         char       *copyStmt;
1565
1566         /* don't do anything if the data isn't wanted */
1567         if (!tbinfo->dobj.dumpdata)
1568                 return;
1569
1570         if (!dump_inserts)
1571         {
1572                 /* Dump/restore using COPY */
1573                 dumpFn = dumpTableData_copy;
1574                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1575                 appendPQExpBuffer(copyBuf, "COPY %s ",
1576                                                   fmtId(tbinfo->dobj.name));
1577                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1578                                                   fmtCopyColumnList(tbinfo),
1579                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1580                 copyStmt = copyBuf->data;
1581         }
1582         else
1583         {
1584                 /* Restore using INSERT */
1585                 dumpFn = dumpTableData_insert;
1586                 copyStmt = NULL;
1587         }
1588
1589         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1590                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1591                                  NULL, tbinfo->rolname,
1592                                  false, "TABLE DATA", SECTION_DATA,
1593                                  "", "", copyStmt,
1594                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1595                                  dumpFn, tdinfo);
1596
1597         destroyPQExpBuffer(copyBuf);
1598 }
1599
1600 /*
1601  * getTableData -
1602  *        set up dumpable objects representing the contents of tables
1603  */
1604 static void
1605 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1606 {
1607         int                     i;
1608
1609         for (i = 0; i < numTables; i++)
1610         {
1611                 /* Skip VIEWs (no data to dump) */
1612                 if (tblinfo[i].relkind == RELKIND_VIEW)
1613                         continue;
1614                 /* Skip SEQUENCEs (handled elsewhere) */
1615                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1616                         continue;
1617                 /* Skip FOREIGN TABLEs (no data to dump) */
1618                 if (tblinfo[i].relkind == RELKIND_FOREIGN_TABLE)
1619                         continue;
1620                 /* Skip unlogged tables if so requested */
1621                 if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED
1622                         && no_unlogged_table_data)
1623                         continue;
1624
1625                 if (tblinfo[i].dobj.dump && tblinfo[i].dataObj == NULL)
1626                         makeTableDataInfo(&(tblinfo[i]), oids);
1627         }
1628 }
1629
1630 /*
1631  * Make a dumpable object for the data of this specific table
1632  */
1633 static void
1634 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1635 {
1636         TableDataInfo *tdinfo;
1637
1638         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1639
1640         tdinfo->dobj.objType = DO_TABLE_DATA;
1641
1642         /*
1643          * Note: use tableoid 0 so that this object won't be mistaken for
1644          * something that pg_depend entries apply to.
1645          */
1646         tdinfo->dobj.catId.tableoid = 0;
1647         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1648         AssignDumpId(&tdinfo->dobj);
1649         tdinfo->dobj.name = tbinfo->dobj.name;
1650         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1651         tdinfo->tdtable = tbinfo;
1652         tdinfo->oids = oids;
1653         tdinfo->filtercond = NULL;      /* might get set later */
1654         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1655
1656         tbinfo->dataObj = tdinfo;
1657 }
1658
1659 /*
1660  * getTableDataFKConstraints -
1661  *        add dump-order dependencies reflecting foreign key constraints
1662  *
1663  * This code is executed only in a data-only dump --- in schema+data dumps
1664  * we handle foreign key issues by not creating the FK constraints until
1665  * after the data is loaded.  In a data-only dump, however, we want to
1666  * order the table data objects in such a way that a table's referenced
1667  * tables are restored first.  (In the presence of circular references or
1668  * self-references this may be impossible; we'll detect and complain about
1669  * that during the dependency sorting step.)
1670  */
1671 static void
1672 getTableDataFKConstraints(void)
1673 {
1674         DumpableObject **dobjs;
1675         int                     numObjs;
1676         int                     i;
1677
1678         /* Search through all the dumpable objects for FK constraints */
1679         getDumpableObjects(&dobjs, &numObjs);
1680         for (i = 0; i < numObjs; i++)
1681         {
1682                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1683                 {
1684                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1685                         TableInfo  *ftable;
1686
1687                         /* Not interesting unless both tables are to be dumped */
1688                         if (cinfo->contable == NULL ||
1689                                 cinfo->contable->dataObj == NULL)
1690                                 continue;
1691                         ftable = findTableByOid(cinfo->confrelid);
1692                         if (ftable == NULL ||
1693                                 ftable->dataObj == NULL)
1694                                 continue;
1695
1696                         /*
1697                          * Okay, make referencing table's TABLE_DATA object depend on the
1698                          * referenced table's TABLE_DATA object.
1699                          */
1700                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1701                                                                 ftable->dataObj->dobj.dumpId);
1702                 }
1703         }
1704         free(dobjs);
1705 }
1706
1707
1708 /*
1709  * guessConstraintInheritance:
1710  *      In pre-8.4 databases, we can't tell for certain which constraints
1711  *      are inherited.  We assume a CHECK constraint is inherited if its name
1712  *      matches the name of any constraint in the parent.  Originally this code
1713  *      tried to compare the expression texts, but that can fail for various
1714  *      reasons --- for example, if the parent and child tables are in different
1715  *      schemas, reverse-listing of function calls may produce different text
1716  *      (schema-qualified or not) depending on search path.
1717  *
1718  *      In 8.4 and up we can rely on the conislocal field to decide which
1719  *      constraints must be dumped; much safer.
1720  *
1721  *      This function assumes all conislocal flags were initialized to TRUE.
1722  *      It clears the flag on anything that seems to be inherited.
1723  */
1724 static void
1725 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1726 {
1727         int                     i,
1728                                 j,
1729                                 k;
1730
1731         for (i = 0; i < numTables; i++)
1732         {
1733                 TableInfo  *tbinfo = &(tblinfo[i]);
1734                 int                     numParents;
1735                 TableInfo **parents;
1736                 TableInfo  *parent;
1737
1738                 /* Sequences and views never have parents */
1739                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1740                         tbinfo->relkind == RELKIND_VIEW)
1741                         continue;
1742
1743                 /* Don't bother computing anything for non-target tables, either */
1744                 if (!tbinfo->dobj.dump)
1745                         continue;
1746
1747                 numParents = tbinfo->numParents;
1748                 parents = tbinfo->parents;
1749
1750                 if (numParents == 0)
1751                         continue;                       /* nothing to see here, move along */
1752
1753                 /* scan for inherited CHECK constraints */
1754                 for (j = 0; j < tbinfo->ncheck; j++)
1755                 {
1756                         ConstraintInfo *constr;
1757
1758                         constr = &(tbinfo->checkexprs[j]);
1759
1760                         for (k = 0; k < numParents; k++)
1761                         {
1762                                 int                     l;
1763
1764                                 parent = parents[k];
1765                                 for (l = 0; l < parent->ncheck; l++)
1766                                 {
1767                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1768
1769                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1770                                         {
1771                                                 constr->conislocal = false;
1772                                                 break;
1773                                         }
1774                                 }
1775                                 if (!constr->conislocal)
1776                                         break;
1777                         }
1778                 }
1779         }
1780 }
1781
1782
1783 /*
1784  * dumpDatabase:
1785  *      dump the database definition
1786  */
1787 static void
1788 dumpDatabase(Archive *AH)
1789 {
1790         PQExpBuffer dbQry = createPQExpBuffer();
1791         PQExpBuffer delQry = createPQExpBuffer();
1792         PQExpBuffer creaQry = createPQExpBuffer();
1793         PGresult   *res;
1794         int                     ntups;
1795         int                     i_tableoid,
1796                                 i_oid,
1797                                 i_dba,
1798                                 i_encoding,
1799                                 i_collate,
1800                                 i_ctype,
1801                                 i_frozenxid,
1802                                 i_tablespace;
1803         CatalogId       dbCatId;
1804         DumpId          dbDumpId;
1805         const char *datname,
1806                            *dba,
1807                            *encoding,
1808                            *collate,
1809                            *ctype,
1810                            *tablespace;
1811         uint32          frozenxid;
1812
1813         datname = PQdb(g_conn);
1814
1815         if (g_verbose)
1816                 write_msg(NULL, "saving database definition\n");
1817
1818         /* Make sure we are in proper schema */
1819         selectSourceSchema("pg_catalog");
1820
1821         /* Get the database owner and parameters from pg_database */
1822         if (g_fout->remoteVersion >= 80400)
1823         {
1824                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1825                                                   "(%s datdba) AS dba, "
1826                                                   "pg_encoding_to_char(encoding) AS encoding, "
1827                                                   "datcollate, datctype, datfrozenxid, "
1828                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1829                                           "shobj_description(oid, 'pg_database') AS description "
1830
1831                                                   "FROM pg_database "
1832                                                   "WHERE datname = ",
1833                                                   username_subquery);
1834                 appendStringLiteralAH(dbQry, datname, AH);
1835         }
1836         else if (g_fout->remoteVersion >= 80200)
1837         {
1838                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1839                                                   "(%s datdba) AS dba, "
1840                                                   "pg_encoding_to_char(encoding) AS encoding, "
1841                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1842                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1843                                           "shobj_description(oid, 'pg_database') AS description "
1844
1845                                                   "FROM pg_database "
1846                                                   "WHERE datname = ",
1847                                                   username_subquery);
1848                 appendStringLiteralAH(dbQry, datname, AH);
1849         }
1850         else if (g_fout->remoteVersion >= 80000)
1851         {
1852                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1853                                                   "(%s datdba) AS dba, "
1854                                                   "pg_encoding_to_char(encoding) AS encoding, "
1855                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1856                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1857                                                   "FROM pg_database "
1858                                                   "WHERE datname = ",
1859                                                   username_subquery);
1860                 appendStringLiteralAH(dbQry, datname, AH);
1861         }
1862         else if (g_fout->remoteVersion >= 70100)
1863         {
1864                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1865                                                   "(%s datdba) AS dba, "
1866                                                   "pg_encoding_to_char(encoding) AS encoding, "
1867                                                   "NULL AS datcollate, NULL AS datctype, "
1868                                                   "0 AS datfrozenxid, "
1869                                                   "NULL AS tablespace "
1870                                                   "FROM pg_database "
1871                                                   "WHERE datname = ",
1872                                                   username_subquery);
1873                 appendStringLiteralAH(dbQry, datname, AH);
1874         }
1875         else
1876         {
1877                 appendPQExpBuffer(dbQry, "SELECT "
1878                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1879                                                   "oid, "
1880                                                   "(%s datdba) AS dba, "
1881                                                   "pg_encoding_to_char(encoding) AS encoding, "
1882                                                   "NULL AS datcollate, NULL AS datctype, "
1883                                                   "0 AS datfrozenxid, "
1884                                                   "NULL AS tablespace "
1885                                                   "FROM pg_database "
1886                                                   "WHERE datname = ",
1887                                                   username_subquery);
1888                 appendStringLiteralAH(dbQry, datname, AH);
1889         }
1890
1891         res = PQexec(g_conn, dbQry->data);
1892         check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1893
1894         ntups = PQntuples(res);
1895
1896         if (ntups <= 0)
1897         {
1898                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1899                                   datname);
1900                 exit_nicely();
1901         }
1902
1903         if (ntups != 1)
1904         {
1905                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1906                                   ntups, datname);
1907                 exit_nicely();
1908         }
1909
1910         i_tableoid = PQfnumber(res, "tableoid");
1911         i_oid = PQfnumber(res, "oid");
1912         i_dba = PQfnumber(res, "dba");
1913         i_encoding = PQfnumber(res, "encoding");
1914         i_collate = PQfnumber(res, "datcollate");
1915         i_ctype = PQfnumber(res, "datctype");
1916         i_frozenxid = PQfnumber(res, "datfrozenxid");
1917         i_tablespace = PQfnumber(res, "tablespace");
1918
1919         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1920         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1921         dba = PQgetvalue(res, 0, i_dba);
1922         encoding = PQgetvalue(res, 0, i_encoding);
1923         collate = PQgetvalue(res, 0, i_collate);
1924         ctype = PQgetvalue(res, 0, i_ctype);
1925         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1926         tablespace = PQgetvalue(res, 0, i_tablespace);
1927
1928         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1929                                           fmtId(datname));
1930         if (strlen(encoding) > 0)
1931         {
1932                 appendPQExpBuffer(creaQry, " ENCODING = ");
1933                 appendStringLiteralAH(creaQry, encoding, AH);
1934         }
1935         if (strlen(collate) > 0)
1936         {
1937                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1938                 appendStringLiteralAH(creaQry, collate, AH);
1939         }
1940         if (strlen(ctype) > 0)
1941         {
1942                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1943                 appendStringLiteralAH(creaQry, ctype, AH);
1944         }
1945         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1946                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1947                                                   fmtId(tablespace));
1948         appendPQExpBuffer(creaQry, ";\n");
1949
1950         if (binary_upgrade)
1951         {
1952                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1953                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
1954                                                   "SET datfrozenxid = '%u'\n"
1955                                                   "WHERE        datname = ",
1956                                                   frozenxid);
1957                 appendStringLiteralAH(creaQry, datname, AH);
1958                 appendPQExpBuffer(creaQry, ";\n");
1959
1960         }
1961
1962         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1963                                           fmtId(datname));
1964
1965         dbDumpId = createDumpId();
1966
1967         ArchiveEntry(AH,
1968                                  dbCatId,               /* catalog ID */
1969                                  dbDumpId,              /* dump ID */
1970                                  datname,               /* Name */
1971                                  NULL,                  /* Namespace */
1972                                  NULL,                  /* Tablespace */
1973                                  dba,                   /* Owner */
1974                                  false,                 /* with oids */
1975                                  "DATABASE",    /* Desc */
1976                                  SECTION_PRE_DATA,              /* Section */
1977                                  creaQry->data, /* Create */
1978                                  delQry->data,  /* Del */
1979                                  NULL,                  /* Copy */
1980                                  NULL,                  /* Deps */
1981                                  0,                             /* # Deps */
1982                                  NULL,                  /* Dumper */
1983                                  NULL);                 /* Dumper Arg */
1984
1985         /*
1986          * pg_largeobject and pg_largeobject_metadata come from the old system
1987          * intact, so set their relfrozenxids.
1988          */
1989         if (binary_upgrade)
1990         {
1991                 PGresult   *lo_res;
1992                 PQExpBuffer loFrozenQry = createPQExpBuffer();
1993                 PQExpBuffer loOutQry = createPQExpBuffer();
1994                 int                     i_relfrozenxid;
1995
1996                 /*
1997                  * pg_largeobject
1998                  */
1999                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2000                                                   "FROM pg_catalog.pg_class\n"
2001                                                   "WHERE oid = %u;\n",
2002                                                   LargeObjectRelationId);
2003
2004                 lo_res = PQexec(g_conn, loFrozenQry->data);
2005                 check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
2006
2007                 if (PQntuples(lo_res) != 1)
2008                 {
2009                         write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
2010                         exit_nicely();
2011                 }
2012
2013                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2014
2015                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2016                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2017                                                   "SET relfrozenxid = '%u'\n"
2018                                                   "WHERE oid = %u;\n",
2019                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2020                                                   LargeObjectRelationId);
2021                 ArchiveEntry(AH, nilCatalogId, createDumpId(),
2022                                          "pg_largeobject", NULL, NULL, "",
2023                                          false, "pg_largeobject", SECTION_PRE_DATA,
2024                                          loOutQry->data, "", NULL,
2025                                          NULL, 0,
2026                                          NULL, NULL);
2027
2028                 PQclear(lo_res);
2029
2030                 /*
2031                  * pg_largeobject_metadata
2032                  */
2033                 if (g_fout->remoteVersion >= 90000)
2034                 {
2035                         resetPQExpBuffer(loFrozenQry);
2036                         resetPQExpBuffer(loOutQry);
2037
2038                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2039                                                           "FROM pg_catalog.pg_class\n"
2040                                                           "WHERE oid = %u;\n",
2041                                                           LargeObjectMetadataRelationId);
2042
2043                         lo_res = PQexec(g_conn, loFrozenQry->data);
2044                         check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
2045
2046                         if (PQntuples(lo_res) != 1)
2047                         {
2048                                 write_msg(NULL, "dumpDatabase(): could not find pg_largeobject_metadata.relfrozenxid\n");
2049                                 exit_nicely();
2050                         }
2051
2052                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2053
2054                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2055                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2056                                                           "SET relfrozenxid = '%u'\n"
2057                                                           "WHERE oid = %u;\n",
2058                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2059                                                           LargeObjectMetadataRelationId);
2060                         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2061                                                  "pg_largeobject_metadata", NULL, NULL, "",
2062                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2063                                                  loOutQry->data, "", NULL,
2064                                                  NULL, 0,
2065                                                  NULL, NULL);
2066
2067                         PQclear(lo_res);
2068                 }
2069
2070                 destroyPQExpBuffer(loFrozenQry);
2071                 destroyPQExpBuffer(loOutQry);
2072         }
2073
2074         /* Dump DB comment if any */
2075         if (g_fout->remoteVersion >= 80200)
2076         {
2077                 /*
2078                  * 8.2 keeps comments on shared objects in a shared table, so we
2079                  * cannot use the dumpComment used for other database objects.
2080                  */
2081                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2082
2083                 if (comment && strlen(comment))
2084                 {
2085                         resetPQExpBuffer(dbQry);
2086
2087                         /*
2088                          * Generates warning when loaded into a differently-named
2089                          * database.
2090                          */
2091                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2092                         appendStringLiteralAH(dbQry, comment, AH);
2093                         appendPQExpBuffer(dbQry, ";\n");
2094
2095                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
2096                                                  dba, false, "COMMENT", SECTION_NONE,
2097                                                  dbQry->data, "", NULL,
2098                                                  &dbDumpId, 1, NULL, NULL);
2099                 }
2100         }
2101         else
2102         {
2103                 resetPQExpBuffer(dbQry);
2104                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2105                 dumpComment(AH, dbQry->data, NULL, "",
2106                                         dbCatId, 0, dbDumpId);
2107         }
2108
2109         PQclear(res);
2110
2111         /* Dump shared security label. */
2112         if (!no_security_labels && g_fout->remoteVersion >= 90200)
2113         {
2114                 PQExpBuffer seclabelQry = createPQExpBuffer();
2115
2116                 buildShSecLabelQuery(g_conn, "pg_database", dbCatId.oid, seclabelQry);
2117                 res = PQexec(g_conn, seclabelQry->data);
2118                 check_sql_result(res, g_conn, seclabelQry->data, PGRES_TUPLES_OK);
2119                 resetPQExpBuffer(seclabelQry);
2120                 emitShSecLabels(g_conn, res, seclabelQry, "DATABASE", datname);
2121                 if (strlen(seclabelQry->data))
2122                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
2123                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2124                                                  seclabelQry->data, "", NULL,
2125                                                  &dbDumpId, 1, NULL, NULL);
2126                 destroyPQExpBuffer(seclabelQry);
2127         }
2128
2129         destroyPQExpBuffer(dbQry);
2130         destroyPQExpBuffer(delQry);
2131         destroyPQExpBuffer(creaQry);
2132 }
2133
2134
2135 /*
2136  * dumpEncoding: put the correct encoding into the archive
2137  */
2138 static void
2139 dumpEncoding(Archive *AH)
2140 {
2141         const char *encname = pg_encoding_to_char(AH->encoding);
2142         PQExpBuffer qry = createPQExpBuffer();
2143
2144         if (g_verbose)
2145                 write_msg(NULL, "saving encoding = %s\n", encname);
2146
2147         appendPQExpBuffer(qry, "SET client_encoding = ");
2148         appendStringLiteralAH(qry, encname, AH);
2149         appendPQExpBuffer(qry, ";\n");
2150
2151         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2152                                  "ENCODING", NULL, NULL, "",
2153                                  false, "ENCODING", SECTION_PRE_DATA,
2154                                  qry->data, "", NULL,
2155                                  NULL, 0,
2156                                  NULL, NULL);
2157
2158         destroyPQExpBuffer(qry);
2159 }
2160
2161
2162 /*
2163  * dumpStdStrings: put the correct escape string behavior into the archive
2164  */
2165 static void
2166 dumpStdStrings(Archive *AH)
2167 {
2168         const char *stdstrings = AH->std_strings ? "on" : "off";
2169         PQExpBuffer qry = createPQExpBuffer();
2170
2171         if (g_verbose)
2172                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2173                                   stdstrings);
2174
2175         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2176                                           stdstrings);
2177
2178         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2179                                  "STDSTRINGS", NULL, NULL, "",
2180                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2181                                  qry->data, "", NULL,
2182                                  NULL, 0,
2183                                  NULL, NULL);
2184
2185         destroyPQExpBuffer(qry);
2186 }
2187
2188
2189 /*
2190  * getBlobs:
2191  *      Collect schema-level data about large objects
2192  */
2193 static void
2194 getBlobs(Archive *AH)
2195 {
2196         PQExpBuffer blobQry = createPQExpBuffer();
2197         BlobInfo   *binfo;
2198         DumpableObject *bdata;
2199         PGresult   *res;
2200         int                     ntups;
2201         int                     i;
2202
2203         /* Verbose message */
2204         if (g_verbose)
2205                 write_msg(NULL, "reading large objects\n");
2206
2207         /* Make sure we are in proper schema */
2208         selectSourceSchema("pg_catalog");
2209
2210         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2211         if (AH->remoteVersion >= 90000)
2212                 appendPQExpBuffer(blobQry,
2213                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2214                                                   " FROM pg_largeobject_metadata",
2215                                                   username_subquery);
2216         else if (AH->remoteVersion >= 70100)
2217                 appendPQExpBuffer(blobQry,
2218                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2219                                                   " FROM pg_largeobject");
2220         else
2221                 appendPQExpBuffer(blobQry,
2222                                                   "SELECT oid, NULL::oid, NULL::oid"
2223                                                   " FROM pg_class WHERE relkind = 'l'");
2224
2225         res = PQexec(g_conn, blobQry->data);
2226         check_sql_result(res, g_conn, blobQry->data, PGRES_TUPLES_OK);
2227
2228         ntups = PQntuples(res);
2229         if (ntups > 0)
2230         {
2231                 /*
2232                  * Each large object has its own BLOB archive entry.
2233                  */
2234                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2235
2236                 for (i = 0; i < ntups; i++)
2237                 {
2238                         binfo[i].dobj.objType = DO_BLOB;
2239                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2240                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2241                         AssignDumpId(&binfo[i].dobj);
2242
2243                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2244                         if (!PQgetisnull(res, i, 1))
2245                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2246                         else
2247                                 binfo[i].rolname = "";
2248                         if (!PQgetisnull(res, i, 2))
2249                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2250                         else
2251                                 binfo[i].blobacl = NULL;
2252                 }
2253
2254                 /*
2255                  * If we have any large objects, a "BLOBS" archive entry is needed.
2256                  * This is just a placeholder for sorting; it carries no data now.
2257                  */
2258                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2259                 bdata->objType = DO_BLOB_DATA;
2260                 bdata->catId = nilCatalogId;
2261                 AssignDumpId(bdata);
2262                 bdata->name = pg_strdup("BLOBS");
2263         }
2264
2265         PQclear(res);
2266         destroyPQExpBuffer(blobQry);
2267 }
2268
2269 /*
2270  * dumpBlob
2271  *
2272  * dump the definition (metadata) of the given large object
2273  */
2274 static void
2275 dumpBlob(Archive *AH, BlobInfo *binfo)
2276 {
2277         PQExpBuffer cquery = createPQExpBuffer();
2278         PQExpBuffer dquery = createPQExpBuffer();
2279
2280         appendPQExpBuffer(cquery,
2281                                           "SELECT pg_catalog.lo_create('%s');\n",
2282                                           binfo->dobj.name);
2283
2284         appendPQExpBuffer(dquery,
2285                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2286                                           binfo->dobj.name);
2287
2288         ArchiveEntry(AH, binfo->dobj.catId, binfo->dobj.dumpId,
2289                                  binfo->dobj.name,
2290                                  NULL, NULL,
2291                                  binfo->rolname, false,
2292                                  "BLOB", SECTION_PRE_DATA,
2293                                  cquery->data, dquery->data, NULL,
2294                                  binfo->dobj.dependencies, binfo->dobj.nDeps,
2295                                  NULL, NULL);
2296
2297         /* set up tag for comment and/or ACL */
2298         resetPQExpBuffer(cquery);
2299         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2300
2301         /* Dump comment if any */
2302         dumpComment(AH, cquery->data,
2303                                 NULL, binfo->rolname,
2304                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2305
2306         /* Dump security label if any */
2307         dumpSecLabel(AH, cquery->data,
2308                                  NULL, binfo->rolname,
2309                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2310
2311         /* Dump ACL if any */
2312         if (binfo->blobacl)
2313                 dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2314                                 binfo->dobj.name, NULL, cquery->data,
2315                                 NULL, binfo->rolname, binfo->blobacl);
2316
2317         destroyPQExpBuffer(cquery);
2318         destroyPQExpBuffer(dquery);
2319 }
2320
2321 /*
2322  * dumpBlobs:
2323  *      dump the data contents of all large objects
2324  */
2325 static int
2326 dumpBlobs(Archive *AH, void *arg)
2327 {
2328         const char *blobQry;
2329         const char *blobFetchQry;
2330         PGresult   *res;
2331         char            buf[LOBBUFSIZE];
2332         int                     ntups;
2333         int                     i;
2334         int                     cnt;
2335
2336         if (g_verbose)
2337                 write_msg(NULL, "saving large objects\n");
2338
2339         /* Make sure we are in proper schema */
2340         selectSourceSchema("pg_catalog");
2341
2342         /*
2343          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2344          * the already-in-memory dumpable objects instead...
2345          */
2346         if (AH->remoteVersion >= 90000)
2347                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2348         else if (AH->remoteVersion >= 70100)
2349                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2350         else
2351                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2352
2353         res = PQexec(g_conn, blobQry);
2354         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2355
2356         /* Command to fetch from cursor */
2357         blobFetchQry = "FETCH 1000 IN bloboid";
2358
2359         do
2360         {
2361                 PQclear(res);
2362
2363                 /* Do a fetch */
2364                 res = PQexec(g_conn, blobFetchQry);
2365                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2366
2367                 /* Process the tuples, if any */
2368                 ntups = PQntuples(res);
2369                 for (i = 0; i < ntups; i++)
2370                 {
2371                         Oid                     blobOid;
2372                         int                     loFd;
2373
2374                         blobOid = atooid(PQgetvalue(res, i, 0));
2375                         /* Open the BLOB */
2376                         loFd = lo_open(g_conn, blobOid, INV_READ);
2377                         if (loFd == -1)
2378                         {
2379                                 write_msg(NULL, "could not open large object %u: %s",
2380                                                   blobOid, PQerrorMessage(g_conn));
2381                                 exit_nicely();
2382                         }
2383
2384                         StartBlob(AH, blobOid);
2385
2386                         /* Now read it in chunks, sending data to archive */
2387                         do
2388                         {
2389                                 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
2390                                 if (cnt < 0)
2391                                 {
2392                                         write_msg(NULL, "error reading large object %u: %s",
2393                                                           blobOid, PQerrorMessage(g_conn));
2394                                         exit_nicely();
2395                                 }
2396
2397                                 WriteData(AH, buf, cnt);
2398                         } while (cnt > 0);
2399
2400                         lo_close(g_conn, loFd);
2401
2402                         EndBlob(AH, blobOid);
2403                 }
2404         } while (ntups > 0);
2405
2406         PQclear(res);
2407
2408         return 1;
2409 }
2410
2411 static void
2412 binary_upgrade_set_type_oids_by_type_oid(PQExpBuffer upgrade_buffer,
2413                                                                                  Oid pg_type_oid)
2414 {
2415         PQExpBuffer upgrade_query = createPQExpBuffer();
2416         int                     ntups;
2417         PGresult   *upgrade_res;
2418         Oid                     pg_type_array_oid;
2419
2420         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2421         appendPQExpBuffer(upgrade_buffer,
2422          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2423                                           pg_type_oid);
2424
2425         /* we only support old >= 8.3 for binary upgrades */
2426         appendPQExpBuffer(upgrade_query,
2427                                           "SELECT typarray "
2428                                           "FROM pg_catalog.pg_type "
2429                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2430                                           pg_type_oid);
2431
2432         upgrade_res = PQexec(g_conn, upgrade_query->data);
2433         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2434
2435         /* Expecting a single result only */
2436         ntups = PQntuples(upgrade_res);
2437         if (ntups != 1)
2438         {
2439                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2440                                                            "query returned %d rows instead of one: %s\n",
2441                                                                  ntups),
2442                                   ntups, upgrade_query->data);
2443                 exit_nicely();
2444         }
2445
2446         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2447
2448         if (OidIsValid(pg_type_array_oid))
2449         {
2450                 appendPQExpBuffer(upgrade_buffer,
2451                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2452                 appendPQExpBuffer(upgrade_buffer,
2453                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2454                                                   pg_type_array_oid);
2455         }
2456
2457         PQclear(upgrade_res);
2458         destroyPQExpBuffer(upgrade_query);
2459 }
2460
2461 static bool
2462 binary_upgrade_set_type_oids_by_rel_oid(PQExpBuffer upgrade_buffer,
2463                                                                                 Oid pg_rel_oid)
2464 {
2465         PQExpBuffer upgrade_query = createPQExpBuffer();
2466         int                     ntups;
2467         PGresult   *upgrade_res;
2468         Oid                     pg_type_oid;
2469         bool            toast_set = false;
2470
2471         /* we only support old >= 8.3 for binary upgrades */
2472         appendPQExpBuffer(upgrade_query,
2473                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2474                                           "FROM pg_catalog.pg_class c "
2475                                           "LEFT JOIN pg_catalog.pg_class t ON "
2476                                           "  (c.reltoastrelid = t.oid) "
2477                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2478                                           pg_rel_oid);
2479
2480         upgrade_res = PQexec(g_conn, upgrade_query->data);
2481         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2482
2483         /* Expecting a single result only */
2484         ntups = PQntuples(upgrade_res);
2485         if (ntups != 1)
2486         {
2487                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2488                                                            "query returned %d rows instead of one: %s\n",
2489                                                                  ntups),
2490                                   ntups, upgrade_query->data);
2491                 exit_nicely();
2492         }
2493
2494         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2495
2496         binary_upgrade_set_type_oids_by_type_oid(upgrade_buffer, pg_type_oid);
2497
2498         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2499         {
2500                 /* Toast tables do not have pg_type array rows */
2501                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2502                                                                                         PQfnumber(upgrade_res, "trel")));
2503
2504                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2505                 appendPQExpBuffer(upgrade_buffer,
2506                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2507                                                   pg_type_toast_oid);
2508
2509                 toast_set = true;
2510         }
2511
2512         PQclear(upgrade_res);
2513         destroyPQExpBuffer(upgrade_query);
2514
2515         return toast_set;
2516 }
2517
2518 static void
2519 binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2520                                                                  bool is_index)
2521 {
2522         PQExpBuffer upgrade_query = createPQExpBuffer();
2523         int                     ntups;
2524         PGresult   *upgrade_res;
2525         Oid                     pg_class_reltoastrelid;
2526         Oid                     pg_class_reltoastidxid;
2527
2528         appendPQExpBuffer(upgrade_query,
2529                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2530                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2531                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2532                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2533                                           pg_class_oid);
2534
2535         upgrade_res = PQexec(g_conn, upgrade_query->data);
2536         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2537
2538         /* Expecting a single result only */
2539         ntups = PQntuples(upgrade_res);
2540         if (ntups != 1)
2541         {
2542                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2543                                                            "query returned %d rows instead of one: %s\n",
2544                                                                  ntups),
2545                                   ntups, upgrade_query->data);
2546                 exit_nicely();
2547         }
2548
2549         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2550         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2551
2552         appendPQExpBuffer(upgrade_buffer,
2553                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2554
2555         if (!is_index)
2556         {
2557                 appendPQExpBuffer(upgrade_buffer,
2558                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2559                                                   pg_class_oid);
2560                 /* only tables have toast tables, not indexes */
2561                 if (OidIsValid(pg_class_reltoastrelid))
2562                 {
2563                         /*
2564                          * One complexity is that the table definition might not require
2565                          * the creation of a TOAST table, and the TOAST table might have
2566                          * been created long after table creation, when the table was
2567                          * loaded with wide data.  By setting the TOAST oid we force
2568                          * creation of the TOAST heap and TOAST index by the backend so we
2569                          * can cleanly copy the files during binary upgrade.
2570                          */
2571
2572                         appendPQExpBuffer(upgrade_buffer,
2573                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2574                                                           pg_class_reltoastrelid);
2575
2576                         /* every toast table has an index */
2577                         appendPQExpBuffer(upgrade_buffer,
2578                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2579                                                           pg_class_reltoastidxid);
2580                 }
2581         }
2582         else
2583                 appendPQExpBuffer(upgrade_buffer,
2584                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2585                                                   pg_class_oid);
2586
2587         appendPQExpBuffer(upgrade_buffer, "\n");
2588
2589         PQclear(upgrade_res);
2590         destroyPQExpBuffer(upgrade_query);
2591 }
2592
2593 /*
2594  * If the DumpableObject is a member of an extension, add a suitable
2595  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2596  */
2597 static void
2598 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2599                                                                 DumpableObject *dobj,
2600                                                                 const char *objlabel)
2601 {
2602         DumpableObject *extobj = NULL;
2603         int                     i;
2604
2605         if (!dobj->ext_member)
2606                 return;
2607
2608         /*
2609          * Find the parent extension.  We could avoid this search if we wanted to
2610          * add a link field to DumpableObject, but the space costs of that would
2611          * be considerable.  We assume that member objects could only have a
2612          * direct dependency on their own extension, not any others.
2613          */
2614         for (i = 0; i < dobj->nDeps; i++)
2615         {
2616                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2617                 if (extobj && extobj->objType == DO_EXTENSION)
2618                         break;
2619                 extobj = NULL;
2620         }
2621         if (extobj == NULL)
2622         {
2623                 write_msg(NULL, "could not find parent extension for %s", objlabel);
2624                 exit_nicely();
2625         }
2626
2627         appendPQExpBuffer(upgrade_buffer,
2628           "\n-- For binary upgrade, handle extension membership the hard way\n");
2629         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2630                                           fmtId(extobj->name),
2631                                           objlabel);
2632 }
2633
2634 /*
2635  * getNamespaces:
2636  *        read all namespaces in the system catalogs and return them in the
2637  * NamespaceInfo* structure
2638  *
2639  *      numNamespaces is set to the number of namespaces read in
2640  */
2641 NamespaceInfo *
2642 getNamespaces(int *numNamespaces)
2643 {
2644         PGresult   *res;
2645         int                     ntups;
2646         int                     i;
2647         PQExpBuffer query;
2648         NamespaceInfo *nsinfo;
2649         int                     i_tableoid;
2650         int                     i_oid;
2651         int                     i_nspname;
2652         int                     i_rolname;
2653         int                     i_nspacl;
2654
2655         /*
2656          * Before 7.3, there are no real namespaces; create two dummy entries, one
2657          * for user stuff and one for system stuff.
2658          */
2659         if (g_fout->remoteVersion < 70300)
2660         {
2661                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2662
2663                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2664                 nsinfo[0].dobj.catId.tableoid = 0;
2665                 nsinfo[0].dobj.catId.oid = 0;
2666                 AssignDumpId(&nsinfo[0].dobj);
2667                 nsinfo[0].dobj.name = pg_strdup("public");
2668                 nsinfo[0].rolname = pg_strdup("");
2669                 nsinfo[0].nspacl = pg_strdup("");
2670
2671                 selectDumpableNamespace(&nsinfo[0]);
2672
2673                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2674                 nsinfo[1].dobj.catId.tableoid = 0;
2675                 nsinfo[1].dobj.catId.oid = 1;
2676                 AssignDumpId(&nsinfo[1].dobj);
2677                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2678                 nsinfo[1].rolname = pg_strdup("");
2679                 nsinfo[1].nspacl = pg_strdup("");
2680
2681                 selectDumpableNamespace(&nsinfo[1]);
2682
2683                 g_namespaces = nsinfo;
2684                 g_numNamespaces = *numNamespaces = 2;
2685
2686                 return nsinfo;
2687         }
2688
2689         query = createPQExpBuffer();
2690
2691         /* Make sure we are in proper schema */
2692         selectSourceSchema("pg_catalog");
2693
2694         /*
2695          * we fetch all namespaces including system ones, so that every object we
2696          * read in can be linked to a containing namespace.
2697          */
2698         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2699                                           "(%s nspowner) AS rolname, "
2700                                           "nspacl FROM pg_namespace",
2701                                           username_subquery);
2702
2703         res = PQexec(g_conn, query->data);
2704         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2705
2706         ntups = PQntuples(res);
2707
2708         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2709
2710         i_tableoid = PQfnumber(res, "tableoid");
2711         i_oid = PQfnumber(res, "oid");
2712         i_nspname = PQfnumber(res, "nspname");
2713         i_rolname = PQfnumber(res, "rolname");
2714         i_nspacl = PQfnumber(res, "nspacl");
2715
2716         for (i = 0; i < ntups; i++)
2717         {
2718                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2719                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2720                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2721                 AssignDumpId(&nsinfo[i].dobj);
2722                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2723                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2724                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2725
2726                 /* Decide whether to dump this namespace */
2727                 selectDumpableNamespace(&nsinfo[i]);
2728
2729                 if (strlen(nsinfo[i].rolname) == 0)
2730                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2731                                           nsinfo[i].dobj.name);
2732         }
2733
2734         PQclear(res);
2735         destroyPQExpBuffer(query);
2736
2737         g_namespaces = nsinfo;
2738         g_numNamespaces = *numNamespaces = ntups;
2739
2740         return nsinfo;
2741 }
2742
2743 /*
2744  * findNamespace:
2745  *              given a namespace OID and an object OID, look up the info read by
2746  *              getNamespaces
2747  *
2748  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2749  * a system object or not.      In 7.3 and later there is no guessing.
2750  */
2751 static NamespaceInfo *
2752 findNamespace(Oid nsoid, Oid objoid)
2753 {
2754         int                     i;
2755
2756         if (g_fout->remoteVersion >= 70300)
2757         {
2758                 for (i = 0; i < g_numNamespaces; i++)
2759                 {
2760                         NamespaceInfo *nsinfo = &g_namespaces[i];
2761
2762                         if (nsoid == nsinfo->dobj.catId.oid)
2763                                 return nsinfo;
2764                 }
2765                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2766                 exit_nicely();
2767         }
2768         else
2769         {
2770                 /* This code depends on the layout set up by getNamespaces. */
2771                 if (objoid > g_last_builtin_oid)
2772                         i = 0;                          /* user object */
2773                 else
2774                         i = 1;                          /* system object */
2775                 return &g_namespaces[i];
2776         }
2777
2778         return NULL;                            /* keep compiler quiet */
2779 }
2780
2781 /*
2782  * getExtensions:
2783  *        read all extensions in the system catalogs and return them in the
2784  * ExtensionInfo* structure
2785  *
2786  *      numExtensions is set to the number of extensions read in
2787  */
2788 ExtensionInfo *
2789 getExtensions(int *numExtensions)
2790 {
2791         PGresult   *res;
2792         int                     ntups;
2793         int                     i;
2794         PQExpBuffer query;
2795         ExtensionInfo *extinfo;
2796         int                     i_tableoid;
2797         int                     i_oid;
2798         int                     i_extname;
2799         int                     i_nspname;
2800         int                     i_extrelocatable;
2801         int                     i_extversion;
2802         int                     i_extconfig;
2803         int                     i_extcondition;
2804
2805         /*
2806          * Before 9.1, there are no extensions.
2807          */
2808         if (g_fout->remoteVersion < 90100)
2809         {
2810                 *numExtensions = 0;
2811                 return NULL;
2812         }
2813
2814         query = createPQExpBuffer();
2815
2816         /* Make sure we are in proper schema */
2817         selectSourceSchema("pg_catalog");
2818
2819         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
2820                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
2821                                           "FROM pg_extension x "
2822                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
2823
2824         res = PQexec(g_conn, query->data);
2825         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2826
2827         ntups = PQntuples(res);
2828
2829         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
2830
2831         i_tableoid = PQfnumber(res, "tableoid");
2832         i_oid = PQfnumber(res, "oid");
2833         i_extname = PQfnumber(res, "extname");
2834         i_nspname = PQfnumber(res, "nspname");
2835         i_extrelocatable = PQfnumber(res, "extrelocatable");
2836         i_extversion = PQfnumber(res, "extversion");
2837         i_extconfig = PQfnumber(res, "extconfig");
2838         i_extcondition = PQfnumber(res, "extcondition");
2839
2840         for (i = 0; i < ntups; i++)
2841         {
2842                 extinfo[i].dobj.objType = DO_EXTENSION;
2843                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2844                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2845                 AssignDumpId(&extinfo[i].dobj);
2846                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
2847                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
2848                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
2849                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
2850                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
2851                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
2852
2853                 /* Decide whether we want to dump it */
2854                 selectDumpableExtension(&(extinfo[i]));
2855         }
2856
2857         PQclear(res);
2858         destroyPQExpBuffer(query);
2859
2860         *numExtensions = ntups;
2861
2862         return extinfo;
2863 }
2864
2865 /*
2866  * getTypes:
2867  *        read all types in the system catalogs and return them in the
2868  * TypeInfo* structure
2869  *
2870  *      numTypes is set to the number of types read in
2871  *
2872  * NB: this must run after getFuncs() because we assume we can do
2873  * findFuncByOid().
2874  */
2875 TypeInfo *
2876 getTypes(int *numTypes)
2877 {
2878         PGresult   *res;
2879         int                     ntups;
2880         int                     i;
2881         PQExpBuffer query = createPQExpBuffer();
2882         TypeInfo   *tyinfo;
2883         ShellTypeInfo *stinfo;
2884         int                     i_tableoid;
2885         int                     i_oid;
2886         int                     i_typname;
2887         int                     i_typnamespace;
2888         int                     i_rolname;
2889         int                     i_typinput;
2890         int                     i_typoutput;
2891         int                     i_typelem;
2892         int                     i_typrelid;
2893         int                     i_typrelkind;
2894         int                     i_typtype;
2895         int                     i_typisdefined;
2896         int                     i_isarray;
2897
2898         /*
2899          * we include even the built-in types because those may be used as array
2900          * elements by user-defined types
2901          *
2902          * we filter out the built-in types when we dump out the types
2903          *
2904          * same approach for undefined (shell) types and array types
2905          *
2906          * Note: as of 8.3 we can reliably detect whether a type is an
2907          * auto-generated array type by checking the element type's typarray.
2908          * (Before that the test is capable of generating false positives.) We
2909          * still check for name beginning with '_', though, so as to avoid the
2910          * cost of the subselect probe for all standard types.  This would have to
2911          * be revisited if the backend ever allows renaming of array types.
2912          */
2913
2914         /* Make sure we are in proper schema */
2915         selectSourceSchema("pg_catalog");
2916
2917         if (g_fout->remoteVersion >= 80300)
2918         {
2919                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2920                                                   "typnamespace, "
2921                                                   "(%s typowner) AS rolname, "
2922                                                   "typinput::oid AS typinput, "
2923                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2924                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2925                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2926                                                   "typtype, typisdefined, "
2927                                                   "typname[0] = '_' AND typelem != 0 AND "
2928                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2929                                                   "FROM pg_type",
2930                                                   username_subquery);
2931         }
2932         else if (g_fout->remoteVersion >= 70300)
2933         {
2934                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2935                                                   "typnamespace, "
2936                                                   "(%s typowner) AS rolname, "
2937                                                   "typinput::oid AS typinput, "
2938                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2939                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2940                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2941                                                   "typtype, typisdefined, "
2942                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2943                                                   "FROM pg_type",
2944                                                   username_subquery);
2945         }
2946         else if (g_fout->remoteVersion >= 70100)
2947         {
2948                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2949                                                   "0::oid AS typnamespace, "
2950                                                   "(%s typowner) AS rolname, "
2951                                                   "typinput::oid AS typinput, "
2952                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2953                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2954                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2955                                                   "typtype, typisdefined, "
2956                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2957                                                   "FROM pg_type",
2958                                                   username_subquery);
2959         }
2960         else
2961         {
2962                 appendPQExpBuffer(query, "SELECT "
2963                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2964                                                   "oid, typname, "
2965                                                   "0::oid AS typnamespace, "
2966                                                   "(%s typowner) AS rolname, "
2967                                                   "typinput::oid AS typinput, "
2968                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2969                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2970                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2971                                                   "typtype, typisdefined, "
2972                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2973                                                   "FROM pg_type",
2974                                                   username_subquery);
2975         }
2976
2977         res = PQexec(g_conn, query->data);
2978         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2979
2980         ntups = PQntuples(res);
2981
2982         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
2983
2984         i_tableoid = PQfnumber(res, "tableoid");
2985         i_oid = PQfnumber(res, "oid");
2986         i_typname = PQfnumber(res, "typname");
2987         i_typnamespace = PQfnumber(res, "typnamespace");
2988         i_rolname = PQfnumber(res, "rolname");
2989         i_typinput = PQfnumber(res, "typinput");
2990         i_typoutput = PQfnumber(res, "typoutput");
2991         i_typelem = PQfnumber(res, "typelem");
2992         i_typrelid = PQfnumber(res, "typrelid");
2993         i_typrelkind = PQfnumber(res, "typrelkind");
2994         i_typtype = PQfnumber(res, "typtype");
2995         i_typisdefined = PQfnumber(res, "typisdefined");
2996         i_isarray = PQfnumber(res, "isarray");
2997
2998         for (i = 0; i < ntups; i++)
2999         {
3000                 tyinfo[i].dobj.objType = DO_TYPE;
3001                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3002                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3003                 AssignDumpId(&tyinfo[i].dobj);
3004                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3005                 tyinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
3006                                                                                                  tyinfo[i].dobj.catId.oid);
3007                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3008                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3009                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3010                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3011                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3012                 tyinfo[i].shellType = NULL;
3013
3014                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3015                         tyinfo[i].isDefined = true;
3016                 else
3017                         tyinfo[i].isDefined = false;
3018
3019                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3020                         tyinfo[i].isArray = true;
3021                 else
3022                         tyinfo[i].isArray = false;
3023
3024                 /* Decide whether we want to dump it */
3025                 selectDumpableType(&tyinfo[i]);
3026
3027                 /*
3028                  * If it's a domain, fetch info about its constraints, if any
3029                  */
3030                 tyinfo[i].nDomChecks = 0;
3031                 tyinfo[i].domChecks = NULL;
3032                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3033                         getDomainConstraints(&(tyinfo[i]));
3034
3035                 /*
3036                  * If it's a base type, make a DumpableObject representing a shell
3037                  * definition of the type.      We will need to dump that ahead of the I/O
3038                  * functions for the type.  Similarly, range types need a shell
3039                  * definition in case they have a canonicalize function.
3040                  *
3041                  * Note: the shell type doesn't have a catId.  You might think it
3042                  * should copy the base type's catId, but then it might capture the
3043                  * pg_depend entries for the type, which we don't want.
3044                  */
3045                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3046                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3047                 {
3048                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3049                         stinfo->dobj.objType = DO_SHELL_TYPE;
3050                         stinfo->dobj.catId = nilCatalogId;
3051                         AssignDumpId(&stinfo->dobj);
3052                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3053                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3054                         stinfo->baseType = &(tyinfo[i]);
3055                         tyinfo[i].shellType = stinfo;
3056
3057                         /*
3058                          * Initially mark the shell type as not to be dumped.  We'll only
3059                          * dump it if the I/O or canonicalize functions need to be dumped;
3060                          * this is taken care of while sorting dependencies.
3061                          */
3062                         stinfo->dobj.dump = false;
3063
3064                         /*
3065                          * However, if dumping from pre-7.3, there will be no dependency
3066                          * info so we have to fake it here.  We only need to worry about
3067                          * typinput and typoutput since the other functions only exist
3068                          * post-7.3.
3069                          */
3070                         if (g_fout->remoteVersion < 70300)
3071                         {
3072                                 Oid                     typinput;
3073                                 Oid                     typoutput;
3074                                 FuncInfo   *funcInfo;
3075
3076                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3077                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3078
3079                                 funcInfo = findFuncByOid(typinput);
3080                                 if (funcInfo && funcInfo->dobj.dump)
3081                                 {
3082                                         /* base type depends on function */
3083                                         addObjectDependency(&tyinfo[i].dobj,
3084                                                                                 funcInfo->dobj.dumpId);
3085                                         /* function depends on shell type */
3086                                         addObjectDependency(&funcInfo->dobj,
3087                                                                                 stinfo->dobj.dumpId);
3088                                         /* mark shell type as to be dumped */
3089                                         stinfo->dobj.dump = true;
3090                                 }
3091
3092                                 funcInfo = findFuncByOid(typoutput);
3093                                 if (funcInfo && funcInfo->dobj.dump)
3094                                 {
3095                                         /* base type depends on function */
3096                                         addObjectDependency(&tyinfo[i].dobj,
3097                                                                                 funcInfo->dobj.dumpId);
3098                                         /* function depends on shell type */
3099                                         addObjectDependency(&funcInfo->dobj,
3100                                                                                 stinfo->dobj.dumpId);
3101                                         /* mark shell type as to be dumped */
3102                                         stinfo->dobj.dump = true;
3103                                 }
3104                         }
3105                 }
3106
3107                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3108                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3109                                           tyinfo[i].dobj.name);
3110         }
3111
3112         *numTypes = ntups;
3113
3114         PQclear(res);
3115
3116         destroyPQExpBuffer(query);
3117
3118         return tyinfo;
3119 }
3120
3121 /*
3122  * getOperators:
3123  *        read all operators in the system catalogs and return them in the
3124  * OprInfo* structure
3125  *
3126  *      numOprs is set to the number of operators read in
3127  */
3128 OprInfo *
3129 getOperators(int *numOprs)
3130 {
3131         PGresult   *res;
3132         int                     ntups;
3133         int                     i;
3134         PQExpBuffer query = createPQExpBuffer();
3135         OprInfo    *oprinfo;
3136         int                     i_tableoid;
3137         int                     i_oid;
3138         int                     i_oprname;
3139         int                     i_oprnamespace;
3140         int                     i_rolname;
3141         int                     i_oprkind;
3142         int                     i_oprcode;
3143
3144         /*
3145          * find all operators, including builtin operators; we filter out
3146          * system-defined operators at dump-out time.
3147          */
3148
3149         /* Make sure we are in proper schema */
3150         selectSourceSchema("pg_catalog");
3151
3152         if (g_fout->remoteVersion >= 70300)
3153         {
3154                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3155                                                   "oprnamespace, "
3156                                                   "(%s oprowner) AS rolname, "
3157                                                   "oprkind, "
3158                                                   "oprcode::oid AS oprcode "
3159                                                   "FROM pg_operator",
3160                                                   username_subquery);
3161         }
3162         else if (g_fout->remoteVersion >= 70100)
3163         {
3164                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3165                                                   "0::oid AS oprnamespace, "
3166                                                   "(%s oprowner) AS rolname, "
3167                                                   "oprkind, "
3168                                                   "oprcode::oid AS oprcode "
3169                                                   "FROM pg_operator",
3170                                                   username_subquery);
3171         }
3172         else
3173         {
3174                 appendPQExpBuffer(query, "SELECT "
3175                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3176                                                   "oid, oprname, "
3177                                                   "0::oid AS oprnamespace, "
3178                                                   "(%s oprowner) AS rolname, "
3179                                                   "oprkind, "
3180                                                   "oprcode::oid AS oprcode "
3181                                                   "FROM pg_operator",
3182                                                   username_subquery);
3183         }
3184
3185         res = PQexec(g_conn, query->data);
3186         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3187
3188         ntups = PQntuples(res);
3189         *numOprs = ntups;
3190
3191         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3192
3193         i_tableoid = PQfnumber(res, "tableoid");
3194         i_oid = PQfnumber(res, "oid");
3195         i_oprname = PQfnumber(res, "oprname");
3196         i_oprnamespace = PQfnumber(res, "oprnamespace");
3197         i_rolname = PQfnumber(res, "rolname");
3198         i_oprkind = PQfnumber(res, "oprkind");
3199         i_oprcode = PQfnumber(res, "oprcode");
3200
3201         for (i = 0; i < ntups; i++)
3202         {
3203                 oprinfo[i].dobj.objType = DO_OPERATOR;
3204                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3205                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3206                 AssignDumpId(&oprinfo[i].dobj);
3207                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3208                 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
3209                                                                                                   oprinfo[i].dobj.catId.oid);
3210                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3211                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3212                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3213
3214                 /* Decide whether we want to dump it */
3215                 selectDumpableObject(&(oprinfo[i].dobj));
3216
3217                 if (strlen(oprinfo[i].rolname) == 0)
3218                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3219                                           oprinfo[i].dobj.name);
3220         }
3221
3222         PQclear(res);
3223
3224         destroyPQExpBuffer(query);
3225
3226         return oprinfo;
3227 }
3228
3229 /*
3230  * getCollations:
3231  *        read all collations in the system catalogs and return them in the
3232  * CollInfo* structure
3233  *
3234  *      numCollations is set to the number of collations read in
3235  */
3236 CollInfo *
3237 getCollations(int *numCollations)
3238 {
3239         PGresult   *res;
3240         int                     ntups;
3241         int                     i;
3242         PQExpBuffer query = createPQExpBuffer();
3243         CollInfo   *collinfo;
3244         int                     i_tableoid;
3245         int                     i_oid;
3246         int                     i_collname;
3247         int                     i_collnamespace;
3248         int                     i_rolname;
3249
3250         /* Collations didn't exist pre-9.1 */
3251         if (g_fout->remoteVersion < 90100)
3252         {
3253                 *numCollations = 0;
3254                 return NULL;
3255         }
3256
3257         /*
3258          * find all collations, including builtin collations; we filter out
3259          * system-defined collations at dump-out time.
3260          */
3261
3262         /* Make sure we are in proper schema */
3263         selectSourceSchema("pg_catalog");
3264
3265         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3266                                           "collnamespace, "
3267                                           "(%s collowner) AS rolname "
3268                                           "FROM pg_collation",
3269                                           username_subquery);
3270
3271         res = PQexec(g_conn, query->data);
3272         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3273
3274         ntups = PQntuples(res);
3275         *numCollations = ntups;
3276
3277         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3278
3279         i_tableoid = PQfnumber(res, "tableoid");
3280         i_oid = PQfnumber(res, "oid");
3281         i_collname = PQfnumber(res, "collname");
3282         i_collnamespace = PQfnumber(res, "collnamespace");
3283         i_rolname = PQfnumber(res, "rolname");
3284
3285         for (i = 0; i < ntups; i++)
3286         {
3287                 collinfo[i].dobj.objType = DO_COLLATION;
3288                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3289                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3290                 AssignDumpId(&collinfo[i].dobj);
3291                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3292                 collinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)),
3293                                                                                                  collinfo[i].dobj.catId.oid);
3294                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3295
3296                 /* Decide whether we want to dump it */
3297                 selectDumpableObject(&(collinfo[i].dobj));
3298         }
3299
3300         PQclear(res);
3301
3302         destroyPQExpBuffer(query);
3303
3304         return collinfo;
3305 }
3306
3307 /*
3308  * getConversions:
3309  *        read all conversions in the system catalogs and return them in the
3310  * ConvInfo* structure
3311  *
3312  *      numConversions is set to the number of conversions read in
3313  */
3314 ConvInfo *
3315 getConversions(int *numConversions)
3316 {
3317         PGresult   *res;
3318         int                     ntups;
3319         int                     i;
3320         PQExpBuffer query = createPQExpBuffer();
3321         ConvInfo   *convinfo;
3322         int                     i_tableoid;
3323         int                     i_oid;
3324         int                     i_conname;
3325         int                     i_connamespace;
3326         int                     i_rolname;
3327
3328         /* Conversions didn't exist pre-7.3 */
3329         if (g_fout->remoteVersion < 70300)
3330         {
3331                 *numConversions = 0;
3332                 return NULL;
3333         }
3334
3335         /*
3336          * find all conversions, including builtin conversions; we filter out
3337          * system-defined conversions at dump-out time.
3338          */
3339
3340         /* Make sure we are in proper schema */
3341         selectSourceSchema("pg_catalog");
3342
3343         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3344                                           "connamespace, "
3345                                           "(%s conowner) AS rolname "
3346                                           "FROM pg_conversion",
3347                                           username_subquery);
3348
3349         res = PQexec(g_conn, query->data);
3350         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3351
3352         ntups = PQntuples(res);
3353         *numConversions = ntups;
3354
3355         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3356
3357         i_tableoid = PQfnumber(res, "tableoid");
3358         i_oid = PQfnumber(res, "oid");
3359         i_conname = PQfnumber(res, "conname");
3360         i_connamespace = PQfnumber(res, "connamespace");
3361         i_rolname = PQfnumber(res, "rolname");
3362
3363         for (i = 0; i < ntups; i++)
3364         {
3365                 convinfo[i].dobj.objType = DO_CONVERSION;
3366                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3367                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3368                 AssignDumpId(&convinfo[i].dobj);
3369                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3370                 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
3371                                                                                                  convinfo[i].dobj.catId.oid);
3372                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3373
3374                 /* Decide whether we want to dump it */
3375                 selectDumpableObject(&(convinfo[i].dobj));
3376         }
3377
3378         PQclear(res);
3379
3380         destroyPQExpBuffer(query);
3381
3382         return convinfo;
3383 }
3384
3385 /*
3386  * getOpclasses:
3387  *        read all opclasses in the system catalogs and return them in the
3388  * OpclassInfo* structure
3389  *
3390  *      numOpclasses is set to the number of opclasses read in
3391  */
3392 OpclassInfo *
3393 getOpclasses(int *numOpclasses)
3394 {
3395         PGresult   *res;
3396         int                     ntups;
3397         int                     i;
3398         PQExpBuffer query = createPQExpBuffer();
3399         OpclassInfo *opcinfo;
3400         int                     i_tableoid;
3401         int                     i_oid;
3402         int                     i_opcname;
3403         int                     i_opcnamespace;
3404         int                     i_rolname;
3405
3406         /*
3407          * find all opclasses, including builtin opclasses; we filter out
3408          * system-defined opclasses at dump-out time.
3409          */
3410
3411         /* Make sure we are in proper schema */
3412         selectSourceSchema("pg_catalog");
3413
3414         if (g_fout->remoteVersion >= 70300)
3415         {
3416                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3417                                                   "opcnamespace, "
3418                                                   "(%s opcowner) AS rolname "
3419                                                   "FROM pg_opclass",
3420                                                   username_subquery);
3421         }
3422         else if (g_fout->remoteVersion >= 70100)
3423         {
3424                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3425                                                   "0::oid AS opcnamespace, "
3426                                                   "''::name AS rolname "
3427                                                   "FROM pg_opclass");
3428         }
3429         else
3430         {
3431                 appendPQExpBuffer(query, "SELECT "
3432                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3433                                                   "oid, opcname, "
3434                                                   "0::oid AS opcnamespace, "
3435                                                   "''::name AS rolname "
3436                                                   "FROM pg_opclass");
3437         }
3438
3439         res = PQexec(g_conn, query->data);
3440         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3441
3442         ntups = PQntuples(res);
3443         *numOpclasses = ntups;
3444
3445         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3446
3447         i_tableoid = PQfnumber(res, "tableoid");
3448         i_oid = PQfnumber(res, "oid");
3449         i_opcname = PQfnumber(res, "opcname");
3450         i_opcnamespace = PQfnumber(res, "opcnamespace");
3451         i_rolname = PQfnumber(res, "rolname");
3452
3453         for (i = 0; i < ntups; i++)
3454         {
3455                 opcinfo[i].dobj.objType = DO_OPCLASS;
3456                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3457                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3458                 AssignDumpId(&opcinfo[i].dobj);
3459                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3460                 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
3461                                                                                                   opcinfo[i].dobj.catId.oid);
3462                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3463
3464                 /* Decide whether we want to dump it */
3465                 selectDumpableObject(&(opcinfo[i].dobj));
3466
3467                 if (g_fout->remoteVersion >= 70300)
3468                 {
3469                         if (strlen(opcinfo[i].rolname) == 0)
3470                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3471                                                   opcinfo[i].dobj.name);
3472                 }
3473         }
3474
3475         PQclear(res);
3476
3477         destroyPQExpBuffer(query);
3478
3479         return opcinfo;
3480 }
3481
3482 /*
3483  * getOpfamilies:
3484  *        read all opfamilies in the system catalogs and return them in the
3485  * OpfamilyInfo* structure
3486  *
3487  *      numOpfamilies is set to the number of opfamilies read in
3488  */
3489 OpfamilyInfo *
3490 getOpfamilies(int *numOpfamilies)
3491 {
3492         PGresult   *res;
3493         int                     ntups;
3494         int                     i;
3495         PQExpBuffer query;
3496         OpfamilyInfo *opfinfo;
3497         int                     i_tableoid;
3498         int                     i_oid;
3499         int                     i_opfname;
3500         int                     i_opfnamespace;
3501         int                     i_rolname;
3502
3503         /* Before 8.3, there is no separate concept of opfamilies */
3504         if (g_fout->remoteVersion < 80300)
3505         {
3506                 *numOpfamilies = 0;
3507                 return NULL;
3508         }
3509
3510         query = createPQExpBuffer();
3511
3512         /*
3513          * find all opfamilies, including builtin opfamilies; we filter out
3514          * system-defined opfamilies at dump-out time.
3515          */
3516
3517         /* Make sure we are in proper schema */
3518         selectSourceSchema("pg_catalog");
3519
3520         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3521                                           "opfnamespace, "
3522                                           "(%s opfowner) AS rolname "
3523                                           "FROM pg_opfamily",
3524                                           username_subquery);
3525
3526         res = PQexec(g_conn, query->data);
3527         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3528
3529         ntups = PQntuples(res);
3530         *numOpfamilies = ntups;
3531
3532         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3533
3534         i_tableoid = PQfnumber(res, "tableoid");
3535         i_oid = PQfnumber(res, "oid");
3536         i_opfname = PQfnumber(res, "opfname");
3537         i_opfnamespace = PQfnumber(res, "opfnamespace");
3538         i_rolname = PQfnumber(res, "rolname");
3539
3540         for (i = 0; i < ntups; i++)
3541         {
3542                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3543                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3544                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3545                 AssignDumpId(&opfinfo[i].dobj);
3546                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3547                 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
3548                                                                                                   opfinfo[i].dobj.catId.oid);
3549                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3550
3551                 /* Decide whether we want to dump it */
3552                 selectDumpableObject(&(opfinfo[i].dobj));
3553
3554                 if (g_fout->remoteVersion >= 70300)
3555                 {
3556                         if (strlen(opfinfo[i].rolname) == 0)
3557                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3558                                                   opfinfo[i].dobj.name);
3559                 }
3560         }
3561
3562         PQclear(res);
3563
3564         destroyPQExpBuffer(query);
3565
3566         return opfinfo;
3567 }
3568
3569 /*
3570  * getAggregates:
3571  *        read all the user-defined aggregates in the system catalogs and
3572  * return them in the AggInfo* structure
3573  *
3574  * numAggs is set to the number of aggregates read in
3575  */
3576 AggInfo *
3577 getAggregates(int *numAggs)
3578 {
3579         PGresult   *res;
3580         int                     ntups;
3581         int                     i;
3582         PQExpBuffer query = createPQExpBuffer();
3583         AggInfo    *agginfo;
3584         int                     i_tableoid;
3585         int                     i_oid;
3586         int                     i_aggname;
3587         int                     i_aggnamespace;
3588         int                     i_pronargs;
3589         int                     i_proargtypes;
3590         int                     i_rolname;
3591         int                     i_aggacl;
3592
3593         /* Make sure we are in proper schema */
3594         selectSourceSchema("pg_catalog");
3595
3596         /*
3597          * Find all user-defined aggregates.  See comment in getFuncs() for the
3598          * rationale behind the filtering logic.
3599          */
3600
3601         if (g_fout->remoteVersion >= 80200)
3602         {
3603                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3604                                                   "pronamespace AS aggnamespace, "
3605                                                   "pronargs, proargtypes, "
3606                                                   "(%s proowner) AS rolname, "
3607                                                   "proacl AS aggacl "
3608                                                   "FROM pg_proc p "
3609                                                   "WHERE proisagg AND ("
3610                                                   "pronamespace != "
3611                                                   "(SELECT oid FROM pg_namespace "
3612                                                   "WHERE nspname = 'pg_catalog')",
3613                                                   username_subquery);
3614                 if (binary_upgrade && g_fout->remoteVersion >= 90100)
3615                         appendPQExpBuffer(query,
3616                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3617                                                           "classid = 'pg_proc'::regclass AND "
3618                                                           "objid = p.oid AND "
3619                                                           "refclassid = 'pg_extension'::regclass AND "
3620                                                           "deptype = 'e')");
3621                 appendPQExpBuffer(query, ")");
3622         }
3623         else if (g_fout->remoteVersion >= 70300)
3624         {
3625                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3626                                                   "pronamespace AS aggnamespace, "
3627                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3628                                                   "proargtypes, "
3629                                                   "(%s proowner) AS rolname, "
3630                                                   "proacl AS aggacl "
3631                                                   "FROM pg_proc "
3632                                                   "WHERE proisagg "
3633                                                   "AND pronamespace != "
3634                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3635                                                   username_subquery);
3636         }
3637         else if (g_fout->remoteVersion >= 70100)
3638         {
3639                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3640                                                   "0::oid AS aggnamespace, "
3641                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3642                                                   "aggbasetype AS proargtypes, "
3643                                                   "(%s aggowner) AS rolname, "
3644                                                   "'{=X}' AS aggacl "
3645                                                   "FROM pg_aggregate "
3646                                                   "where oid > '%u'::oid",
3647                                                   username_subquery,
3648                                                   g_last_builtin_oid);
3649         }
3650         else
3651         {
3652                 appendPQExpBuffer(query, "SELECT "
3653                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3654                                                   "oid, aggname, "
3655                                                   "0::oid AS aggnamespace, "
3656                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3657                                                   "aggbasetype AS proargtypes, "
3658                                                   "(%s aggowner) AS rolname, "
3659                                                   "'{=X}' AS aggacl "
3660                                                   "FROM pg_aggregate "
3661                                                   "where oid > '%u'::oid",
3662                                                   username_subquery,
3663                                                   g_last_builtin_oid);
3664         }
3665
3666         res = PQexec(g_conn, query->data);
3667         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3668
3669         ntups = PQntuples(res);
3670         *numAggs = ntups;
3671
3672         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3673
3674         i_tableoid = PQfnumber(res, "tableoid");
3675         i_oid = PQfnumber(res, "oid");
3676         i_aggname = PQfnumber(res, "aggname");
3677         i_aggnamespace = PQfnumber(res, "aggnamespace");
3678         i_pronargs = PQfnumber(res, "pronargs");
3679         i_proargtypes = PQfnumber(res, "proargtypes");
3680         i_rolname = PQfnumber(res, "rolname");
3681         i_aggacl = PQfnumber(res, "aggacl");
3682
3683         for (i = 0; i < ntups; i++)
3684         {
3685                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3686                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3687                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3688                 AssignDumpId(&agginfo[i].aggfn.dobj);
3689                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3690                 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
3691                                                                                         agginfo[i].aggfn.dobj.catId.oid);
3692                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3693                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3694                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3695                                           agginfo[i].aggfn.dobj.name);
3696                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3697                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3698                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3699                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3700                 if (agginfo[i].aggfn.nargs == 0)
3701                         agginfo[i].aggfn.argtypes = NULL;
3702                 else
3703                 {
3704                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3705                         if (g_fout->remoteVersion >= 70300)
3706                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3707                                                           agginfo[i].aggfn.argtypes,
3708                                                           agginfo[i].aggfn.nargs);
3709                         else
3710                                 /* it's just aggbasetype */
3711                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3712                 }
3713
3714                 /* Decide whether we want to dump it */
3715                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3716         }
3717
3718         PQclear(res);
3719
3720         destroyPQExpBuffer(query);
3721
3722         return agginfo;
3723 }
3724
3725 /*
3726  * getFuncs:
3727  *        read all the user-defined functions in the system catalogs and
3728  * return them in the FuncInfo* structure
3729  *
3730  * numFuncs is set to the number of functions read in
3731  */
3732 FuncInfo *
3733 getFuncs(int *numFuncs)
3734 {
3735         PGresult   *res;
3736         int                     ntups;
3737         int                     i;
3738         PQExpBuffer query = createPQExpBuffer();
3739         FuncInfo   *finfo;
3740         int                     i_tableoid;
3741         int                     i_oid;
3742         int                     i_proname;
3743         int                     i_pronamespace;
3744         int                     i_rolname;
3745         int                     i_prolang;
3746         int                     i_pronargs;
3747         int                     i_proargtypes;
3748         int                     i_prorettype;
3749         int                     i_proacl;
3750
3751         /* Make sure we are in proper schema */
3752         selectSourceSchema("pg_catalog");
3753
3754         /*
3755          * Find all user-defined functions.  Normally we can exclude functions in
3756          * pg_catalog, which is worth doing since there are several thousand of
3757          * 'em.  However, there are some extensions that create functions in
3758          * pg_catalog.  In normal dumps we can still ignore those --- but in
3759          * binary-upgrade mode, we must dump the member objects of the extension,
3760          * so be sure to fetch any such functions.
3761          *
3762          * Also, in 9.2 and up, exclude functions that are internally dependent on
3763          * something else, since presumably those will be created as a result of
3764          * creating the something else.  This currently only acts to suppress
3765          * constructor functions for range types.  Note that this is OK only
3766          * because the constructors don't have any dependencies the range type
3767          * doesn't have; otherwise we might not get creation ordering correct.
3768          */
3769
3770         if (g_fout->remoteVersion >= 70300)
3771         {
3772                 appendPQExpBuffer(query,
3773                                                   "SELECT tableoid, oid, proname, prolang, "
3774                                                   "pronargs, proargtypes, prorettype, proacl, "
3775                                                   "pronamespace, "
3776                                                   "(%s proowner) AS rolname "
3777                                                   "FROM pg_proc p "
3778                                                   "WHERE NOT proisagg AND ("
3779                                                   "pronamespace != "
3780                                                   "(SELECT oid FROM pg_namespace "
3781                                                   "WHERE nspname = 'pg_catalog')",
3782                                                   username_subquery);
3783                 if (g_fout->remoteVersion >= 90200)
3784                         appendPQExpBuffer(query,
3785                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
3786                                                           "WHERE classid = 'pg_proc'::regclass AND "
3787                                                           "objid = p.oid AND deptype = 'i')");
3788                 if (binary_upgrade && g_fout->remoteVersion >= 90100)
3789                         appendPQExpBuffer(query,
3790                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3791                                                           "classid = 'pg_proc'::regclass AND "
3792                                                           "objid = p.oid AND "
3793                                                           "refclassid = 'pg_extension'::regclass AND "
3794                                                           "deptype = 'e')");
3795                 appendPQExpBuffer(query, ")");
3796         }
3797         else if (g_fout->remoteVersion >= 70100)
3798         {
3799                 appendPQExpBuffer(query,
3800                                                   "SELECT tableoid, oid, proname, prolang, "
3801                                                   "pronargs, proargtypes, prorettype, "
3802                                                   "'{=X}' AS proacl, "
3803                                                   "0::oid AS pronamespace, "
3804                                                   "(%s proowner) AS rolname "
3805                                                   "FROM pg_proc "
3806                                                   "WHERE pg_proc.oid > '%u'::oid",
3807                                                   username_subquery,
3808                                                   g_last_builtin_oid);
3809         }
3810         else
3811         {
3812                 appendPQExpBuffer(query,
3813                                                   "SELECT "
3814                                                   "(SELECT oid FROM pg_class "
3815                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3816                                                   "oid, proname, prolang, "
3817                                                   "pronargs, proargtypes, prorettype, "
3818                                                   "'{=X}' AS proacl, "
3819                                                   "0::oid AS pronamespace, "
3820                                                   "(%s proowner) AS rolname "
3821                                                   "FROM pg_proc "
3822                                                   "where pg_proc.oid > '%u'::oid",
3823                                                   username_subquery,
3824                                                   g_last_builtin_oid);
3825         }
3826
3827         res = PQexec(g_conn, query->data);
3828         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3829
3830         ntups = PQntuples(res);
3831
3832         *numFuncs = ntups;
3833
3834         finfo = (FuncInfo *) pg_calloc(ntups, sizeof(FuncInfo));
3835
3836         i_tableoid = PQfnumber(res, "tableoid");
3837         i_oid = PQfnumber(res, "oid");
3838         i_proname = PQfnumber(res, "proname");
3839         i_pronamespace = PQfnumber(res, "pronamespace");
3840         i_rolname = PQfnumber(res, "rolname");
3841         i_prolang = PQfnumber(res, "prolang");
3842         i_pronargs = PQfnumber(res, "pronargs");
3843         i_proargtypes = PQfnumber(res, "proargtypes");
3844         i_prorettype = PQfnumber(res, "prorettype");
3845         i_proacl = PQfnumber(res, "proacl");
3846
3847         for (i = 0; i < ntups; i++)
3848         {
3849                 finfo[i].dobj.objType = DO_FUNC;
3850                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3851                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3852                 AssignDumpId(&finfo[i].dobj);
3853                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
3854                 finfo[i].dobj.namespace =
3855                         findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3856                                                   finfo[i].dobj.catId.oid);
3857                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3858                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3859                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3860                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
3861                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3862                 if (finfo[i].nargs == 0)
3863                         finfo[i].argtypes = NULL;
3864                 else
3865                 {
3866                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
3867                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3868                                                   finfo[i].argtypes, finfo[i].nargs);
3869                 }
3870
3871                 /* Decide whether we want to dump it */
3872                 selectDumpableObject(&(finfo[i].dobj));
3873
3874                 if (strlen(finfo[i].rolname) == 0)
3875                         write_msg(NULL,
3876                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3877                                           finfo[i].dobj.name);
3878         }
3879
3880         PQclear(res);
3881
3882         destroyPQExpBuffer(query);
3883
3884         return finfo;
3885 }
3886
3887 /*
3888  * getTables
3889  *        read all the user-defined tables (no indexes, no catalogs)
3890  * in the system catalogs return them in the TableInfo* structure
3891  *
3892  * numTables is set to the number of tables read in
3893  */
3894 TableInfo *
3895 getTables(int *numTables)
3896 {
3897         PGresult   *res;
3898         int                     ntups;
3899         int                     i;
3900         PQExpBuffer query = createPQExpBuffer();
3901         TableInfo  *tblinfo;
3902         int                     i_reltableoid;
3903         int                     i_reloid;
3904         int                     i_relname;
3905         int                     i_relnamespace;
3906         int                     i_relkind;
3907         int                     i_relacl;
3908         int                     i_rolname;
3909         int                     i_relchecks;
3910         int                     i_relhastriggers;
3911         int                     i_relhasindex;
3912         int                     i_relhasrules;
3913         int                     i_relhasoids;
3914         int                     i_relfrozenxid;
3915         int                     i_toastoid;
3916         int                     i_toastfrozenxid;
3917         int                     i_relpersistence;
3918         int                     i_owning_tab;
3919         int                     i_owning_col;
3920         int                     i_reltablespace;
3921         int                     i_reloptions;
3922         int                     i_toastreloptions;
3923         int                     i_reloftype;
3924
3925         /* Make sure we are in proper schema */
3926         selectSourceSchema("pg_catalog");
3927
3928         /*
3929          * Find all the tables (including views and sequences).
3930          *
3931          * We include system catalogs, so that we can work if a user table is
3932          * defined to inherit from a system catalog (pretty weird, but...)
3933          *
3934          * We ignore tables that are not type 'r' (ordinary relation), 'S'
3935          * (sequence), 'v' (view), or 'c' (composite type).
3936          *
3937          * Composite-type table entries won't be dumped as such, but we have to
3938          * make a DumpableObject for them so that we can track dependencies of the
3939          * composite type (pg_depend entries for columns of the composite type
3940          * link to the pg_class entry not the pg_type entry).
3941          *
3942          * Note: in this phase we should collect only a minimal amount of
3943          * information about each table, basically just enough to decide if it is
3944          * interesting. We must fetch all tables in this phase because otherwise
3945          * we cannot correctly identify inherited columns, owned sequences, etc.
3946          */
3947
3948         if (g_fout->remoteVersion >= 90100)
3949         {
3950                 /*
3951                  * Left join to pick up dependency info linking sequences to their
3952                  * owning column, if any (note this dependency is AUTO as of 8.2)
3953                  */
3954                 appendPQExpBuffer(query,
3955                                                   "SELECT c.tableoid, c.oid, c.relname, "
3956                                                   "c.relacl, c.relkind, c.relnamespace, "
3957                                                   "(%s c.relowner) AS rolname, "
3958                                                   "c.relchecks, c.relhastriggers, "
3959                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3960                                                   "c.relfrozenxid, tc.oid AS toid, "
3961                                                   "tc.relfrozenxid AS tfrozenxid, "
3962                                                   "c.relpersistence, "
3963                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3964                                                   "d.refobjid AS owning_tab, "
3965                                                   "d.refobjsubid AS owning_col, "
3966                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3967                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3968                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3969                                                   "FROM pg_class c "
3970                                                   "LEFT JOIN pg_depend d ON "
3971                                                   "(c.relkind = '%c' AND "
3972                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3973                                                   "d.objsubid = 0 AND "
3974                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3975                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3976                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
3977                                                   "ORDER BY c.oid",
3978                                                   username_subquery,
3979                                                   RELKIND_SEQUENCE,
3980                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3981                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
3982                                                   RELKIND_FOREIGN_TABLE);
3983         }
3984         else if (g_fout->remoteVersion >= 90000)
3985         {
3986                 /*
3987                  * Left join to pick up dependency info linking sequences to their
3988                  * owning column, if any (note this dependency is AUTO as of 8.2)
3989                  */
3990                 appendPQExpBuffer(query,
3991                                                   "SELECT c.tableoid, c.oid, c.relname, "
3992                                                   "c.relacl, c.relkind, c.relnamespace, "
3993                                                   "(%s c.relowner) AS rolname, "
3994                                                   "c.relchecks, c.relhastriggers, "
3995                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3996                                                   "c.relfrozenxid, tc.oid AS toid, "
3997                                                   "tc.relfrozenxid AS tfrozenxid, "
3998                                                   "'p' AS relpersistence, "
3999                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4000                                                   "d.refobjid AS owning_tab, "
4001                                                   "d.refobjsubid AS owning_col, "
4002                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4003                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4004                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4005                                                   "FROM pg_class c "
4006                                                   "LEFT JOIN pg_depend d ON "
4007                                                   "(c.relkind = '%c' AND "
4008                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4009                                                   "d.objsubid = 0 AND "
4010                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4011                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4012                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4013                                                   "ORDER BY c.oid",
4014                                                   username_subquery,
4015                                                   RELKIND_SEQUENCE,
4016                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4017                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4018         }
4019         else if (g_fout->remoteVersion >= 80400)
4020         {
4021                 /*
4022                  * Left join to pick up dependency info linking sequences to their
4023                  * owning column, if any (note this dependency is AUTO as of 8.2)
4024                  */
4025                 appendPQExpBuffer(query,
4026                                                   "SELECT c.tableoid, c.oid, c.relname, "
4027                                                   "c.relacl, c.relkind, c.relnamespace, "
4028                                                   "(%s c.relowner) AS rolname, "
4029                                                   "c.relchecks, c.relhastriggers, "
4030                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4031                                                   "c.relfrozenxid, tc.oid AS toid, "
4032                                                   "tc.relfrozenxid AS tfrozenxid, "
4033                                                   "'p' AS relpersistence, "
4034                                                   "NULL AS reloftype, "
4035                                                   "d.refobjid AS owning_tab, "
4036                                                   "d.refobjsubid AS owning_col, "
4037                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4038                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4039                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4040                                                   "FROM pg_class c "
4041                                                   "LEFT JOIN pg_depend d ON "
4042                                                   "(c.relkind = '%c' AND "
4043                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4044                                                   "d.objsubid = 0 AND "
4045                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4046                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4047                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4048                                                   "ORDER BY c.oid",
4049                                                   username_subquery,
4050                                                   RELKIND_SEQUENCE,
4051                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4052                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4053         }
4054         else if (g_fout->remoteVersion >= 80200)
4055         {
4056                 /*
4057                  * Left join to pick up dependency info linking sequences to their
4058                  * owning column, if any (note this dependency is AUTO as of 8.2)
4059                  */
4060                 appendPQExpBuffer(query,
4061                                                   "SELECT c.tableoid, c.oid, c.relname, "
4062                                                   "c.relacl, c.relkind, c.relnamespace, "
4063                                                   "(%s c.relowner) AS rolname, "
4064                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4065                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4066                                                   "c.relfrozenxid, tc.oid AS toid, "
4067                                                   "tc.relfrozenxid AS tfrozenxid, "
4068                                                   "'p' AS relpersistence, "
4069                                                   "NULL AS reloftype, "
4070                                                   "d.refobjid AS owning_tab, "
4071                                                   "d.refobjsubid AS owning_col, "
4072                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4073                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4074                                                   "NULL AS toast_reloptions "
4075                                                   "FROM pg_class c "
4076                                                   "LEFT JOIN pg_depend d ON "
4077                                                   "(c.relkind = '%c' AND "
4078                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4079                                                   "d.objsubid = 0 AND "
4080                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4081                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4082                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4083                                                   "ORDER BY c.oid",
4084                                                   username_subquery,
4085                                                   RELKIND_SEQUENCE,
4086                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4087                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4088         }
4089         else if (g_fout->remoteVersion >= 80000)
4090         {
4091                 /*
4092                  * Left join to pick up dependency info linking sequences to their
4093                  * owning column, if any
4094                  */
4095                 appendPQExpBuffer(query,
4096                                                   "SELECT c.tableoid, c.oid, relname, "
4097                                                   "relacl, relkind, relnamespace, "
4098                                                   "(%s relowner) AS rolname, "
4099                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4100                                                   "relhasindex, relhasrules, relhasoids, "
4101                                                   "0 AS relfrozenxid, "
4102                                                   "0 AS toid, "
4103                                                   "0 AS tfrozenxid, "
4104                                                   "'p' AS relpersistence, "
4105                                                   "NULL AS reloftype, "
4106                                                   "d.refobjid AS owning_tab, "
4107                                                   "d.refobjsubid AS owning_col, "
4108                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4109                                                   "NULL AS reloptions, "
4110                                                   "NULL AS toast_reloptions "
4111                                                   "FROM pg_class c "
4112                                                   "LEFT JOIN pg_depend d ON "
4113                                                   "(c.relkind = '%c' AND "
4114                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4115                                                   "d.objsubid = 0 AND "
4116                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4117                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4118                                                   "ORDER BY c.oid",
4119                                                   username_subquery,
4120                                                   RELKIND_SEQUENCE,
4121                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4122                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4123         }
4124         else if (g_fout->remoteVersion >= 70300)
4125         {
4126                 /*
4127                  * Left join to pick up dependency info linking sequences to their
4128                  * owning column, if any
4129                  */
4130                 appendPQExpBuffer(query,
4131                                                   "SELECT c.tableoid, c.oid, relname, "
4132                                                   "relacl, relkind, relnamespace, "
4133                                                   "(%s relowner) AS rolname, "
4134                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4135                                                   "relhasindex, relhasrules, relhasoids, "
4136                                                   "0 AS relfrozenxid, "
4137                                                   "0 AS toid, "
4138                                                   "0 AS tfrozenxid, "
4139                                                   "'p' AS relpersistence, "
4140                                                   "NULL AS reloftype, "
4141                                                   "d.refobjid AS owning_tab, "
4142                                                   "d.refobjsubid AS owning_col, "
4143                                                   "NULL AS reltablespace, "
4144                                                   "NULL AS reloptions, "
4145                                                   "NULL AS toast_reloptions "
4146                                                   "FROM pg_class c "
4147                                                   "LEFT JOIN pg_depend d ON "
4148                                                   "(c.relkind = '%c' AND "
4149                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4150                                                   "d.objsubid = 0 AND "
4151                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4152                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4153                                                   "ORDER BY c.oid",
4154                                                   username_subquery,
4155                                                   RELKIND_SEQUENCE,
4156                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4157                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4158         }
4159         else if (g_fout->remoteVersion >= 70200)
4160         {
4161                 appendPQExpBuffer(query,
4162                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4163                                                   "0::oid AS relnamespace, "
4164                                                   "(%s relowner) AS rolname, "
4165                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4166                                                   "relhasindex, relhasrules, relhasoids, "
4167                                                   "0 AS relfrozenxid, "
4168                                                   "0 AS toid, "
4169                                                   "0 AS tfrozenxid, "
4170                                                   "'p' AS relpersistence, "
4171                                                   "NULL AS reloftype, "
4172                                                   "NULL::oid AS owning_tab, "
4173                                                   "NULL::int4 AS owning_col, "
4174                                                   "NULL AS reltablespace, "
4175                                                   "NULL AS reloptions, "
4176                                                   "NULL AS toast_reloptions "
4177                                                   "FROM pg_class "
4178                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4179                                                   "ORDER BY oid",
4180                                                   username_subquery,
4181                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4182         }
4183         else if (g_fout->remoteVersion >= 70100)
4184         {
4185                 /* all tables have oids in 7.1 */
4186                 appendPQExpBuffer(query,
4187                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4188                                                   "0::oid AS relnamespace, "
4189                                                   "(%s relowner) AS rolname, "
4190                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4191                                                   "relhasindex, relhasrules, "
4192                                                   "'t'::bool AS relhasoids, "
4193                                                   "0 AS relfrozenxid, "
4194                                                   "0 AS toid, "
4195                                                   "0 AS tfrozenxid, "
4196                                                   "'p' AS relpersistence, "
4197                                                   "NULL AS reloftype, "
4198                                                   "NULL::oid AS owning_tab, "
4199                                                   "NULL::int4 AS owning_col, "
4200                                                   "NULL AS reltablespace, "
4201                                                   "NULL AS reloptions, "
4202                                                   "NULL AS toast_reloptions "
4203                                                   "FROM pg_class "
4204                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4205                                                   "ORDER BY oid",
4206                                                   username_subquery,
4207                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4208         }
4209         else
4210         {
4211                 /*
4212                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4213                  * have a view by looking for a rule in pg_rewrite.
4214                  */
4215                 appendPQExpBuffer(query,
4216                                                   "SELECT "
4217                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4218                                                   "oid, relname, relacl, "
4219                                                   "CASE WHEN relhasrules and relkind = 'r' "
4220                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4221                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4222                                                   "THEN '%c'::\"char\" "
4223                                                   "ELSE relkind END AS relkind,"
4224                                                   "0::oid AS relnamespace, "
4225                                                   "(%s relowner) AS rolname, "
4226                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4227                                                   "relhasindex, relhasrules, "
4228                                                   "'t'::bool AS relhasoids, "
4229                                                   "0 as relfrozenxid, "
4230                                                   "0 AS toid, "
4231                                                   "0 AS tfrozenxid, "
4232                                                   "'p' AS relpersistence, "
4233                                                   "NULL AS reloftype, "
4234                                                   "NULL::oid AS owning_tab, "
4235                                                   "NULL::int4 AS owning_col, "
4236                                                   "NULL AS reltablespace, "
4237                                                   "NULL AS reloptions, "
4238                                                   "NULL AS toast_reloptions "
4239                                                   "FROM pg_class c "
4240                                                   "WHERE relkind IN ('%c', '%c') "
4241                                                   "ORDER BY oid",
4242                                                   RELKIND_VIEW,
4243                                                   username_subquery,
4244                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4245         }
4246
4247         res = PQexec(g_conn, query->data);
4248         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4249
4250         ntups = PQntuples(res);
4251
4252         *numTables = ntups;
4253
4254         /*
4255          * Extract data from result and lock dumpable tables.  We do the locking
4256          * before anything else, to minimize the window wherein a table could
4257          * disappear under us.
4258          *
4259          * Note that we have to save info about all tables here, even when dumping
4260          * only one, because we don't yet know which tables might be inheritance
4261          * ancestors of the target table.
4262          */
4263         tblinfo = (TableInfo *) pg_calloc(ntups, sizeof(TableInfo));
4264
4265         i_reltableoid = PQfnumber(res, "tableoid");
4266         i_reloid = PQfnumber(res, "oid");
4267         i_relname = PQfnumber(res, "relname");
4268         i_relnamespace = PQfnumber(res, "relnamespace");
4269         i_relacl = PQfnumber(res, "relacl");
4270         i_relkind = PQfnumber(res, "relkind");
4271         i_rolname = PQfnumber(res, "rolname");
4272         i_relchecks = PQfnumber(res, "relchecks");
4273         i_relhastriggers = PQfnumber(res, "relhastriggers");
4274         i_relhasindex = PQfnumber(res, "relhasindex");
4275         i_relhasrules = PQfnumber(res, "relhasrules");
4276         i_relhasoids = PQfnumber(res, "relhasoids");
4277         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4278         i_toastoid = PQfnumber(res, "toid");
4279         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4280         i_relpersistence = PQfnumber(res, "relpersistence");
4281         i_owning_tab = PQfnumber(res, "owning_tab");
4282         i_owning_col = PQfnumber(res, "owning_col");
4283         i_reltablespace = PQfnumber(res, "reltablespace");
4284         i_reloptions = PQfnumber(res, "reloptions");
4285         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4286         i_reloftype = PQfnumber(res, "reloftype");
4287
4288         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
4289         {
4290                 /*
4291                  * Arrange to fail instead of waiting forever for a table lock.
4292                  *
4293                  * NB: this coding assumes that the only queries issued within the
4294                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4295                  * applied to other things too.
4296                  */
4297                 resetPQExpBuffer(query);
4298                 appendPQExpBuffer(query, "SET statement_timeout = ");
4299                 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
4300                 do_sql_command(g_conn, query->data);
4301         }
4302
4303         for (i = 0; i < ntups; i++)
4304         {
4305                 tblinfo[i].dobj.objType = DO_TABLE;
4306                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4307                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4308                 AssignDumpId(&tblinfo[i].dobj);
4309                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4310                 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
4311                                                                                                   tblinfo[i].dobj.catId.oid);
4312                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4313                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4314                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4315                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4316                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4317                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4318                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4319                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4320                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4321                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4322                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4323                 if (PQgetisnull(res, i, i_reloftype))
4324                         tblinfo[i].reloftype = NULL;
4325                 else
4326                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4327                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4328                 if (PQgetisnull(res, i, i_owning_tab))
4329                 {
4330                         tblinfo[i].owning_tab = InvalidOid;
4331                         tblinfo[i].owning_col = 0;
4332                 }
4333                 else
4334                 {
4335                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4336                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4337                 }
4338                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4339                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4340                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4341
4342                 /* other fields were zeroed above */
4343
4344                 /*
4345                  * Decide whether we want to dump this table.
4346                  */
4347                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4348                         tblinfo[i].dobj.dump = false;
4349                 else
4350                         selectDumpableTable(&tblinfo[i]);
4351                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4352
4353                 /*
4354                  * Read-lock target tables to make sure they aren't DROPPED or altered
4355                  * in schema before we get around to dumping them.
4356                  *
4357                  * Note that we don't explicitly lock parents of the target tables; we
4358                  * assume our lock on the child is enough to prevent schema
4359                  * alterations to parent tables.
4360                  *
4361                  * NOTE: it'd be kinda nice to lock other relations too, not only
4362                  * plain tables, but the backend doesn't presently allow that.
4363                  */
4364                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4365                 {
4366                         resetPQExpBuffer(query);
4367                         appendPQExpBuffer(query,
4368                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4369                                                  fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
4370                                                                                 tblinfo[i].dobj.name));
4371                         do_sql_command(g_conn, query->data);
4372                 }
4373
4374                 /* Emit notice if join for owner failed */
4375                 if (strlen(tblinfo[i].rolname) == 0)
4376                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4377                                           tblinfo[i].dobj.name);
4378         }
4379
4380         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
4381         {
4382                 do_sql_command(g_conn, "SET statement_timeout = 0");
4383         }
4384
4385         PQclear(res);
4386
4387         /*
4388          * Force sequences that are "owned" by table columns to be dumped whenever
4389          * their owning table is being dumped.
4390          */
4391         for (i = 0; i < ntups; i++)
4392         {
4393                 TableInfo  *seqinfo = &tblinfo[i];
4394                 int                     j;
4395
4396                 if (!OidIsValid(seqinfo->owning_tab))
4397                         continue;                       /* not an owned sequence */
4398                 if (seqinfo->dobj.dump)
4399                         continue;                       /* no need to search */
4400
4401                 /* can't use findTableByOid yet, unfortunately */
4402                 for (j = 0; j < ntups; j++)
4403                 {
4404                         if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
4405                         {
4406                                 if (tblinfo[j].dobj.dump)
4407                                 {
4408                                         seqinfo->interesting = true;
4409                                         seqinfo->dobj.dump = true;
4410                                 }
4411                                 break;
4412                         }
4413                 }
4414         }
4415
4416         destroyPQExpBuffer(query);
4417
4418         return tblinfo;
4419 }
4420
4421 /*
4422  * getInherits
4423  *        read all the inheritance information
4424  * from the system catalogs return them in the InhInfo* structure
4425  *
4426  * numInherits is set to the number of pairs read in
4427  */
4428 InhInfo *
4429 getInherits(int *numInherits)
4430 {
4431         PGresult   *res;
4432         int                     ntups;
4433         int                     i;
4434         PQExpBuffer query = createPQExpBuffer();
4435         InhInfo    *inhinfo;
4436
4437         int                     i_inhrelid;
4438         int                     i_inhparent;
4439
4440         /* Make sure we are in proper schema */
4441         selectSourceSchema("pg_catalog");
4442
4443         /* find all the inheritance information */
4444
4445         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4446
4447         res = PQexec(g_conn, query->data);
4448         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4449
4450         ntups = PQntuples(res);
4451
4452         *numInherits = ntups;
4453
4454         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4455
4456         i_inhrelid = PQfnumber(res, "inhrelid");
4457         i_inhparent = PQfnumber(res, "inhparent");
4458
4459         for (i = 0; i < ntups; i++)
4460         {
4461                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4462                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4463         }
4464
4465         PQclear(res);
4466
4467         destroyPQExpBuffer(query);
4468
4469         return inhinfo;
4470 }
4471
4472 /*
4473  * getIndexes
4474  *        get information about every index on a dumpable table
4475  *
4476  * Note: index data is not returned directly to the caller, but it
4477  * does get entered into the DumpableObject tables.
4478  */
4479 void
4480 getIndexes(TableInfo tblinfo[], int numTables)
4481 {
4482         int                     i,
4483                                 j;
4484         PQExpBuffer query = createPQExpBuffer();
4485         PGresult   *res;
4486         IndxInfo   *indxinfo;
4487         ConstraintInfo *constrinfo;
4488         int                     i_tableoid,
4489                                 i_oid,
4490                                 i_indexname,
4491                                 i_indexdef,
4492                                 i_indnkeys,
4493                                 i_indkey,
4494                                 i_indisclustered,
4495                                 i_contype,
4496                                 i_conname,
4497                                 i_condeferrable,
4498                                 i_condeferred,
4499                                 i_contableoid,
4500                                 i_conoid,
4501                                 i_condef,
4502                                 i_tablespace,
4503                                 i_options;
4504         int                     ntups;
4505
4506         for (i = 0; i < numTables; i++)
4507         {
4508                 TableInfo  *tbinfo = &tblinfo[i];
4509
4510                 /* Only plain tables have indexes */
4511                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
4512                         continue;
4513
4514                 /* Ignore indexes of tables not to be dumped */
4515                 if (!tbinfo->dobj.dump)
4516                         continue;
4517
4518                 if (g_verbose)
4519                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4520                                           tbinfo->dobj.name);
4521
4522                 /* Make sure we are in proper schema so indexdef is right */
4523                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4524
4525                 /*
4526                  * The point of the messy-looking outer join is to find a constraint
4527                  * that is related by an internal dependency link to the index. If we
4528                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4529                  * assume an index won't have more than one internal dependency.
4530                  *
4531                  * As of 9.0 we don't need to look at pg_depend but can check for a
4532                  * match to pg_constraint.conindid.  The check on conrelid is
4533                  * redundant but useful because that column is indexed while conindid
4534                  * is not.
4535                  */
4536                 resetPQExpBuffer(query);
4537                 if (g_fout->remoteVersion >= 90000)
4538                 {
4539                         appendPQExpBuffer(query,
4540                                                           "SELECT t.tableoid, t.oid, "
4541                                                           "t.relname AS indexname, "
4542                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4543                                                           "t.relnatts AS indnkeys, "
4544                                                           "i.indkey, i.indisclustered, "
4545                                                           "c.contype, c.conname, "
4546                                                           "c.condeferrable, c.condeferred, "
4547                                                           "c.tableoid AS contableoid, "
4548                                                           "c.oid AS conoid, "
4549                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4550                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4551                                                         "array_to_string(t.reloptions, ', ') AS options "
4552                                                           "FROM pg_catalog.pg_index i "
4553                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4554                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4555                                                           "ON (i.indrelid = c.conrelid AND "
4556                                                           "i.indexrelid = c.conindid AND "
4557                                                           "c.contype IN ('p','u','x')) "
4558                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4559                                                           "ORDER BY indexname",
4560                                                           tbinfo->dobj.catId.oid);
4561                 }
4562                 else if (g_fout->remoteVersion >= 80200)
4563                 {
4564                         appendPQExpBuffer(query,
4565                                                           "SELECT t.tableoid, t.oid, "
4566                                                           "t.relname AS indexname, "
4567                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4568                                                           "t.relnatts AS indnkeys, "
4569                                                           "i.indkey, i.indisclustered, "
4570                                                           "c.contype, c.conname, "
4571                                                           "c.condeferrable, c.condeferred, "
4572                                                           "c.tableoid AS contableoid, "
4573                                                           "c.oid AS conoid, "
4574                                                           "null AS condef, "
4575                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4576                                                         "array_to_string(t.reloptions, ', ') AS options "
4577                                                           "FROM pg_catalog.pg_index i "
4578                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4579                                                           "LEFT JOIN pg_catalog.pg_depend d "
4580                                                           "ON (d.classid = t.tableoid "
4581                                                           "AND d.objid = t.oid "
4582                                                           "AND d.deptype = 'i') "
4583                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4584                                                           "ON (d.refclassid = c.tableoid "
4585                                                           "AND d.refobjid = c.oid) "
4586                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4587                                                           "ORDER BY indexname",
4588                                                           tbinfo->dobj.catId.oid);
4589                 }
4590                 else if (g_fout->remoteVersion >= 80000)
4591                 {
4592                         appendPQExpBuffer(query,
4593                                                           "SELECT t.tableoid, t.oid, "
4594                                                           "t.relname AS indexname, "
4595                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4596                                                           "t.relnatts AS indnkeys, "
4597                                                           "i.indkey, i.indisclustered, "
4598                                                           "c.contype, c.conname, "
4599                                                           "c.condeferrable, c.condeferred, "
4600                                                           "c.tableoid AS contableoid, "
4601                                                           "c.oid AS conoid, "
4602                                                           "null AS condef, "
4603                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4604                                                           "null AS options "
4605                                                           "FROM pg_catalog.pg_index i "
4606                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4607                                                           "LEFT JOIN pg_catalog.pg_depend d "
4608                                                           "ON (d.classid = t.tableoid "
4609                                                           "AND d.objid = t.oid "
4610                                                           "AND d.deptype = 'i') "
4611                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4612                                                           "ON (d.refclassid = c.tableoid "
4613                                                           "AND d.refobjid = c.oid) "
4614                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4615                                                           "ORDER BY indexname",
4616                                                           tbinfo->dobj.catId.oid);
4617                 }
4618                 else if (g_fout->remoteVersion >= 70300)
4619                 {
4620                         appendPQExpBuffer(query,
4621                                                           "SELECT t.tableoid, t.oid, "
4622                                                           "t.relname AS indexname, "
4623                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4624                                                           "t.relnatts AS indnkeys, "
4625                                                           "i.indkey, i.indisclustered, "
4626                                                           "c.contype, c.conname, "
4627                                                           "c.condeferrable, c.condeferred, "
4628                                                           "c.tableoid AS contableoid, "
4629                                                           "c.oid AS conoid, "
4630                                                           "null AS condef, "
4631                                                           "NULL AS tablespace, "
4632                                                           "null AS options "
4633                                                           "FROM pg_catalog.pg_index i "
4634                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4635                                                           "LEFT JOIN pg_catalog.pg_depend d "
4636                                                           "ON (d.classid = t.tableoid "
4637                                                           "AND d.objid = t.oid "
4638                                                           "AND d.deptype = 'i') "
4639                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4640                                                           "ON (d.refclassid = c.tableoid "
4641                                                           "AND d.refobjid = c.oid) "
4642                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4643                                                           "ORDER BY indexname",
4644                                                           tbinfo->dobj.catId.oid);
4645                 }
4646                 else if (g_fout->remoteVersion >= 70100)
4647                 {
4648                         appendPQExpBuffer(query,
4649                                                           "SELECT t.tableoid, t.oid, "
4650                                                           "t.relname AS indexname, "
4651                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4652                                                           "t.relnatts AS indnkeys, "
4653                                                           "i.indkey, false AS indisclustered, "
4654                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4655                                                           "ELSE '0'::char END AS contype, "
4656                                                           "t.relname AS conname, "
4657                                                           "false AS condeferrable, "
4658                                                           "false AS condeferred, "
4659                                                           "0::oid AS contableoid, "
4660                                                           "t.oid AS conoid, "
4661                                                           "null AS condef, "
4662                                                           "NULL AS tablespace, "
4663                                                           "null AS options "
4664                                                           "FROM pg_index i, pg_class t "
4665                                                           "WHERE t.oid = i.indexrelid "
4666                                                           "AND i.indrelid = '%u'::oid "
4667                                                           "ORDER BY indexname",
4668                                                           tbinfo->dobj.catId.oid);
4669                 }
4670                 else
4671                 {
4672                         appendPQExpBuffer(query,
4673                                                           "SELECT "
4674                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4675                                                           "t.oid, "
4676                                                           "t.relname AS indexname, "
4677                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4678                                                           "t.relnatts AS indnkeys, "
4679                                                           "i.indkey, false AS indisclustered, "
4680                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4681                                                           "ELSE '0'::char END AS contype, "
4682                                                           "t.relname AS conname, "
4683                                                           "false AS condeferrable, "
4684                                                           "false AS condeferred, "
4685                                                           "0::oid AS contableoid, "
4686                                                           "t.oid AS conoid, "
4687                                                           "null AS condef, "
4688                                                           "NULL AS tablespace, "
4689                                                           "null AS options "
4690                                                           "FROM pg_index i, pg_class t "
4691                                                           "WHERE t.oid = i.indexrelid "
4692                                                           "AND i.indrelid = '%u'::oid "
4693                                                           "ORDER BY indexname",
4694                                                           tbinfo->dobj.catId.oid);
4695                 }
4696
4697                 res = PQexec(g_conn, query->data);
4698                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4699
4700                 ntups = PQntuples(res);
4701
4702                 i_tableoid = PQfnumber(res, "tableoid");
4703                 i_oid = PQfnumber(res, "oid");
4704                 i_indexname = PQfnumber(res, "indexname");
4705                 i_indexdef = PQfnumber(res, "indexdef");
4706                 i_indnkeys = PQfnumber(res, "indnkeys");
4707                 i_indkey = PQfnumber(res, "indkey");
4708                 i_indisclustered = PQfnumber(res, "indisclustered");
4709                 i_contype = PQfnumber(res, "contype");
4710                 i_conname = PQfnumber(res, "conname");
4711                 i_condeferrable = PQfnumber(res, "condeferrable");
4712                 i_condeferred = PQfnumber(res, "condeferred");
4713                 i_contableoid = PQfnumber(res, "contableoid");
4714                 i_conoid = PQfnumber(res, "conoid");
4715                 i_condef = PQfnumber(res, "condef");
4716                 i_tablespace = PQfnumber(res, "tablespace");
4717                 i_options = PQfnumber(res, "options");
4718
4719                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
4720                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4721
4722                 for (j = 0; j < ntups; j++)
4723                 {
4724                         char            contype;
4725
4726                         indxinfo[j].dobj.objType = DO_INDEX;
4727                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4728                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4729                         AssignDumpId(&indxinfo[j].dobj);
4730                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
4731                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4732                         indxinfo[j].indextable = tbinfo;
4733                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
4734                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
4735                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
4736                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
4737
4738                         /*
4739                          * In pre-7.4 releases, indkeys may contain more entries than
4740                          * indnkeys says (since indnkeys will be 1 for a functional
4741                          * index).      We don't actually care about this case since we don't
4742                          * examine indkeys except for indexes associated with PRIMARY and
4743                          * UNIQUE constraints, which are never functional indexes. But we
4744                          * have to allocate enough space to keep parseOidArray from
4745                          * complaining.
4746                          */
4747                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
4748                         parseOidArray(PQgetvalue(res, j, i_indkey),
4749                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
4750                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4751                         contype = *(PQgetvalue(res, j, i_contype));
4752
4753                         if (contype == 'p' || contype == 'u' || contype == 'x')
4754                         {
4755                                 /*
4756                                  * If we found a constraint matching the index, create an
4757                                  * entry for it.
4758                                  *
4759                                  * In a pre-7.3 database, we take this path iff the index was
4760                                  * marked indisprimary.
4761                                  */
4762                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
4763                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4764                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4765                                 AssignDumpId(&constrinfo[j].dobj);
4766                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4767                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4768                                 constrinfo[j].contable = tbinfo;
4769                                 constrinfo[j].condomain = NULL;
4770                                 constrinfo[j].contype = contype;
4771                                 if (contype == 'x')
4772                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4773                                 else
4774                                         constrinfo[j].condef = NULL;
4775                                 constrinfo[j].confrelid = InvalidOid;
4776                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
4777                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
4778                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
4779                                 constrinfo[j].conislocal = true;
4780                                 constrinfo[j].separate = true;
4781
4782                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
4783
4784                                 /* If pre-7.3 DB, better make sure table comes first */
4785                                 addObjectDependency(&constrinfo[j].dobj,
4786                                                                         tbinfo->dobj.dumpId);
4787                         }
4788                         else
4789                         {
4790                                 /* Plain secondary index */
4791                                 indxinfo[j].indexconstraint = 0;
4792                         }
4793                 }
4794
4795                 PQclear(res);
4796         }
4797
4798         destroyPQExpBuffer(query);
4799 }
4800
4801 /*
4802  * getConstraints
4803  *
4804  * Get info about constraints on dumpable tables.
4805  *
4806  * Currently handles foreign keys only.
4807  * Unique and primary key constraints are handled with indexes,
4808  * while check constraints are processed in getTableAttrs().
4809  */
4810 void
4811 getConstraints(TableInfo tblinfo[], int numTables)
4812 {
4813         int                     i,
4814                                 j;
4815         ConstraintInfo *constrinfo;
4816         PQExpBuffer query;
4817         PGresult   *res;
4818         int                     i_contableoid,
4819                                 i_conoid,
4820                                 i_conname,
4821                                 i_confrelid,
4822                                 i_condef;
4823         int                     ntups;
4824
4825         /* pg_constraint was created in 7.3, so nothing to do if older */
4826         if (g_fout->remoteVersion < 70300)
4827                 return;
4828
4829         query = createPQExpBuffer();
4830
4831         for (i = 0; i < numTables; i++)
4832         {
4833                 TableInfo  *tbinfo = &tblinfo[i];
4834
4835                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4836                         continue;
4837
4838                 if (g_verbose)
4839                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
4840                                           tbinfo->dobj.name);
4841
4842                 /*
4843                  * select table schema to ensure constraint expr is qualified if
4844                  * needed
4845                  */
4846                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4847
4848                 resetPQExpBuffer(query);
4849                 appendPQExpBuffer(query,
4850                                                   "SELECT tableoid, oid, conname, confrelid, "
4851                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
4852                                                   "FROM pg_catalog.pg_constraint "
4853                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4854                                                   "AND contype = 'f'",
4855                                                   tbinfo->dobj.catId.oid);
4856                 res = PQexec(g_conn, query->data);
4857                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4858
4859                 ntups = PQntuples(res);
4860
4861                 i_contableoid = PQfnumber(res, "tableoid");
4862                 i_conoid = PQfnumber(res, "oid");
4863                 i_conname = PQfnumber(res, "conname");
4864                 i_confrelid = PQfnumber(res, "confrelid");
4865                 i_condef = PQfnumber(res, "condef");
4866
4867                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4868
4869                 for (j = 0; j < ntups; j++)
4870                 {
4871                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
4872                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4873                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4874                         AssignDumpId(&constrinfo[j].dobj);
4875                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4876                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4877                         constrinfo[j].contable = tbinfo;
4878                         constrinfo[j].condomain = NULL;
4879                         constrinfo[j].contype = 'f';
4880                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4881                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
4882                         constrinfo[j].conindex = 0;
4883                         constrinfo[j].condeferrable = false;
4884                         constrinfo[j].condeferred = false;
4885                         constrinfo[j].conislocal = true;
4886                         constrinfo[j].separate = true;
4887                 }
4888
4889                 PQclear(res);
4890         }
4891
4892         destroyPQExpBuffer(query);
4893 }
4894
4895 /*
4896  * getDomainConstraints
4897  *
4898  * Get info about constraints on a domain.
4899  */
4900 static void
4901 getDomainConstraints(TypeInfo *tyinfo)
4902 {
4903         int                     i;
4904         ConstraintInfo *constrinfo;
4905         PQExpBuffer query;
4906         PGresult   *res;
4907         int                     i_tableoid,
4908                                 i_oid,
4909                                 i_conname,
4910                                 i_consrc;
4911         int                     ntups;
4912
4913         /* pg_constraint was created in 7.3, so nothing to do if older */
4914         if (g_fout->remoteVersion < 70300)
4915                 return;
4916
4917         /*
4918          * select appropriate schema to ensure names in constraint are properly
4919          * qualified
4920          */
4921         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
4922
4923         query = createPQExpBuffer();
4924
4925         if (g_fout->remoteVersion >= 90100)
4926                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4927                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4928                                                   "convalidated "
4929                                                   "FROM pg_catalog.pg_constraint "
4930                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4931                                                   "ORDER BY conname",
4932                                                   tyinfo->dobj.catId.oid);
4933
4934         else if (g_fout->remoteVersion >= 70400)
4935                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4936                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4937                                                   "true as convalidated "
4938                                                   "FROM pg_catalog.pg_constraint "
4939                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4940                                                   "ORDER BY conname",
4941                                                   tyinfo->dobj.catId.oid);
4942         else
4943                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4944                                                   "'CHECK (' || consrc || ')' AS consrc, "
4945                                                   "true as convalidated "
4946                                                   "FROM pg_catalog.pg_constraint "
4947                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4948                                                   "ORDER BY conname",
4949                                                   tyinfo->dobj.catId.oid);
4950
4951         res = PQexec(g_conn, query->data);
4952         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4953
4954         ntups = PQntuples(res);
4955
4956         i_tableoid = PQfnumber(res, "tableoid");
4957         i_oid = PQfnumber(res, "oid");
4958         i_conname = PQfnumber(res, "conname");
4959         i_consrc = PQfnumber(res, "consrc");
4960
4961         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4962
4963         tyinfo->nDomChecks = ntups;
4964         tyinfo->domChecks = constrinfo;
4965
4966         for (i = 0; i < ntups; i++)
4967         {
4968                 bool    validated = PQgetvalue(res, i, 4)[0] == 't';
4969
4970                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4971                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4972                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4973                 AssignDumpId(&constrinfo[i].dobj);
4974                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4975                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
4976                 constrinfo[i].contable = NULL;
4977                 constrinfo[i].condomain = tyinfo;
4978                 constrinfo[i].contype = 'c';
4979                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
4980                 constrinfo[i].confrelid = InvalidOid;
4981                 constrinfo[i].conindex = 0;
4982                 constrinfo[i].condeferrable = false;
4983                 constrinfo[i].condeferred = false;
4984                 constrinfo[i].conislocal = true;
4985
4986                 constrinfo[i].separate = !validated;
4987
4988                 /*
4989                  * Make the domain depend on the constraint, ensuring it won't be
4990                  * output till any constraint dependencies are OK.  If the constraint
4991                  * has not been validated, it's going to be dumped after the domain
4992                  * anyway, so this doesn't matter.
4993                  */
4994                 if (validated)
4995                         addObjectDependency(&tyinfo->dobj,
4996                                                                 constrinfo[i].dobj.dumpId);
4997         }
4998
4999         PQclear(res);
5000
5001         destroyPQExpBuffer(query);
5002 }
5003
5004 /*
5005  * getRules
5006  *        get basic information about every rule in the system
5007  *
5008  * numRules is set to the number of rules read in
5009  */
5010 RuleInfo *
5011 getRules(int *numRules)
5012 {
5013         PGresult   *res;
5014         int                     ntups;
5015         int                     i;
5016         PQExpBuffer query = createPQExpBuffer();
5017         RuleInfo   *ruleinfo;
5018         int                     i_tableoid;
5019         int                     i_oid;
5020         int                     i_rulename;
5021         int                     i_ruletable;
5022         int                     i_ev_type;
5023         int                     i_is_instead;
5024         int                     i_ev_enabled;
5025
5026         /* Make sure we are in proper schema */
5027         selectSourceSchema("pg_catalog");
5028
5029         if (g_fout->remoteVersion >= 80300)
5030         {
5031                 appendPQExpBuffer(query, "SELECT "
5032                                                   "tableoid, oid, rulename, "
5033                                                   "ev_class AS ruletable, ev_type, is_instead, "
5034                                                   "ev_enabled "
5035                                                   "FROM pg_rewrite "
5036                                                   "ORDER BY oid");
5037         }
5038         else if (g_fout->remoteVersion >= 70100)
5039         {
5040                 appendPQExpBuffer(query, "SELECT "
5041                                                   "tableoid, oid, rulename, "
5042                                                   "ev_class AS ruletable, ev_type, is_instead, "
5043                                                   "'O'::char AS ev_enabled "
5044                                                   "FROM pg_rewrite "
5045                                                   "ORDER BY oid");
5046         }
5047         else
5048         {
5049                 appendPQExpBuffer(query, "SELECT "
5050                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5051                                                   "oid, rulename, "
5052                                                   "ev_class AS ruletable, ev_type, is_instead, "
5053                                                   "'O'::char AS ev_enabled "
5054                                                   "FROM pg_rewrite "
5055                                                   "ORDER BY oid");
5056         }
5057
5058         res = PQexec(g_conn, query->data);
5059         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5060
5061         ntups = PQntuples(res);
5062
5063         *numRules = ntups;
5064
5065         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5066
5067         i_tableoid = PQfnumber(res, "tableoid");
5068         i_oid = PQfnumber(res, "oid");
5069         i_rulename = PQfnumber(res, "rulename");
5070         i_ruletable = PQfnumber(res, "ruletable");
5071         i_ev_type = PQfnumber(res, "ev_type");
5072         i_is_instead = PQfnumber(res, "is_instead");
5073         i_ev_enabled = PQfnumber(res, "ev_enabled");
5074
5075         for (i = 0; i < ntups; i++)
5076         {
5077                 Oid                     ruletableoid;
5078
5079                 ruleinfo[i].dobj.objType = DO_RULE;
5080                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5081                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5082                 AssignDumpId(&ruleinfo[i].dobj);
5083                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5084                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5085                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5086                 if (ruleinfo[i].ruletable == NULL)
5087                 {
5088                         write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5089                                           ruletableoid,
5090                                           ruleinfo[i].dobj.catId.oid);
5091                         exit_nicely();
5092                 }
5093                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5094                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5095                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5096                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5097                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5098                 if (ruleinfo[i].ruletable)
5099                 {
5100                         /*
5101                          * If the table is a view, force its ON SELECT rule to be sorted
5102                          * before the view itself --- this ensures that any dependencies
5103                          * for the rule affect the table's positioning. Other rules are
5104                          * forced to appear after their table.
5105                          */
5106                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
5107                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5108                         {
5109                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5110                                                                         ruleinfo[i].dobj.dumpId);
5111                                 /* We'll merge the rule into CREATE VIEW, if possible */
5112                                 ruleinfo[i].separate = false;
5113                         }
5114                         else
5115                         {
5116                                 addObjectDependency(&ruleinfo[i].dobj,
5117                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5118                                 ruleinfo[i].separate = true;
5119                         }
5120                 }
5121                 else
5122                         ruleinfo[i].separate = true;
5123         }
5124
5125         PQclear(res);
5126
5127         destroyPQExpBuffer(query);
5128
5129         return ruleinfo;
5130 }
5131
5132 /*
5133  * getTriggers
5134  *        get information about every trigger on a dumpable table
5135  *
5136  * Note: trigger data is not returned directly to the caller, but it
5137  * does get entered into the DumpableObject tables.
5138  */
5139 void
5140 getTriggers(TableInfo tblinfo[], int numTables)
5141 {
5142         int                     i,
5143                                 j;
5144         PQExpBuffer query = createPQExpBuffer();
5145         PGresult   *res;
5146         TriggerInfo *tginfo;
5147         int                     i_tableoid,
5148                                 i_oid,
5149                                 i_tgname,
5150                                 i_tgfname,
5151                                 i_tgtype,
5152                                 i_tgnargs,
5153                                 i_tgargs,
5154                                 i_tgisconstraint,
5155                                 i_tgconstrname,
5156                                 i_tgconstrrelid,
5157                                 i_tgconstrrelname,
5158                                 i_tgenabled,
5159                                 i_tgdeferrable,
5160                                 i_tginitdeferred,
5161                                 i_tgdef;
5162         int                     ntups;
5163
5164         for (i = 0; i < numTables; i++)
5165         {
5166                 TableInfo  *tbinfo = &tblinfo[i];
5167
5168                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5169                         continue;
5170
5171                 if (g_verbose)
5172                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5173                                           tbinfo->dobj.name);
5174
5175                 /*
5176                  * select table schema to ensure regproc name is qualified if needed
5177                  */
5178                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
5179
5180                 resetPQExpBuffer(query);
5181                 if (g_fout->remoteVersion >= 90000)
5182                 {
5183                         /*
5184                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5185                          * could result in non-forward-compatible dumps of WHEN clauses
5186                          * due to under-parenthesization.
5187                          */
5188                         appendPQExpBuffer(query,
5189                                                           "SELECT tgname, "
5190                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5191                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5192                                                           "tgenabled, tableoid, oid "
5193                                                           "FROM pg_catalog.pg_trigger t "
5194                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5195                                                           "AND NOT tgisinternal",
5196                                                           tbinfo->dobj.catId.oid);
5197                 }
5198                 else if (g_fout->remoteVersion >= 80300)
5199                 {
5200                         /*
5201                          * We ignore triggers that are tied to a foreign-key constraint
5202                          */
5203                         appendPQExpBuffer(query,
5204                                                           "SELECT tgname, "
5205                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5206                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5207                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5208                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5209                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5210                                                           "FROM pg_catalog.pg_trigger t "
5211                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5212                                                           "AND tgconstraint = 0",
5213                                                           tbinfo->dobj.catId.oid);
5214                 }
5215                 else if (g_fout->remoteVersion >= 70300)
5216                 {
5217                         /*
5218                          * We ignore triggers that are tied to a foreign-key constraint,
5219                          * but in these versions we have to grovel through pg_constraint
5220                          * to find out
5221                          */
5222                         appendPQExpBuffer(query,
5223                                                           "SELECT tgname, "
5224                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5225                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5226                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5227                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5228                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5229                                                           "FROM pg_catalog.pg_trigger t "
5230                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5231                                                           "AND (NOT tgisconstraint "
5232                                                           " OR NOT EXISTS"
5233                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5234                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5235                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5236                                                           tbinfo->dobj.catId.oid);
5237                 }
5238                 else if (g_fout->remoteVersion >= 70100)
5239                 {
5240                         appendPQExpBuffer(query,
5241                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5242                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5243                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5244                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5245                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5246                                                           "             AS tgconstrrelname "
5247                                                           "FROM pg_trigger "
5248                                                           "WHERE tgrelid = '%u'::oid",
5249                                                           tbinfo->dobj.catId.oid);
5250                 }
5251                 else
5252                 {
5253                         appendPQExpBuffer(query,
5254                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5255                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5256                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5257                                                           "tgconstrrelid, tginitdeferred, "
5258                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5259                                                           "oid, "
5260                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5261                                                           "             AS tgconstrrelname "
5262                                                           "FROM pg_trigger "
5263                                                           "WHERE tgrelid = '%u'::oid",
5264                                                           tbinfo->dobj.catId.oid);
5265                 }
5266                 res = PQexec(g_conn, query->data);
5267                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5268
5269                 ntups = PQntuples(res);
5270
5271                 i_tableoid = PQfnumber(res, "tableoid");
5272                 i_oid = PQfnumber(res, "oid");
5273                 i_tgname = PQfnumber(res, "tgname");
5274                 i_tgfname = PQfnumber(res, "tgfname");
5275                 i_tgtype = PQfnumber(res, "tgtype");
5276                 i_tgnargs = PQfnumber(res, "tgnargs");
5277                 i_tgargs = PQfnumber(res, "tgargs");
5278                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5279                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5280                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5281                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5282                 i_tgenabled = PQfnumber(res, "tgenabled");
5283                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5284                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5285                 i_tgdef = PQfnumber(res, "tgdef");
5286
5287                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5288
5289                 for (j = 0; j < ntups; j++)
5290                 {
5291                         tginfo[j].dobj.objType = DO_TRIGGER;
5292                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5293                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5294                         AssignDumpId(&tginfo[j].dobj);
5295                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5296                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5297                         tginfo[j].tgtable = tbinfo;
5298                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5299                         if (i_tgdef >= 0)
5300                         {
5301                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5302
5303                                 /* remaining fields are not valid if we have tgdef */
5304                                 tginfo[j].tgfname = NULL;
5305                                 tginfo[j].tgtype = 0;
5306                                 tginfo[j].tgnargs = 0;
5307                                 tginfo[j].tgargs = NULL;
5308                                 tginfo[j].tgisconstraint = false;
5309                                 tginfo[j].tgdeferrable = false;
5310                                 tginfo[j].tginitdeferred = false;
5311                                 tginfo[j].tgconstrname = NULL;
5312                                 tginfo[j].tgconstrrelid = InvalidOid;
5313                                 tginfo[j].tgconstrrelname = NULL;
5314                         }
5315                         else
5316                         {
5317                                 tginfo[j].tgdef = NULL;
5318
5319                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5320                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5321                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5322                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5323                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5324                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5325                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5326
5327                                 if (tginfo[j].tgisconstraint)
5328                                 {
5329                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5330                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5331                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5332                                         {
5333                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5334                                                 {
5335                                                         write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5336                                                                           tginfo[j].dobj.name, tbinfo->dobj.name,
5337                                                                           tginfo[j].tgconstrrelid);
5338                                                         exit_nicely();
5339                                                 }
5340                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5341                                         }
5342                                         else
5343                                                 tginfo[j].tgconstrrelname = NULL;
5344                                 }
5345                                 else
5346                                 {
5347                                         tginfo[j].tgconstrname = NULL;
5348                                         tginfo[j].tgconstrrelid = InvalidOid;
5349                                         tginfo[j].tgconstrrelname = NULL;
5350                                 }
5351                         }
5352                 }
5353
5354                 PQclear(res);
5355         }
5356
5357         destroyPQExpBuffer(query);
5358 }
5359
5360 /*
5361  * getProcLangs
5362  *        get basic information about every procedural language in the system
5363  *
5364  * numProcLangs is set to the number of langs read in
5365  *
5366  * NB: this must run after getFuncs() because we assume we can do
5367  * findFuncByOid().
5368  */
5369 ProcLangInfo *
5370 getProcLangs(int *numProcLangs)
5371 {
5372         PGresult   *res;
5373         int                     ntups;
5374         int                     i;
5375         PQExpBuffer query = createPQExpBuffer();
5376         ProcLangInfo *planginfo;
5377         int                     i_tableoid;
5378         int                     i_oid;
5379         int                     i_lanname;
5380         int                     i_lanpltrusted;
5381         int                     i_lanplcallfoid;
5382         int                     i_laninline;
5383         int                     i_lanvalidator;
5384         int                     i_lanacl;
5385         int                     i_lanowner;
5386
5387         /* Make sure we are in proper schema */
5388         selectSourceSchema("pg_catalog");
5389
5390         if (g_fout->remoteVersion >= 90000)
5391         {
5392                 /* pg_language has a laninline column */
5393                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5394                                                   "lanname, lanpltrusted, lanplcallfoid, "
5395                                                   "laninline, lanvalidator,  lanacl, "
5396                                                   "(%s lanowner) AS lanowner "
5397                                                   "FROM pg_language "
5398                                                   "WHERE lanispl "
5399                                                   "ORDER BY oid",
5400                                                   username_subquery);
5401         }
5402         else if (g_fout->remoteVersion >= 80300)
5403         {
5404                 /* pg_language has a lanowner column */
5405                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5406                                                   "lanname, lanpltrusted, lanplcallfoid, "
5407                                                   "lanvalidator,  lanacl, "
5408                                                   "(%s lanowner) AS lanowner "
5409                                                   "FROM pg_language "
5410                                                   "WHERE lanispl "
5411                                                   "ORDER BY oid",
5412                                                   username_subquery);
5413         }
5414         else if (g_fout->remoteVersion >= 80100)
5415         {
5416                 /* Languages are owned by the bootstrap superuser, OID 10 */
5417                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5418                                                   "(%s '10') AS lanowner "
5419                                                   "FROM pg_language "
5420                                                   "WHERE lanispl "
5421                                                   "ORDER BY oid",
5422                                                   username_subquery);
5423         }
5424         else if (g_fout->remoteVersion >= 70400)
5425         {
5426                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5427                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5428                                                   "(%s '1') AS lanowner "
5429                                                   "FROM pg_language "
5430                                                   "WHERE lanispl "
5431                                                   "ORDER BY oid",
5432                                                   username_subquery);
5433         }
5434         else if (g_fout->remoteVersion >= 70100)
5435         {
5436                 /* No clear notion of an owner at all before 7.4 ... */
5437                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5438                                                   "WHERE lanispl "
5439                                                   "ORDER BY oid");
5440         }
5441         else
5442         {
5443                 appendPQExpBuffer(query, "SELECT "
5444                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5445                                                   "oid, * FROM pg_language "
5446                                                   "WHERE lanispl "
5447                                                   "ORDER BY oid");
5448         }
5449
5450         res = PQexec(g_conn, query->data);
5451         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5452
5453         ntups = PQntuples(res);
5454
5455         *numProcLangs = ntups;
5456
5457         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5458
5459         i_tableoid = PQfnumber(res, "tableoid");
5460         i_oid = PQfnumber(res, "oid");
5461         i_lanname = PQfnumber(res, "lanname");
5462         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5463         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5464         /* these may fail and return -1: */
5465         i_laninline = PQfnumber(res, "laninline");
5466         i_lanvalidator = PQfnumber(res, "lanvalidator");
5467         i_lanacl = PQfnumber(res, "lanacl");
5468         i_lanowner = PQfnumber(res, "lanowner");
5469
5470         for (i = 0; i < ntups; i++)
5471         {
5472                 planginfo[i].dobj.objType = DO_PROCLANG;
5473                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5474                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5475                 AssignDumpId(&planginfo[i].dobj);
5476
5477                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5478                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5479                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5480                 if (i_laninline >= 0)
5481                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5482                 else
5483                         planginfo[i].laninline = InvalidOid;
5484                 if (i_lanvalidator >= 0)
5485                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5486                 else
5487                         planginfo[i].lanvalidator = InvalidOid;
5488                 if (i_lanacl >= 0)
5489                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5490                 else
5491                         planginfo[i].lanacl = pg_strdup("{=U}");
5492                 if (i_lanowner >= 0)
5493                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5494                 else
5495                         planginfo[i].lanowner = pg_strdup("");
5496
5497                 if (g_fout->remoteVersion < 70300)
5498                 {
5499                         /*
5500                          * We need to make a dependency to ensure the function will be
5501                          * dumped first.  (In 7.3 and later the regular dependency
5502                          * mechanism will handle this for us.)
5503                          */
5504                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5505
5506                         if (funcInfo)
5507                                 addObjectDependency(&planginfo[i].dobj,
5508                                                                         funcInfo->dobj.dumpId);
5509                 }
5510         }
5511
5512         PQclear(res);
5513
5514         destroyPQExpBuffer(query);
5515
5516         return planginfo;
5517 }
5518
5519 /*
5520  * getCasts
5521  *        get basic information about every cast in the system
5522  *
5523  * numCasts is set to the number of casts read in
5524  */
5525 CastInfo *
5526 getCasts(int *numCasts)
5527 {
5528         PGresult   *res;
5529         int                     ntups;
5530         int                     i;
5531         PQExpBuffer query = createPQExpBuffer();
5532         CastInfo   *castinfo;
5533         int                     i_tableoid;
5534         int                     i_oid;
5535         int                     i_castsource;
5536         int                     i_casttarget;
5537         int                     i_castfunc;
5538         int                     i_castcontext;
5539         int                     i_castmethod;
5540
5541         /* Make sure we are in proper schema */
5542         selectSourceSchema("pg_catalog");
5543
5544         if (g_fout->remoteVersion >= 80400)
5545         {
5546                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5547                                                   "castsource, casttarget, castfunc, castcontext, "
5548                                                   "castmethod "
5549                                                   "FROM pg_cast ORDER BY 3,4");
5550         }
5551         else if (g_fout->remoteVersion >= 70300)
5552         {
5553                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5554                                                   "castsource, casttarget, castfunc, castcontext, "
5555                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
5556                                                   "FROM pg_cast ORDER BY 3,4");
5557         }
5558         else
5559         {
5560                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
5561                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
5562                                                   "p.oid AS castfunc, 'e' AS castcontext, "
5563                                                   "'f' AS castmethod "
5564                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
5565                                                   "WHERE p.pronargs = 1 AND "
5566                                                   "p.proargtypes[0] = t1.oid AND "
5567                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
5568                                                   "ORDER BY 3,4");
5569         }
5570
5571         res = PQexec(g_conn, query->data);
5572         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5573
5574         ntups = PQntuples(res);
5575
5576         *numCasts = ntups;
5577
5578         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
5579
5580         i_tableoid = PQfnumber(res, "tableoid");
5581         i_oid = PQfnumber(res, "oid");
5582         i_castsource = PQfnumber(res, "castsource");
5583         i_casttarget = PQfnumber(res, "casttarget");
5584         i_castfunc = PQfnumber(res, "castfunc");
5585         i_castcontext = PQfnumber(res, "castcontext");
5586         i_castmethod = PQfnumber(res, "castmethod");
5587
5588         for (i = 0; i < ntups; i++)
5589         {
5590                 PQExpBufferData namebuf;
5591                 TypeInfo   *sTypeInfo;
5592                 TypeInfo   *tTypeInfo;
5593
5594                 castinfo[i].dobj.objType = DO_CAST;
5595                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5596                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5597                 AssignDumpId(&castinfo[i].dobj);
5598                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
5599                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
5600                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
5601                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
5602                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
5603
5604                 /*
5605                  * Try to name cast as concatenation of typnames.  This is only used
5606                  * for purposes of sorting.  If we fail to find either type, the name
5607                  * will be an empty string.
5608                  */
5609                 initPQExpBuffer(&namebuf);
5610                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
5611                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
5612                 if (sTypeInfo && tTypeInfo)
5613                         appendPQExpBuffer(&namebuf, "%s %s",
5614                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
5615                 castinfo[i].dobj.name = namebuf.data;
5616
5617                 if (OidIsValid(castinfo[i].castfunc))
5618                 {
5619                         /*
5620                          * We need to make a dependency to ensure the function will be
5621                          * dumped first.  (In 7.3 and later the regular dependency
5622                          * mechanism will handle this for us.)
5623                          */
5624                         FuncInfo   *funcInfo;
5625
5626                         funcInfo = findFuncByOid(castinfo[i].castfunc);
5627                         if (funcInfo)
5628                                 addObjectDependency(&castinfo[i].dobj,
5629                                                                         funcInfo->dobj.dumpId);
5630                 }
5631         }
5632
5633         PQclear(res);
5634
5635         destroyPQExpBuffer(query);
5636
5637         return castinfo;
5638 }
5639
5640 /*
5641  * getTableAttrs -
5642  *        for each interesting table, read info about its attributes
5643  *        (names, types, default values, CHECK constraints, etc)
5644  *
5645  * This is implemented in a very inefficient way right now, looping
5646  * through the tblinfo and doing a join per table to find the attrs and their
5647  * types.  However, because we want type names and so forth to be named
5648  * relative to the schema of each table, we couldn't do it in just one
5649  * query.  (Maybe one query per schema?)
5650  *
5651  *      modifies tblinfo
5652  */
5653 void
5654 getTableAttrs(TableInfo *tblinfo, int numTables)
5655 {
5656         int                     i,
5657                                 j;
5658         PQExpBuffer q = createPQExpBuffer();
5659         int                     i_attnum;
5660         int                     i_attname;
5661         int                     i_atttypname;
5662         int                     i_atttypmod;
5663         int                     i_attstattarget;
5664         int                     i_attstorage;
5665         int                     i_typstorage;
5666         int                     i_attnotnull;
5667         int                     i_atthasdef;
5668         int                     i_attisdropped;
5669         int                     i_attlen;
5670         int                     i_attalign;
5671         int                     i_attislocal;
5672         int                     i_attoptions;
5673         int                     i_attcollation;
5674         int                     i_attfdwoptions;
5675         PGresult   *res;
5676         int                     ntups;
5677         bool            hasdefaults;
5678
5679         for (i = 0; i < numTables; i++)
5680         {
5681                 TableInfo  *tbinfo = &tblinfo[i];
5682
5683                 /* Don't bother to collect info for sequences */
5684                 if (tbinfo->relkind == RELKIND_SEQUENCE)
5685                         continue;
5686
5687                 /* Don't bother with uninteresting tables, either */
5688                 if (!tbinfo->interesting)
5689                         continue;
5690
5691                 /*
5692                  * Make sure we are in proper schema for this table; this allows
5693                  * correct retrieval of formatted type names and default exprs
5694                  */
5695                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
5696
5697                 /* find all the user attributes and their types */
5698
5699                 /*
5700                  * we must read the attribute names in attribute number order! because
5701                  * we will use the attnum to index into the attnames array later.  We
5702                  * actually ask to order by "attrelid, attnum" because (at least up to
5703                  * 7.3) the planner is not smart enough to realize it needn't re-sort
5704                  * the output of an indexscan on pg_attribute_relid_attnum_index.
5705                  */
5706                 if (g_verbose)
5707                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
5708                                           tbinfo->dobj.name);
5709
5710                 resetPQExpBuffer(q);
5711
5712                 if (g_fout->remoteVersion >= 90200)
5713                 {
5714                         /*
5715                          * attfdwoptions is new in 9.2.
5716                          */
5717                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5718                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5719                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5720                                                           "a.attlen, a.attalign, a.attislocal, "
5721                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5722                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5723                                                           "CASE WHEN a.attcollation <> t.typcollation "
5724                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5725                                                           "pg_catalog.array_to_string(ARRAY("
5726                                                           "SELECT pg_catalog.quote_ident(option_name) || "
5727                                                           "' ' || pg_catalog.quote_literal(option_value) "
5728                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions)"
5729                                                           "), E',\n    ') AS attfdwoptions "
5730                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5731                                                           "ON a.atttypid = t.oid "
5732                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5733                                                           "AND a.attnum > 0::pg_catalog.int2 "
5734                                                           "ORDER BY a.attrelid, a.attnum",
5735                                                           tbinfo->dobj.catId.oid);
5736                 }
5737                 else if (g_fout->remoteVersion >= 90100)
5738                 {
5739                         /*
5740                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
5741                          * clauses for attributes whose collation is different from their
5742                          * type's default, we use a CASE here to suppress uninteresting
5743                          * attcollations cheaply.
5744                          */
5745                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5746                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5747                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5748                                                           "a.attlen, a.attalign, a.attislocal, "
5749                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5750                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5751                                                           "CASE WHEN a.attcollation <> t.typcollation "
5752                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5753                                                           "NULL AS attfdwoptions "
5754                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5755                                                           "ON a.atttypid = t.oid "
5756                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5757                                                           "AND a.attnum > 0::pg_catalog.int2 "
5758                                                           "ORDER BY a.attrelid, a.attnum",
5759                                                           tbinfo->dobj.catId.oid);
5760                 }
5761                 else if (g_fout->remoteVersion >= 90000)
5762                 {
5763                         /* attoptions is new in 9.0 */
5764                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5765                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5766                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5767                                                           "a.attlen, a.attalign, a.attislocal, "
5768                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5769                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5770                                                           "0 AS attcollation, "
5771                                                           "NULL AS attfdwoptions "
5772                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5773                                                           "ON a.atttypid = t.oid "
5774                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5775                                                           "AND a.attnum > 0::pg_catalog.int2 "
5776                                                           "ORDER BY a.attrelid, a.attnum",
5777                                                           tbinfo->dobj.catId.oid);
5778                 }
5779                 else if (g_fout->remoteVersion >= 70300)
5780                 {
5781                         /* need left join here to not fail on dropped columns ... */
5782                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5783                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5784                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5785                                                           "a.attlen, a.attalign, a.attislocal, "
5786                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5787                                                           "'' AS attoptions, 0 AS attcollation, "
5788                                                           "NULL AS attfdwoptions "
5789                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5790                                                           "ON a.atttypid = t.oid "
5791                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5792                                                           "AND a.attnum > 0::pg_catalog.int2 "
5793                                                           "ORDER BY a.attrelid, a.attnum",
5794                                                           tbinfo->dobj.catId.oid);
5795                 }
5796                 else if (g_fout->remoteVersion >= 70100)
5797                 {
5798                         /*
5799                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
5800                          * we don't dump it because we can't tell whether it's been
5801                          * explicitly set or was just a default.
5802                          */
5803                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5804                                                           "-1 AS attstattarget, a.attstorage, "
5805                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
5806                                                           "false AS attisdropped, a.attlen, "
5807                                                           "a.attalign, false AS attislocal, "
5808                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
5809                                                           "'' AS attoptions, 0 AS attcollation, "
5810                                                           "NULL AS attfdwoptions "
5811                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
5812                                                           "ON a.atttypid = t.oid "
5813                                                           "WHERE a.attrelid = '%u'::oid "
5814                                                           "AND a.attnum > 0::int2 "
5815                                                           "ORDER BY a.attrelid, a.attnum",
5816                                                           tbinfo->dobj.catId.oid);
5817                 }
5818                 else
5819                 {
5820                         /* format_type not available before 7.1 */
5821                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
5822                                                           "-1 AS attstattarget, "
5823                                                           "attstorage, attstorage AS typstorage, "
5824                                                           "attnotnull, atthasdef, false AS attisdropped, "
5825                                                           "attlen, attalign, "
5826                                                           "false AS attislocal, "
5827                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
5828                                                           "'' AS attoptions, 0 AS attcollation, "
5829                                                           "NULL AS attfdwoptions "
5830                                                           "FROM pg_attribute a "
5831                                                           "WHERE attrelid = '%u'::oid "
5832                                                           "AND attnum > 0::int2 "
5833                                                           "ORDER BY attrelid, attnum",
5834                                                           tbinfo->dobj.catId.oid);
5835                 }
5836
5837                 res = PQexec(g_conn, q->data);
5838                 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5839
5840                 ntups = PQntuples(res);
5841
5842                 i_attnum = PQfnumber(res, "attnum");
5843                 i_attname = PQfnumber(res, "attname");
5844                 i_atttypname = PQfnumber(res, "atttypname");
5845                 i_atttypmod = PQfnumber(res, "atttypmod");
5846                 i_attstattarget = PQfnumber(res, "attstattarget");
5847                 i_attstorage = PQfnumber(res, "attstorage");
5848                 i_typstorage = PQfnumber(res, "typstorage");
5849                 i_attnotnull = PQfnumber(res, "attnotnull");
5850                 i_atthasdef = PQfnumber(res, "atthasdef");
5851                 i_attisdropped = PQfnumber(res, "attisdropped");
5852                 i_attlen = PQfnumber(res, "attlen");
5853                 i_attalign = PQfnumber(res, "attalign");
5854                 i_attislocal = PQfnumber(res, "attislocal");
5855                 i_attoptions = PQfnumber(res, "attoptions");
5856                 i_attcollation = PQfnumber(res, "attcollation");
5857                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
5858
5859                 tbinfo->numatts = ntups;
5860                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
5861                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
5862                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
5863                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
5864                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
5865                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
5866                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
5867                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
5868                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
5869                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
5870                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
5871                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
5872                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
5873                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
5874                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
5875                 tbinfo->inhAttrs = (bool *) pg_malloc(ntups * sizeof(bool));
5876                 tbinfo->inhAttrDef = (bool *) pg_malloc(ntups * sizeof(bool));
5877                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
5878                 hasdefaults = false;
5879
5880                 for (j = 0; j < ntups; j++)
5881                 {
5882                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
5883                         {
5884                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
5885                                                   tbinfo->dobj.name);
5886                                 exit_nicely();
5887                         }
5888                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
5889                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
5890                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
5891                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
5892                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
5893                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
5894                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
5895                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
5896                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
5897                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
5898                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
5899                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
5900                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
5901                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
5902                         tbinfo->attrdefs[j] = NULL; /* fix below */
5903                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
5904                                 hasdefaults = true;
5905                         /* these flags will be set in flagInhAttrs() */
5906                         tbinfo->inhAttrs[j] = false;
5907                         tbinfo->inhAttrDef[j] = false;
5908                         tbinfo->inhNotNull[j] = false;
5909                 }
5910
5911                 PQclear(res);
5912
5913                 /*
5914                  * Get info about column defaults
5915                  */
5916                 if (hasdefaults)
5917                 {
5918                         AttrDefInfo *attrdefs;
5919                         int                     numDefaults;
5920
5921                         if (g_verbose)
5922                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
5923                                                   tbinfo->dobj.name);
5924
5925                         resetPQExpBuffer(q);
5926                         if (g_fout->remoteVersion >= 70300)
5927                         {
5928                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
5929                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
5930                                                                   "FROM pg_catalog.pg_attrdef "
5931                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
5932                                                                   tbinfo->dobj.catId.oid);
5933                         }
5934                         else if (g_fout->remoteVersion >= 70200)
5935                         {
5936                                 /* 7.2 did not have OIDs in pg_attrdef */
5937                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
5938                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
5939                                                                   "FROM pg_attrdef "
5940                                                                   "WHERE adrelid = '%u'::oid",
5941                                                                   tbinfo->dobj.catId.oid);
5942                         }
5943                         else if (g_fout->remoteVersion >= 70100)
5944                         {
5945                                 /* no pg_get_expr, so must rely on adsrc */
5946                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
5947                                                                   "FROM pg_attrdef "
5948                                                                   "WHERE adrelid = '%u'::oid",
5949                                                                   tbinfo->dobj.catId.oid);
5950                         }
5951                         else
5952                         {
5953                                 /* no pg_get_expr, no tableoid either */
5954                                 appendPQExpBuffer(q, "SELECT "
5955                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
5956                                                                   "oid, adnum, adsrc "
5957                                                                   "FROM pg_attrdef "
5958                                                                   "WHERE adrelid = '%u'::oid",
5959                                                                   tbinfo->dobj.catId.oid);
5960                         }
5961                         res = PQexec(g_conn, q->data);
5962                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5963
5964                         numDefaults = PQntuples(res);
5965                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
5966
5967                         for (j = 0; j < numDefaults; j++)
5968                         {
5969                                 int                     adnum;
5970
5971                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
5972                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5973                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5974                                 AssignDumpId(&attrdefs[j].dobj);
5975                                 attrdefs[j].adtable = tbinfo;
5976                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
5977                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
5978
5979                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
5980                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
5981
5982                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
5983
5984                                 /*
5985                                  * Defaults on a VIEW must always be dumped as separate ALTER
5986                                  * TABLE commands.      Defaults on regular tables are dumped as
5987                                  * part of the CREATE TABLE if possible.  To check if it's
5988                                  * safe, we mark the default as needing to appear before the
5989                                  * CREATE.
5990                                  */
5991                                 if (tbinfo->relkind == RELKIND_VIEW)
5992                                 {
5993                                         attrdefs[j].separate = true;
5994                                         /* needed in case pre-7.3 DB: */
5995                                         addObjectDependency(&attrdefs[j].dobj,
5996                                                                                 tbinfo->dobj.dumpId);
5997                                 }
5998                                 else
5999                                 {
6000                                         attrdefs[j].separate = false;
6001                                         addObjectDependency(&tbinfo->dobj,
6002                                                                                 attrdefs[j].dobj.dumpId);
6003                                 }
6004
6005                                 if (adnum <= 0 || adnum > ntups)
6006                                 {
6007                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
6008                                                           adnum, tbinfo->dobj.name);
6009                                         exit_nicely();
6010                                 }
6011                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6012                         }
6013                         PQclear(res);
6014                 }
6015
6016                 /*
6017                  * Get info about table CHECK constraints
6018                  */
6019                 if (tbinfo->ncheck > 0)
6020                 {
6021                         ConstraintInfo *constrs;
6022                         int                     numConstrs;
6023
6024                         if (g_verbose)
6025                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6026                                                   tbinfo->dobj.name);
6027
6028                         resetPQExpBuffer(q);
6029                         if (g_fout->remoteVersion >= 90200)
6030                         {
6031                                 /*
6032                                  * conisonly and convalidated are new in 9.2 (actually, the latter
6033                                  * is there in 9.1, but it wasn't ever false for check constraints
6034                                  * until 9.2).
6035                                  */
6036                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6037                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6038                                                                   "conislocal, convalidated, conisonly "
6039                                                                   "FROM pg_catalog.pg_constraint "
6040                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6041                                                                   "   AND contype = 'c' "
6042                                                                   "ORDER BY conname",
6043                                                                   tbinfo->dobj.catId.oid);
6044                         }
6045                         else if (g_fout->remoteVersion >= 80400)
6046                         {
6047                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6048                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6049                                                                   "conislocal, true AS convalidated, "
6050                                                                   "false as conisonly "
6051                                                                   "FROM pg_catalog.pg_constraint "
6052                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6053                                                                   "   AND contype = 'c' "
6054                                                                   "ORDER BY conname",
6055                                                                   tbinfo->dobj.catId.oid);
6056                         }
6057                         else if (g_fout->remoteVersion >= 70400)
6058                         {
6059                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6060                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6061                                                                   "true AS conislocal, true AS convalidated, "
6062                                                                   "false as conisonly "
6063                                                                   "FROM pg_catalog.pg_constraint "
6064                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6065                                                                   "   AND contype = 'c' "
6066                                                                   "ORDER BY conname",
6067                                                                   tbinfo->dobj.catId.oid);
6068                         }
6069                         else if (g_fout->remoteVersion >= 70300)
6070                         {
6071                                 /* no pg_get_constraintdef, must use consrc */
6072                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6073                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6074                                                                   "true AS conislocal, true AS convalidated, "
6075                                                                   "false as conisonly "
6076                                                                   "FROM pg_catalog.pg_constraint "
6077                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6078                                                                   "   AND contype = 'c' "
6079                                                                   "ORDER BY conname",
6080                                                                   tbinfo->dobj.catId.oid);
6081                         }
6082                         else if (g_fout->remoteVersion >= 70200)
6083                         {
6084                                 /* 7.2 did not have OIDs in pg_relcheck */
6085                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6086                                                                   "rcname AS conname, "
6087                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6088                                                                   "true AS conislocal, true AS convalidated, "
6089                                                                   "false as conisonly "
6090                                                                   "FROM pg_relcheck "
6091                                                                   "WHERE rcrelid = '%u'::oid "
6092                                                                   "ORDER BY rcname",
6093                                                                   tbinfo->dobj.catId.oid);
6094                         }
6095                         else if (g_fout->remoteVersion >= 70100)
6096                         {
6097                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6098                                                                   "rcname AS conname, "
6099                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6100                                                                   "true AS conislocal, true AS convalidated, "
6101                                                                   "false as conisonly "
6102                                                                   "FROM pg_relcheck "
6103                                                                   "WHERE rcrelid = '%u'::oid "
6104                                                                   "ORDER BY rcname",
6105                                                                   tbinfo->dobj.catId.oid);
6106                         }
6107                         else
6108                         {
6109                                 /* no tableoid in 7.0 */
6110                                 appendPQExpBuffer(q, "SELECT "
6111                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6112                                                                   "oid, rcname AS conname, "
6113                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6114                                                                   "true AS conislocal, true AS convalidated, "
6115                                                                   "false as conisonly "
6116                                                                   "FROM pg_relcheck "
6117                                                                   "WHERE rcrelid = '%u'::oid "
6118                                                                   "ORDER BY rcname",
6119                                                                   tbinfo->dobj.catId.oid);
6120                         }
6121                         res = PQexec(g_conn, q->data);
6122                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
6123
6124                         numConstrs = PQntuples(res);
6125                         if (numConstrs != tbinfo->ncheck)
6126                         {
6127                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6128                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6129                                                                                  tbinfo->ncheck),
6130                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6131                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6132                                 exit_nicely();
6133                         }
6134
6135                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6136                         tbinfo->checkexprs = constrs;
6137
6138                         for (j = 0; j < numConstrs; j++)
6139                         {
6140                                 bool    validated = PQgetvalue(res, j, 5)[0] == 't';
6141                                 bool    isonly = PQgetvalue(res, j, 6)[0] == 't';
6142
6143                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6144                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6145                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6146                                 AssignDumpId(&constrs[j].dobj);
6147                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6148                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6149                                 constrs[j].contable = tbinfo;
6150                                 constrs[j].condomain = NULL;
6151                                 constrs[j].contype = 'c';
6152                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6153                                 constrs[j].confrelid = InvalidOid;
6154                                 constrs[j].conindex = 0;
6155                                 constrs[j].condeferrable = false;
6156                                 constrs[j].condeferred = false;
6157                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6158                                 constrs[j].conisonly = isonly;
6159                                 /*
6160                                  * An unvalidated constraint needs to be dumped separately, so
6161                                  * that potentially-violating existing data is loaded before
6162                                  * the constraint.  An ONLY constraint needs to be dumped
6163                                  * separately too.
6164                                  */
6165                                 constrs[j].separate = !validated || isonly;
6166
6167                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6168
6169                                 /*
6170                                  * Mark the constraint as needing to appear before the table
6171                                  * --- this is so that any other dependencies of the
6172                                  * constraint will be emitted before we try to create the
6173                                  * table.  If the constraint is to be dumped separately, it will be
6174                                  * dumped after data is loaded anyway, so don't do it.  (There's
6175                                  * an automatic dependency in the opposite direction anyway, so
6176                                  * don't need to add one manually here.)
6177                                  */
6178                                 if (!constrs[j].separate)
6179                                         addObjectDependency(&tbinfo->dobj,
6180                                                                                 constrs[j].dobj.dumpId);
6181
6182                                 /*
6183                                  * If the constraint is inherited, this will be detected later
6184                                  * (in pre-8.4 databases).      We also detect later if the
6185                                  * constraint must be split out from the table definition.
6186                                  */
6187                         }
6188                         PQclear(res);
6189                 }
6190         }
6191
6192         destroyPQExpBuffer(q);
6193 }
6194
6195
6196 /*
6197  * getTSParsers:
6198  *        read all text search parsers in the system catalogs and return them
6199  *        in the TSParserInfo* structure
6200  *
6201  *      numTSParsers is set to the number of parsers read in
6202  */
6203 TSParserInfo *
6204 getTSParsers(int *numTSParsers)
6205 {
6206         PGresult   *res;
6207         int                     ntups;
6208         int                     i;
6209         PQExpBuffer query = createPQExpBuffer();
6210         TSParserInfo *prsinfo;
6211         int                     i_tableoid;
6212         int                     i_oid;
6213         int                     i_prsname;
6214         int                     i_prsnamespace;
6215         int                     i_prsstart;
6216         int                     i_prstoken;
6217         int                     i_prsend;
6218         int                     i_prsheadline;
6219         int                     i_prslextype;
6220
6221         /* Before 8.3, there is no built-in text search support */
6222         if (g_fout->remoteVersion < 80300)
6223         {
6224                 *numTSParsers = 0;
6225                 return NULL;
6226         }
6227
6228         /*
6229          * find all text search objects, including builtin ones; we filter out
6230          * system-defined objects at dump-out time.
6231          */
6232
6233         /* Make sure we are in proper schema */
6234         selectSourceSchema("pg_catalog");
6235
6236         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6237                                           "prsstart::oid, prstoken::oid, "
6238                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6239                                           "FROM pg_ts_parser");
6240
6241         res = PQexec(g_conn, query->data);
6242         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6243
6244         ntups = PQntuples(res);
6245         *numTSParsers = ntups;
6246
6247         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6248
6249         i_tableoid = PQfnumber(res, "tableoid");
6250         i_oid = PQfnumber(res, "oid");
6251         i_prsname = PQfnumber(res, "prsname");
6252         i_prsnamespace = PQfnumber(res, "prsnamespace");
6253         i_prsstart = PQfnumber(res, "prsstart");
6254         i_prstoken = PQfnumber(res, "prstoken");
6255         i_prsend = PQfnumber(res, "prsend");
6256         i_prsheadline = PQfnumber(res, "prsheadline");
6257         i_prslextype = PQfnumber(res, "prslextype");
6258
6259         for (i = 0; i < ntups; i++)
6260         {
6261                 prsinfo[i].dobj.objType = DO_TSPARSER;
6262                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6263                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6264                 AssignDumpId(&prsinfo[i].dobj);
6265                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6266                 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
6267                                                                                                   prsinfo[i].dobj.catId.oid);
6268                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6269                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6270                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6271                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6272                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6273
6274                 /* Decide whether we want to dump it */
6275                 selectDumpableObject(&(prsinfo[i].dobj));
6276         }
6277
6278         PQclear(res);
6279
6280         destroyPQExpBuffer(query);
6281
6282         return prsinfo;
6283 }
6284
6285 /*
6286  * getTSDictionaries:
6287  *        read all text search dictionaries in the system catalogs and return them
6288  *        in the TSDictInfo* structure
6289  *
6290  *      numTSDicts is set to the number of dictionaries read in
6291  */
6292 TSDictInfo *
6293 getTSDictionaries(int *numTSDicts)
6294 {
6295         PGresult   *res;
6296         int                     ntups;
6297         int                     i;
6298         PQExpBuffer query = createPQExpBuffer();
6299         TSDictInfo *dictinfo;
6300         int                     i_tableoid;
6301         int                     i_oid;
6302         int                     i_dictname;
6303         int                     i_dictnamespace;
6304         int                     i_rolname;
6305         int                     i_dicttemplate;
6306         int                     i_dictinitoption;
6307
6308         /* Before 8.3, there is no built-in text search support */
6309         if (g_fout->remoteVersion < 80300)
6310         {
6311                 *numTSDicts = 0;
6312                 return NULL;
6313         }
6314
6315         /* Make sure we are in proper schema */
6316         selectSourceSchema("pg_catalog");
6317
6318         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6319                                           "dictnamespace, (%s dictowner) AS rolname, "
6320                                           "dicttemplate, dictinitoption "
6321                                           "FROM pg_ts_dict",
6322                                           username_subquery);
6323
6324         res = PQexec(g_conn, query->data);
6325         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6326
6327         ntups = PQntuples(res);
6328         *numTSDicts = ntups;
6329
6330         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6331
6332         i_tableoid = PQfnumber(res, "tableoid");
6333         i_oid = PQfnumber(res, "oid");
6334         i_dictname = PQfnumber(res, "dictname");
6335         i_dictnamespace = PQfnumber(res, "dictnamespace");
6336         i_rolname = PQfnumber(res, "rolname");
6337         i_dictinitoption = PQfnumber(res, "dictinitoption");
6338         i_dicttemplate = PQfnumber(res, "dicttemplate");
6339
6340         for (i = 0; i < ntups; i++)
6341         {
6342                 dictinfo[i].dobj.objType = DO_TSDICT;
6343                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6344                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6345                 AssignDumpId(&dictinfo[i].dobj);
6346                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6347                 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
6348                                                                                                  dictinfo[i].dobj.catId.oid);
6349                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6350                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6351                 if (PQgetisnull(res, i, i_dictinitoption))
6352                         dictinfo[i].dictinitoption = NULL;
6353                 else
6354                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6355
6356                 /* Decide whether we want to dump it */
6357                 selectDumpableObject(&(dictinfo[i].dobj));
6358         }
6359
6360         PQclear(res);
6361
6362         destroyPQExpBuffer(query);
6363
6364         return dictinfo;
6365 }
6366
6367 /*
6368  * getTSTemplates:
6369  *        read all text search templates in the system catalogs and return them
6370  *        in the TSTemplateInfo* structure
6371  *
6372  *      numTSTemplates is set to the number of templates read in
6373  */
6374 TSTemplateInfo *
6375 getTSTemplates(int *numTSTemplates)
6376 {
6377         PGresult   *res;
6378         int                     ntups;
6379         int                     i;
6380         PQExpBuffer query = createPQExpBuffer();
6381         TSTemplateInfo *tmplinfo;
6382         int                     i_tableoid;
6383         int                     i_oid;
6384         int                     i_tmplname;
6385         int                     i_tmplnamespace;
6386         int                     i_tmplinit;
6387         int                     i_tmpllexize;
6388
6389         /* Before 8.3, there is no built-in text search support */
6390         if (g_fout->remoteVersion < 80300)
6391         {
6392                 *numTSTemplates = 0;
6393                 return NULL;
6394         }
6395
6396         /* Make sure we are in proper schema */
6397         selectSourceSchema("pg_catalog");
6398
6399         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6400                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6401                                           "FROM pg_ts_template");
6402
6403         res = PQexec(g_conn, query->data);
6404         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6405
6406         ntups = PQntuples(res);
6407         *numTSTemplates = ntups;
6408
6409         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6410
6411         i_tableoid = PQfnumber(res, "tableoid");
6412         i_oid = PQfnumber(res, "oid");
6413         i_tmplname = PQfnumber(res, "tmplname");
6414         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6415         i_tmplinit = PQfnumber(res, "tmplinit");
6416         i_tmpllexize = PQfnumber(res, "tmpllexize");
6417
6418         for (i = 0; i < ntups; i++)
6419         {
6420                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6421                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6422                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6423                 AssignDumpId(&tmplinfo[i].dobj);
6424                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6425                 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
6426                                                                                                  tmplinfo[i].dobj.catId.oid);
6427                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6428                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6429
6430                 /* Decide whether we want to dump it */
6431                 selectDumpableObject(&(tmplinfo[i].dobj));
6432         }
6433
6434         PQclear(res);
6435
6436         destroyPQExpBuffer(query);
6437
6438         return tmplinfo;
6439 }
6440
6441 /*
6442  * getTSConfigurations:
6443  *        read all text search configurations in the system catalogs and return
6444  *        them in the TSConfigInfo* structure
6445  *
6446  *      numTSConfigs is set to the number of configurations read in
6447  */
6448 TSConfigInfo *
6449 getTSConfigurations(int *numTSConfigs)
6450 {
6451         PGresult   *res;
6452         int                     ntups;
6453         int                     i;
6454         PQExpBuffer query = createPQExpBuffer();
6455         TSConfigInfo *cfginfo;
6456         int                     i_tableoid;
6457         int                     i_oid;
6458         int                     i_cfgname;
6459         int                     i_cfgnamespace;
6460         int                     i_rolname;
6461         int                     i_cfgparser;
6462
6463         /* Before 8.3, there is no built-in text search support */
6464         if (g_fout->remoteVersion < 80300)
6465         {
6466                 *numTSConfigs = 0;
6467                 return NULL;
6468         }
6469
6470         /* Make sure we are in proper schema */
6471         selectSourceSchema("pg_catalog");
6472
6473         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6474                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6475                                           "FROM pg_ts_config",
6476                                           username_subquery);
6477
6478         res = PQexec(g_conn, query->data);
6479         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6480
6481         ntups = PQntuples(res);
6482         *numTSConfigs = ntups;
6483
6484         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6485
6486         i_tableoid = PQfnumber(res, "tableoid");
6487         i_oid = PQfnumber(res, "oid");
6488         i_cfgname = PQfnumber(res, "cfgname");
6489         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6490         i_rolname = PQfnumber(res, "rolname");
6491         i_cfgparser = PQfnumber(res, "cfgparser");
6492
6493         for (i = 0; i < ntups; i++)
6494         {
6495                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6496                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6497                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6498                 AssignDumpId(&cfginfo[i].dobj);
6499                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
6500                 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
6501                                                                                                   cfginfo[i].dobj.catId.oid);
6502                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6503                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
6504
6505                 /* Decide whether we want to dump it */
6506                 selectDumpableObject(&(cfginfo[i].dobj));
6507         }
6508
6509         PQclear(res);
6510
6511         destroyPQExpBuffer(query);
6512
6513         return cfginfo;
6514 }
6515
6516 /*
6517  * getForeignDataWrappers:
6518  *        read all foreign-data wrappers in the system catalogs and return
6519  *        them in the FdwInfo* structure
6520  *
6521  *      numForeignDataWrappers is set to the number of fdws read in
6522  */
6523 FdwInfo *
6524 getForeignDataWrappers(int *numForeignDataWrappers)
6525 {
6526         PGresult   *res;
6527         int                     ntups;
6528         int                     i;
6529         PQExpBuffer query = createPQExpBuffer();
6530         FdwInfo    *fdwinfo;
6531         int                     i_tableoid;
6532         int                     i_oid;
6533         int                     i_fdwname;
6534         int                     i_rolname;
6535         int                     i_fdwhandler;
6536         int                     i_fdwvalidator;
6537         int                     i_fdwacl;
6538         int                     i_fdwoptions;
6539
6540         /* Before 8.4, there are no foreign-data wrappers */
6541         if (g_fout->remoteVersion < 80400)
6542         {
6543                 *numForeignDataWrappers = 0;
6544                 return NULL;
6545         }
6546
6547         /* Make sure we are in proper schema */
6548         selectSourceSchema("pg_catalog");
6549
6550         if (g_fout->remoteVersion >= 90100)
6551         {
6552                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6553                                                   "(%s fdwowner) AS rolname, "
6554                                                   "fdwhandler::pg_catalog.regproc, "
6555                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6556                                                   "array_to_string(ARRAY("
6557                                                   "SELECT quote_ident(option_name) || ' ' || "
6558                                                   "quote_literal(option_value) "
6559                                                   "FROM pg_options_to_table(fdwoptions)"
6560                                                   "), E',\n    ') AS fdwoptions "
6561                                                   "FROM pg_foreign_data_wrapper",
6562                                                   username_subquery);
6563         }
6564         else
6565         {
6566                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6567                                                   "(%s fdwowner) AS rolname, "
6568                                                   "'-' AS fdwhandler, "
6569                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6570                                                   "array_to_string(ARRAY("
6571                                                   "SELECT quote_ident(option_name) || ' ' || "
6572                                                   "quote_literal(option_value) "
6573                                                   "FROM pg_options_to_table(fdwoptions)"
6574                                                   "), E',\n    ') AS fdwoptions "
6575                                                   "FROM pg_foreign_data_wrapper",
6576                                                   username_subquery);
6577         }
6578
6579         res = PQexec(g_conn, query->data);
6580         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6581
6582         ntups = PQntuples(res);
6583         *numForeignDataWrappers = ntups;
6584
6585         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
6586
6587         i_tableoid = PQfnumber(res, "tableoid");
6588         i_oid = PQfnumber(res, "oid");
6589         i_fdwname = PQfnumber(res, "fdwname");
6590         i_rolname = PQfnumber(res, "rolname");
6591         i_fdwhandler = PQfnumber(res, "fdwhandler");
6592         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6593         i_fdwacl = PQfnumber(res, "fdwacl");
6594         i_fdwoptions = PQfnumber(res, "fdwoptions");
6595
6596         for (i = 0; i < ntups; i++)
6597         {
6598                 fdwinfo[i].dobj.objType = DO_FDW;
6599                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6600                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6601                 AssignDumpId(&fdwinfo[i].dobj);
6602                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6603                 fdwinfo[i].dobj.namespace = NULL;
6604                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6605                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
6606                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
6607                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
6608                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
6609
6610                 /* Decide whether we want to dump it */
6611                 selectDumpableObject(&(fdwinfo[i].dobj));
6612         }
6613
6614         PQclear(res);
6615
6616         destroyPQExpBuffer(query);
6617
6618         return fdwinfo;
6619 }
6620
6621 /*
6622  * getForeignServers:
6623  *        read all foreign servers in the system catalogs and return
6624  *        them in the ForeignServerInfo * structure
6625  *
6626  *      numForeignServers is set to the number of servers read in
6627  */
6628 ForeignServerInfo *
6629 getForeignServers(int *numForeignServers)
6630 {
6631         PGresult   *res;
6632         int                     ntups;
6633         int                     i;
6634         PQExpBuffer query = createPQExpBuffer();
6635         ForeignServerInfo *srvinfo;
6636         int                     i_tableoid;
6637         int                     i_oid;
6638         int                     i_srvname;
6639         int                     i_rolname;
6640         int                     i_srvfdw;
6641         int                     i_srvtype;
6642         int                     i_srvversion;
6643         int                     i_srvacl;
6644         int                     i_srvoptions;
6645
6646         /* Before 8.4, there are no foreign servers */
6647         if (g_fout->remoteVersion < 80400)
6648         {
6649                 *numForeignServers = 0;
6650                 return NULL;
6651         }
6652
6653         /* Make sure we are in proper schema */
6654         selectSourceSchema("pg_catalog");
6655
6656         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
6657                                           "(%s srvowner) AS rolname, "
6658                                           "srvfdw, srvtype, srvversion, srvacl,"
6659                                           "array_to_string(ARRAY("
6660                                           "SELECT quote_ident(option_name) || ' ' || "
6661                                           "quote_literal(option_value) "
6662                                           "FROM pg_options_to_table(srvoptions)"
6663                                           "), E',\n    ') AS srvoptions "
6664                                           "FROM pg_foreign_server",
6665                                           username_subquery);
6666
6667         res = PQexec(g_conn, query->data);
6668         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6669
6670         ntups = PQntuples(res);
6671         *numForeignServers = ntups;
6672
6673         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
6674
6675         i_tableoid = PQfnumber(res, "tableoid");
6676         i_oid = PQfnumber(res, "oid");
6677         i_srvname = PQfnumber(res, "srvname");
6678         i_rolname = PQfnumber(res, "rolname");
6679         i_srvfdw = PQfnumber(res, "srvfdw");
6680         i_srvtype = PQfnumber(res, "srvtype");
6681         i_srvversion = PQfnumber(res, "srvversion");
6682         i_srvacl = PQfnumber(res, "srvacl");
6683         i_srvoptions = PQfnumber(res, "srvoptions");
6684
6685         for (i = 0; i < ntups; i++)
6686         {
6687                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
6688                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6689                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6690                 AssignDumpId(&srvinfo[i].dobj);
6691                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6692                 srvinfo[i].dobj.namespace = NULL;
6693                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6694                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
6695                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
6696                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
6697                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
6698                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
6699
6700                 /* Decide whether we want to dump it */
6701                 selectDumpableObject(&(srvinfo[i].dobj));
6702         }
6703
6704         PQclear(res);
6705
6706         destroyPQExpBuffer(query);
6707
6708         return srvinfo;
6709 }
6710
6711 /*
6712  * getDefaultACLs:
6713  *        read all default ACL information in the system catalogs and return
6714  *        them in the DefaultACLInfo structure
6715  *
6716  *      numDefaultACLs is set to the number of ACLs read in
6717  */
6718 DefaultACLInfo *
6719 getDefaultACLs(int *numDefaultACLs)
6720 {
6721         DefaultACLInfo *daclinfo;
6722         PQExpBuffer query;
6723         PGresult   *res;
6724         int                     i_oid;
6725         int                     i_tableoid;
6726         int                     i_defaclrole;
6727         int                     i_defaclnamespace;
6728         int                     i_defaclobjtype;
6729         int                     i_defaclacl;
6730         int                     i,
6731                                 ntups;
6732
6733         if (g_fout->remoteVersion < 90000)
6734         {
6735                 *numDefaultACLs = 0;
6736                 return NULL;
6737         }
6738
6739         query = createPQExpBuffer();
6740
6741         /* Make sure we are in proper schema */
6742         selectSourceSchema("pg_catalog");
6743
6744         appendPQExpBuffer(query, "SELECT oid, tableoid, "
6745                                           "(%s defaclrole) AS defaclrole, "
6746                                           "defaclnamespace, "
6747                                           "defaclobjtype, "
6748                                           "defaclacl "
6749                                           "FROM pg_default_acl",
6750                                           username_subquery);
6751
6752         res = PQexec(g_conn, query->data);
6753         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6754
6755         ntups = PQntuples(res);
6756         *numDefaultACLs = ntups;
6757
6758         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
6759
6760         i_oid = PQfnumber(res, "oid");
6761         i_tableoid = PQfnumber(res, "tableoid");
6762         i_defaclrole = PQfnumber(res, "defaclrole");
6763         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
6764         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
6765         i_defaclacl = PQfnumber(res, "defaclacl");
6766
6767         for (i = 0; i < ntups; i++)
6768         {
6769                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
6770
6771                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
6772                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6773                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6774                 AssignDumpId(&daclinfo[i].dobj);
6775                 /* cheesy ... is it worth coming up with a better object name? */
6776                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
6777
6778                 if (nspid != InvalidOid)
6779                         daclinfo[i].dobj.namespace = findNamespace(nspid,
6780                                                                                                  daclinfo[i].dobj.catId.oid);
6781                 else
6782                         daclinfo[i].dobj.namespace = NULL;
6783
6784                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
6785                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
6786                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
6787
6788                 /* Decide whether we want to dump it */
6789                 selectDumpableDefaultACL(&(daclinfo[i]));
6790         }
6791
6792         PQclear(res);
6793
6794         destroyPQExpBuffer(query);
6795
6796         return daclinfo;
6797 }
6798
6799 /*
6800  * dumpComment --
6801  *
6802  * This routine is used to dump any comments associated with the
6803  * object handed to this routine. The routine takes a constant character
6804  * string for the target part of the comment-creation command, plus
6805  * the namespace and owner of the object (for labeling the ArchiveEntry),
6806  * plus catalog ID and subid which are the lookup key for pg_description,
6807  * plus the dump ID for the object (for setting a dependency).
6808  * If a matching pg_description entry is found, it is dumped.
6809  *
6810  * Note: although this routine takes a dumpId for dependency purposes,
6811  * that purpose is just to mark the dependency in the emitted dump file
6812  * for possible future use by pg_restore.  We do NOT use it for determining
6813  * ordering of the comment in the dump file, because this routine is called
6814  * after dependency sorting occurs.  This routine should be called just after
6815  * calling ArchiveEntry() for the specified object.
6816  */
6817 static void
6818 dumpComment(Archive *fout, const char *target,
6819                         const char *namespace, const char *owner,
6820                         CatalogId catalogId, int subid, DumpId dumpId)
6821 {
6822         CommentItem *comments;
6823         int                     ncomments;
6824
6825         /* Comments are schema not data ... except blob comments are data */
6826         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
6827         {
6828                 if (dataOnly)
6829                         return;
6830         }
6831         else
6832         {
6833                 if (schemaOnly)
6834                         return;
6835         }
6836
6837         /* Search for comments associated with catalogId, using table */
6838         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
6839                                                          &comments);
6840
6841         /* Is there one matching the subid? */
6842         while (ncomments > 0)
6843         {
6844                 if (comments->objsubid == subid)
6845                         break;
6846                 comments++;
6847                 ncomments--;
6848         }
6849
6850         /* If a comment exists, build COMMENT ON statement */
6851         if (ncomments > 0)
6852         {
6853                 PQExpBuffer query = createPQExpBuffer();
6854
6855                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
6856                 appendStringLiteralAH(query, comments->descr, fout);
6857                 appendPQExpBuffer(query, ";\n");
6858
6859                 /*
6860                  * We mark comments as SECTION_NONE because they really belong in the
6861                  * same section as their parent, whether that is pre-data or
6862                  * post-data.
6863                  */
6864                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
6865                                          target, namespace, NULL, owner,
6866                                          false, "COMMENT", SECTION_NONE,
6867                                          query->data, "", NULL,
6868                                          &(dumpId), 1,
6869                                          NULL, NULL);
6870
6871                 destroyPQExpBuffer(query);
6872         }
6873 }
6874
6875 /*
6876  * dumpTableComment --
6877  *
6878  * As above, but dump comments for both the specified table (or view)
6879  * and its columns.
6880  */
6881 static void
6882 dumpTableComment(Archive *fout, TableInfo *tbinfo,
6883                                  const char *reltypename)
6884 {
6885         CommentItem *comments;
6886         int                     ncomments;
6887         PQExpBuffer query;
6888         PQExpBuffer target;
6889
6890         /* Comments are SCHEMA not data */
6891         if (dataOnly)
6892                 return;
6893
6894         /* Search for comments associated with relation, using table */
6895         ncomments = findComments(fout,
6896                                                          tbinfo->dobj.catId.tableoid,
6897                                                          tbinfo->dobj.catId.oid,
6898                                                          &comments);
6899
6900         /* If comments exist, build COMMENT ON statements */
6901         if (ncomments <= 0)
6902                 return;
6903
6904         query = createPQExpBuffer();
6905         target = createPQExpBuffer();
6906
6907         while (ncomments > 0)
6908         {
6909                 const char *descr = comments->descr;
6910                 int                     objsubid = comments->objsubid;
6911
6912                 if (objsubid == 0)
6913                 {
6914                         resetPQExpBuffer(target);
6915                         appendPQExpBuffer(target, "%s %s", reltypename,
6916                                                           fmtId(tbinfo->dobj.name));
6917
6918                         resetPQExpBuffer(query);
6919                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6920                         appendStringLiteralAH(query, descr, fout);
6921                         appendPQExpBuffer(query, ";\n");
6922
6923                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6924                                                  target->data,
6925                                                  tbinfo->dobj.namespace->dobj.name,
6926                                                  NULL, tbinfo->rolname,
6927                                                  false, "COMMENT", SECTION_NONE,
6928                                                  query->data, "", NULL,
6929                                                  &(tbinfo->dobj.dumpId), 1,
6930                                                  NULL, NULL);
6931                 }
6932                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
6933                 {
6934                         resetPQExpBuffer(target);
6935                         appendPQExpBuffer(target, "COLUMN %s.",
6936                                                           fmtId(tbinfo->dobj.name));
6937                         appendPQExpBuffer(target, "%s",
6938                                                           fmtId(tbinfo->attnames[objsubid - 1]));
6939
6940                         resetPQExpBuffer(query);
6941                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6942                         appendStringLiteralAH(query, descr, fout);
6943                         appendPQExpBuffer(query, ";\n");
6944
6945                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6946                                                  target->data,
6947                                                  tbinfo->dobj.namespace->dobj.name,
6948                                                  NULL, tbinfo->rolname,
6949                                                  false, "COMMENT", SECTION_NONE,
6950                                                  query->data, "", NULL,
6951                                                  &(tbinfo->dobj.dumpId), 1,
6952                                                  NULL, NULL);
6953                 }
6954
6955                 comments++;
6956                 ncomments--;
6957         }
6958
6959         destroyPQExpBuffer(query);
6960         destroyPQExpBuffer(target);
6961 }
6962
6963 /*
6964  * findComments --
6965  *
6966  * Find the comment(s), if any, associated with the given object.  All the
6967  * objsubid values associated with the given classoid/objoid are found with
6968  * one search.
6969  */
6970 static int
6971 findComments(Archive *fout, Oid classoid, Oid objoid,
6972                          CommentItem **items)
6973 {
6974         /* static storage for table of comments */
6975         static CommentItem *comments = NULL;
6976         static int      ncomments = -1;
6977
6978         CommentItem *middle = NULL;
6979         CommentItem *low;
6980         CommentItem *high;
6981         int                     nmatch;
6982
6983         /* Get comments if we didn't already */
6984         if (ncomments < 0)
6985                 ncomments = collectComments(fout, &comments);
6986
6987         /*
6988          * Pre-7.2, pg_description does not contain classoid, so collectComments
6989          * just stores a zero.  If there's a collision on object OID, well, you
6990          * get duplicate comments.
6991          */
6992         if (fout->remoteVersion < 70200)
6993                 classoid = 0;
6994
6995         /*
6996          * Do binary search to find some item matching the object.
6997          */
6998         low = &comments[0];
6999         high = &comments[ncomments - 1];
7000         while (low <= high)
7001         {
7002                 middle = low + (high - low) / 2;
7003
7004                 if (classoid < middle->classoid)
7005                         high = middle - 1;
7006                 else if (classoid > middle->classoid)
7007                         low = middle + 1;
7008                 else if (objoid < middle->objoid)
7009                         high = middle - 1;
7010                 else if (objoid > middle->objoid)
7011                         low = middle + 1;
7012                 else
7013                         break;                          /* found a match */
7014         }
7015
7016         if (low > high)                         /* no matches */
7017         {
7018                 *items = NULL;
7019                 return 0;
7020         }
7021
7022         /*
7023          * Now determine how many items match the object.  The search loop
7024          * invariant still holds: only items between low and high inclusive could
7025          * match.
7026          */
7027         nmatch = 1;
7028         while (middle > low)
7029         {
7030                 if (classoid != middle[-1].classoid ||
7031                         objoid != middle[-1].objoid)
7032                         break;
7033                 middle--;
7034                 nmatch++;
7035         }
7036
7037         *items = middle;
7038
7039         middle += nmatch;
7040         while (middle <= high)
7041         {
7042                 if (classoid != middle->classoid ||
7043                         objoid != middle->objoid)
7044                         break;
7045                 middle++;
7046                 nmatch++;
7047         }
7048
7049         return nmatch;
7050 }
7051
7052 /*
7053  * collectComments --
7054  *
7055  * Construct a table of all comments available for database objects.
7056  * We used to do per-object queries for the comments, but it's much faster
7057  * to pull them all over at once, and on most databases the memory cost
7058  * isn't high.
7059  *
7060  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7061  */
7062 static int
7063 collectComments(Archive *fout, CommentItem **items)
7064 {
7065         PGresult   *res;
7066         PQExpBuffer query;
7067         int                     i_description;
7068         int                     i_classoid;
7069         int                     i_objoid;
7070         int                     i_objsubid;
7071         int                     ntups;
7072         int                     i;
7073         CommentItem *comments;
7074
7075         /*
7076          * Note we do NOT change source schema here; preserve the caller's
7077          * setting, instead.
7078          */
7079
7080         query = createPQExpBuffer();
7081
7082         if (fout->remoteVersion >= 70300)
7083         {
7084                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7085                                                   "FROM pg_catalog.pg_description "
7086                                                   "ORDER BY classoid, objoid, objsubid");
7087         }
7088         else if (fout->remoteVersion >= 70200)
7089         {
7090                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7091                                                   "FROM pg_description "
7092                                                   "ORDER BY classoid, objoid, objsubid");
7093         }
7094         else
7095         {
7096                 /* Note: this will fail to find attribute comments in pre-7.2... */
7097                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7098                                                   "FROM pg_description "
7099                                                   "ORDER BY objoid");
7100         }
7101
7102         res = PQexec(g_conn, query->data);
7103         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7104
7105         /* Construct lookup table containing OIDs in numeric form */
7106
7107         i_description = PQfnumber(res, "description");
7108         i_classoid = PQfnumber(res, "classoid");
7109         i_objoid = PQfnumber(res, "objoid");
7110         i_objsubid = PQfnumber(res, "objsubid");
7111
7112         ntups = PQntuples(res);
7113
7114         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7115
7116         for (i = 0; i < ntups; i++)
7117         {
7118                 comments[i].descr = PQgetvalue(res, i, i_description);
7119                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7120                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7121                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7122         }
7123
7124         /* Do NOT free the PGresult since we are keeping pointers into it */
7125         destroyPQExpBuffer(query);
7126
7127         *items = comments;
7128         return ntups;
7129 }
7130
7131 /*
7132  * dumpDumpableObject
7133  *
7134  * This routine and its subsidiaries are responsible for creating
7135  * ArchiveEntries (TOC objects) for each object to be dumped.
7136  */
7137 static void
7138 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7139 {
7140
7141         bool skip = false;
7142
7143         switch (dobj->objType)
7144         {
7145                 case DO_INDEX:
7146                 case DO_TRIGGER:
7147                 case DO_CONSTRAINT:
7148                 case DO_FK_CONSTRAINT:
7149                 case DO_RULE:
7150                         skip = !(dumpSections & DUMP_POST_DATA);
7151                         break;
7152                 case DO_TABLE_DATA:
7153                         skip = !(dumpSections & DUMP_DATA);
7154                         break;
7155                 default:
7156                         skip = !(dumpSections & DUMP_PRE_DATA);
7157         }
7158
7159         if (skip)
7160                 return;
7161
7162         switch (dobj->objType)
7163         {
7164                 case DO_NAMESPACE:
7165                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7166                         break;
7167                 case DO_EXTENSION:
7168                         dumpExtension(fout, (ExtensionInfo *) dobj);
7169                         break;
7170                 case DO_TYPE:
7171                         dumpType(fout, (TypeInfo *) dobj);
7172                         break;
7173                 case DO_SHELL_TYPE:
7174                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7175                         break;
7176                 case DO_FUNC:
7177                         dumpFunc(fout, (FuncInfo *) dobj);
7178                         break;
7179                 case DO_AGG:
7180                         dumpAgg(fout, (AggInfo *) dobj);
7181                         break;
7182                 case DO_OPERATOR:
7183                         dumpOpr(fout, (OprInfo *) dobj);
7184                         break;
7185                 case DO_OPCLASS:
7186                         dumpOpclass(fout, (OpclassInfo *) dobj);
7187                         break;
7188                 case DO_OPFAMILY:
7189                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7190                         break;
7191                 case DO_COLLATION:
7192                         dumpCollation(fout, (CollInfo *) dobj);
7193                         break;
7194                 case DO_CONVERSION:
7195                         dumpConversion(fout, (ConvInfo *) dobj);
7196                         break;
7197                 case DO_TABLE:
7198                         dumpTable(fout, (TableInfo *) dobj);
7199                         break;
7200                 case DO_ATTRDEF:
7201                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7202                         break;
7203                 case DO_INDEX:
7204                         dumpIndex(fout, (IndxInfo *) dobj);
7205                         break;
7206                 case DO_RULE:
7207                         dumpRule(fout, (RuleInfo *) dobj);
7208                         break;
7209                 case DO_TRIGGER:
7210                         dumpTrigger(fout, (TriggerInfo *) dobj);
7211                         break;
7212                 case DO_CONSTRAINT:
7213                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7214                         break;
7215                 case DO_FK_CONSTRAINT:
7216                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7217                         break;
7218                 case DO_PROCLANG:
7219                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7220                         break;
7221                 case DO_CAST:
7222                         dumpCast(fout, (CastInfo *) dobj);
7223                         break;
7224                 case DO_TABLE_DATA:
7225                         dumpTableData(fout, (TableDataInfo *) dobj);
7226                         break;
7227                 case DO_DUMMY_TYPE:
7228                         /* table rowtypes and array types are never dumped separately */
7229                         break;
7230                 case DO_TSPARSER:
7231                         dumpTSParser(fout, (TSParserInfo *) dobj);
7232                         break;
7233                 case DO_TSDICT:
7234                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7235                         break;
7236                 case DO_TSTEMPLATE:
7237                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7238                         break;
7239                 case DO_TSCONFIG:
7240                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7241                         break;
7242                 case DO_FDW:
7243                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7244                         break;
7245                 case DO_FOREIGN_SERVER:
7246                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7247                         break;
7248                 case DO_DEFAULT_ACL:
7249                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7250                         break;
7251                 case DO_BLOB:
7252                         dumpBlob(fout, (BlobInfo *) dobj);
7253                         break;
7254                 case DO_BLOB_DATA:
7255                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7256                                                  dobj->name, NULL, NULL, "",
7257                                                  false, "BLOBS", SECTION_DATA,
7258                                                  "", "", NULL,
7259                                                  dobj->dependencies, dobj->nDeps,
7260                                                  dumpBlobs, NULL);
7261                         break;
7262         }
7263 }
7264
7265 /*
7266  * dumpNamespace
7267  *        writes out to fout the queries to recreate a user-defined namespace
7268  */
7269 static void
7270 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7271 {
7272         PQExpBuffer q;
7273         PQExpBuffer delq;
7274         PQExpBuffer labelq;
7275         char       *qnspname;
7276
7277         /* Skip if not to be dumped */
7278         if (!nspinfo->dobj.dump || dataOnly)
7279                 return;
7280
7281         /* don't dump dummy namespace from pre-7.3 source */
7282         if (strlen(nspinfo->dobj.name) == 0)
7283                 return;
7284
7285         q = createPQExpBuffer();
7286         delq = createPQExpBuffer();
7287         labelq = createPQExpBuffer();
7288
7289         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7290
7291         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7292
7293         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7294
7295         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7296
7297         if (binary_upgrade)
7298                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7299
7300         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7301                                  nspinfo->dobj.name,
7302                                  NULL, NULL,
7303                                  nspinfo->rolname,
7304                                  false, "SCHEMA", SECTION_PRE_DATA,
7305                                  q->data, delq->data, NULL,
7306                                  nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
7307                                  NULL, NULL);
7308
7309         /* Dump Schema Comments and Security Labels */
7310         dumpComment(fout, labelq->data,
7311                                 NULL, nspinfo->rolname,
7312                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7313         dumpSecLabel(fout, labelq->data,
7314                                  NULL, nspinfo->rolname,
7315                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7316
7317         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7318                         qnspname, NULL, nspinfo->dobj.name, NULL,
7319                         nspinfo->rolname, nspinfo->nspacl);
7320
7321         free(qnspname);
7322
7323         destroyPQExpBuffer(q);
7324         destroyPQExpBuffer(delq);
7325         destroyPQExpBuffer(labelq);
7326 }
7327
7328 /*
7329  * dumpExtension
7330  *        writes out to fout the queries to recreate an extension
7331  */
7332 static void
7333 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7334 {
7335         PQExpBuffer q;
7336         PQExpBuffer delq;
7337         PQExpBuffer labelq;
7338         char       *qextname;
7339
7340         /* Skip if not to be dumped */
7341         if (!extinfo->dobj.dump || dataOnly)
7342                 return;
7343
7344         q = createPQExpBuffer();
7345         delq = createPQExpBuffer();
7346         labelq = createPQExpBuffer();
7347
7348         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7349
7350         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7351
7352         if (!binary_upgrade)
7353         {
7354                 /*
7355                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7356                  * problem if the extension already exists in the target database;
7357                  * this is essential for installed-by-default extensions such as
7358                  * plpgsql.
7359                  *
7360                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7361                  * built-in extensions based on their OIDs; see
7362                  * selectDumpableExtension.
7363                  */
7364                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7365                                                   qextname, fmtId(extinfo->namespace));
7366         }
7367         else
7368         {
7369                 int                     i;
7370                 int                     n;
7371
7372                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7373                 appendPQExpBuffer(q,
7374                                                   "SELECT binary_upgrade.create_empty_extension(");
7375                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7376                 appendPQExpBuffer(q, ", ");
7377                 appendStringLiteralAH(q, extinfo->namespace, fout);
7378                 appendPQExpBuffer(q, ", ");
7379                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7380                 appendStringLiteralAH(q, extinfo->extversion, fout);
7381                 appendPQExpBuffer(q, ", ");
7382
7383                 /*
7384                  * Note that we're pushing extconfig (an OID array) back into
7385                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7386                  * preserved in binary upgrade.
7387                  */
7388                 if (strlen(extinfo->extconfig) > 2)
7389                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7390                 else
7391                         appendPQExpBuffer(q, "NULL");
7392                 appendPQExpBuffer(q, ", ");
7393                 if (strlen(extinfo->extcondition) > 2)
7394                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7395                 else
7396                         appendPQExpBuffer(q, "NULL");
7397                 appendPQExpBuffer(q, ", ");
7398                 appendPQExpBuffer(q, "ARRAY[");
7399                 n = 0;
7400                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7401                 {
7402                         DumpableObject *extobj;
7403
7404                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7405                         if (extobj && extobj->objType == DO_EXTENSION)
7406                         {
7407                                 if (n++ > 0)
7408                                         appendPQExpBuffer(q, ",");
7409                                 appendStringLiteralAH(q, extobj->name, fout);
7410                         }
7411                 }
7412                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7413                 appendPQExpBuffer(q, ");\n");
7414         }
7415
7416         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7417
7418         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7419                                  extinfo->dobj.name,
7420                                  NULL, NULL,
7421                                  "",
7422                                  false, "EXTENSION", SECTION_PRE_DATA,
7423                                  q->data, delq->data, NULL,
7424                                  extinfo->dobj.dependencies, extinfo->dobj.nDeps,
7425                                  NULL, NULL);
7426
7427         /* Dump Extension Comments and Security Labels */
7428         dumpComment(fout, labelq->data,
7429                                 NULL, "",
7430                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7431         dumpSecLabel(fout, labelq->data,
7432                                  NULL, "",
7433                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7434
7435         free(qextname);
7436
7437         destroyPQExpBuffer(q);
7438         destroyPQExpBuffer(delq);
7439         destroyPQExpBuffer(labelq);
7440 }
7441
7442 /*
7443  * dumpType
7444  *        writes out to fout the queries to recreate a user-defined type
7445  */
7446 static void
7447 dumpType(Archive *fout, TypeInfo *tyinfo)
7448 {
7449         /* Skip if not to be dumped */
7450         if (!tyinfo->dobj.dump || dataOnly)
7451                 return;
7452
7453         /* Dump out in proper style */
7454         if (tyinfo->typtype == TYPTYPE_BASE)
7455                 dumpBaseType(fout, tyinfo);
7456         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7457                 dumpDomain(fout, tyinfo);
7458         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7459                 dumpCompositeType(fout, tyinfo);
7460         else if (tyinfo->typtype == TYPTYPE_ENUM)
7461                 dumpEnumType(fout, tyinfo);
7462         else if (tyinfo->typtype == TYPTYPE_RANGE)
7463                 dumpRangeType(fout, tyinfo);
7464         else
7465                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7466                                   tyinfo->dobj.name);
7467 }
7468
7469 /*
7470  * dumpEnumType
7471  *        writes out to fout the queries to recreate a user-defined enum type
7472  */
7473 static void
7474 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7475 {
7476         PQExpBuffer q = createPQExpBuffer();
7477         PQExpBuffer delq = createPQExpBuffer();
7478         PQExpBuffer labelq = createPQExpBuffer();
7479         PQExpBuffer query = createPQExpBuffer();
7480         PGresult   *res;
7481         int                     num,
7482                                 i;
7483         Oid                     enum_oid;
7484         char       *label;
7485
7486         /* Set proper schema search path */
7487         selectSourceSchema("pg_catalog");
7488
7489         if (fout->remoteVersion >= 90100)
7490                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7491                                                   "FROM pg_catalog.pg_enum "
7492                                                   "WHERE enumtypid = '%u'"
7493                                                   "ORDER BY enumsortorder",
7494                                                   tyinfo->dobj.catId.oid);
7495         else
7496                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7497                                                   "FROM pg_catalog.pg_enum "
7498                                                   "WHERE enumtypid = '%u'"
7499                                                   "ORDER BY oid",
7500                                                   tyinfo->dobj.catId.oid);
7501
7502         res = PQexec(g_conn, query->data);
7503         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7504
7505         num = PQntuples(res);
7506
7507         /*
7508          * DROP must be fully qualified in case same name appears in pg_catalog.
7509          * CASCADE shouldn't be required here as for normal types since the I/O
7510          * functions are generic and do not get dropped.
7511          */
7512         appendPQExpBuffer(delq, "DROP TYPE %s.",
7513                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7514         appendPQExpBuffer(delq, "%s;\n",
7515                                           fmtId(tyinfo->dobj.name));
7516
7517         if (binary_upgrade)
7518                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7519
7520         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
7521                                           fmtId(tyinfo->dobj.name));
7522
7523         if (!binary_upgrade)
7524         {
7525                 /* Labels with server-assigned oids */
7526                 for (i = 0; i < num; i++)
7527                 {
7528                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7529                         if (i > 0)
7530                                 appendPQExpBuffer(q, ",");
7531                         appendPQExpBuffer(q, "\n    ");
7532                         appendStringLiteralAH(q, label, fout);
7533                 }
7534         }
7535
7536         appendPQExpBuffer(q, "\n);\n");
7537
7538         if (binary_upgrade)
7539         {
7540                 /* Labels with dump-assigned (preserved) oids */
7541                 for (i = 0; i < num; i++)
7542                 {
7543                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
7544                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7545
7546                         if (i == 0)
7547                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
7548                         appendPQExpBuffer(q,
7549                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
7550                                                           enum_oid);
7551                         appendPQExpBuffer(q, "ALTER TYPE %s.",
7552                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7553                         appendPQExpBuffer(q, "%s ADD VALUE ",
7554                                                           fmtId(tyinfo->dobj.name));
7555                         appendStringLiteralAH(q, label, fout);
7556                         appendPQExpBuffer(q, ";\n\n");
7557                 }
7558         }
7559
7560         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7561
7562         if (binary_upgrade)
7563                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7564
7565         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7566                                  tyinfo->dobj.name,
7567                                  tyinfo->dobj.namespace->dobj.name,
7568                                  NULL,
7569                                  tyinfo->rolname, false,
7570                                  "TYPE", SECTION_PRE_DATA,
7571                                  q->data, delq->data, NULL,
7572                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7573                                  NULL, NULL);
7574
7575         /* Dump Type Comments and Security Labels */
7576         dumpComment(fout, labelq->data,
7577                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7578                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7579         dumpSecLabel(fout, labelq->data,
7580                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7581                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7582
7583         PQclear(res);
7584         destroyPQExpBuffer(q);
7585         destroyPQExpBuffer(delq);
7586         destroyPQExpBuffer(labelq);
7587         destroyPQExpBuffer(query);
7588 }
7589
7590 /*
7591  * dumpRangeType
7592  *        writes out to fout the queries to recreate a user-defined range type
7593  */
7594 static void
7595 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
7596 {
7597         PQExpBuffer q = createPQExpBuffer();
7598         PQExpBuffer delq = createPQExpBuffer();
7599         PQExpBuffer labelq = createPQExpBuffer();
7600         PQExpBuffer query = createPQExpBuffer();
7601         PGresult   *res;
7602         Oid                     collationOid;
7603         char       *procname;
7604
7605         /*
7606          * select appropriate schema to ensure names in CREATE are properly
7607          * qualified
7608          */
7609         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
7610
7611         appendPQExpBuffer(query,
7612                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
7613                                           "opc.opcname AS opcname, "
7614                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
7615                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
7616                                           "opc.opcdefault, "
7617                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
7618                                           "     ELSE rngcollation END AS collation, "
7619                                           "rngcanonical, rngsubdiff "
7620                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
7621                                           "     pg_catalog.pg_opclass opc "
7622                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
7623                                           "rngtypid = '%u'",
7624                                           tyinfo->dobj.catId.oid);
7625
7626         res = PQexec(g_conn, query->data);
7627         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7628         if (PQntuples(res) != 1)
7629         {
7630                 write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
7631                                   PQntuples(res), tyinfo->dobj.name);
7632                 exit_nicely();
7633         }
7634
7635         /*
7636          * DROP must be fully qualified in case same name appears in pg_catalog.
7637          * CASCADE shouldn't be required here as for normal types since the I/O
7638          * functions are generic and do not get dropped.
7639          */
7640         appendPQExpBuffer(delq, "DROP TYPE %s.",
7641                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7642         appendPQExpBuffer(delq, "%s;\n",
7643                                           fmtId(tyinfo->dobj.name));
7644
7645         if (binary_upgrade)
7646                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7647
7648         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
7649                                           fmtId(tyinfo->dobj.name));
7650
7651         appendPQExpBuffer(q, "\n    subtype = %s",
7652                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
7653
7654         /* print subtype_opclass only if not default for subtype */
7655         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
7656         {
7657                 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
7658                 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
7659
7660                 /* always schema-qualify, don't try to be smart */
7661                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
7662                                                   fmtId(nspname));
7663                 appendPQExpBuffer(q, "%s", fmtId(opcname));
7664         }
7665
7666         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
7667         if (OidIsValid(collationOid))
7668         {
7669                 CollInfo   *coll = findCollationByOid(collationOid);
7670
7671                 if (coll)
7672                 {
7673                         /* always schema-qualify, don't try to be smart */
7674                         appendPQExpBuffer(q, ",\n    collation = %s.",
7675                                                           fmtId(coll->dobj.namespace->dobj.name));
7676                         appendPQExpBuffer(q, "%s",
7677                                                           fmtId(coll->dobj.name));
7678                 }
7679         }
7680
7681         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
7682         if (strcmp(procname, "-") != 0)
7683                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
7684
7685         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
7686         if (strcmp(procname, "-") != 0)
7687                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
7688
7689         appendPQExpBuffer(q, "\n);\n");
7690
7691         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7692
7693         if (binary_upgrade)
7694                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7695
7696         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7697                                  tyinfo->dobj.name,
7698                                  tyinfo->dobj.namespace->dobj.name,
7699                                  NULL,
7700                                  tyinfo->rolname, false,
7701                                  "TYPE", SECTION_PRE_DATA,
7702                                  q->data, delq->data, NULL,
7703                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7704                                  NULL, NULL);
7705
7706         /* Dump Type Comments and Security Labels */
7707         dumpComment(fout, labelq->data,
7708                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7709                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7710         dumpSecLabel(fout, labelq->data,
7711                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7712                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7713
7714         PQclear(res);
7715         destroyPQExpBuffer(q);
7716         destroyPQExpBuffer(delq);
7717         destroyPQExpBuffer(labelq);
7718         destroyPQExpBuffer(query);
7719 }
7720
7721 /*
7722  * dumpBaseType
7723  *        writes out to fout the queries to recreate a user-defined base type
7724  */
7725 static void
7726 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
7727 {
7728         PQExpBuffer q = createPQExpBuffer();
7729         PQExpBuffer delq = createPQExpBuffer();
7730         PQExpBuffer labelq = createPQExpBuffer();
7731         PQExpBuffer query = createPQExpBuffer();
7732         PGresult   *res;
7733         int                     ntups;
7734         char       *typlen;
7735         char       *typinput;
7736         char       *typoutput;
7737         char       *typreceive;
7738         char       *typsend;
7739         char       *typmodin;
7740         char       *typmodout;
7741         char       *typanalyze;
7742         Oid                     typreceiveoid;
7743         Oid                     typsendoid;
7744         Oid                     typmodinoid;
7745         Oid                     typmodoutoid;
7746         Oid                     typanalyzeoid;
7747         char       *typcategory;
7748         char       *typispreferred;
7749         char       *typdelim;
7750         char       *typbyval;
7751         char       *typalign;
7752         char       *typstorage;
7753         char       *typcollatable;
7754         char       *typdefault;
7755         bool            typdefault_is_literal = false;
7756
7757         /* Set proper schema search path so regproc references list correctly */
7758         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
7759
7760         /* Fetch type-specific details */
7761         if (fout->remoteVersion >= 90100)
7762         {
7763                 appendPQExpBuffer(query, "SELECT typlen, "
7764                                                   "typinput, typoutput, typreceive, typsend, "
7765                                                   "typmodin, typmodout, typanalyze, "
7766                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7767                                                   "typsend::pg_catalog.oid AS typsendoid, "
7768                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7769                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7770                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7771                                                   "typcategory, typispreferred, "
7772                                                   "typdelim, typbyval, typalign, typstorage, "
7773                                                   "(typcollation <> 0) AS typcollatable, "
7774                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7775                                                   "FROM pg_catalog.pg_type "
7776                                                   "WHERE oid = '%u'::pg_catalog.oid",
7777                                                   tyinfo->dobj.catId.oid);
7778         }
7779         else if (fout->remoteVersion >= 80400)
7780         {
7781                 appendPQExpBuffer(query, "SELECT typlen, "
7782                                                   "typinput, typoutput, typreceive, typsend, "
7783                                                   "typmodin, typmodout, typanalyze, "
7784                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7785                                                   "typsend::pg_catalog.oid AS typsendoid, "
7786                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7787                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7788                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7789                                                   "typcategory, typispreferred, "
7790                                                   "typdelim, typbyval, typalign, typstorage, "
7791                                                   "false AS typcollatable, "
7792                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7793                                                   "FROM pg_catalog.pg_type "
7794                                                   "WHERE oid = '%u'::pg_catalog.oid",
7795                                                   tyinfo->dobj.catId.oid);
7796         }
7797         else if (fout->remoteVersion >= 80300)
7798         {
7799                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
7800                 appendPQExpBuffer(query, "SELECT typlen, "
7801                                                   "typinput, typoutput, typreceive, typsend, "
7802                                                   "typmodin, typmodout, typanalyze, "
7803                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7804                                                   "typsend::pg_catalog.oid AS typsendoid, "
7805                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7806                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7807                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7808                                                   "'U' AS typcategory, false AS typispreferred, "
7809                                                   "typdelim, typbyval, typalign, typstorage, "
7810                                                   "false AS typcollatable, "
7811                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7812                                                   "FROM pg_catalog.pg_type "
7813                                                   "WHERE oid = '%u'::pg_catalog.oid",
7814                                                   tyinfo->dobj.catId.oid);
7815         }
7816         else if (fout->remoteVersion >= 80000)
7817         {
7818                 appendPQExpBuffer(query, "SELECT typlen, "
7819                                                   "typinput, typoutput, typreceive, typsend, "
7820                                                   "'-' AS typmodin, '-' AS typmodout, "
7821                                                   "typanalyze, "
7822                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7823                                                   "typsend::pg_catalog.oid AS typsendoid, "
7824                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7825                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7826                                                   "'U' AS typcategory, false AS typispreferred, "
7827                                                   "typdelim, typbyval, typalign, typstorage, "
7828                                                   "false AS typcollatable, "
7829                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7830                                                   "FROM pg_catalog.pg_type "
7831                                                   "WHERE oid = '%u'::pg_catalog.oid",
7832                                                   tyinfo->dobj.catId.oid);
7833         }
7834         else if (fout->remoteVersion >= 70400)
7835         {
7836                 appendPQExpBuffer(query, "SELECT typlen, "
7837                                                   "typinput, typoutput, typreceive, typsend, "
7838                                                   "'-' AS typmodin, '-' AS typmodout, "
7839                                                   "'-' AS typanalyze, "
7840                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7841                                                   "typsend::pg_catalog.oid AS typsendoid, "
7842                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7843                                                   "0 AS typanalyzeoid, "
7844                                                   "'U' AS typcategory, false AS typispreferred, "
7845                                                   "typdelim, typbyval, typalign, typstorage, "
7846                                                   "false AS typcollatable, "
7847                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7848                                                   "FROM pg_catalog.pg_type "
7849                                                   "WHERE oid = '%u'::pg_catalog.oid",
7850                                                   tyinfo->dobj.catId.oid);
7851         }
7852         else if (fout->remoteVersion >= 70300)
7853         {
7854                 appendPQExpBuffer(query, "SELECT typlen, "
7855                                                   "typinput, typoutput, "
7856                                                   "'-' AS typreceive, '-' AS typsend, "
7857                                                   "'-' AS typmodin, '-' AS typmodout, "
7858                                                   "'-' AS typanalyze, "
7859                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7860                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7861                                                   "0 AS typanalyzeoid, "
7862                                                   "'U' AS typcategory, false AS typispreferred, "
7863                                                   "typdelim, typbyval, typalign, typstorage, "
7864                                                   "false AS typcollatable, "
7865                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7866                                                   "FROM pg_catalog.pg_type "
7867                                                   "WHERE oid = '%u'::pg_catalog.oid",
7868                                                   tyinfo->dobj.catId.oid);
7869         }
7870         else if (fout->remoteVersion >= 70200)
7871         {
7872                 /*
7873                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
7874                  * ignore them because they are not right.
7875                  */
7876                 appendPQExpBuffer(query, "SELECT typlen, "
7877                                                   "typinput, typoutput, "
7878                                                   "'-' AS typreceive, '-' AS typsend, "
7879                                                   "'-' AS typmodin, '-' AS typmodout, "
7880                                                   "'-' AS typanalyze, "
7881                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7882                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7883                                                   "0 AS typanalyzeoid, "
7884                                                   "'U' AS typcategory, false AS typispreferred, "
7885                                                   "typdelim, typbyval, typalign, typstorage, "
7886                                                   "false AS typcollatable, "
7887                                                   "NULL AS typdefaultbin, typdefault "
7888                                                   "FROM pg_type "
7889                                                   "WHERE oid = '%u'::oid",
7890                                                   tyinfo->dobj.catId.oid);
7891         }
7892         else if (fout->remoteVersion >= 70100)
7893         {
7894                 /*
7895                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
7896                  * representation.
7897                  */
7898                 appendPQExpBuffer(query, "SELECT typlen, "
7899                                                   "typinput, typoutput, "
7900                                                   "'-' AS typreceive, '-' AS typsend, "
7901                                                   "'-' AS typmodin, '-' AS typmodout, "
7902                                                   "'-' AS typanalyze, "
7903                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7904                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7905                                                   "0 AS typanalyzeoid, "
7906                                                   "'U' AS typcategory, false AS typispreferred, "
7907                                                   "typdelim, typbyval, typalign, typstorage, "
7908                                                   "false AS typcollatable, "
7909                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7910                                                   "FROM pg_type "
7911                                                   "WHERE oid = '%u'::oid",
7912                                                   tyinfo->dobj.catId.oid);
7913         }
7914         else
7915         {
7916                 appendPQExpBuffer(query, "SELECT typlen, "
7917                                                   "typinput, typoutput, "
7918                                                   "'-' AS typreceive, '-' AS typsend, "
7919                                                   "'-' AS typmodin, '-' AS typmodout, "
7920                                                   "'-' AS typanalyze, "
7921                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7922                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7923                                                   "0 AS typanalyzeoid, "
7924                                                   "'U' AS typcategory, false AS typispreferred, "
7925                                                   "typdelim, typbyval, typalign, "
7926                                                   "'p'::char AS typstorage, "
7927                                                   "false AS typcollatable, "
7928                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7929                                                   "FROM pg_type "
7930                                                   "WHERE oid = '%u'::oid",
7931                                                   tyinfo->dobj.catId.oid);
7932         }
7933
7934         res = PQexec(g_conn, query->data);
7935         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7936
7937         /* Expecting a single result only */
7938         ntups = PQntuples(res);
7939         if (ntups != 1)
7940         {
7941                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7942                                                            "query returned %d rows instead of one: %s\n",
7943                                                                  ntups),
7944                                   ntups, query->data);
7945                 exit_nicely();
7946         }
7947
7948         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
7949         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
7950         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7951         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
7952         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
7953         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
7954         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7955         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
7956         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
7957         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
7958         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
7959         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7960         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
7961         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
7962         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
7963         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
7964         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
7965         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
7966         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
7967         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
7968         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
7969                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
7970         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
7971         {
7972                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
7973                 typdefault_is_literal = true;   /* it needs quotes */
7974         }
7975         else
7976                 typdefault = NULL;
7977
7978         /*
7979          * DROP must be fully qualified in case same name appears in pg_catalog.
7980          * The reason we include CASCADE is that the circular dependency between
7981          * the type and its I/O functions makes it impossible to drop the type any
7982          * other way.
7983          */
7984         appendPQExpBuffer(delq, "DROP TYPE %s.",
7985                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7986         appendPQExpBuffer(delq, "%s CASCADE;\n",
7987                                           fmtId(tyinfo->dobj.name));
7988
7989         /* We might already have a shell type, but setting pg_type_oid is harmless */
7990         if (binary_upgrade)
7991                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7992
7993         appendPQExpBuffer(q,
7994                                           "CREATE TYPE %s (\n"
7995                                           "    INTERNALLENGTH = %s",
7996                                           fmtId(tyinfo->dobj.name),
7997                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
7998
7999         if (fout->remoteVersion >= 70300)
8000         {
8001                 /* regproc result is correctly quoted as of 7.3 */
8002                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8003                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8004                 if (OidIsValid(typreceiveoid))
8005                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8006                 if (OidIsValid(typsendoid))
8007                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8008                 if (OidIsValid(typmodinoid))
8009                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8010                 if (OidIsValid(typmodoutoid))
8011                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8012                 if (OidIsValid(typanalyzeoid))
8013                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8014         }
8015         else
8016         {
8017                 /* regproc delivers an unquoted name before 7.3 */
8018                 /* cannot combine these because fmtId uses static result area */
8019                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8020                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8021                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8022         }
8023
8024         if (strcmp(typcollatable, "t") == 0)
8025                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8026
8027         if (typdefault != NULL)
8028         {
8029                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8030                 if (typdefault_is_literal)
8031                         appendStringLiteralAH(q, typdefault, fout);
8032                 else
8033                         appendPQExpBufferStr(q, typdefault);
8034         }
8035
8036         if (OidIsValid(tyinfo->typelem))
8037         {
8038                 char       *elemType;
8039
8040                 /* reselect schema in case changed by function dump */
8041                 selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
8042                 elemType = getFormattedTypeName(tyinfo->typelem, zeroAsOpaque);
8043                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8044                 free(elemType);
8045         }
8046
8047         if (strcmp(typcategory, "U") != 0)
8048         {
8049                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8050                 appendStringLiteralAH(q, typcategory, fout);
8051         }
8052
8053         if (strcmp(typispreferred, "t") == 0)
8054                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8055
8056         if (typdelim && strcmp(typdelim, ",") != 0)
8057         {
8058                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8059                 appendStringLiteralAH(q, typdelim, fout);
8060         }
8061
8062         if (strcmp(typalign, "c") == 0)
8063                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8064         else if (strcmp(typalign, "s") == 0)
8065                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8066         else if (strcmp(typalign, "i") == 0)
8067                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8068         else if (strcmp(typalign, "d") == 0)
8069                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8070
8071         if (strcmp(typstorage, "p") == 0)
8072                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8073         else if (strcmp(typstorage, "e") == 0)
8074                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8075         else if (strcmp(typstorage, "x") == 0)
8076                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8077         else if (strcmp(typstorage, "m") == 0)
8078                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8079
8080         if (strcmp(typbyval, "t") == 0)
8081                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8082
8083         appendPQExpBuffer(q, "\n);\n");
8084
8085         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8086
8087         if (binary_upgrade)
8088                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8089
8090         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8091                                  tyinfo->dobj.name,
8092                                  tyinfo->dobj.namespace->dobj.name,
8093                                  NULL,
8094                                  tyinfo->rolname, false,
8095                                  "TYPE", SECTION_PRE_DATA,
8096                                  q->data, delq->data, NULL,
8097                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8098                                  NULL, NULL);
8099
8100         /* Dump Type Comments and Security Labels */
8101         dumpComment(fout, labelq->data,
8102                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8103                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8104         dumpSecLabel(fout, labelq->data,
8105                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8106                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8107
8108         PQclear(res);
8109         destroyPQExpBuffer(q);
8110         destroyPQExpBuffer(delq);
8111         destroyPQExpBuffer(labelq);
8112         destroyPQExpBuffer(query);
8113 }
8114
8115 /*
8116  * dumpDomain
8117  *        writes out to fout the queries to recreate a user-defined domain
8118  */
8119 static void
8120 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8121 {
8122         PQExpBuffer q = createPQExpBuffer();
8123         PQExpBuffer delq = createPQExpBuffer();
8124         PQExpBuffer labelq = createPQExpBuffer();
8125         PQExpBuffer query = createPQExpBuffer();
8126         PGresult   *res;
8127         int                     ntups;
8128         int                     i;
8129         char       *typnotnull;
8130         char       *typdefn;
8131         char       *typdefault;
8132         Oid                     typcollation;
8133         bool            typdefault_is_literal = false;
8134
8135         /* Set proper schema search path so type references list correctly */
8136         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
8137
8138         /* Fetch domain specific details */
8139         if (g_fout->remoteVersion >= 90100)
8140         {
8141                 /* typcollation is new in 9.1 */
8142                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8143                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8144                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8145                                                   "t.typdefault, "
8146                                                   "CASE WHEN t.typcollation <> u.typcollation "
8147                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8148                                                   "FROM pg_catalog.pg_type t "
8149                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8150                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8151                                                   tyinfo->dobj.catId.oid);
8152         }
8153         else
8154         {
8155                 /* We assume here that remoteVersion must be at least 70300 */
8156                 appendPQExpBuffer(query, "SELECT typnotnull, "
8157                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8158                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8159                                                   "typdefault, 0 AS typcollation "
8160                                                   "FROM pg_catalog.pg_type "
8161                                                   "WHERE oid = '%u'::pg_catalog.oid",
8162                                                   tyinfo->dobj.catId.oid);
8163         }
8164
8165         res = PQexec(g_conn, query->data);
8166         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8167
8168         /* Expecting a single result only */
8169         ntups = PQntuples(res);
8170         if (ntups != 1)
8171         {
8172                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8173                                                            "query returned %d rows instead of one: %s\n",
8174                                                                  ntups),
8175                                   ntups, query->data);
8176                 exit_nicely();
8177         }
8178
8179         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8180         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8181         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8182                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8183         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8184         {
8185                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8186                 typdefault_is_literal = true;   /* it needs quotes */
8187         }
8188         else
8189                 typdefault = NULL;
8190         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8191
8192         if (binary_upgrade)
8193                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
8194
8195         appendPQExpBuffer(q,
8196                                           "CREATE DOMAIN %s AS %s",
8197                                           fmtId(tyinfo->dobj.name),
8198                                           typdefn);
8199
8200         /* Print collation only if different from base type's collation */
8201         if (OidIsValid(typcollation))
8202         {
8203                 CollInfo   *coll;
8204
8205                 coll = findCollationByOid(typcollation);
8206                 if (coll)
8207                 {
8208                         /* always schema-qualify, don't try to be smart */
8209                         appendPQExpBuffer(q, " COLLATE %s.",
8210                                                           fmtId(coll->dobj.namespace->dobj.name));
8211                         appendPQExpBuffer(q, "%s",
8212                                                           fmtId(coll->dobj.name));
8213                 }
8214         }
8215
8216         if (typnotnull[0] == 't')
8217                 appendPQExpBuffer(q, " NOT NULL");
8218
8219         if (typdefault != NULL)
8220         {
8221                 appendPQExpBuffer(q, " DEFAULT ");
8222                 if (typdefault_is_literal)
8223                         appendStringLiteralAH(q, typdefault, fout);
8224                 else
8225                         appendPQExpBufferStr(q, typdefault);
8226         }
8227
8228         PQclear(res);
8229
8230         /*
8231          * Add any CHECK constraints for the domain
8232          */
8233         for (i = 0; i < tyinfo->nDomChecks; i++)
8234         {
8235                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8236
8237                 if (!domcheck->separate)
8238                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8239                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8240         }
8241
8242         appendPQExpBuffer(q, ";\n");
8243
8244         /*
8245          * DROP must be fully qualified in case same name appears in pg_catalog
8246          */
8247         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8248                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8249         appendPQExpBuffer(delq, "%s;\n",
8250                                           fmtId(tyinfo->dobj.name));
8251
8252         appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
8253
8254         if (binary_upgrade)
8255                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8256
8257         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8258                                  tyinfo->dobj.name,
8259                                  tyinfo->dobj.namespace->dobj.name,
8260                                  NULL,
8261                                  tyinfo->rolname, false,
8262                                  "DOMAIN", SECTION_PRE_DATA,
8263                                  q->data, delq->data, NULL,
8264                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8265                                  NULL, NULL);
8266
8267         /* Dump Domain Comments and Security Labels */
8268         dumpComment(fout, labelq->data,
8269                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8270                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8271         dumpSecLabel(fout, labelq->data,
8272                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8273                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8274
8275         destroyPQExpBuffer(q);
8276         destroyPQExpBuffer(delq);
8277         destroyPQExpBuffer(labelq);
8278         destroyPQExpBuffer(query);
8279 }
8280
8281 /*
8282  * dumpCompositeType
8283  *        writes out to fout the queries to recreate a user-defined stand-alone
8284  *        composite type
8285  */
8286 static void
8287 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8288 {
8289         PQExpBuffer q = createPQExpBuffer();
8290         PQExpBuffer dropped = createPQExpBuffer();
8291         PQExpBuffer delq = createPQExpBuffer();
8292         PQExpBuffer labelq = createPQExpBuffer();
8293         PQExpBuffer query = createPQExpBuffer();
8294         PGresult   *res;
8295         int                     ntups;
8296         int                     i_attname;
8297         int                     i_atttypdefn;
8298         int                     i_attlen;
8299         int                     i_attalign;
8300         int                     i_attisdropped;
8301         int                     i_attcollation;
8302         int                     i_typrelid;
8303         int                     i;
8304         int                     actual_atts;
8305
8306         /* Set proper schema search path so type references list correctly */
8307         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
8308
8309         /* Fetch type specific details */
8310         if (fout->remoteVersion >= 90100)
8311         {
8312                 /*
8313                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8314                  * clauses for attributes whose collation is different from their
8315                  * type's default, we use a CASE here to suppress uninteresting
8316                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8317                  * collation does not matter for those.
8318                  */
8319                 appendPQExpBuffer(query, "SELECT a.attname, "
8320                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8321                                                   "a.attlen, a.attalign, a.attisdropped, "
8322                                                   "CASE WHEN a.attcollation <> at.typcollation "
8323                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8324                                                   "ct.typrelid "
8325                                                   "FROM pg_catalog.pg_type ct "
8326                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8327                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8328                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8329                                                   "ORDER BY a.attnum ",
8330                                                   tyinfo->dobj.catId.oid);
8331         }
8332         else
8333         {
8334                 /*
8335                  * We assume here that remoteVersion must be at least 70300.  Since
8336                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8337                  * always be false.
8338                  */
8339                 appendPQExpBuffer(query, "SELECT a.attname, "
8340                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8341                                                   "a.attlen, a.attalign, a.attisdropped, "
8342                                                   "0 AS attcollation, "
8343                                                   "ct.typrelid "
8344                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8345                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8346                                                   "AND a.attrelid = ct.typrelid "
8347                                                   "ORDER BY a.attnum ",
8348                                                   tyinfo->dobj.catId.oid);
8349         }
8350
8351         res = PQexec(g_conn, query->data);
8352         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8353
8354         ntups = PQntuples(res);
8355
8356         i_attname = PQfnumber(res, "attname");
8357         i_atttypdefn = PQfnumber(res, "atttypdefn");
8358         i_attlen = PQfnumber(res, "attlen");
8359         i_attalign = PQfnumber(res, "attalign");
8360         i_attisdropped = PQfnumber(res, "attisdropped");
8361         i_attcollation = PQfnumber(res, "attcollation");
8362         i_typrelid = PQfnumber(res, "typrelid");
8363
8364         if (binary_upgrade)
8365         {
8366                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8367
8368                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
8369                 binary_upgrade_set_pg_class_oids(q, typrelid, false);
8370         }
8371
8372         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8373                                           fmtId(tyinfo->dobj.name));
8374
8375         actual_atts = 0;
8376         for (i = 0; i < ntups; i++)
8377         {
8378                 char       *attname;
8379                 char       *atttypdefn;
8380                 char       *attlen;
8381                 char       *attalign;
8382                 bool            attisdropped;
8383                 Oid                     attcollation;
8384
8385                 attname = PQgetvalue(res, i, i_attname);
8386                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8387                 attlen = PQgetvalue(res, i, i_attlen);
8388                 attalign = PQgetvalue(res, i, i_attalign);
8389                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8390                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8391
8392                 if (attisdropped && !binary_upgrade)
8393                         continue;
8394
8395                 /* Format properly if not first attr */
8396                 if (actual_atts++ > 0)
8397                         appendPQExpBuffer(q, ",");
8398                 appendPQExpBuffer(q, "\n\t");
8399
8400                 if (!attisdropped)
8401                 {
8402                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8403
8404                         /* Add collation if not default for the column type */
8405                         if (OidIsValid(attcollation))
8406                         {
8407                                 CollInfo   *coll;
8408
8409                                 coll = findCollationByOid(attcollation);
8410                                 if (coll)
8411                                 {
8412                                         /* always schema-qualify, don't try to be smart */
8413                                         appendPQExpBuffer(q, " COLLATE %s.",
8414                                                                           fmtId(coll->dobj.namespace->dobj.name));
8415                                         appendPQExpBuffer(q, "%s",
8416                                                                           fmtId(coll->dobj.name));
8417                                 }
8418                         }
8419                 }
8420                 else
8421                 {
8422                         /*
8423                          * This is a dropped attribute and we're in binary_upgrade mode.
8424                          * Insert a placeholder for it in the CREATE TYPE command, and set
8425                          * length and alignment with direct UPDATE to the catalogs
8426                          * afterwards. See similar code in dumpTableSchema().
8427                          */
8428                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8429
8430                         /* stash separately for insertion after the CREATE TYPE */
8431                         appendPQExpBuffer(dropped,
8432                                           "\n-- For binary upgrade, recreate dropped column.\n");
8433                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8434                                                           "SET attlen = %s, "
8435                                                           "attalign = '%s', attbyval = false\n"
8436                                                           "WHERE attname = ", attlen, attalign);
8437                         appendStringLiteralAH(dropped, attname, fout);
8438                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8439                         appendStringLiteralAH(dropped, fmtId(tyinfo->dobj.name), fout);
8440                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8441
8442                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8443                                                           fmtId(tyinfo->dobj.name));
8444                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8445                                                           fmtId(attname));
8446                 }
8447         }
8448         appendPQExpBuffer(q, "\n);\n");
8449         appendPQExpBufferStr(q, dropped->data);
8450
8451         /*
8452          * DROP must be fully qualified in case same name appears in pg_catalog
8453          */
8454         appendPQExpBuffer(delq, "DROP TYPE %s.",
8455                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8456         appendPQExpBuffer(delq, "%s;\n",
8457                                           fmtId(tyinfo->dobj.name));
8458
8459         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8460
8461         if (binary_upgrade)
8462                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8463
8464         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8465                                  tyinfo->dobj.name,
8466                                  tyinfo->dobj.namespace->dobj.name,
8467                                  NULL,
8468                                  tyinfo->rolname, false,
8469                                  "TYPE", SECTION_PRE_DATA,
8470                                  q->data, delq->data, NULL,
8471                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8472                                  NULL, NULL);
8473
8474
8475         /* Dump Type Comments and Security Labels */
8476         dumpComment(fout, labelq->data,
8477                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8478                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8479         dumpSecLabel(fout, labelq->data,
8480                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8481                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8482
8483         PQclear(res);
8484         destroyPQExpBuffer(q);
8485         destroyPQExpBuffer(dropped);
8486         destroyPQExpBuffer(delq);
8487         destroyPQExpBuffer(labelq);
8488         destroyPQExpBuffer(query);
8489
8490         /* Dump any per-column comments */
8491         dumpCompositeTypeColComments(fout, tyinfo);
8492 }
8493
8494 /*
8495  * dumpCompositeTypeColComments
8496  *        writes out to fout the queries to recreate comments on the columns of
8497  *        a user-defined stand-alone composite type
8498  */
8499 static void
8500 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
8501 {
8502         CommentItem *comments;
8503         int                     ncomments;
8504         PGresult   *res;
8505         PQExpBuffer query;
8506         PQExpBuffer target;
8507         Oid                     pgClassOid;
8508         int                     i;
8509         int                     ntups;
8510         int                     i_attname;
8511         int                     i_attnum;
8512
8513         query = createPQExpBuffer();
8514
8515         /* We assume here that remoteVersion must be at least 70300 */
8516         appendPQExpBuffer(query,
8517                                           "SELECT c.tableoid, a.attname, a.attnum "
8518                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
8519                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
8520                                           "  AND NOT a.attisdropped "
8521                                           "ORDER BY a.attnum ",
8522                                           tyinfo->typrelid);
8523
8524         /* Fetch column attnames */
8525         res = PQexec(g_conn, query->data);
8526         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8527
8528         ntups = PQntuples(res);
8529         if (ntups < 1)
8530         {
8531                 PQclear(res);
8532                 destroyPQExpBuffer(query);
8533                 return;
8534         }
8535
8536         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
8537
8538         /* Search for comments associated with type's pg_class OID */
8539         ncomments = findComments(fout,
8540                                                          pgClassOid,
8541                                                          tyinfo->typrelid,
8542                                                          &comments);
8543
8544         /* If no comments exist, we're done */
8545         if (ncomments <= 0)
8546         {
8547                 PQclear(res);
8548                 destroyPQExpBuffer(query);
8549                 return;
8550         }
8551
8552         /* Build COMMENT ON statements */
8553         target = createPQExpBuffer();
8554
8555         i_attnum = PQfnumber(res, "attnum");
8556         i_attname = PQfnumber(res, "attname");
8557         while (ncomments > 0)
8558         {
8559                 const char *attname;
8560
8561                 attname = NULL;
8562                 for (i = 0; i < ntups; i++)
8563                 {
8564                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
8565                         {
8566                                 attname = PQgetvalue(res, i, i_attname);
8567                                 break;
8568                         }
8569                 }
8570                 if (attname)                    /* just in case we don't find it */
8571                 {
8572                         const char *descr = comments->descr;
8573
8574                         resetPQExpBuffer(target);
8575                         appendPQExpBuffer(target, "COLUMN %s.",
8576                                                           fmtId(tyinfo->dobj.name));
8577                         appendPQExpBuffer(target, "%s",
8578                                                           fmtId(attname));
8579
8580                         resetPQExpBuffer(query);
8581                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
8582                         appendStringLiteralAH(query, descr, fout);
8583                         appendPQExpBuffer(query, ";\n");
8584
8585                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
8586                                                  target->data,
8587                                                  tyinfo->dobj.namespace->dobj.name,
8588                                                  NULL, tyinfo->rolname,
8589                                                  false, "COMMENT", SECTION_NONE,
8590                                                  query->data, "", NULL,
8591                                                  &(tyinfo->dobj.dumpId), 1,
8592                                                  NULL, NULL);
8593                 }
8594
8595                 comments++;
8596                 ncomments--;
8597         }
8598
8599         PQclear(res);
8600         destroyPQExpBuffer(query);
8601         destroyPQExpBuffer(target);
8602 }
8603
8604 /*
8605  * dumpShellType
8606  *        writes out to fout the queries to create a shell type
8607  *
8608  * We dump a shell definition in advance of the I/O functions for the type.
8609  */
8610 static void
8611 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
8612 {
8613         PQExpBuffer q;
8614
8615         /* Skip if not to be dumped */
8616         if (!stinfo->dobj.dump || dataOnly)
8617                 return;
8618
8619         q = createPQExpBuffer();
8620
8621         /*
8622          * Note the lack of a DROP command for the shell type; any required DROP
8623          * is driven off the base type entry, instead.  This interacts with
8624          * _printTocEntry()'s use of the presence of a DROP command to decide
8625          * whether an entry needs an ALTER OWNER command.  We don't want to alter
8626          * the shell type's owner immediately on creation; that should happen only
8627          * after it's filled in, otherwise the backend complains.
8628          */
8629
8630         if (binary_upgrade)
8631                 binary_upgrade_set_type_oids_by_type_oid(q,
8632                                                                                    stinfo->baseType->dobj.catId.oid);
8633
8634         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
8635                                           fmtId(stinfo->dobj.name));
8636
8637         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
8638                                  stinfo->dobj.name,
8639                                  stinfo->dobj.namespace->dobj.name,
8640                                  NULL,
8641                                  stinfo->baseType->rolname, false,
8642                                  "SHELL TYPE", SECTION_PRE_DATA,
8643                                  q->data, "", NULL,
8644                                  stinfo->dobj.dependencies, stinfo->dobj.nDeps,
8645                                  NULL, NULL);
8646
8647         destroyPQExpBuffer(q);
8648 }
8649
8650 /*
8651  * Determine whether we want to dump definitions for procedural languages.
8652  * Since the languages themselves don't have schemas, we can't rely on
8653  * the normal schema-based selection mechanism.  We choose to dump them
8654  * whenever neither --schema nor --table was given.  (Before 8.1, we used
8655  * the dump flag of the PL's call handler function, but in 8.1 this will
8656  * probably always be false since call handlers are created in pg_catalog.)
8657  *
8658  * For some backwards compatibility with the older behavior, we forcibly
8659  * dump a PL if its handler function (and validator if any) are in a
8660  * dumpable namespace.  That case is not checked here.
8661  *
8662  * Also, if the PL belongs to an extension, we do not use this heuristic.
8663  * That case isn't checked here either.
8664  */
8665 static bool
8666 shouldDumpProcLangs(void)
8667 {
8668         if (!include_everything)
8669                 return false;
8670         /* And they're schema not data */
8671         if (dataOnly)
8672                 return false;
8673         return true;
8674 }
8675
8676 /*
8677  * dumpProcLang
8678  *                writes out to fout the queries to recreate a user-defined
8679  *                procedural language
8680  */
8681 static void
8682 dumpProcLang(Archive *fout, ProcLangInfo *plang)
8683 {
8684         PQExpBuffer defqry;
8685         PQExpBuffer delqry;
8686         PQExpBuffer labelq;
8687         bool            useParams;
8688         char       *qlanname;
8689         char       *lanschema;
8690         FuncInfo   *funcInfo;
8691         FuncInfo   *inlineInfo = NULL;
8692         FuncInfo   *validatorInfo = NULL;
8693
8694         /* Skip if not to be dumped */
8695         if (!plang->dobj.dump || dataOnly)
8696                 return;
8697
8698         /*
8699          * Try to find the support function(s).  It is not an error if we don't
8700          * find them --- if the functions are in the pg_catalog schema, as is
8701          * standard in 8.1 and up, then we won't have loaded them. (In this case
8702          * we will emit a parameterless CREATE LANGUAGE command, which will
8703          * require PL template knowledge in the backend to reload.)
8704          */
8705
8706         funcInfo = findFuncByOid(plang->lanplcallfoid);
8707         if (funcInfo != NULL && !funcInfo->dobj.dump)
8708                 funcInfo = NULL;                /* treat not-dumped same as not-found */
8709
8710         if (OidIsValid(plang->laninline))
8711         {
8712                 inlineInfo = findFuncByOid(plang->laninline);
8713                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
8714                         inlineInfo = NULL;
8715         }
8716
8717         if (OidIsValid(plang->lanvalidator))
8718         {
8719                 validatorInfo = findFuncByOid(plang->lanvalidator);
8720                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
8721                         validatorInfo = NULL;
8722         }
8723
8724         /*
8725          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
8726          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
8727          * dump it.
8728          *
8729          * However, for a language that belongs to an extension, we must not use
8730          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
8731          * told to (via dobj.dump).  Generally the support functions will belong
8732          * to the same extension and so have the same dump flags ... if they
8733          * don't, this might not work terribly nicely.
8734          */
8735         useParams = (funcInfo != NULL &&
8736                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
8737                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
8738
8739         if (!plang->dobj.ext_member)
8740         {
8741                 if (!useParams && !shouldDumpProcLangs())
8742                         return;
8743         }
8744
8745         defqry = createPQExpBuffer();
8746         delqry = createPQExpBuffer();
8747         labelq = createPQExpBuffer();
8748
8749         qlanname = pg_strdup(fmtId(plang->dobj.name));
8750
8751         /*
8752          * If dumping a HANDLER clause, treat the language as being in the handler
8753          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
8754          * it doesn't really have a schema.
8755          */
8756         if (useParams)
8757                 lanschema = funcInfo->dobj.namespace->dobj.name;
8758         else
8759                 lanschema = NULL;
8760
8761         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
8762                                           qlanname);
8763
8764         if (useParams)
8765         {
8766                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
8767                                                   plang->lanpltrusted ? "TRUSTED " : "",
8768                                                   qlanname);
8769                 appendPQExpBuffer(defqry, " HANDLER %s",
8770                                                   fmtId(funcInfo->dobj.name));
8771                 if (OidIsValid(plang->laninline))
8772                 {
8773                         appendPQExpBuffer(defqry, " INLINE ");
8774                         /* Cope with possibility that inline is in different schema */
8775                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
8776                                 appendPQExpBuffer(defqry, "%s.",
8777                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
8778                         appendPQExpBuffer(defqry, "%s",
8779                                                           fmtId(inlineInfo->dobj.name));
8780                 }
8781                 if (OidIsValid(plang->lanvalidator))
8782                 {
8783                         appendPQExpBuffer(defqry, " VALIDATOR ");
8784                         /* Cope with possibility that validator is in different schema */
8785                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
8786                                 appendPQExpBuffer(defqry, "%s.",
8787                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
8788                         appendPQExpBuffer(defqry, "%s",
8789                                                           fmtId(validatorInfo->dobj.name));
8790                 }
8791         }
8792         else
8793         {
8794                 /*
8795                  * If not dumping parameters, then use CREATE OR REPLACE so that the
8796                  * command will not fail if the language is preinstalled in the target
8797                  * database.  We restrict the use of REPLACE to this case so as to
8798                  * eliminate the risk of replacing a language with incompatible
8799                  * parameter settings: this command will only succeed at all if there
8800                  * is a pg_pltemplate entry, and if there is one, the existing entry
8801                  * must match it too.
8802                  */
8803                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
8804                                                   qlanname);
8805         }
8806         appendPQExpBuffer(defqry, ";\n");
8807
8808         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
8809
8810         if (binary_upgrade)
8811                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
8812
8813         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
8814                                  plang->dobj.name,
8815                                  lanschema, NULL, plang->lanowner,
8816                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
8817                                  defqry->data, delqry->data, NULL,
8818                                  plang->dobj.dependencies, plang->dobj.nDeps,
8819                                  NULL, NULL);
8820
8821         /* Dump Proc Lang Comments and Security Labels */
8822         dumpComment(fout, labelq->data,
8823                                 NULL, "",
8824                                 plang->dobj.catId, 0, plang->dobj.dumpId);
8825         dumpSecLabel(fout, labelq->data,
8826                                  NULL, "",
8827                                  plang->dobj.catId, 0, plang->dobj.dumpId);
8828
8829         if (plang->lanpltrusted)
8830                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
8831                                 qlanname, NULL, plang->dobj.name,
8832                                 lanschema,
8833                                 plang->lanowner, plang->lanacl);
8834
8835         free(qlanname);
8836
8837         destroyPQExpBuffer(defqry);
8838         destroyPQExpBuffer(delqry);
8839         destroyPQExpBuffer(labelq);
8840 }
8841
8842 /*
8843  * format_function_arguments: generate function name and argument list
8844  *
8845  * This is used when we can rely on pg_get_function_arguments to format
8846  * the argument list.
8847  */
8848 static char *
8849 format_function_arguments(FuncInfo *finfo, char *funcargs)
8850 {
8851         PQExpBufferData fn;
8852
8853         initPQExpBuffer(&fn);
8854         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
8855         return fn.data;
8856 }
8857
8858 /*
8859  * format_function_arguments_old: generate function name and argument list
8860  *
8861  * The argument type names are qualified if needed.  The function name
8862  * is never qualified.
8863  *
8864  * This is used only with pre-8.4 servers, so we aren't expecting to see
8865  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
8866  *
8867  * Any or all of allargtypes, argmodes, argnames may be NULL.
8868  */
8869 static char *
8870 format_function_arguments_old(FuncInfo *finfo, int nallargs,
8871                                                           char **allargtypes,
8872                                                           char **argmodes,
8873                                                           char **argnames)
8874 {
8875         PQExpBufferData fn;
8876         int                     j;
8877
8878         initPQExpBuffer(&fn);
8879         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8880         for (j = 0; j < nallargs; j++)
8881         {
8882                 Oid                     typid;
8883                 char       *typname;
8884                 const char *argmode;
8885                 const char *argname;
8886
8887                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
8888                 typname = getFormattedTypeName(typid, zeroAsOpaque);
8889
8890                 if (argmodes)
8891                 {
8892                         switch (argmodes[j][0])
8893                         {
8894                                 case PROARGMODE_IN:
8895                                         argmode = "";
8896                                         break;
8897                                 case PROARGMODE_OUT:
8898                                         argmode = "OUT ";
8899                                         break;
8900                                 case PROARGMODE_INOUT:
8901                                         argmode = "INOUT ";
8902                                         break;
8903                                 default:
8904                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
8905                                         argmode = "";
8906                                         break;
8907                         }
8908                 }
8909                 else
8910                         argmode = "";
8911
8912                 argname = argnames ? argnames[j] : (char *) NULL;
8913                 if (argname && argname[0] == '\0')
8914                         argname = NULL;
8915
8916                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
8917                                                   (j > 0) ? ", " : "",
8918                                                   argmode,
8919                                                   argname ? fmtId(argname) : "",
8920                                                   argname ? " " : "",
8921                                                   typname);
8922                 free(typname);
8923         }
8924         appendPQExpBuffer(&fn, ")");
8925         return fn.data;
8926 }
8927
8928 /*
8929  * format_function_signature: generate function name and argument list
8930  *
8931  * This is like format_function_arguments_old except that only a minimal
8932  * list of input argument types is generated; this is sufficient to
8933  * reference the function, but not to define it.
8934  *
8935  * If honor_quotes is false then the function name is never quoted.
8936  * This is appropriate for use in TOC tags, but not in SQL commands.
8937  */
8938 static char *
8939 format_function_signature(FuncInfo *finfo, bool honor_quotes)
8940 {
8941         PQExpBufferData fn;
8942         int                     j;
8943
8944         initPQExpBuffer(&fn);
8945         if (honor_quotes)
8946                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8947         else
8948                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
8949         for (j = 0; j < finfo->nargs; j++)
8950         {
8951                 char       *typname;
8952
8953                 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
8954
8955                 appendPQExpBuffer(&fn, "%s%s",
8956                                                   (j > 0) ? ", " : "",
8957                                                   typname);
8958                 free(typname);
8959         }
8960         appendPQExpBuffer(&fn, ")");
8961         return fn.data;
8962 }
8963
8964
8965 /*
8966  * dumpFunc:
8967  *        dump out one function
8968  */
8969 static void
8970 dumpFunc(Archive *fout, FuncInfo *finfo)
8971 {
8972         PQExpBuffer query;
8973         PQExpBuffer q;
8974         PQExpBuffer delqry;
8975         PQExpBuffer labelq;
8976         PQExpBuffer asPart;
8977         PGresult   *res;
8978         char       *funcsig;            /* identity signature */
8979         char       *funcfullsig;        /* full signature */
8980         char       *funcsig_tag;
8981         int                     ntups;
8982         char       *proretset;
8983         char       *prosrc;
8984         char       *probin;
8985         char       *funcargs;
8986         char       *funciargs;
8987         char       *funcresult;
8988         char       *proallargtypes;
8989         char       *proargmodes;
8990         char       *proargnames;
8991         char       *proiswindow;
8992         char       *provolatile;
8993         char       *proisstrict;
8994         char       *prosecdef;
8995         char       *proconfig;
8996         char       *procost;
8997         char       *prorows;
8998         char       *lanname;
8999         char       *rettypename;
9000         int                     nallargs;
9001         char      **allargtypes = NULL;
9002         char      **argmodes = NULL;
9003         char      **argnames = NULL;
9004         char      **configitems = NULL;
9005         int                     nconfigitems = 0;
9006         int                     i;
9007
9008         /* Skip if not to be dumped */
9009         if (!finfo->dobj.dump || dataOnly)
9010                 return;
9011
9012         query = createPQExpBuffer();
9013         q = createPQExpBuffer();
9014         delqry = createPQExpBuffer();
9015         labelq = createPQExpBuffer();
9016         asPart = createPQExpBuffer();
9017
9018         /* Set proper schema search path so type references list correctly */
9019         selectSourceSchema(finfo->dobj.namespace->dobj.name);
9020
9021         /* Fetch function-specific details */
9022         if (g_fout->remoteVersion >= 80400)
9023         {
9024                 /*
9025                  * In 8.4 and up we rely on pg_get_function_arguments and
9026                  * pg_get_function_result instead of examining proallargtypes etc.
9027                  */
9028                 appendPQExpBuffer(query,
9029                                                   "SELECT proretset, prosrc, probin, "
9030                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9031                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9032                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9033                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9034                                                   "proconfig, procost, prorows, "
9035                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9036                                                   "FROM pg_catalog.pg_proc "
9037                                                   "WHERE oid = '%u'::pg_catalog.oid",
9038                                                   finfo->dobj.catId.oid);
9039         }
9040         else if (g_fout->remoteVersion >= 80300)
9041         {
9042                 appendPQExpBuffer(query,
9043                                                   "SELECT proretset, prosrc, probin, "
9044                                                   "proallargtypes, proargmodes, proargnames, "
9045                                                   "false AS proiswindow, "
9046                                                   "provolatile, proisstrict, prosecdef, "
9047                                                   "proconfig, procost, prorows, "
9048                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9049                                                   "FROM pg_catalog.pg_proc "
9050                                                   "WHERE oid = '%u'::pg_catalog.oid",
9051                                                   finfo->dobj.catId.oid);
9052         }
9053         else if (g_fout->remoteVersion >= 80100)
9054         {
9055                 appendPQExpBuffer(query,
9056                                                   "SELECT proretset, prosrc, probin, "
9057                                                   "proallargtypes, proargmodes, proargnames, "
9058                                                   "false AS proiswindow, "
9059                                                   "provolatile, proisstrict, prosecdef, "
9060                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9061                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9062                                                   "FROM pg_catalog.pg_proc "
9063                                                   "WHERE oid = '%u'::pg_catalog.oid",
9064                                                   finfo->dobj.catId.oid);
9065         }
9066         else if (g_fout->remoteVersion >= 80000)
9067         {
9068                 appendPQExpBuffer(query,
9069                                                   "SELECT proretset, prosrc, probin, "
9070                                                   "null AS proallargtypes, "
9071                                                   "null AS proargmodes, "
9072                                                   "proargnames, "
9073                                                   "false AS proiswindow, "
9074                                                   "provolatile, proisstrict, prosecdef, "
9075                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9076                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9077                                                   "FROM pg_catalog.pg_proc "
9078                                                   "WHERE oid = '%u'::pg_catalog.oid",
9079                                                   finfo->dobj.catId.oid);
9080         }
9081         else if (g_fout->remoteVersion >= 70300)
9082         {
9083                 appendPQExpBuffer(query,
9084                                                   "SELECT proretset, prosrc, probin, "
9085                                                   "null AS proallargtypes, "
9086                                                   "null AS proargmodes, "
9087                                                   "null AS proargnames, "
9088                                                   "false AS proiswindow, "
9089                                                   "provolatile, proisstrict, prosecdef, "
9090                                                   "null AS proconfig, 0 AS procost, 0 AS 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 (g_fout->remoteVersion >= 70100)
9097         {
9098                 appendPQExpBuffer(query,
9099                                                   "SELECT proretset, prosrc, probin, "
9100                                                   "null AS proallargtypes, "
9101                                                   "null AS proargmodes, "
9102                                                   "null AS proargnames, "
9103                                                   "false AS proiswindow, "
9104                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9105                                                   "proisstrict, "
9106                                                   "false AS prosecdef, "
9107                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9108                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9109                                                   "FROM pg_proc "
9110                                                   "WHERE oid = '%u'::oid",
9111                                                   finfo->dobj.catId.oid);
9112         }
9113         else
9114         {
9115                 appendPQExpBuffer(query,
9116                                                   "SELECT proretset, prosrc, probin, "
9117                                                   "null AS proallargtypes, "
9118                                                   "null AS proargmodes, "
9119                                                   "null AS proargnames, "
9120                                                   "false AS proiswindow, "
9121                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9122                                                   "false AS proisstrict, "
9123                                                   "false AS prosecdef, "
9124                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9125                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9126                                                   "FROM pg_proc "
9127                                                   "WHERE oid = '%u'::oid",
9128                                                   finfo->dobj.catId.oid);
9129         }
9130
9131         res = PQexec(g_conn, query->data);
9132         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9133
9134         /* Expecting a single result only */
9135         ntups = PQntuples(res);
9136         if (ntups != 1)
9137         {
9138                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9139                                                            "query returned %d rows instead of one: %s\n",
9140                                                                  ntups),
9141                                   ntups, query->data);
9142                 exit_nicely();
9143         }
9144
9145         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9146         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9147         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9148         if (g_fout->remoteVersion >= 80400)
9149         {
9150                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9151                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9152                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9153                 proallargtypes = proargmodes = proargnames = NULL;
9154         }
9155         else
9156         {
9157                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9158                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9159                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9160                 funcargs = funciargs = funcresult = NULL;
9161         }
9162         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9163         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9164         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9165         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9166         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9167         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9168         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9169         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9170
9171         /*
9172          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9173          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9174          * versions would set it to "-".  There are no known cases in which prosrc
9175          * is unused, so the tests below for "-" are probably useless.
9176          */
9177         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9178         {
9179                 appendPQExpBuffer(asPart, "AS ");
9180                 appendStringLiteralAH(asPart, probin, fout);
9181                 if (strcmp(prosrc, "-") != 0)
9182                 {
9183                         appendPQExpBuffer(asPart, ", ");
9184
9185                         /*
9186                          * where we have bin, use dollar quoting if allowed and src
9187                          * contains quote or backslash; else use regular quoting.
9188                          */
9189                         if (disable_dollar_quoting ||
9190                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9191                                 appendStringLiteralAH(asPart, prosrc, fout);
9192                         else
9193                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9194                 }
9195         }
9196         else
9197         {
9198                 if (strcmp(prosrc, "-") != 0)
9199                 {
9200                         appendPQExpBuffer(asPart, "AS ");
9201                         /* with no bin, dollar quote src unconditionally if allowed */
9202                         if (disable_dollar_quoting)
9203                                 appendStringLiteralAH(asPart, prosrc, fout);
9204                         else
9205                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9206                 }
9207         }
9208
9209         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9210
9211         if (proallargtypes && *proallargtypes)
9212         {
9213                 int                     nitems = 0;
9214
9215                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9216                         nitems < finfo->nargs)
9217                 {
9218                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9219                         if (allargtypes)
9220                                 free(allargtypes);
9221                         allargtypes = NULL;
9222                 }
9223                 else
9224                         nallargs = nitems;
9225         }
9226
9227         if (proargmodes && *proargmodes)
9228         {
9229                 int                     nitems = 0;
9230
9231                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9232                         nitems != nallargs)
9233                 {
9234                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9235                         if (argmodes)
9236                                 free(argmodes);
9237                         argmodes = NULL;
9238                 }
9239         }
9240
9241         if (proargnames && *proargnames)
9242         {
9243                 int                     nitems = 0;
9244
9245                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9246                         nitems != nallargs)
9247                 {
9248                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9249                         if (argnames)
9250                                 free(argnames);
9251                         argnames = NULL;
9252                 }
9253         }
9254
9255         if (proconfig && *proconfig)
9256         {
9257                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9258                 {
9259                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9260                         if (configitems)
9261                                 free(configitems);
9262                         configitems = NULL;
9263                         nconfigitems = 0;
9264                 }
9265         }
9266
9267         if (funcargs)
9268         {
9269                 /* 8.4 or later; we rely on server-side code for most of the work */
9270                 funcfullsig = format_function_arguments(finfo, funcargs);
9271                 funcsig = format_function_arguments(finfo, funciargs);
9272         }
9273         else
9274         {
9275                 /* pre-8.4, do it ourselves */
9276                 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
9277                                                                                                 argmodes, argnames);
9278                 funcfullsig = funcsig;
9279         }
9280
9281         funcsig_tag = format_function_signature(finfo, false);
9282
9283         /*
9284          * DROP must be fully qualified in case same name appears in pg_catalog
9285          */
9286         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9287                                           fmtId(finfo->dobj.namespace->dobj.name),
9288                                           funcsig);
9289
9290         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9291         if (funcresult)
9292                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9293         else
9294         {
9295                 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
9296                 appendPQExpBuffer(q, "RETURNS %s%s",
9297                                                   (proretset[0] == 't') ? "SETOF " : "",
9298                                                   rettypename);
9299                 free(rettypename);
9300         }
9301
9302         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9303
9304         if (proiswindow[0] == 't')
9305                 appendPQExpBuffer(q, " WINDOW");
9306
9307         if (provolatile[0] != PROVOLATILE_VOLATILE)
9308         {
9309                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9310                         appendPQExpBuffer(q, " IMMUTABLE");
9311                 else if (provolatile[0] == PROVOLATILE_STABLE)
9312                         appendPQExpBuffer(q, " STABLE");
9313                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9314                 {
9315                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
9316                                           finfo->dobj.name);
9317                         exit_nicely();
9318                 }
9319         }
9320
9321         if (proisstrict[0] == 't')
9322                 appendPQExpBuffer(q, " STRICT");
9323
9324         if (prosecdef[0] == 't')
9325                 appendPQExpBuffer(q, " SECURITY DEFINER");
9326
9327         /*
9328          * COST and ROWS are emitted only if present and not default, so as not to
9329          * break backwards-compatibility of the dump without need.      Keep this code
9330          * in sync with the defaults in functioncmds.c.
9331          */
9332         if (strcmp(procost, "0") != 0)
9333         {
9334                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9335                 {
9336                         /* default cost is 1 */
9337                         if (strcmp(procost, "1") != 0)
9338                                 appendPQExpBuffer(q, " COST %s", procost);
9339                 }
9340                 else
9341                 {
9342                         /* default cost is 100 */
9343                         if (strcmp(procost, "100") != 0)
9344                                 appendPQExpBuffer(q, " COST %s", procost);
9345                 }
9346         }
9347         if (proretset[0] == 't' &&
9348                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9349                 appendPQExpBuffer(q, " ROWS %s", prorows);
9350
9351         for (i = 0; i < nconfigitems; i++)
9352         {
9353                 /* we feel free to scribble on configitems[] here */
9354                 char       *configitem = configitems[i];
9355                 char       *pos;
9356
9357                 pos = strchr(configitem, '=');
9358                 if (pos == NULL)
9359                         continue;
9360                 *pos++ = '\0';
9361                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9362
9363                 /*
9364                  * Some GUC variable names are 'LIST' type and hence must not be
9365                  * quoted.
9366                  */
9367                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9368                         || pg_strcasecmp(configitem, "search_path") == 0)
9369                         appendPQExpBuffer(q, "%s", pos);
9370                 else
9371                         appendStringLiteralAH(q, pos, fout);
9372         }
9373
9374         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9375
9376         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9377
9378         if (binary_upgrade)
9379                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9380
9381         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9382                                  funcsig_tag,
9383                                  finfo->dobj.namespace->dobj.name,
9384                                  NULL,
9385                                  finfo->rolname, false,
9386                                  "FUNCTION", SECTION_PRE_DATA,
9387                                  q->data, delqry->data, NULL,
9388                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
9389                                  NULL, NULL);
9390
9391         /* Dump Function Comments and Security Labels */
9392         dumpComment(fout, labelq->data,
9393                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9394                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9395         dumpSecLabel(fout, labelq->data,
9396                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9397                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9398
9399         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9400                         funcsig, NULL, funcsig_tag,
9401                         finfo->dobj.namespace->dobj.name,
9402                         finfo->rolname, finfo->proacl);
9403
9404         PQclear(res);
9405
9406         destroyPQExpBuffer(query);
9407         destroyPQExpBuffer(q);
9408         destroyPQExpBuffer(delqry);
9409         destroyPQExpBuffer(labelq);
9410         destroyPQExpBuffer(asPart);
9411         free(funcsig);
9412         free(funcsig_tag);
9413         if (allargtypes)
9414                 free(allargtypes);
9415         if (argmodes)
9416                 free(argmodes);
9417         if (argnames)
9418                 free(argnames);
9419         if (configitems)
9420                 free(configitems);
9421 }
9422
9423
9424 /*
9425  * Dump a user-defined cast
9426  */
9427 static void
9428 dumpCast(Archive *fout, CastInfo *cast)
9429 {
9430         PQExpBuffer defqry;
9431         PQExpBuffer delqry;
9432         PQExpBuffer labelq;
9433         FuncInfo   *funcInfo = NULL;
9434
9435         /* Skip if not to be dumped */
9436         if (!cast->dobj.dump || dataOnly)
9437                 return;
9438
9439         /* Cannot dump if we don't have the cast function's info */
9440         if (OidIsValid(cast->castfunc))
9441         {
9442                 funcInfo = findFuncByOid(cast->castfunc);
9443                 if (funcInfo == NULL)
9444                         return;
9445         }
9446
9447         /*
9448          * As per discussion we dump casts if one or more of the underlying
9449          * objects (the conversion function and the two data types) are not
9450          * builtin AND if all of the non-builtin objects are included in the dump.
9451          * Builtin meaning, the namespace name does not start with "pg_".
9452          *
9453          * However, for a cast that belongs to an extension, we must not use this
9454          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9455          */
9456         if (!cast->dobj.ext_member)
9457         {
9458                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9459                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9460
9461                 if (sourceInfo == NULL || targetInfo == NULL)
9462                         return;
9463
9464                 /*
9465                  * Skip this cast if all objects are from pg_
9466                  */
9467                 if ((funcInfo == NULL ||
9468                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9469                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
9470                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
9471                         return;
9472
9473                 /*
9474                  * Skip cast if function isn't from pg_ and is not to be dumped.
9475                  */
9476                 if (funcInfo &&
9477                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9478                         !funcInfo->dobj.dump)
9479                         return;
9480
9481                 /*
9482                  * Same for the source type
9483                  */
9484                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9485                         !sourceInfo->dobj.dump)
9486                         return;
9487
9488                 /*
9489                  * and the target type.
9490                  */
9491                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9492                         !targetInfo->dobj.dump)
9493                         return;
9494         }
9495
9496         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
9497         selectSourceSchema("pg_catalog");
9498
9499         defqry = createPQExpBuffer();
9500         delqry = createPQExpBuffer();
9501         labelq = createPQExpBuffer();
9502
9503         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
9504                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9505                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9506
9507         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
9508                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9509                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9510
9511         switch (cast->castmethod)
9512         {
9513                 case COERCION_METHOD_BINARY:
9514                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
9515                         break;
9516                 case COERCION_METHOD_INOUT:
9517                         appendPQExpBuffer(defqry, "WITH INOUT");
9518                         break;
9519                 case COERCION_METHOD_FUNCTION:
9520
9521                         /*
9522                          * Always qualify the function name, in case it is not in
9523                          * pg_catalog schema (format_function_signature won't qualify it).
9524                          */
9525                         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
9526                                                           fmtId(funcInfo->dobj.namespace->dobj.name));
9527                         appendPQExpBuffer(defqry, "%s",
9528                                                           format_function_signature(funcInfo, true));
9529                         break;
9530                 default:
9531                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
9532         }
9533
9534         if (cast->castcontext == 'a')
9535                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
9536         else if (cast->castcontext == 'i')
9537                 appendPQExpBuffer(defqry, " AS IMPLICIT");
9538         appendPQExpBuffer(defqry, ";\n");
9539
9540         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
9541                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9542                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9543
9544         if (binary_upgrade)
9545                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
9546
9547         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
9548                                  labelq->data,
9549                                  "pg_catalog", NULL, "",
9550                                  false, "CAST", SECTION_PRE_DATA,
9551                                  defqry->data, delqry->data, NULL,
9552                                  cast->dobj.dependencies, cast->dobj.nDeps,
9553                                  NULL, NULL);
9554
9555         /* Dump Cast Comments */
9556         dumpComment(fout, labelq->data,
9557                                 NULL, "",
9558                                 cast->dobj.catId, 0, cast->dobj.dumpId);
9559
9560         destroyPQExpBuffer(defqry);
9561         destroyPQExpBuffer(delqry);
9562         destroyPQExpBuffer(labelq);
9563 }
9564
9565 /*
9566  * dumpOpr
9567  *        write out a single operator definition
9568  */
9569 static void
9570 dumpOpr(Archive *fout, OprInfo *oprinfo)
9571 {
9572         PQExpBuffer query;
9573         PQExpBuffer q;
9574         PQExpBuffer delq;
9575         PQExpBuffer labelq;
9576         PQExpBuffer oprid;
9577         PQExpBuffer details;
9578         const char *name;
9579         PGresult   *res;
9580         int                     ntups;
9581         int                     i_oprkind;
9582         int                     i_oprcode;
9583         int                     i_oprleft;
9584         int                     i_oprright;
9585         int                     i_oprcom;
9586         int                     i_oprnegate;
9587         int                     i_oprrest;
9588         int                     i_oprjoin;
9589         int                     i_oprcanmerge;
9590         int                     i_oprcanhash;
9591         char       *oprkind;
9592         char       *oprcode;
9593         char       *oprleft;
9594         char       *oprright;
9595         char       *oprcom;
9596         char       *oprnegate;
9597         char       *oprrest;
9598         char       *oprjoin;
9599         char       *oprcanmerge;
9600         char       *oprcanhash;
9601
9602         /* Skip if not to be dumped */
9603         if (!oprinfo->dobj.dump || dataOnly)
9604                 return;
9605
9606         /*
9607          * some operators are invalid because they were the result of user
9608          * defining operators before commutators exist
9609          */
9610         if (!OidIsValid(oprinfo->oprcode))
9611                 return;
9612
9613         query = createPQExpBuffer();
9614         q = createPQExpBuffer();
9615         delq = createPQExpBuffer();
9616         labelq = createPQExpBuffer();
9617         oprid = createPQExpBuffer();
9618         details = createPQExpBuffer();
9619
9620         /* Make sure we are in proper schema so regoperator works correctly */
9621         selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
9622
9623         if (g_fout->remoteVersion >= 80300)
9624         {
9625                 appendPQExpBuffer(query, "SELECT oprkind, "
9626                                                   "oprcode::pg_catalog.regprocedure, "
9627                                                   "oprleft::pg_catalog.regtype, "
9628                                                   "oprright::pg_catalog.regtype, "
9629                                                   "oprcom::pg_catalog.regoperator, "
9630                                                   "oprnegate::pg_catalog.regoperator, "
9631                                                   "oprrest::pg_catalog.regprocedure, "
9632                                                   "oprjoin::pg_catalog.regprocedure, "
9633                                                   "oprcanmerge, oprcanhash "
9634                                                   "FROM pg_catalog.pg_operator "
9635                                                   "WHERE oid = '%u'::pg_catalog.oid",
9636                                                   oprinfo->dobj.catId.oid);
9637         }
9638         else if (g_fout->remoteVersion >= 70300)
9639         {
9640                 appendPQExpBuffer(query, "SELECT oprkind, "
9641                                                   "oprcode::pg_catalog.regprocedure, "
9642                                                   "oprleft::pg_catalog.regtype, "
9643                                                   "oprright::pg_catalog.regtype, "
9644                                                   "oprcom::pg_catalog.regoperator, "
9645                                                   "oprnegate::pg_catalog.regoperator, "
9646                                                   "oprrest::pg_catalog.regprocedure, "
9647                                                   "oprjoin::pg_catalog.regprocedure, "
9648                                                   "(oprlsortop != 0) AS oprcanmerge, "
9649                                                   "oprcanhash "
9650                                                   "FROM pg_catalog.pg_operator "
9651                                                   "WHERE oid = '%u'::pg_catalog.oid",
9652                                                   oprinfo->dobj.catId.oid);
9653         }
9654         else if (g_fout->remoteVersion >= 70100)
9655         {
9656                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9657                                                   "CASE WHEN oprleft = 0 THEN '-' "
9658                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
9659                                                   "CASE WHEN oprright = 0 THEN '-' "
9660                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
9661                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9662                                                   "(oprlsortop != 0) AS oprcanmerge, "
9663                                                   "oprcanhash "
9664                                                   "FROM pg_operator "
9665                                                   "WHERE oid = '%u'::oid",
9666                                                   oprinfo->dobj.catId.oid);
9667         }
9668         else
9669         {
9670                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9671                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
9672                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
9673                                                   "CASE WHEN oprright = 0 THEN '-'::name "
9674                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
9675                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9676                                                   "(oprlsortop != 0) AS oprcanmerge, "
9677                                                   "oprcanhash "
9678                                                   "FROM pg_operator "
9679                                                   "WHERE oid = '%u'::oid",
9680                                                   oprinfo->dobj.catId.oid);
9681         }
9682
9683         res = PQexec(g_conn, query->data);
9684         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9685
9686         /* Expecting a single result only */
9687         ntups = PQntuples(res);
9688         if (ntups != 1)
9689         {
9690                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9691                                                            "query returned %d rows instead of one: %s\n",
9692                                                                  ntups),
9693                                   ntups, query->data);
9694                 exit_nicely();
9695         }
9696
9697         i_oprkind = PQfnumber(res, "oprkind");
9698         i_oprcode = PQfnumber(res, "oprcode");
9699         i_oprleft = PQfnumber(res, "oprleft");
9700         i_oprright = PQfnumber(res, "oprright");
9701         i_oprcom = PQfnumber(res, "oprcom");
9702         i_oprnegate = PQfnumber(res, "oprnegate");
9703         i_oprrest = PQfnumber(res, "oprrest");
9704         i_oprjoin = PQfnumber(res, "oprjoin");
9705         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
9706         i_oprcanhash = PQfnumber(res, "oprcanhash");
9707
9708         oprkind = PQgetvalue(res, 0, i_oprkind);
9709         oprcode = PQgetvalue(res, 0, i_oprcode);
9710         oprleft = PQgetvalue(res, 0, i_oprleft);
9711         oprright = PQgetvalue(res, 0, i_oprright);
9712         oprcom = PQgetvalue(res, 0, i_oprcom);
9713         oprnegate = PQgetvalue(res, 0, i_oprnegate);
9714         oprrest = PQgetvalue(res, 0, i_oprrest);
9715         oprjoin = PQgetvalue(res, 0, i_oprjoin);
9716         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
9717         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
9718
9719         appendPQExpBuffer(details, "    PROCEDURE = %s",
9720                                           convertRegProcReference(oprcode));
9721
9722         appendPQExpBuffer(oprid, "%s (",
9723                                           oprinfo->dobj.name);
9724
9725         /*
9726          * right unary means there's a left arg and left unary means there's a
9727          * right arg
9728          */
9729         if (strcmp(oprkind, "r") == 0 ||
9730                 strcmp(oprkind, "b") == 0)
9731         {
9732                 if (g_fout->remoteVersion >= 70100)
9733                         name = oprleft;
9734                 else
9735                         name = fmtId(oprleft);
9736                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
9737                 appendPQExpBuffer(oprid, "%s", name);
9738         }
9739         else
9740                 appendPQExpBuffer(oprid, "NONE");
9741
9742         if (strcmp(oprkind, "l") == 0 ||
9743                 strcmp(oprkind, "b") == 0)
9744         {
9745                 if (g_fout->remoteVersion >= 70100)
9746                         name = oprright;
9747                 else
9748                         name = fmtId(oprright);
9749                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
9750                 appendPQExpBuffer(oprid, ", %s)", name);
9751         }
9752         else
9753                 appendPQExpBuffer(oprid, ", NONE)");
9754
9755         name = convertOperatorReference(oprcom);
9756         if (name)
9757                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
9758
9759         name = convertOperatorReference(oprnegate);
9760         if (name)
9761                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
9762
9763         if (strcmp(oprcanmerge, "t") == 0)
9764                 appendPQExpBuffer(details, ",\n    MERGES");
9765
9766         if (strcmp(oprcanhash, "t") == 0)
9767                 appendPQExpBuffer(details, ",\n    HASHES");
9768
9769         name = convertRegProcReference(oprrest);
9770         if (name)
9771                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
9772
9773         name = convertRegProcReference(oprjoin);
9774         if (name)
9775                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
9776
9777         /*
9778          * DROP must be fully qualified in case same name appears in pg_catalog
9779          */
9780         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
9781                                           fmtId(oprinfo->dobj.namespace->dobj.name),
9782                                           oprid->data);
9783
9784         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
9785                                           oprinfo->dobj.name, details->data);
9786
9787         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
9788
9789         if (binary_upgrade)
9790                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
9791
9792         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
9793                                  oprinfo->dobj.name,
9794                                  oprinfo->dobj.namespace->dobj.name,
9795                                  NULL,
9796                                  oprinfo->rolname,
9797                                  false, "OPERATOR", SECTION_PRE_DATA,
9798                                  q->data, delq->data, NULL,
9799                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
9800                                  NULL, NULL);
9801
9802         /* Dump Operator Comments */
9803         dumpComment(fout, labelq->data,
9804                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
9805                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
9806
9807         PQclear(res);
9808
9809         destroyPQExpBuffer(query);
9810         destroyPQExpBuffer(q);
9811         destroyPQExpBuffer(delq);
9812         destroyPQExpBuffer(labelq);
9813         destroyPQExpBuffer(oprid);
9814         destroyPQExpBuffer(details);
9815 }
9816
9817 /*
9818  * Convert a function reference obtained from pg_operator
9819  *
9820  * Returns what to print, or NULL if function references is InvalidOid
9821  *
9822  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
9823  * argument-types part.  In prior versions, the input is a REGPROC display.
9824  */
9825 static const char *
9826 convertRegProcReference(const char *proc)
9827 {
9828         /* In all cases "-" means a null reference */
9829         if (strcmp(proc, "-") == 0)
9830                 return NULL;
9831
9832         if (g_fout->remoteVersion >= 70300)
9833         {
9834                 char       *name;
9835                 char       *paren;
9836                 bool            inquote;
9837
9838                 name = pg_strdup(proc);
9839                 /* find non-double-quoted left paren */
9840                 inquote = false;
9841                 for (paren = name; *paren; paren++)
9842                 {
9843                         if (*paren == '(' && !inquote)
9844                         {
9845                                 *paren = '\0';
9846                                 break;
9847                         }
9848                         if (*paren == '"')
9849                                 inquote = !inquote;
9850                 }
9851                 return name;
9852         }
9853
9854         /* REGPROC before 7.3 does not quote its result */
9855         return fmtId(proc);
9856 }
9857
9858 /*
9859  * Convert an operator cross-reference obtained from pg_operator
9860  *
9861  * Returns what to print, or NULL to print nothing
9862  *
9863  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
9864  * argument-types part, and add OPERATOR() decoration if the name is
9865  * schema-qualified.  In older versions, the input is just a numeric OID,
9866  * which we search our operator list for.
9867  */
9868 static const char *
9869 convertOperatorReference(const char *opr)
9870 {
9871         OprInfo    *oprInfo;
9872
9873         /* In all cases "0" means a null reference */
9874         if (strcmp(opr, "0") == 0)
9875                 return NULL;
9876
9877         if (g_fout->remoteVersion >= 70300)
9878         {
9879                 char       *name;
9880                 char       *oname;
9881                 char       *ptr;
9882                 bool            inquote;
9883                 bool            sawdot;
9884
9885                 name = pg_strdup(opr);
9886                 /* find non-double-quoted left paren, and check for non-quoted dot */
9887                 inquote = false;
9888                 sawdot = false;
9889                 for (ptr = name; *ptr; ptr++)
9890                 {
9891                         if (*ptr == '"')
9892                                 inquote = !inquote;
9893                         else if (*ptr == '.' && !inquote)
9894                                 sawdot = true;
9895                         else if (*ptr == '(' && !inquote)
9896                         {
9897                                 *ptr = '\0';
9898                                 break;
9899                         }
9900                 }
9901                 /* If not schema-qualified, don't need to add OPERATOR() */
9902                 if (!sawdot)
9903                         return name;
9904                 oname = pg_malloc(strlen(name) + 11);
9905                 sprintf(oname, "OPERATOR(%s)", name);
9906                 free(name);
9907                 return oname;
9908         }
9909
9910         oprInfo = findOprByOid(atooid(opr));
9911         if (oprInfo == NULL)
9912         {
9913                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
9914                                   opr);
9915                 return NULL;
9916         }
9917         return oprInfo->dobj.name;
9918 }
9919
9920 /*
9921  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
9922  *
9923  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
9924  * argument lists of these functions are predetermined.  Note that the
9925  * caller should ensure we are in the proper schema, because the results
9926  * are search path dependent!
9927  */
9928 static const char *
9929 convertTSFunction(Oid funcOid)
9930 {
9931         char       *result;
9932         char            query[128];
9933         PGresult   *res;
9934         int                     ntups;
9935
9936         snprintf(query, sizeof(query),
9937                          "SELECT '%u'::pg_catalog.regproc", funcOid);
9938         res = PQexec(g_conn, query);
9939         check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
9940
9941         ntups = PQntuples(res);
9942         if (ntups != 1)
9943         {
9944                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9945                                                            "query returned %d rows instead of one: %s\n",
9946                                                                  ntups),
9947                                   ntups, query);
9948                 exit_nicely();
9949         }
9950
9951         result = pg_strdup(PQgetvalue(res, 0, 0));
9952
9953         PQclear(res);
9954
9955         return result;
9956 }
9957
9958
9959 /*
9960  * dumpOpclass
9961  *        write out a single operator class definition
9962  */
9963 static void
9964 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
9965 {
9966         PQExpBuffer query;
9967         PQExpBuffer q;
9968         PQExpBuffer delq;
9969         PQExpBuffer labelq;
9970         PGresult   *res;
9971         int                     ntups;
9972         int                     i_opcintype;
9973         int                     i_opckeytype;
9974         int                     i_opcdefault;
9975         int                     i_opcfamily;
9976         int                     i_opcfamilyname;
9977         int                     i_opcfamilynsp;
9978         int                     i_amname;
9979         int                     i_amopstrategy;
9980         int                     i_amopreqcheck;
9981         int                     i_amopopr;
9982         int                     i_sortfamily;
9983         int                     i_sortfamilynsp;
9984         int                     i_amprocnum;
9985         int                     i_amproc;
9986         int                     i_amproclefttype;
9987         int                     i_amprocrighttype;
9988         char       *opcintype;
9989         char       *opckeytype;
9990         char       *opcdefault;
9991         char       *opcfamily;
9992         char       *opcfamilyname;
9993         char       *opcfamilynsp;
9994         char       *amname;
9995         char       *amopstrategy;
9996         char       *amopreqcheck;
9997         char       *amopopr;
9998         char       *sortfamily;
9999         char       *sortfamilynsp;
10000         char       *amprocnum;
10001         char       *amproc;
10002         char       *amproclefttype;
10003         char       *amprocrighttype;
10004         bool            needComma;
10005         int                     i;
10006
10007         /* Skip if not to be dumped */
10008         if (!opcinfo->dobj.dump || dataOnly)
10009                 return;
10010
10011         /*
10012          * XXX currently we do not implement dumping of operator classes from
10013          * pre-7.3 databases.  This could be done but it seems not worth the
10014          * trouble.
10015          */
10016         if (g_fout->remoteVersion < 70300)
10017                 return;
10018
10019         query = createPQExpBuffer();
10020         q = createPQExpBuffer();
10021         delq = createPQExpBuffer();
10022         labelq = createPQExpBuffer();
10023
10024         /* Make sure we are in proper schema so regoperator works correctly */
10025         selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
10026
10027         /* Get additional fields from the pg_opclass row */
10028         if (g_fout->remoteVersion >= 80300)
10029         {
10030                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10031                                                   "opckeytype::pg_catalog.regtype, "
10032                                                   "opcdefault, opcfamily, "
10033                                                   "opfname AS opcfamilyname, "
10034                                                   "nspname AS opcfamilynsp, "
10035                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10036                                                   "FROM pg_catalog.pg_opclass c "
10037                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10038                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10039                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10040                                                   opcinfo->dobj.catId.oid);
10041         }
10042         else
10043         {
10044                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10045                                                   "opckeytype::pg_catalog.regtype, "
10046                                                   "opcdefault, NULL AS opcfamily, "
10047                                                   "NULL AS opcfamilyname, "
10048                                                   "NULL AS opcfamilynsp, "
10049                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10050                                                   "FROM pg_catalog.pg_opclass "
10051                                                   "WHERE oid = '%u'::pg_catalog.oid",
10052                                                   opcinfo->dobj.catId.oid);
10053         }
10054
10055         res = PQexec(g_conn, query->data);
10056         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10057
10058         /* Expecting a single result only */
10059         ntups = PQntuples(res);
10060         if (ntups != 1)
10061         {
10062                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10063                                                            "query returned %d rows instead of one: %s\n",
10064                                                                  ntups),
10065                                   ntups, query->data);
10066                 exit_nicely();
10067         }
10068
10069         i_opcintype = PQfnumber(res, "opcintype");
10070         i_opckeytype = PQfnumber(res, "opckeytype");
10071         i_opcdefault = PQfnumber(res, "opcdefault");
10072         i_opcfamily = PQfnumber(res, "opcfamily");
10073         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10074         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10075         i_amname = PQfnumber(res, "amname");
10076
10077         opcintype = PQgetvalue(res, 0, i_opcintype);
10078         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10079         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10080         /* opcfamily will still be needed after we PQclear res */
10081         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10082         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10083         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10084         /* amname will still be needed after we PQclear res */
10085         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10086
10087         /*
10088          * DROP must be fully qualified in case same name appears in pg_catalog
10089          */
10090         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10091                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10092         appendPQExpBuffer(delq, ".%s",
10093                                           fmtId(opcinfo->dobj.name));
10094         appendPQExpBuffer(delq, " USING %s;\n",
10095                                           fmtId(amname));
10096
10097         /* Build the fixed portion of the CREATE command */
10098         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10099                                           fmtId(opcinfo->dobj.name));
10100         if (strcmp(opcdefault, "t") == 0)
10101                 appendPQExpBuffer(q, "DEFAULT ");
10102         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10103                                           opcintype,
10104                                           fmtId(amname));
10105         if (strlen(opcfamilyname) > 0 &&
10106                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10107                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10108         {
10109                 appendPQExpBuffer(q, " FAMILY ");
10110                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10111                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10112                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10113         }
10114         appendPQExpBuffer(q, " AS\n    ");
10115
10116         needComma = false;
10117
10118         if (strcmp(opckeytype, "-") != 0)
10119         {
10120                 appendPQExpBuffer(q, "STORAGE %s",
10121                                                   opckeytype);
10122                 needComma = true;
10123         }
10124
10125         PQclear(res);
10126
10127         /*
10128          * Now fetch and print the OPERATOR entries (pg_amop rows).
10129          *
10130          * Print only those opfamily members that are tied to the opclass by
10131          * pg_depend entries.
10132          *
10133          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10134          * older server's opclass in which it is used.  This is to avoid
10135          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10136          * older server and then reload into that old version.  This can go away
10137          * once 8.3 is so old as to not be of interest to anyone.
10138          */
10139         resetPQExpBuffer(query);
10140
10141         if (g_fout->remoteVersion >= 90100)
10142         {
10143                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10144                                                   "amopopr::pg_catalog.regoperator, "
10145                                                   "opfname AS sortfamily, "
10146                                                   "nspname AS sortfamilynsp "
10147                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10148                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10149                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10150                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10151                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10152                                                   "AND refobjid = '%u'::pg_catalog.oid "
10153                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10154                                                   "ORDER BY amopstrategy",
10155                                                   opcinfo->dobj.catId.oid,
10156                                                   opcfamily);
10157         }
10158         else if (g_fout->remoteVersion >= 80400)
10159         {
10160                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10161                                                   "amopopr::pg_catalog.regoperator, "
10162                                                   "NULL AS sortfamily, "
10163                                                   "NULL AS sortfamilynsp "
10164                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10165                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10166                                                   "AND refobjid = '%u'::pg_catalog.oid "
10167                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10168                                                   "AND objid = ao.oid "
10169                                                   "ORDER BY amopstrategy",
10170                                                   opcinfo->dobj.catId.oid);
10171         }
10172         else if (g_fout->remoteVersion >= 80300)
10173         {
10174                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10175                                                   "amopopr::pg_catalog.regoperator, "
10176                                                   "NULL AS sortfamily, "
10177                                                   "NULL AS sortfamilynsp "
10178                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10179                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10180                                                   "AND refobjid = '%u'::pg_catalog.oid "
10181                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10182                                                   "AND objid = ao.oid "
10183                                                   "ORDER BY amopstrategy",
10184                                                   opcinfo->dobj.catId.oid);
10185         }
10186         else
10187         {
10188                 /*
10189                  * Here, we print all entries since there are no opfamilies and hence
10190                  * no loose operators to worry about.
10191                  */
10192                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10193                                                   "amopopr::pg_catalog.regoperator, "
10194                                                   "NULL AS sortfamily, "
10195                                                   "NULL AS sortfamilynsp "
10196                                                   "FROM pg_catalog.pg_amop "
10197                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10198                                                   "ORDER BY amopstrategy",
10199                                                   opcinfo->dobj.catId.oid);
10200         }
10201
10202         res = PQexec(g_conn, query->data);
10203         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10204
10205         ntups = PQntuples(res);
10206
10207         i_amopstrategy = PQfnumber(res, "amopstrategy");
10208         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10209         i_amopopr = PQfnumber(res, "amopopr");
10210         i_sortfamily = PQfnumber(res, "sortfamily");
10211         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10212
10213         for (i = 0; i < ntups; i++)
10214         {
10215                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10216                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10217                 amopopr = PQgetvalue(res, i, i_amopopr);
10218                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10219                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10220
10221                 if (needComma)
10222                         appendPQExpBuffer(q, " ,\n    ");
10223
10224                 appendPQExpBuffer(q, "OPERATOR %s %s",
10225                                                   amopstrategy, amopopr);
10226
10227                 if (strlen(sortfamily) > 0)
10228                 {
10229                         appendPQExpBuffer(q, " FOR ORDER BY ");
10230                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10231                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10232                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10233                 }
10234
10235                 if (strcmp(amopreqcheck, "t") == 0)
10236                         appendPQExpBuffer(q, " RECHECK");
10237
10238                 needComma = true;
10239         }
10240
10241         PQclear(res);
10242
10243         /*
10244          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10245          *
10246          * Print only those opfamily members that are tied to the opclass by
10247          * pg_depend entries.
10248          *
10249          * We print the amproclefttype/amprocrighttype even though in most cases
10250          * the backend could deduce the right values, because of the corner case
10251          * of a btree sort support function for a cross-type comparison.  That's
10252          * only allowed in 9.2 and later, but for simplicity print them in all
10253          * versions that have the columns.
10254          */
10255         resetPQExpBuffer(query);
10256
10257         if (g_fout->remoteVersion >= 80300)
10258         {
10259                 appendPQExpBuffer(query, "SELECT amprocnum, "
10260                                                   "amproc::pg_catalog.regprocedure, "
10261                                                   "amproclefttype::pg_catalog.regtype, "
10262                                                   "amprocrighttype::pg_catalog.regtype "
10263                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10264                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10265                                                   "AND refobjid = '%u'::pg_catalog.oid "
10266                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10267                                                   "AND objid = ap.oid "
10268                                                   "ORDER BY amprocnum",
10269                                                   opcinfo->dobj.catId.oid);
10270         }
10271         else
10272         {
10273                 appendPQExpBuffer(query, "SELECT amprocnum, "
10274                                                   "amproc::pg_catalog.regprocedure, "
10275                                                   "'' AS amproclefttype, "
10276                                                   "'' AS amprocrighttype "
10277                                                   "FROM pg_catalog.pg_amproc "
10278                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10279                                                   "ORDER BY amprocnum",
10280                                                   opcinfo->dobj.catId.oid);
10281         }
10282
10283         res = PQexec(g_conn, query->data);
10284         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10285
10286         ntups = PQntuples(res);
10287
10288         i_amprocnum = PQfnumber(res, "amprocnum");
10289         i_amproc = PQfnumber(res, "amproc");
10290         i_amproclefttype = PQfnumber(res, "amproclefttype");
10291         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10292
10293         for (i = 0; i < ntups; i++)
10294         {
10295                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10296                 amproc = PQgetvalue(res, i, i_amproc);
10297                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10298                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10299
10300                 if (needComma)
10301                         appendPQExpBuffer(q, " ,\n    ");
10302
10303                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10304
10305                 if (*amproclefttype && *amprocrighttype)
10306                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10307
10308                 appendPQExpBuffer(q, " %s", amproc);
10309
10310                 needComma = true;
10311         }
10312
10313         PQclear(res);
10314
10315         appendPQExpBuffer(q, ";\n");
10316
10317         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10318                                           fmtId(opcinfo->dobj.name));
10319         appendPQExpBuffer(labelq, " USING %s",
10320                                           fmtId(amname));
10321
10322         if (binary_upgrade)
10323                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10324
10325         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10326                                  opcinfo->dobj.name,
10327                                  opcinfo->dobj.namespace->dobj.name,
10328                                  NULL,
10329                                  opcinfo->rolname,
10330                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10331                                  q->data, delq->data, NULL,
10332                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
10333                                  NULL, NULL);
10334
10335         /* Dump Operator Class Comments */
10336         dumpComment(fout, labelq->data,
10337                                 NULL, opcinfo->rolname,
10338                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10339
10340         free(amname);
10341         destroyPQExpBuffer(query);
10342         destroyPQExpBuffer(q);
10343         destroyPQExpBuffer(delq);
10344         destroyPQExpBuffer(labelq);
10345 }
10346
10347 /*
10348  * dumpOpfamily
10349  *        write out a single operator family definition
10350  *
10351  * Note: this also dumps any "loose" operator members that aren't bound to a
10352  * specific opclass within the opfamily.
10353  */
10354 static void
10355 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10356 {
10357         PQExpBuffer query;
10358         PQExpBuffer q;
10359         PQExpBuffer delq;
10360         PQExpBuffer labelq;
10361         PGresult   *res;
10362         PGresult   *res_ops;
10363         PGresult   *res_procs;
10364         int                     ntups;
10365         int                     i_amname;
10366         int                     i_amopstrategy;
10367         int                     i_amopreqcheck;
10368         int                     i_amopopr;
10369         int                     i_sortfamily;
10370         int                     i_sortfamilynsp;
10371         int                     i_amprocnum;
10372         int                     i_amproc;
10373         int                     i_amproclefttype;
10374         int                     i_amprocrighttype;
10375         char       *amname;
10376         char       *amopstrategy;
10377         char       *amopreqcheck;
10378         char       *amopopr;
10379         char       *sortfamily;
10380         char       *sortfamilynsp;
10381         char       *amprocnum;
10382         char       *amproc;
10383         char       *amproclefttype;
10384         char       *amprocrighttype;
10385         bool            needComma;
10386         int                     i;
10387
10388         /* Skip if not to be dumped */
10389         if (!opfinfo->dobj.dump || dataOnly)
10390                 return;
10391
10392         /*
10393          * We want to dump the opfamily only if (1) it contains "loose" operators
10394          * or functions, or (2) it contains an opclass with a different name or
10395          * owner.  Otherwise it's sufficient to let it be created during creation
10396          * of the contained opclass, and not dumping it improves portability of
10397          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10398          * that first.
10399          */
10400
10401         query = createPQExpBuffer();
10402         q = createPQExpBuffer();
10403         delq = createPQExpBuffer();
10404         labelq = createPQExpBuffer();
10405
10406         /* Make sure we are in proper schema so regoperator works correctly */
10407         selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
10408
10409         /*
10410          * Fetch only those opfamily members that are tied directly to the
10411          * opfamily by pg_depend entries.
10412          *
10413          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10414          * older server's opclass in which it is used.  This is to avoid
10415          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10416          * older server and then reload into that old version.  This can go away
10417          * once 8.3 is so old as to not be of interest to anyone.
10418          */
10419         if (g_fout->remoteVersion >= 90100)
10420         {
10421                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10422                                                   "amopopr::pg_catalog.regoperator, "
10423                                                   "opfname AS sortfamily, "
10424                                                   "nspname AS sortfamilynsp "
10425                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10426                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10427                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10428                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10429                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10430                                                   "AND refobjid = '%u'::pg_catalog.oid "
10431                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10432                                                   "ORDER BY amopstrategy",
10433                                                   opfinfo->dobj.catId.oid,
10434                                                   opfinfo->dobj.catId.oid);
10435         }
10436         else if (g_fout->remoteVersion >= 80400)
10437         {
10438                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10439                                                   "amopopr::pg_catalog.regoperator, "
10440                                                   "NULL AS sortfamily, "
10441                                                   "NULL AS sortfamilynsp "
10442                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10443                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10444                                                   "AND refobjid = '%u'::pg_catalog.oid "
10445                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10446                                                   "AND objid = ao.oid "
10447                                                   "ORDER BY amopstrategy",
10448                                                   opfinfo->dobj.catId.oid);
10449         }
10450         else
10451         {
10452                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10453                                                   "amopopr::pg_catalog.regoperator, "
10454                                                   "NULL AS sortfamily, "
10455                                                   "NULL AS sortfamilynsp "
10456                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10457                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10458                                                   "AND refobjid = '%u'::pg_catalog.oid "
10459                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10460                                                   "AND objid = ao.oid "
10461                                                   "ORDER BY amopstrategy",
10462                                                   opfinfo->dobj.catId.oid);
10463         }
10464
10465         res_ops = PQexec(g_conn, query->data);
10466         check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
10467
10468         resetPQExpBuffer(query);
10469
10470         appendPQExpBuffer(query, "SELECT amprocnum, "
10471                                           "amproc::pg_catalog.regprocedure, "
10472                                           "amproclefttype::pg_catalog.regtype, "
10473                                           "amprocrighttype::pg_catalog.regtype "
10474                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10475                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10476                                           "AND refobjid = '%u'::pg_catalog.oid "
10477                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10478                                           "AND objid = ap.oid "
10479                                           "ORDER BY amprocnum",
10480                                           opfinfo->dobj.catId.oid);
10481
10482         res_procs = PQexec(g_conn, query->data);
10483         check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
10484
10485         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10486         {
10487                 /* No loose members, so check contained opclasses */
10488                 resetPQExpBuffer(query);
10489
10490                 appendPQExpBuffer(query, "SELECT 1 "
10491                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10492                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10493                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10494                                                   "AND refobjid = f.oid "
10495                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10496                                                   "AND objid = c.oid "
10497                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10498                                                   "LIMIT 1",
10499                                                   opfinfo->dobj.catId.oid);
10500
10501                 res = PQexec(g_conn, query->data);
10502                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10503
10504                 if (PQntuples(res) == 0)
10505                 {
10506                         /* no need to dump it, so bail out */
10507                         PQclear(res);
10508                         PQclear(res_ops);
10509                         PQclear(res_procs);
10510                         destroyPQExpBuffer(query);
10511                         destroyPQExpBuffer(q);
10512                         destroyPQExpBuffer(delq);
10513                         destroyPQExpBuffer(labelq);
10514                         return;
10515                 }
10516
10517                 PQclear(res);
10518         }
10519
10520         /* Get additional fields from the pg_opfamily row */
10521         resetPQExpBuffer(query);
10522
10523         appendPQExpBuffer(query, "SELECT "
10524          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
10525                                           "FROM pg_catalog.pg_opfamily "
10526                                           "WHERE oid = '%u'::pg_catalog.oid",
10527                                           opfinfo->dobj.catId.oid);
10528
10529         res = PQexec(g_conn, query->data);
10530         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10531
10532         /* Expecting a single result only */
10533         ntups = PQntuples(res);
10534         if (ntups != 1)
10535         {
10536                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10537                                                            "query returned %d rows instead of one: %s\n",
10538                                                                  ntups),
10539                                   ntups, query->data);
10540                 exit_nicely();
10541         }
10542
10543         i_amname = PQfnumber(res, "amname");
10544
10545         /* amname will still be needed after we PQclear res */
10546         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10547
10548         /*
10549          * DROP must be fully qualified in case same name appears in pg_catalog
10550          */
10551         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
10552                                           fmtId(opfinfo->dobj.namespace->dobj.name));
10553         appendPQExpBuffer(delq, ".%s",
10554                                           fmtId(opfinfo->dobj.name));
10555         appendPQExpBuffer(delq, " USING %s;\n",
10556                                           fmtId(amname));
10557
10558         /* Build the fixed portion of the CREATE command */
10559         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
10560                                           fmtId(opfinfo->dobj.name));
10561         appendPQExpBuffer(q, " USING %s;\n",
10562                                           fmtId(amname));
10563
10564         PQclear(res);
10565
10566         /* Do we need an ALTER to add loose members? */
10567         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
10568         {
10569                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
10570                                                   fmtId(opfinfo->dobj.name));
10571                 appendPQExpBuffer(q, " USING %s ADD\n    ",
10572                                                   fmtId(amname));
10573
10574                 needComma = false;
10575
10576                 /*
10577                  * Now fetch and print the OPERATOR entries (pg_amop rows).
10578                  */
10579                 ntups = PQntuples(res_ops);
10580
10581                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
10582                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
10583                 i_amopopr = PQfnumber(res_ops, "amopopr");
10584                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
10585                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
10586
10587                 for (i = 0; i < ntups; i++)
10588                 {
10589                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
10590                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
10591                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
10592                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
10593                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
10594
10595                         if (needComma)
10596                                 appendPQExpBuffer(q, " ,\n    ");
10597
10598                         appendPQExpBuffer(q, "OPERATOR %s %s",
10599                                                           amopstrategy, amopopr);
10600
10601                         if (strlen(sortfamily) > 0)
10602                         {
10603                                 appendPQExpBuffer(q, " FOR ORDER BY ");
10604                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
10605                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10606                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10607                         }
10608
10609                         if (strcmp(amopreqcheck, "t") == 0)
10610                                 appendPQExpBuffer(q, " RECHECK");
10611
10612                         needComma = true;
10613                 }
10614
10615                 /*
10616                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
10617                  */
10618                 ntups = PQntuples(res_procs);
10619
10620                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
10621                 i_amproc = PQfnumber(res_procs, "amproc");
10622                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
10623                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
10624
10625                 for (i = 0; i < ntups; i++)
10626                 {
10627                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
10628                         amproc = PQgetvalue(res_procs, i, i_amproc);
10629                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
10630                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
10631
10632                         if (needComma)
10633                                 appendPQExpBuffer(q, " ,\n    ");
10634
10635                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
10636                                                           amprocnum, amproclefttype, amprocrighttype,
10637                                                           amproc);
10638
10639                         needComma = true;
10640                 }
10641
10642                 appendPQExpBuffer(q, ";\n");
10643         }
10644
10645         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
10646                                           fmtId(opfinfo->dobj.name));
10647         appendPQExpBuffer(labelq, " USING %s",
10648                                           fmtId(amname));
10649
10650         if (binary_upgrade)
10651                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
10652
10653         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
10654                                  opfinfo->dobj.name,
10655                                  opfinfo->dobj.namespace->dobj.name,
10656                                  NULL,
10657                                  opfinfo->rolname,
10658                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
10659                                  q->data, delq->data, NULL,
10660                                  opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
10661                                  NULL, NULL);
10662
10663         /* Dump Operator Family Comments */
10664         dumpComment(fout, labelq->data,
10665                                 NULL, opfinfo->rolname,
10666                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
10667
10668         free(amname);
10669         PQclear(res_ops);
10670         PQclear(res_procs);
10671         destroyPQExpBuffer(query);
10672         destroyPQExpBuffer(q);
10673         destroyPQExpBuffer(delq);
10674         destroyPQExpBuffer(labelq);
10675 }
10676
10677 /*
10678  * dumpCollation
10679  *        write out a single collation definition
10680  */
10681 static void
10682 dumpCollation(Archive *fout, CollInfo *collinfo)
10683 {
10684         PQExpBuffer query;
10685         PQExpBuffer q;
10686         PQExpBuffer delq;
10687         PQExpBuffer labelq;
10688         PGresult   *res;
10689         int                     ntups;
10690         int                     i_collcollate;
10691         int                     i_collctype;
10692         const char *collcollate;
10693         const char *collctype;
10694
10695         /* Skip if not to be dumped */
10696         if (!collinfo->dobj.dump || dataOnly)
10697                 return;
10698
10699         query = createPQExpBuffer();
10700         q = createPQExpBuffer();
10701         delq = createPQExpBuffer();
10702         labelq = createPQExpBuffer();
10703
10704         /* Make sure we are in proper schema */
10705         selectSourceSchema(collinfo->dobj.namespace->dobj.name);
10706
10707         /* Get conversion-specific details */
10708         appendPQExpBuffer(query, "SELECT "
10709                                           "collcollate, "
10710                                           "collctype "
10711                                           "FROM pg_catalog.pg_collation c "
10712                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10713                                           collinfo->dobj.catId.oid);
10714
10715         res = PQexec(g_conn, query->data);
10716         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10717
10718         /* Expecting a single result only */
10719         ntups = PQntuples(res);
10720         if (ntups != 1)
10721         {
10722                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10723                                                            "query returned %d rows instead of one: %s\n",
10724                                                                  ntups),
10725                                   ntups, query->data);
10726                 exit_nicely();
10727         }
10728
10729         i_collcollate = PQfnumber(res, "collcollate");
10730         i_collctype = PQfnumber(res, "collctype");
10731
10732         collcollate = PQgetvalue(res, 0, i_collcollate);
10733         collctype = PQgetvalue(res, 0, i_collctype);
10734
10735         /*
10736          * DROP must be fully qualified in case same name appears in pg_catalog
10737          */
10738         appendPQExpBuffer(delq, "DROP COLLATION %s",
10739                                           fmtId(collinfo->dobj.namespace->dobj.name));
10740         appendPQExpBuffer(delq, ".%s;\n",
10741                                           fmtId(collinfo->dobj.name));
10742
10743         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
10744                                           fmtId(collinfo->dobj.name));
10745         appendStringLiteralAH(q, collcollate, fout);
10746         appendPQExpBuffer(q, ", lc_ctype = ");
10747         appendStringLiteralAH(q, collctype, fout);
10748         appendPQExpBuffer(q, ");\n");
10749
10750         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
10751
10752         if (binary_upgrade)
10753                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
10754
10755         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
10756                                  collinfo->dobj.name,
10757                                  collinfo->dobj.namespace->dobj.name,
10758                                  NULL,
10759                                  collinfo->rolname,
10760                                  false, "COLLATION", SECTION_PRE_DATA,
10761                                  q->data, delq->data, NULL,
10762                                  collinfo->dobj.dependencies, collinfo->dobj.nDeps,
10763                                  NULL, NULL);
10764
10765         /* Dump Collation Comments */
10766         dumpComment(fout, labelq->data,
10767                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
10768                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
10769
10770         PQclear(res);
10771
10772         destroyPQExpBuffer(query);
10773         destroyPQExpBuffer(q);
10774         destroyPQExpBuffer(delq);
10775         destroyPQExpBuffer(labelq);
10776 }
10777
10778 /*
10779  * dumpConversion
10780  *        write out a single conversion definition
10781  */
10782 static void
10783 dumpConversion(Archive *fout, ConvInfo *convinfo)
10784 {
10785         PQExpBuffer query;
10786         PQExpBuffer q;
10787         PQExpBuffer delq;
10788         PQExpBuffer labelq;
10789         PGresult   *res;
10790         int                     ntups;
10791         int                     i_conforencoding;
10792         int                     i_contoencoding;
10793         int                     i_conproc;
10794         int                     i_condefault;
10795         const char *conforencoding;
10796         const char *contoencoding;
10797         const char *conproc;
10798         bool            condefault;
10799
10800         /* Skip if not to be dumped */
10801         if (!convinfo->dobj.dump || dataOnly)
10802                 return;
10803
10804         query = createPQExpBuffer();
10805         q = createPQExpBuffer();
10806         delq = createPQExpBuffer();
10807         labelq = createPQExpBuffer();
10808
10809         /* Make sure we are in proper schema */
10810         selectSourceSchema(convinfo->dobj.namespace->dobj.name);
10811
10812         /* Get conversion-specific details */
10813         appendPQExpBuffer(query, "SELECT "
10814                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
10815                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
10816                                           "conproc, condefault "
10817                                           "FROM pg_catalog.pg_conversion c "
10818                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10819                                           convinfo->dobj.catId.oid);
10820
10821         res = PQexec(g_conn, query->data);
10822         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10823
10824         /* Expecting a single result only */
10825         ntups = PQntuples(res);
10826         if (ntups != 1)
10827         {
10828                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10829                                                            "query returned %d rows instead of one: %s\n",
10830                                                                  ntups),
10831                                   ntups, query->data);
10832                 exit_nicely();
10833         }
10834
10835         i_conforencoding = PQfnumber(res, "conforencoding");
10836         i_contoencoding = PQfnumber(res, "contoencoding");
10837         i_conproc = PQfnumber(res, "conproc");
10838         i_condefault = PQfnumber(res, "condefault");
10839
10840         conforencoding = PQgetvalue(res, 0, i_conforencoding);
10841         contoencoding = PQgetvalue(res, 0, i_contoencoding);
10842         conproc = PQgetvalue(res, 0, i_conproc);
10843         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
10844
10845         /*
10846          * DROP must be fully qualified in case same name appears in pg_catalog
10847          */
10848         appendPQExpBuffer(delq, "DROP CONVERSION %s",
10849                                           fmtId(convinfo->dobj.namespace->dobj.name));
10850         appendPQExpBuffer(delq, ".%s;\n",
10851                                           fmtId(convinfo->dobj.name));
10852
10853         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
10854                                           (condefault) ? "DEFAULT " : "",
10855                                           fmtId(convinfo->dobj.name));
10856         appendStringLiteralAH(q, conforencoding, fout);
10857         appendPQExpBuffer(q, " TO ");
10858         appendStringLiteralAH(q, contoencoding, fout);
10859         /* regproc is automatically quoted in 7.3 and above */
10860         appendPQExpBuffer(q, " FROM %s;\n", conproc);
10861
10862         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
10863
10864         if (binary_upgrade)
10865                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
10866
10867         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
10868                                  convinfo->dobj.name,
10869                                  convinfo->dobj.namespace->dobj.name,
10870                                  NULL,
10871                                  convinfo->rolname,
10872                                  false, "CONVERSION", SECTION_PRE_DATA,
10873                                  q->data, delq->data, NULL,
10874                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
10875                                  NULL, NULL);
10876
10877         /* Dump Conversion Comments */
10878         dumpComment(fout, labelq->data,
10879                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
10880                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
10881
10882         PQclear(res);
10883
10884         destroyPQExpBuffer(query);
10885         destroyPQExpBuffer(q);
10886         destroyPQExpBuffer(delq);
10887         destroyPQExpBuffer(labelq);
10888 }
10889
10890 /*
10891  * format_aggregate_signature: generate aggregate name and argument list
10892  *
10893  * The argument type names are qualified if needed.  The aggregate name
10894  * is never qualified.
10895  */
10896 static char *
10897 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
10898 {
10899         PQExpBufferData buf;
10900         int                     j;
10901
10902         initPQExpBuffer(&buf);
10903         if (honor_quotes)
10904                 appendPQExpBuffer(&buf, "%s",
10905                                                   fmtId(agginfo->aggfn.dobj.name));
10906         else
10907                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
10908
10909         if (agginfo->aggfn.nargs == 0)
10910                 appendPQExpBuffer(&buf, "(*)");
10911         else
10912         {
10913                 appendPQExpBuffer(&buf, "(");
10914                 for (j = 0; j < agginfo->aggfn.nargs; j++)
10915                 {
10916                         char       *typname;
10917
10918                         typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
10919
10920                         appendPQExpBuffer(&buf, "%s%s",
10921                                                           (j > 0) ? ", " : "",
10922                                                           typname);
10923                         free(typname);
10924                 }
10925                 appendPQExpBuffer(&buf, ")");
10926         }
10927         return buf.data;
10928 }
10929
10930 /*
10931  * dumpAgg
10932  *        write out a single aggregate definition
10933  */
10934 static void
10935 dumpAgg(Archive *fout, AggInfo *agginfo)
10936 {
10937         PQExpBuffer query;
10938         PQExpBuffer q;
10939         PQExpBuffer delq;
10940         PQExpBuffer labelq;
10941         PQExpBuffer details;
10942         char       *aggsig;
10943         char       *aggsig_tag;
10944         PGresult   *res;
10945         int                     ntups;
10946         int                     i_aggtransfn;
10947         int                     i_aggfinalfn;
10948         int                     i_aggsortop;
10949         int                     i_aggtranstype;
10950         int                     i_agginitval;
10951         int                     i_convertok;
10952         const char *aggtransfn;
10953         const char *aggfinalfn;
10954         const char *aggsortop;
10955         const char *aggtranstype;
10956         const char *agginitval;
10957         bool            convertok;
10958
10959         /* Skip if not to be dumped */
10960         if (!agginfo->aggfn.dobj.dump || dataOnly)
10961                 return;
10962
10963         query = createPQExpBuffer();
10964         q = createPQExpBuffer();
10965         delq = createPQExpBuffer();
10966         labelq = createPQExpBuffer();
10967         details = createPQExpBuffer();
10968
10969         /* Make sure we are in proper schema */
10970         selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
10971
10972         /* Get aggregate-specific details */
10973         if (g_fout->remoteVersion >= 80100)
10974         {
10975                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10976                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10977                                                   "aggsortop::pg_catalog.regoperator, "
10978                                                   "agginitval, "
10979                                                   "'t'::boolean AS convertok "
10980                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10981                                                   "WHERE a.aggfnoid = p.oid "
10982                                                   "AND p.oid = '%u'::pg_catalog.oid",
10983                                                   agginfo->aggfn.dobj.catId.oid);
10984         }
10985         else if (g_fout->remoteVersion >= 70300)
10986         {
10987                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10988                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10989                                                   "0 AS aggsortop, "
10990                                                   "agginitval, "
10991                                                   "'t'::boolean AS convertok "
10992                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10993                                                   "WHERE a.aggfnoid = p.oid "
10994                                                   "AND p.oid = '%u'::pg_catalog.oid",
10995                                                   agginfo->aggfn.dobj.catId.oid);
10996         }
10997         else if (g_fout->remoteVersion >= 70100)
10998         {
10999                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11000                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11001                                                   "0 AS aggsortop, "
11002                                                   "agginitval, "
11003                                                   "'t'::boolean AS convertok "
11004                                                   "FROM pg_aggregate "
11005                                                   "WHERE oid = '%u'::oid",
11006                                                   agginfo->aggfn.dobj.catId.oid);
11007         }
11008         else
11009         {
11010                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11011                                                   "aggfinalfn, "
11012                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11013                                                   "0 AS aggsortop, "
11014                                                   "agginitval1 AS agginitval, "
11015                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11016                                                   "FROM pg_aggregate "
11017                                                   "WHERE oid = '%u'::oid",
11018                                                   agginfo->aggfn.dobj.catId.oid);
11019         }
11020
11021         res = PQexec(g_conn, query->data);
11022         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11023
11024         /* Expecting a single result only */
11025         ntups = PQntuples(res);
11026         if (ntups != 1)
11027         {
11028                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11029                                                            "query returned %d rows instead of one: %s\n",
11030                                                                  ntups),
11031                                   ntups, query->data);
11032                 exit_nicely();
11033         }
11034
11035         i_aggtransfn = PQfnumber(res, "aggtransfn");
11036         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11037         i_aggsortop = PQfnumber(res, "aggsortop");
11038         i_aggtranstype = PQfnumber(res, "aggtranstype");
11039         i_agginitval = PQfnumber(res, "agginitval");
11040         i_convertok = PQfnumber(res, "convertok");
11041
11042         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11043         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11044         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11045         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11046         agginitval = PQgetvalue(res, 0, i_agginitval);
11047         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11048
11049         aggsig = format_aggregate_signature(agginfo, fout, true);
11050         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11051
11052         if (!convertok)
11053         {
11054                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11055                                   aggsig);
11056                 return;
11057         }
11058
11059         if (g_fout->remoteVersion >= 70300)
11060         {
11061                 /* If using 7.3's regproc or regtype, data is already quoted */
11062                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11063                                                   aggtransfn,
11064                                                   aggtranstype);
11065         }
11066         else if (g_fout->remoteVersion >= 70100)
11067         {
11068                 /* format_type quotes, regproc does not */
11069                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11070                                                   fmtId(aggtransfn),
11071                                                   aggtranstype);
11072         }
11073         else
11074         {
11075                 /* need quotes all around */
11076                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11077                                                   fmtId(aggtransfn));
11078                 appendPQExpBuffer(details, "    STYPE = %s",
11079                                                   fmtId(aggtranstype));
11080         }
11081
11082         if (!PQgetisnull(res, 0, i_agginitval))
11083         {
11084                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11085                 appendStringLiteralAH(details, agginitval, fout);
11086         }
11087
11088         if (strcmp(aggfinalfn, "-") != 0)
11089         {
11090                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11091                                                   aggfinalfn);
11092         }
11093
11094         aggsortop = convertOperatorReference(aggsortop);
11095         if (aggsortop)
11096         {
11097                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11098                                                   aggsortop);
11099         }
11100
11101         /*
11102          * DROP must be fully qualified in case same name appears in pg_catalog
11103          */
11104         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11105                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11106                                           aggsig);
11107
11108         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11109                                           aggsig, details->data);
11110
11111         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11112
11113         if (binary_upgrade)
11114                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11115
11116         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11117                                  aggsig_tag,
11118                                  agginfo->aggfn.dobj.namespace->dobj.name,
11119                                  NULL,
11120                                  agginfo->aggfn.rolname,
11121                                  false, "AGGREGATE", SECTION_PRE_DATA,
11122                                  q->data, delq->data, NULL,
11123                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
11124                                  NULL, NULL);
11125
11126         /* Dump Aggregate Comments */
11127         dumpComment(fout, labelq->data,
11128                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11129                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11130         dumpSecLabel(fout, labelq->data,
11131                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11132                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11133
11134         /*
11135          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11136          * command look like a function's GRANT; in particular this affects the
11137          * syntax for zero-argument aggregates.
11138          */
11139         free(aggsig);
11140         free(aggsig_tag);
11141
11142         aggsig = format_function_signature(&agginfo->aggfn, true);
11143         aggsig_tag = format_function_signature(&agginfo->aggfn, false);
11144
11145         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11146                         "FUNCTION",
11147                         aggsig, NULL, aggsig_tag,
11148                         agginfo->aggfn.dobj.namespace->dobj.name,
11149                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11150
11151         free(aggsig);
11152         free(aggsig_tag);
11153
11154         PQclear(res);
11155
11156         destroyPQExpBuffer(query);
11157         destroyPQExpBuffer(q);
11158         destroyPQExpBuffer(delq);
11159         destroyPQExpBuffer(labelq);
11160         destroyPQExpBuffer(details);
11161 }
11162
11163 /*
11164  * dumpTSParser
11165  *        write out a single text search parser
11166  */
11167 static void
11168 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11169 {
11170         PQExpBuffer q;
11171         PQExpBuffer delq;
11172         PQExpBuffer labelq;
11173
11174         /* Skip if not to be dumped */
11175         if (!prsinfo->dobj.dump || dataOnly)
11176                 return;
11177
11178         q = createPQExpBuffer();
11179         delq = createPQExpBuffer();
11180         labelq = createPQExpBuffer();
11181
11182         /* Make sure we are in proper schema */
11183         selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
11184
11185         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11186                                           fmtId(prsinfo->dobj.name));
11187
11188         appendPQExpBuffer(q, "    START = %s,\n",
11189                                           convertTSFunction(prsinfo->prsstart));
11190         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11191                                           convertTSFunction(prsinfo->prstoken));
11192         appendPQExpBuffer(q, "    END = %s,\n",
11193                                           convertTSFunction(prsinfo->prsend));
11194         if (prsinfo->prsheadline != InvalidOid)
11195                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11196                                                   convertTSFunction(prsinfo->prsheadline));
11197         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11198                                           convertTSFunction(prsinfo->prslextype));
11199
11200         /*
11201          * DROP must be fully qualified in case same name appears in pg_catalog
11202          */
11203         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11204                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11205         appendPQExpBuffer(delq, ".%s;\n",
11206                                           fmtId(prsinfo->dobj.name));
11207
11208         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11209                                           fmtId(prsinfo->dobj.name));
11210
11211         if (binary_upgrade)
11212                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11213
11214         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11215                                  prsinfo->dobj.name,
11216                                  prsinfo->dobj.namespace->dobj.name,
11217                                  NULL,
11218                                  "",
11219                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11220                                  q->data, delq->data, NULL,
11221                                  prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
11222                                  NULL, NULL);
11223
11224         /* Dump Parser Comments */
11225         dumpComment(fout, labelq->data,
11226                                 NULL, "",
11227                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11228
11229         destroyPQExpBuffer(q);
11230         destroyPQExpBuffer(delq);
11231         destroyPQExpBuffer(labelq);
11232 }
11233
11234 /*
11235  * dumpTSDictionary
11236  *        write out a single text search dictionary
11237  */
11238 static void
11239 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11240 {
11241         PQExpBuffer q;
11242         PQExpBuffer delq;
11243         PQExpBuffer labelq;
11244         PQExpBuffer query;
11245         PGresult   *res;
11246         int                     ntups;
11247         char       *nspname;
11248         char       *tmplname;
11249
11250         /* Skip if not to be dumped */
11251         if (!dictinfo->dobj.dump || dataOnly)
11252                 return;
11253
11254         q = createPQExpBuffer();
11255         delq = createPQExpBuffer();
11256         labelq = createPQExpBuffer();
11257         query = createPQExpBuffer();
11258
11259         /* Fetch name and namespace of the dictionary's template */
11260         selectSourceSchema("pg_catalog");
11261         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11262                                           "FROM pg_ts_template p, pg_namespace n "
11263                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11264                                           dictinfo->dicttemplate);
11265         res = PQexec(g_conn, query->data);
11266         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11267         ntups = PQntuples(res);
11268         if (ntups != 1)
11269         {
11270                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11271                                                            "query returned %d rows instead of one: %s\n",
11272                                                                  ntups),
11273                                   ntups, query->data);
11274                 exit_nicely();
11275         }
11276         nspname = PQgetvalue(res, 0, 0);
11277         tmplname = PQgetvalue(res, 0, 1);
11278
11279         /* Make sure we are in proper schema */
11280         selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
11281
11282         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11283                                           fmtId(dictinfo->dobj.name));
11284
11285         appendPQExpBuffer(q, "    TEMPLATE = ");
11286         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11287                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11288         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11289
11290         PQclear(res);
11291
11292         /* the dictinitoption can be dumped straight into the command */
11293         if (dictinfo->dictinitoption)
11294                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11295
11296         appendPQExpBuffer(q, " );\n");
11297
11298         /*
11299          * DROP must be fully qualified in case same name appears in pg_catalog
11300          */
11301         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11302                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11303         appendPQExpBuffer(delq, ".%s;\n",
11304                                           fmtId(dictinfo->dobj.name));
11305
11306         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11307                                           fmtId(dictinfo->dobj.name));
11308
11309         if (binary_upgrade)
11310                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11311
11312         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11313                                  dictinfo->dobj.name,
11314                                  dictinfo->dobj.namespace->dobj.name,
11315                                  NULL,
11316                                  dictinfo->rolname,
11317                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11318                                  q->data, delq->data, NULL,
11319                                  dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
11320                                  NULL, NULL);
11321
11322         /* Dump Dictionary Comments */
11323         dumpComment(fout, labelq->data,
11324                                 NULL, dictinfo->rolname,
11325                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11326
11327         destroyPQExpBuffer(q);
11328         destroyPQExpBuffer(delq);
11329         destroyPQExpBuffer(labelq);
11330         destroyPQExpBuffer(query);
11331 }
11332
11333 /*
11334  * dumpTSTemplate
11335  *        write out a single text search template
11336  */
11337 static void
11338 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11339 {
11340         PQExpBuffer q;
11341         PQExpBuffer delq;
11342         PQExpBuffer labelq;
11343
11344         /* Skip if not to be dumped */
11345         if (!tmplinfo->dobj.dump || dataOnly)
11346                 return;
11347
11348         q = createPQExpBuffer();
11349         delq = createPQExpBuffer();
11350         labelq = createPQExpBuffer();
11351
11352         /* Make sure we are in proper schema */
11353         selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
11354
11355         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11356                                           fmtId(tmplinfo->dobj.name));
11357
11358         if (tmplinfo->tmplinit != InvalidOid)
11359                 appendPQExpBuffer(q, "    INIT = %s,\n",
11360                                                   convertTSFunction(tmplinfo->tmplinit));
11361         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11362                                           convertTSFunction(tmplinfo->tmpllexize));
11363
11364         /*
11365          * DROP must be fully qualified in case same name appears in pg_catalog
11366          */
11367         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11368                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11369         appendPQExpBuffer(delq, ".%s;\n",
11370                                           fmtId(tmplinfo->dobj.name));
11371
11372         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11373                                           fmtId(tmplinfo->dobj.name));
11374
11375         if (binary_upgrade)
11376                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11377
11378         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11379                                  tmplinfo->dobj.name,
11380                                  tmplinfo->dobj.namespace->dobj.name,
11381                                  NULL,
11382                                  "",
11383                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11384                                  q->data, delq->data, NULL,
11385                                  tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
11386                                  NULL, NULL);
11387
11388         /* Dump Template Comments */
11389         dumpComment(fout, labelq->data,
11390                                 NULL, "",
11391                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11392
11393         destroyPQExpBuffer(q);
11394         destroyPQExpBuffer(delq);
11395         destroyPQExpBuffer(labelq);
11396 }
11397
11398 /*
11399  * dumpTSConfig
11400  *        write out a single text search configuration
11401  */
11402 static void
11403 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11404 {
11405         PQExpBuffer q;
11406         PQExpBuffer delq;
11407         PQExpBuffer labelq;
11408         PQExpBuffer query;
11409         PGresult   *res;
11410         char       *nspname;
11411         char       *prsname;
11412         int                     ntups,
11413                                 i;
11414         int                     i_tokenname;
11415         int                     i_dictname;
11416
11417         /* Skip if not to be dumped */
11418         if (!cfginfo->dobj.dump || dataOnly)
11419                 return;
11420
11421         q = createPQExpBuffer();
11422         delq = createPQExpBuffer();
11423         labelq = createPQExpBuffer();
11424         query = createPQExpBuffer();
11425
11426         /* Fetch name and namespace of the config's parser */
11427         selectSourceSchema("pg_catalog");
11428         appendPQExpBuffer(query, "SELECT nspname, prsname "
11429                                           "FROM pg_ts_parser p, pg_namespace n "
11430                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11431                                           cfginfo->cfgparser);
11432         res = PQexec(g_conn, query->data);
11433         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11434         ntups = PQntuples(res);
11435         if (ntups != 1)
11436         {
11437                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11438                                                            "query returned %d rows instead of one: %s\n",
11439                                                                  ntups),
11440                                   ntups, query->data);
11441                 exit_nicely();
11442         }
11443         nspname = PQgetvalue(res, 0, 0);
11444         prsname = PQgetvalue(res, 0, 1);
11445
11446         /* Make sure we are in proper schema */
11447         selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
11448
11449         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11450                                           fmtId(cfginfo->dobj.name));
11451
11452         appendPQExpBuffer(q, "    PARSER = ");
11453         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11454                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11455         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11456
11457         PQclear(res);
11458
11459         resetPQExpBuffer(query);
11460         appendPQExpBuffer(query,
11461                                           "SELECT \n"
11462                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11463                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11464                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11465                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11466                                           "WHERE m.mapcfg = '%u' \n"
11467                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11468                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11469
11470         res = PQexec(g_conn, query->data);
11471         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11472         ntups = PQntuples(res);
11473
11474         i_tokenname = PQfnumber(res, "tokenname");
11475         i_dictname = PQfnumber(res, "dictname");
11476
11477         for (i = 0; i < ntups; i++)
11478         {
11479                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11480                 char       *dictname = PQgetvalue(res, i, i_dictname);
11481
11482                 if (i == 0 ||
11483                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11484                 {
11485                         /* starting a new token type, so start a new command */
11486                         if (i > 0)
11487                                 appendPQExpBuffer(q, ";\n");
11488                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11489                                                           fmtId(cfginfo->dobj.name));
11490                         /* tokenname needs quoting, dictname does NOT */
11491                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11492                                                           fmtId(tokenname), dictname);
11493                 }
11494                 else
11495                         appendPQExpBuffer(q, ", %s", dictname);
11496         }
11497
11498         if (ntups > 0)
11499                 appendPQExpBuffer(q, ";\n");
11500
11501         PQclear(res);
11502
11503         /*
11504          * DROP must be fully qualified in case same name appears in pg_catalog
11505          */
11506         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11507                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11508         appendPQExpBuffer(delq, ".%s;\n",
11509                                           fmtId(cfginfo->dobj.name));
11510
11511         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11512                                           fmtId(cfginfo->dobj.name));
11513
11514         if (binary_upgrade)
11515                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11516
11517         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11518                                  cfginfo->dobj.name,
11519                                  cfginfo->dobj.namespace->dobj.name,
11520                                  NULL,
11521                                  cfginfo->rolname,
11522                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11523                                  q->data, delq->data, NULL,
11524                                  cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
11525                                  NULL, NULL);
11526
11527         /* Dump Configuration Comments */
11528         dumpComment(fout, labelq->data,
11529                                 NULL, cfginfo->rolname,
11530                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11531
11532         destroyPQExpBuffer(q);
11533         destroyPQExpBuffer(delq);
11534         destroyPQExpBuffer(labelq);
11535         destroyPQExpBuffer(query);
11536 }
11537
11538 /*
11539  * dumpForeignDataWrapper
11540  *        write out a single foreign-data wrapper definition
11541  */
11542 static void
11543 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11544 {
11545         PQExpBuffer q;
11546         PQExpBuffer delq;
11547         PQExpBuffer labelq;
11548         char       *qfdwname;
11549
11550         /* Skip if not to be dumped */
11551         if (!fdwinfo->dobj.dump || dataOnly)
11552                 return;
11553
11554         /*
11555          * FDWs that belong to an extension are dumped based on their "dump"
11556          * field. Otherwise omit them if we are only dumping some specific object.
11557          */
11558         if (!fdwinfo->dobj.ext_member)
11559                 if (!include_everything)
11560                         return;
11561
11562         q = createPQExpBuffer();
11563         delq = createPQExpBuffer();
11564         labelq = createPQExpBuffer();
11565
11566         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11567
11568         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11569                                           qfdwname);
11570
11571         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11572                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11573
11574         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11575                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11576
11577         if (strlen(fdwinfo->fdwoptions) > 0)
11578                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
11579
11580         appendPQExpBuffer(q, ";\n");
11581
11582         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
11583                                           qfdwname);
11584
11585         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
11586                                           qfdwname);
11587
11588         if (binary_upgrade)
11589                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
11590
11591         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11592                                  fdwinfo->dobj.name,
11593                                  NULL,
11594                                  NULL,
11595                                  fdwinfo->rolname,
11596                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
11597                                  q->data, delq->data, NULL,
11598                                  fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
11599                                  NULL, NULL);
11600
11601         /* Handle the ACL */
11602         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11603                         "FOREIGN DATA WRAPPER",
11604                         qfdwname, NULL, fdwinfo->dobj.name,
11605                         NULL, fdwinfo->rolname,
11606                         fdwinfo->fdwacl);
11607
11608         /* Dump Foreign Data Wrapper Comments */
11609         dumpComment(fout, labelq->data,
11610                                 NULL, fdwinfo->rolname,
11611                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
11612
11613         free(qfdwname);
11614
11615         destroyPQExpBuffer(q);
11616         destroyPQExpBuffer(delq);
11617         destroyPQExpBuffer(labelq);
11618 }
11619
11620 /*
11621  * dumpForeignServer
11622  *        write out a foreign server definition
11623  */
11624 static void
11625 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
11626 {
11627         PQExpBuffer q;
11628         PQExpBuffer delq;
11629         PQExpBuffer labelq;
11630         PQExpBuffer query;
11631         PGresult   *res;
11632         int                     ntups;
11633         char       *qsrvname;
11634         char       *fdwname;
11635
11636         /* Skip if not to be dumped */
11637         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
11638                 return;
11639
11640         q = createPQExpBuffer();
11641         delq = createPQExpBuffer();
11642         labelq = createPQExpBuffer();
11643         query = createPQExpBuffer();
11644
11645         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
11646
11647         /* look up the foreign-data wrapper */
11648         selectSourceSchema("pg_catalog");
11649         appendPQExpBuffer(query, "SELECT fdwname "
11650                                           "FROM pg_foreign_data_wrapper w "
11651                                           "WHERE w.oid = '%u'",
11652                                           srvinfo->srvfdw);
11653         res = PQexec(g_conn, query->data);
11654         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11655         ntups = PQntuples(res);
11656         if (ntups != 1)
11657         {
11658                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11659                                                            "query returned %d rows instead of one: %s\n",
11660                                                                  ntups),
11661                                   ntups, query->data);
11662                 exit_nicely();
11663         }
11664         fdwname = PQgetvalue(res, 0, 0);
11665
11666         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
11667         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
11668         {
11669                 appendPQExpBuffer(q, " TYPE ");
11670                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
11671         }
11672         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
11673         {
11674                 appendPQExpBuffer(q, " VERSION ");
11675                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
11676         }
11677
11678         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
11679         appendPQExpBuffer(q, "%s", fmtId(fdwname));
11680
11681         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
11682                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
11683
11684         appendPQExpBuffer(q, ";\n");
11685
11686         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
11687                                           qsrvname);
11688
11689         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
11690
11691         if (binary_upgrade)
11692                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
11693
11694         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11695                                  srvinfo->dobj.name,
11696                                  NULL,
11697                                  NULL,
11698                                  srvinfo->rolname,
11699                                  false, "SERVER", SECTION_PRE_DATA,
11700                                  q->data, delq->data, NULL,
11701                                  srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
11702                                  NULL, NULL);
11703
11704         /* Handle the ACL */
11705         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11706                         "FOREIGN SERVER",
11707                         qsrvname, NULL, srvinfo->dobj.name,
11708                         NULL, srvinfo->rolname,
11709                         srvinfo->srvacl);
11710
11711         /* Dump user mappings */
11712         dumpUserMappings(fout,
11713                                          srvinfo->dobj.name, NULL,
11714                                          srvinfo->rolname,
11715                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
11716
11717         /* Dump Foreign Server Comments */
11718         dumpComment(fout, labelq->data,
11719                                 NULL, srvinfo->rolname,
11720                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
11721
11722         free(qsrvname);
11723
11724         destroyPQExpBuffer(q);
11725         destroyPQExpBuffer(delq);
11726         destroyPQExpBuffer(labelq);
11727 }
11728
11729 /*
11730  * dumpUserMappings
11731  *
11732  * This routine is used to dump any user mappings associated with the
11733  * server handed to this routine. Should be called after ArchiveEntry()
11734  * for the server.
11735  */
11736 static void
11737 dumpUserMappings(Archive *fout,
11738                                  const char *servername, const char *namespace,
11739                                  const char *owner,
11740                                  CatalogId catalogId, DumpId dumpId)
11741 {
11742         PQExpBuffer q;
11743         PQExpBuffer delq;
11744         PQExpBuffer query;
11745         PQExpBuffer tag;
11746         PGresult   *res;
11747         int                     ntups;
11748         int                     i_usename;
11749         int                     i_umoptions;
11750         int                     i;
11751
11752         q = createPQExpBuffer();
11753         tag = createPQExpBuffer();
11754         delq = createPQExpBuffer();
11755         query = createPQExpBuffer();
11756
11757         /*
11758          * We read from the publicly accessible view pg_user_mappings, so as not
11759          * to fail if run by a non-superuser.  Note that the view will show
11760          * umoptions as null if the user hasn't got privileges for the associated
11761          * server; this means that pg_dump will dump such a mapping, but with no
11762          * OPTIONS clause.      A possible alternative is to skip such mappings
11763          * altogether, but it's not clear that that's an improvement.
11764          */
11765         selectSourceSchema("pg_catalog");
11766
11767         appendPQExpBuffer(query,
11768                                           "SELECT usename, "
11769                                           "array_to_string(ARRAY("
11770                                           "SELECT quote_ident(option_name) || ' ' || "
11771                                           "quote_literal(option_value) "
11772                                           "FROM pg_options_to_table(umoptions)"
11773                                           "), E',\n    ') AS umoptions "
11774                                           "FROM pg_user_mappings "
11775                                           "WHERE srvid = '%u' "
11776                                           "ORDER BY usename",
11777                                           catalogId.oid);
11778
11779         res = PQexec(g_conn, query->data);
11780         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11781
11782         ntups = PQntuples(res);
11783         i_usename = PQfnumber(res, "usename");
11784         i_umoptions = PQfnumber(res, "umoptions");
11785
11786         for (i = 0; i < ntups; i++)
11787         {
11788                 char       *usename;
11789                 char       *umoptions;
11790
11791                 usename = PQgetvalue(res, i, i_usename);
11792                 umoptions = PQgetvalue(res, i, i_umoptions);
11793
11794                 resetPQExpBuffer(q);
11795                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
11796                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
11797
11798                 if (umoptions && strlen(umoptions) > 0)
11799                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
11800
11801                 appendPQExpBuffer(q, ";\n");
11802
11803                 resetPQExpBuffer(delq);
11804                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
11805                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
11806
11807                 resetPQExpBuffer(tag);
11808                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
11809                                                   usename, servername);
11810
11811                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11812                                          tag->data,
11813                                          namespace,
11814                                          NULL,
11815                                          owner, false,
11816                                          "USER MAPPING", SECTION_PRE_DATA,
11817                                          q->data, delq->data, NULL,
11818                                          &dumpId, 1,
11819                                          NULL, NULL);
11820         }
11821
11822         PQclear(res);
11823
11824         destroyPQExpBuffer(query);
11825         destroyPQExpBuffer(delq);
11826         destroyPQExpBuffer(q);
11827 }
11828
11829 /*
11830  * Write out default privileges information
11831  */
11832 static void
11833 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
11834 {
11835         PQExpBuffer q;
11836         PQExpBuffer tag;
11837         const char *type;
11838
11839         /* Skip if not to be dumped */
11840         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
11841                 return;
11842
11843         q = createPQExpBuffer();
11844         tag = createPQExpBuffer();
11845
11846         switch (daclinfo->defaclobjtype)
11847         {
11848                 case DEFACLOBJ_RELATION:
11849                         type = "TABLES";
11850                         break;
11851                 case DEFACLOBJ_SEQUENCE:
11852                         type = "SEQUENCES";
11853                         break;
11854                 case DEFACLOBJ_FUNCTION:
11855                         type = "FUNCTIONS";
11856                         break;
11857                 default:
11858                         /* shouldn't get here */
11859                         write_msg(NULL, "unknown object type (%d) in default privileges\n",
11860                                           (int) daclinfo->defaclobjtype);
11861                         exit_nicely();
11862                         type = "";                      /* keep compiler quiet */
11863         }
11864
11865         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
11866
11867         /* build the actual command(s) for this tuple */
11868         if (!buildDefaultACLCommands(type,
11869                                                                  daclinfo->dobj.namespace != NULL ?
11870                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
11871                                                                  daclinfo->defaclacl,
11872                                                                  daclinfo->defaclrole,
11873                                                                  fout->remoteVersion,
11874                                                                  q))
11875         {
11876                 write_msg(NULL, "could not parse default ACL list (%s)\n",
11877                                   daclinfo->defaclacl);
11878                 exit_nicely();
11879         }
11880
11881         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
11882                                  tag->data,
11883            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
11884                                  NULL,
11885                                  daclinfo->defaclrole,
11886                                  false, "DEFAULT ACL", SECTION_NONE,
11887                                  q->data, "", NULL,
11888                                  daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
11889                                  NULL, NULL);
11890
11891         destroyPQExpBuffer(tag);
11892         destroyPQExpBuffer(q);
11893 }
11894
11895 /*----------
11896  * Write out grant/revoke information
11897  *
11898  * 'objCatId' is the catalog ID of the underlying object.
11899  * 'objDumpId' is the dump ID of the underlying object.
11900  * 'type' must be one of
11901  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
11902  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
11903  * 'name' is the formatted name of the object.  Must be quoted etc. already.
11904  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
11905  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
11906  * 'nspname' is the namespace the object is in (NULL if none).
11907  * 'owner' is the owner, NULL if there is no owner (for languages).
11908  * 'acls' is the string read out of the fooacl system catalog field;
11909  *              it will be parsed here.
11910  *----------
11911  */
11912 static void
11913 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
11914                 const char *type, const char *name, const char *subname,
11915                 const char *tag, const char *nspname, const char *owner,
11916                 const char *acls)
11917 {
11918         PQExpBuffer sql;
11919
11920         /* Do nothing if ACL dump is not enabled */
11921         if (aclsSkip)
11922                 return;
11923
11924         /* --data-only skips ACLs *except* BLOB ACLs */
11925         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
11926                 return;
11927
11928         sql = createPQExpBuffer();
11929
11930         if (!buildACLCommands(name, subname, type, acls, owner,
11931                                                   "", fout->remoteVersion, sql))
11932         {
11933                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
11934                                   acls, name, type);
11935                 exit_nicely();
11936         }
11937
11938         if (sql->len > 0)
11939                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11940                                          tag, nspname,
11941                                          NULL,
11942                                          owner ? owner : "",
11943                                          false, "ACL", SECTION_NONE,
11944                                          sql->data, "", NULL,
11945                                          &(objDumpId), 1,
11946                                          NULL, NULL);
11947
11948         destroyPQExpBuffer(sql);
11949 }
11950
11951 /*
11952  * dumpSecLabel
11953  *
11954  * This routine is used to dump any security labels associated with the
11955  * object handed to this routine. The routine takes a constant character
11956  * string for the target part of the security-label command, plus
11957  * the namespace and owner of the object (for labeling the ArchiveEntry),
11958  * plus catalog ID and subid which are the lookup key for pg_seclabel,
11959  * plus the dump ID for the object (for setting a dependency).
11960  * If a matching pg_seclabel entry is found, it is dumped.
11961  *
11962  * Note: although this routine takes a dumpId for dependency purposes,
11963  * that purpose is just to mark the dependency in the emitted dump file
11964  * for possible future use by pg_restore.  We do NOT use it for determining
11965  * ordering of the label in the dump file, because this routine is called
11966  * after dependency sorting occurs.  This routine should be called just after
11967  * calling ArchiveEntry() for the specified object.
11968  */
11969 static void
11970 dumpSecLabel(Archive *fout, const char *target,
11971                          const char *namespace, const char *owner,
11972                          CatalogId catalogId, int subid, DumpId dumpId)
11973 {
11974         SecLabelItem *labels;
11975         int                     nlabels;
11976         int                     i;
11977         PQExpBuffer query;
11978
11979         /* do nothing, if --no-security-labels is supplied */
11980         if (no_security_labels)
11981                 return;
11982
11983         /* Comments are schema not data ... except blob comments are data */
11984         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
11985         {
11986                 if (dataOnly)
11987                         return;
11988         }
11989         else
11990         {
11991                 if (schemaOnly)
11992                         return;
11993         }
11994
11995         /* Search for security labels associated with catalogId, using table */
11996         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
11997
11998         query = createPQExpBuffer();
11999
12000         for (i = 0; i < nlabels; i++)
12001         {
12002                 /*
12003                  * Ignore label entries for which the subid doesn't match.
12004                  */
12005                 if (labels[i].objsubid != subid)
12006                         continue;
12007
12008                 appendPQExpBuffer(query,
12009                                                   "SECURITY LABEL FOR %s ON %s IS ",
12010                                                   fmtId(labels[i].provider), target);
12011                 appendStringLiteralAH(query, labels[i].label, fout);
12012                 appendPQExpBuffer(query, ";\n");
12013         }
12014
12015         if (query->len > 0)
12016         {
12017                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12018                                          target, namespace, NULL, owner,
12019                                          false, "SECURITY LABEL", SECTION_NONE,
12020                                          query->data, "", NULL,
12021                                          &(dumpId), 1,
12022                                          NULL, NULL);
12023         }
12024         destroyPQExpBuffer(query);
12025 }
12026
12027 /*
12028  * dumpTableSecLabel
12029  *
12030  * As above, but dump security label for both the specified table (or view)
12031  * and its columns.
12032  */
12033 static void
12034 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12035 {
12036         SecLabelItem *labels;
12037         int                     nlabels;
12038         int                     i;
12039         PQExpBuffer query;
12040         PQExpBuffer target;
12041
12042         /* do nothing, if --no-security-labels is supplied */
12043         if (no_security_labels)
12044                 return;
12045
12046         /* SecLabel are SCHEMA not data */
12047         if (dataOnly)
12048                 return;
12049
12050         /* Search for comments associated with relation, using table */
12051         nlabels = findSecLabels(fout,
12052                                                         tbinfo->dobj.catId.tableoid,
12053                                                         tbinfo->dobj.catId.oid,
12054                                                         &labels);
12055
12056         /* If security labels exist, build SECURITY LABEL statements */
12057         if (nlabels <= 0)
12058                 return;
12059
12060         query = createPQExpBuffer();
12061         target = createPQExpBuffer();
12062
12063         for (i = 0; i < nlabels; i++)
12064         {
12065                 const char *colname;
12066                 const char *provider = labels[i].provider;
12067                 const char *label = labels[i].label;
12068                 int                     objsubid = labels[i].objsubid;
12069
12070                 resetPQExpBuffer(target);
12071                 if (objsubid == 0)
12072                 {
12073                         appendPQExpBuffer(target, "%s %s", reltypename,
12074                                                           fmtId(tbinfo->dobj.name));
12075                 }
12076                 else
12077                 {
12078                         colname = getAttrName(objsubid, tbinfo);
12079                         /* first fmtId result must be consumed before calling it again */
12080                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12081                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12082                 }
12083                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12084                                                   fmtId(provider), target->data);
12085                 appendStringLiteralAH(query, label, fout);
12086                 appendPQExpBuffer(query, ";\n");
12087         }
12088         if (query->len > 0)
12089         {
12090                 resetPQExpBuffer(target);
12091                 appendPQExpBuffer(target, "%s %s", reltypename,
12092                                                   fmtId(tbinfo->dobj.name));
12093                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12094                                          target->data,
12095                                          tbinfo->dobj.namespace->dobj.name,
12096                                          NULL, tbinfo->rolname,
12097                                          false, "SECURITY LABEL", SECTION_NONE,
12098                                          query->data, "", NULL,
12099                                          &(tbinfo->dobj.dumpId), 1,
12100                                          NULL, NULL);
12101         }
12102         destroyPQExpBuffer(query);
12103         destroyPQExpBuffer(target);
12104 }
12105
12106 /*
12107  * findSecLabels
12108  *
12109  * Find the security label(s), if any, associated with the given object.
12110  * All the objsubid values associated with the given classoid/objoid are
12111  * found with one search.
12112  */
12113 static int
12114 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12115 {
12116         /* static storage for table of security labels */
12117         static SecLabelItem *labels = NULL;
12118         static int      nlabels = -1;
12119
12120         SecLabelItem *middle = NULL;
12121         SecLabelItem *low;
12122         SecLabelItem *high;
12123         int                     nmatch;
12124
12125         /* Get security labels if we didn't already */
12126         if (nlabels < 0)
12127                 nlabels = collectSecLabels(fout, &labels);
12128
12129         if (nlabels <= 0)                       /* no labels, so no match is possible */
12130         {
12131                 *items = NULL;
12132                 return 0;
12133         }
12134
12135         /*
12136          * Do binary search to find some item matching the object.
12137          */
12138         low = &labels[0];
12139         high = &labels[nlabels - 1];
12140         while (low <= high)
12141         {
12142                 middle = low + (high - low) / 2;
12143
12144                 if (classoid < middle->classoid)
12145                         high = middle - 1;
12146                 else if (classoid > middle->classoid)
12147                         low = middle + 1;
12148                 else if (objoid < middle->objoid)
12149                         high = middle - 1;
12150                 else if (objoid > middle->objoid)
12151                         low = middle + 1;
12152                 else
12153                         break;                          /* found a match */
12154         }
12155
12156         if (low > high)                         /* no matches */
12157         {
12158                 *items = NULL;
12159                 return 0;
12160         }
12161
12162         /*
12163          * Now determine how many items match the object.  The search loop
12164          * invariant still holds: only items between low and high inclusive could
12165          * match.
12166          */
12167         nmatch = 1;
12168         while (middle > low)
12169         {
12170                 if (classoid != middle[-1].classoid ||
12171                         objoid != middle[-1].objoid)
12172                         break;
12173                 middle--;
12174                 nmatch++;
12175         }
12176
12177         *items = middle;
12178
12179         middle += nmatch;
12180         while (middle <= high)
12181         {
12182                 if (classoid != middle->classoid ||
12183                         objoid != middle->objoid)
12184                         break;
12185                 middle++;
12186                 nmatch++;
12187         }
12188
12189         return nmatch;
12190 }
12191
12192 /*
12193  * collectSecLabels
12194  *
12195  * Construct a table of all security labels available for database objects.
12196  * It's much faster to pull them all at once.
12197  *
12198  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12199  */
12200 static int
12201 collectSecLabels(Archive *fout, SecLabelItem **items)
12202 {
12203         PGresult   *res;
12204         PQExpBuffer query;
12205         int                     i_label;
12206         int                     i_provider;
12207         int                     i_classoid;
12208         int                     i_objoid;
12209         int                     i_objsubid;
12210         int                     ntups;
12211         int                     i;
12212         SecLabelItem *labels;
12213
12214         query = createPQExpBuffer();
12215
12216         appendPQExpBuffer(query,
12217                                           "SELECT label, provider, classoid, objoid, objsubid "
12218                                           "FROM pg_catalog.pg_seclabel "
12219                                           "ORDER BY classoid, objoid, objsubid");
12220
12221         res = PQexec(g_conn, query->data);
12222         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12223
12224         /* Construct lookup table containing OIDs in numeric form */
12225         i_label = PQfnumber(res, "label");
12226         i_provider = PQfnumber(res, "provider");
12227         i_classoid = PQfnumber(res, "classoid");
12228         i_objoid = PQfnumber(res, "objoid");
12229         i_objsubid = PQfnumber(res, "objsubid");
12230
12231         ntups = PQntuples(res);
12232
12233         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12234
12235         for (i = 0; i < ntups; i++)
12236         {
12237                 labels[i].label = PQgetvalue(res, i, i_label);
12238                 labels[i].provider = PQgetvalue(res, i, i_provider);
12239                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12240                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12241                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12242         }
12243
12244         /* Do NOT free the PGresult since we are keeping pointers into it */
12245         destroyPQExpBuffer(query);
12246
12247         *items = labels;
12248         return ntups;
12249 }
12250
12251 /*
12252  * dumpTable
12253  *        write out to fout the declarations (not data) of a user-defined table
12254  */
12255 static void
12256 dumpTable(Archive *fout, TableInfo *tbinfo)
12257 {
12258         if (tbinfo->dobj.dump)
12259         {
12260                 char       *namecopy;
12261
12262                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12263                         dumpSequence(fout, tbinfo);
12264                 else if (!dataOnly)
12265                         dumpTableSchema(fout, tbinfo);
12266
12267                 /* Handle the ACL here */
12268                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12269                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12270                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12271                                 "TABLE",
12272                                 namecopy, NULL, tbinfo->dobj.name,
12273                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12274                                 tbinfo->relacl);
12275
12276                 /*
12277                  * Handle column ACLs, if any.  Note: we pull these with a separate
12278                  * query rather than trying to fetch them during getTableAttrs, so
12279                  * that we won't miss ACLs on system columns.
12280                  */
12281                 if (g_fout->remoteVersion >= 80400)
12282                 {
12283                         PQExpBuffer query = createPQExpBuffer();
12284                         PGresult   *res;
12285                         int                     i;
12286
12287                         appendPQExpBuffer(query,
12288                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12289                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12290                                                           "ORDER BY attnum",
12291                                                           tbinfo->dobj.catId.oid);
12292                         res = PQexec(g_conn, query->data);
12293                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12294
12295                         for (i = 0; i < PQntuples(res); i++)
12296                         {
12297                                 char       *attname = PQgetvalue(res, i, 0);
12298                                 char       *attacl = PQgetvalue(res, i, 1);
12299                                 char       *attnamecopy;
12300                                 char       *acltag;
12301
12302                                 attnamecopy = pg_strdup(fmtId(attname));
12303                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12304                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12305                                 /* Column's GRANT type is always TABLE */
12306                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12307                                                 namecopy, attnamecopy, acltag,
12308                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12309                                                 attacl);
12310                                 free(attnamecopy);
12311                                 free(acltag);
12312                         }
12313                         PQclear(res);
12314                         destroyPQExpBuffer(query);
12315                 }
12316
12317                 free(namecopy);
12318         }
12319 }
12320
12321 /*
12322  * dumpTableSchema
12323  *        write the declaration (not data) of one user-defined table or view
12324  */
12325 static void
12326 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12327 {
12328         PQExpBuffer query = createPQExpBuffer();
12329         PQExpBuffer q = createPQExpBuffer();
12330         PQExpBuffer delq = createPQExpBuffer();
12331         PQExpBuffer labelq = createPQExpBuffer();
12332         PGresult   *res;
12333         int                     numParents;
12334         TableInfo **parents;
12335         int                     actual_atts;    /* number of attrs in this CREATE statment */
12336         const char *reltypename;
12337         char       *storage;
12338         char       *srvname;
12339         char       *ftoptions;
12340         int                     j,
12341                                 k;
12342
12343         /* Make sure we are in proper schema */
12344         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
12345
12346         if (binary_upgrade)
12347                 binary_upgrade_set_type_oids_by_rel_oid(q,
12348                                                                                                 tbinfo->dobj.catId.oid);
12349
12350         /* Is it a table or a view? */
12351         if (tbinfo->relkind == RELKIND_VIEW)
12352         {
12353                 char       *viewdef;
12354
12355                 reltypename = "VIEW";
12356
12357                 /* Fetch the view definition */
12358                 if (g_fout->remoteVersion >= 70300)
12359                 {
12360                         /* Beginning in 7.3, viewname is not unique; rely on OID */
12361                         appendPQExpBuffer(query,
12362                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12363                                                           tbinfo->dobj.catId.oid);
12364                 }
12365                 else
12366                 {
12367                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
12368                                                           "FROM pg_views WHERE viewname = ");
12369                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12370                         appendPQExpBuffer(query, ";");
12371                 }
12372
12373                 res = PQexec(g_conn, query->data);
12374                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12375
12376                 if (PQntuples(res) != 1)
12377                 {
12378                         if (PQntuples(res) < 1)
12379                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12380                                                   tbinfo->dobj.name);
12381                         else
12382                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12383                                                   tbinfo->dobj.name);
12384                         exit_nicely();
12385                 }
12386
12387                 viewdef = PQgetvalue(res, 0, 0);
12388
12389                 if (strlen(viewdef) == 0)
12390                 {
12391                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12392                                           tbinfo->dobj.name);
12393                         exit_nicely();
12394                 }
12395
12396                 /*
12397                  * DROP must be fully qualified in case same name appears in
12398                  * pg_catalog
12399                  */
12400                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12401                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12402                 appendPQExpBuffer(delq, "%s;\n",
12403                                                   fmtId(tbinfo->dobj.name));
12404
12405                 if (binary_upgrade)
12406                         binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
12407
12408                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12409                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12410                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12411                 appendPQExpBuffer(q, " AS\n    %s\n", viewdef);
12412
12413                 appendPQExpBuffer(labelq, "VIEW %s",
12414                                                   fmtId(tbinfo->dobj.name));
12415
12416                 PQclear(res);
12417         }
12418         else
12419         {
12420                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12421                 {
12422                         int                     i_srvname;
12423                         int                     i_ftoptions;
12424
12425                         reltypename = "FOREIGN TABLE";
12426
12427                         /* retrieve name of foreign server and generic options */
12428                         appendPQExpBuffer(query,
12429                                                           "SELECT fs.srvname, "
12430                                                           "pg_catalog.array_to_string(ARRAY("
12431                                                           "SELECT pg_catalog.quote_ident(option_name) || "
12432                                                           "' ' || pg_catalog.quote_literal(option_value) "
12433                                                           "FROM pg_catalog.pg_options_to_table(ftoptions)"
12434                                                           "), E',\n    ') AS ftoptions "
12435                                                           "FROM pg_catalog.pg_foreign_table ft "
12436                                                           "JOIN pg_catalog.pg_foreign_server fs "
12437                                                           "ON (fs.oid = ft.ftserver) "
12438                                                           "WHERE ft.ftrelid = '%u'",
12439                                                           tbinfo->dobj.catId.oid);
12440                         res = PQexec(g_conn, query->data);
12441                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12442                         if (PQntuples(res) != 1)
12443                         {
12444                                 write_msg(NULL, ngettext("query returned %d foreign server entry for foreign table \"%s\"\n",
12445                                                                                  "query returned %d foreign server entries for foreign table \"%s\"\n",
12446                                                                                  PQntuples(res)),
12447                                                   PQntuples(res), tbinfo->dobj.name);
12448                                 exit_nicely();
12449                         }
12450                         i_srvname = PQfnumber(res, "srvname");
12451                         i_ftoptions = PQfnumber(res, "ftoptions");
12452                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12453                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12454                         PQclear(res);
12455                 }
12456                 else
12457                 {
12458                         reltypename = "TABLE";
12459                         srvname = NULL;
12460                         ftoptions = NULL;
12461                 }
12462                 numParents = tbinfo->numParents;
12463                 parents = tbinfo->parents;
12464
12465                 /*
12466                  * DROP must be fully qualified in case same name appears in
12467                  * pg_catalog
12468                  */
12469                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12470                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12471                 appendPQExpBuffer(delq, "%s;\n",
12472                                                   fmtId(tbinfo->dobj.name));
12473
12474                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12475                                                   fmtId(tbinfo->dobj.name));
12476
12477                 if (binary_upgrade)
12478                         binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
12479
12480                 appendPQExpBuffer(q, "CREATE %s%s %s",
12481                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12482                                                   "UNLOGGED " : "",
12483                                                   reltypename,
12484                                                   fmtId(tbinfo->dobj.name));
12485
12486                 /*
12487                  * In case of a binary upgrade, we dump the table normally and attach
12488                  * it to the type afterward.
12489                  */
12490                 if (tbinfo->reloftype && !binary_upgrade)
12491                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12492                 actual_atts = 0;
12493                 for (j = 0; j < tbinfo->numatts; j++)
12494                 {
12495                         /*
12496                          * Normally, dump if it's one of the table's own attrs, and not
12497                          * dropped.  But for binary upgrade, dump all the columns.
12498                          */
12499                         if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
12500                                 binary_upgrade)
12501                         {
12502                                 /*
12503                                  * Default value --- suppress if inherited (except in
12504                                  * binary-upgrade case, where we're not doing normal
12505                                  * inheritance) or if it's to be printed separately.
12506                                  */
12507                                 bool            has_default = (tbinfo->attrdefs[j] != NULL
12508                                                                 && (!tbinfo->inhAttrDef[j] || binary_upgrade)
12509                                                                                    && !tbinfo->attrdefs[j]->separate);
12510
12511                                 /*
12512                                  * Not Null constraint --- suppress if inherited, except in
12513                                  * binary-upgrade case.
12514                                  */
12515                                 bool            has_notnull = (tbinfo->notnull[j]
12516                                                           && (!tbinfo->inhNotNull[j] || binary_upgrade));
12517
12518                                 if (tbinfo->reloftype && !has_default && !has_notnull && !binary_upgrade)
12519                                         continue;
12520
12521                                 /* Format properly if not first attr */
12522                                 if (actual_atts == 0)
12523                                         appendPQExpBuffer(q, " (");
12524                                 else
12525                                         appendPQExpBuffer(q, ",");
12526                                 appendPQExpBuffer(q, "\n    ");
12527                                 actual_atts++;
12528
12529                                 /* Attribute name */
12530                                 appendPQExpBuffer(q, "%s ",
12531                                                                   fmtId(tbinfo->attnames[j]));
12532
12533                                 if (tbinfo->attisdropped[j])
12534                                 {
12535                                         /*
12536                                          * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
12537                                          * so we will not have gotten a valid type name; insert
12538                                          * INTEGER as a stopgap.  We'll clean things up later.
12539                                          */
12540                                         appendPQExpBuffer(q, "INTEGER /* dummy */");
12541                                         /* Skip all the rest, too */
12542                                         continue;
12543                                 }
12544
12545                                 /* Attribute type */
12546                                 if (tbinfo->reloftype && !binary_upgrade)
12547                                 {
12548                                         appendPQExpBuffer(q, "WITH OPTIONS");
12549                                 }
12550                                 else if (g_fout->remoteVersion >= 70100)
12551                                 {
12552                                         appendPQExpBuffer(q, "%s",
12553                                                                           tbinfo->atttypnames[j]);
12554                                 }
12555                                 else
12556                                 {
12557                                         /* If no format_type, fake it */
12558                                         appendPQExpBuffer(q, "%s",
12559                                                                           myFormatType(tbinfo->atttypnames[j],
12560                                                                                                    tbinfo->atttypmod[j]));
12561                                 }
12562
12563                                 /* Add collation if not default for the type */
12564                                 if (OidIsValid(tbinfo->attcollation[j]))
12565                                 {
12566                                         CollInfo   *coll;
12567
12568                                         coll = findCollationByOid(tbinfo->attcollation[j]);
12569                                         if (coll)
12570                                         {
12571                                                 /* always schema-qualify, don't try to be smart */
12572                                                 appendPQExpBuffer(q, " COLLATE %s.",
12573                                                                          fmtId(coll->dobj.namespace->dobj.name));
12574                                                 appendPQExpBuffer(q, "%s",
12575                                                                                   fmtId(coll->dobj.name));
12576                                         }
12577                                 }
12578
12579                                 if (has_default)
12580                                         appendPQExpBuffer(q, " DEFAULT %s",
12581                                                                           tbinfo->attrdefs[j]->adef_expr);
12582
12583                                 if (has_notnull)
12584                                         appendPQExpBuffer(q, " NOT NULL");
12585                         }
12586                 }
12587
12588                 /*
12589                  * Add non-inherited CHECK constraints, if any.
12590                  */
12591                 for (j = 0; j < tbinfo->ncheck; j++)
12592                 {
12593                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12594
12595                         if (constr->separate || !constr->conislocal)
12596                                 continue;
12597
12598                         if (actual_atts == 0)
12599                                 appendPQExpBuffer(q, " (\n    ");
12600                         else
12601                                 appendPQExpBuffer(q, ",\n    ");
12602
12603                         appendPQExpBuffer(q, "CONSTRAINT %s ",
12604                                                           fmtId(constr->dobj.name));
12605                         appendPQExpBuffer(q, "%s", constr->condef);
12606
12607                         actual_atts++;
12608                 }
12609
12610                 if (actual_atts)
12611                         appendPQExpBuffer(q, "\n)");
12612                 else if (!(tbinfo->reloftype && !binary_upgrade))
12613                 {
12614                         /*
12615                          * We must have a parenthesized attribute list, even though empty,
12616                          * when not using the OF TYPE syntax.
12617                          */
12618                         appendPQExpBuffer(q, " (\n)");
12619                 }
12620
12621                 if (numParents > 0 && !binary_upgrade)
12622                 {
12623                         appendPQExpBuffer(q, "\nINHERITS (");
12624                         for (k = 0; k < numParents; k++)
12625                         {
12626                                 TableInfo  *parentRel = parents[k];
12627
12628                                 if (k > 0)
12629                                         appendPQExpBuffer(q, ", ");
12630                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12631                                         appendPQExpBuffer(q, "%s.",
12632                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12633                                 appendPQExpBuffer(q, "%s",
12634                                                                   fmtId(parentRel->dobj.name));
12635                         }
12636                         appendPQExpBuffer(q, ")");
12637                 }
12638
12639                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12640                         appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
12641
12642                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
12643                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
12644                 {
12645                         bool            addcomma = false;
12646
12647                         appendPQExpBuffer(q, "\nWITH (");
12648                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12649                         {
12650                                 addcomma = true;
12651                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
12652                         }
12653                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
12654                         {
12655                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
12656                                                                   tbinfo->toast_reloptions);
12657                         }
12658                         appendPQExpBuffer(q, ")");
12659                 }
12660
12661                 /* Dump generic options if any */
12662                 if (ftoptions && ftoptions[0])
12663                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
12664
12665                 appendPQExpBuffer(q, ";\n");
12666
12667                 /*
12668                  * To create binary-compatible heap files, we have to ensure the same
12669                  * physical column order, including dropped columns, as in the
12670                  * original.  Therefore, we create dropped columns above and drop them
12671                  * here, also updating their attlen/attalign values so that the
12672                  * dropped column can be skipped properly.      (We do not bother with
12673                  * restoring the original attbyval setting.)  Also, inheritance
12674                  * relationships are set up by doing ALTER INHERIT rather than using
12675                  * an INHERITS clause --- the latter would possibly mess up the column
12676                  * order.  That also means we have to take care about setting
12677                  * attislocal correctly, plus fix up any inherited CHECK constraints.
12678                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
12679                  */
12680                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
12681                 {
12682                         for (j = 0; j < tbinfo->numatts; j++)
12683                         {
12684                                 if (tbinfo->attisdropped[j])
12685                                 {
12686                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
12687                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12688                                                                           "SET attlen = %d, "
12689                                                                           "attalign = '%c', attbyval = false\n"
12690                                                                           "WHERE attname = ",
12691                                                                           tbinfo->attlen[j],
12692                                                                           tbinfo->attalign[j]);
12693                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12694                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12695                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12696                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12697
12698                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12699                                                                           fmtId(tbinfo->dobj.name));
12700                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
12701                                                                           fmtId(tbinfo->attnames[j]));
12702                                 }
12703                                 else if (!tbinfo->attislocal[j])
12704                                 {
12705                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
12706                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12707                                                                           "SET attislocal = false\n"
12708                                                                           "WHERE attname = ");
12709                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12710                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12711                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12712                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12713                                 }
12714                         }
12715
12716                         for (k = 0; k < tbinfo->ncheck; k++)
12717                         {
12718                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
12719
12720                                 if (constr->separate || constr->conislocal)
12721                                         continue;
12722
12723                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
12724                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12725                                                                   fmtId(tbinfo->dobj.name));
12726                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
12727                                                                   fmtId(constr->dobj.name));
12728                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
12729                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
12730                                                                   "SET conislocal = false\n"
12731                                                                   "WHERE contype = 'c' AND conname = ");
12732                                 appendStringLiteralAH(q, constr->dobj.name, fout);
12733                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
12734                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12735                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12736                         }
12737
12738                         if (numParents > 0)
12739                         {
12740                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
12741                                 for (k = 0; k < numParents; k++)
12742                                 {
12743                                         TableInfo  *parentRel = parents[k];
12744
12745                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
12746                                                                           fmtId(tbinfo->dobj.name));
12747                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12748                                                 appendPQExpBuffer(q, "%s.",
12749                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12750                                         appendPQExpBuffer(q, "%s;\n",
12751                                                                           fmtId(parentRel->dobj.name));
12752                                 }
12753                         }
12754
12755                         if (tbinfo->reloftype)
12756                         {
12757                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
12758                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
12759                                                                   fmtId(tbinfo->dobj.name),
12760                                                                   tbinfo->reloftype);
12761                         }
12762
12763                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
12764                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12765                                                           "SET relfrozenxid = '%u'\n"
12766                                                           "WHERE oid = ",
12767                                                           tbinfo->frozenxid);
12768                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12769                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12770
12771                         if (tbinfo->toast_oid)
12772                         {
12773                                 /* We preserve the toast oids, so we can use it during restore */
12774                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
12775                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12776                                                                   "SET relfrozenxid = '%u'\n"
12777                                                                   "WHERE oid = '%u';\n",
12778                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
12779                         }
12780                 }
12781
12782                 /* Loop dumping statistics and storage statements */
12783                 for (j = 0; j < tbinfo->numatts; j++)
12784                 {
12785                         /*
12786                          * Dump per-column statistics information. We only issue an ALTER
12787                          * TABLE statement if the attstattarget entry for this column is
12788                          * non-negative (i.e. it's not the default value)
12789                          */
12790                         if (tbinfo->attstattarget[j] >= 0 &&
12791                                 !tbinfo->attisdropped[j])
12792                         {
12793                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12794                                                                   fmtId(tbinfo->dobj.name));
12795                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12796                                                                   fmtId(tbinfo->attnames[j]));
12797                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
12798                                                                   tbinfo->attstattarget[j]);
12799                         }
12800
12801                         /*
12802                          * Dump per-column storage information.  The statement is only
12803                          * dumped if the storage has been changed from the type's default.
12804                          */
12805                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
12806                         {
12807                                 switch (tbinfo->attstorage[j])
12808                                 {
12809                                         case 'p':
12810                                                 storage = "PLAIN";
12811                                                 break;
12812                                         case 'e':
12813                                                 storage = "EXTERNAL";
12814                                                 break;
12815                                         case 'm':
12816                                                 storage = "MAIN";
12817                                                 break;
12818                                         case 'x':
12819                                                 storage = "EXTENDED";
12820                                                 break;
12821                                         default:
12822                                                 storage = NULL;
12823                                 }
12824
12825                                 /*
12826                                  * Only dump the statement if it's a storage type we recognize
12827                                  */
12828                                 if (storage != NULL)
12829                                 {
12830                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12831                                                                           fmtId(tbinfo->dobj.name));
12832                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
12833                                                                           fmtId(tbinfo->attnames[j]));
12834                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
12835                                                                           storage);
12836                                 }
12837                         }
12838
12839                         /*
12840                          * Dump per-column attributes.
12841                          */
12842                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
12843                         {
12844                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12845                                                                   fmtId(tbinfo->dobj.name));
12846                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12847                                                                   fmtId(tbinfo->attnames[j]));
12848                                 appendPQExpBuffer(q, "SET (%s);\n",
12849                                                                   tbinfo->attoptions[j]);
12850                         }
12851
12852                         /*
12853                          * Dump per-column fdw options.
12854                          */
12855                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
12856                                 tbinfo->attfdwoptions[j] &&
12857                                 tbinfo->attfdwoptions[j][0] != '\0')
12858                         {
12859                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
12860                                                                   fmtId(tbinfo->dobj.name));
12861                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12862                                                                   fmtId(tbinfo->attnames[j]));
12863                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
12864                                                                   tbinfo->attfdwoptions[j]);
12865                         }
12866                 }
12867         }
12868
12869         if (binary_upgrade)
12870                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
12871
12872         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12873                                  tbinfo->dobj.name,
12874                                  tbinfo->dobj.namespace->dobj.name,
12875                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
12876                                  tbinfo->rolname,
12877                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
12878                                  reltypename, SECTION_PRE_DATA,
12879                                  q->data, delq->data, NULL,
12880                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
12881                                  NULL, NULL);
12882
12883
12884         /* Dump Table Comments */
12885         dumpTableComment(fout, tbinfo, reltypename);
12886
12887         /* Dump Table Security Labels */
12888         dumpTableSecLabel(fout, tbinfo, reltypename);
12889
12890         /* Dump comments on inlined table constraints */
12891         for (j = 0; j < tbinfo->ncheck; j++)
12892         {
12893                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12894
12895                 if (constr->separate || !constr->conislocal)
12896                         continue;
12897
12898                 dumpTableConstraintComment(fout, constr);
12899         }
12900
12901         destroyPQExpBuffer(query);
12902         destroyPQExpBuffer(q);
12903         destroyPQExpBuffer(delq);
12904         destroyPQExpBuffer(labelq);
12905 }
12906
12907 /*
12908  * dumpAttrDef --- dump an attribute's default-value declaration
12909  */
12910 static void
12911 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
12912 {
12913         TableInfo  *tbinfo = adinfo->adtable;
12914         int                     adnum = adinfo->adnum;
12915         PQExpBuffer q;
12916         PQExpBuffer delq;
12917
12918         /* Only print it if "separate" mode is selected */
12919         if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
12920                 return;
12921
12922         /* Don't print inherited defaults, either, except for binary upgrade */
12923         if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
12924                 return;
12925
12926         q = createPQExpBuffer();
12927         delq = createPQExpBuffer();
12928
12929         appendPQExpBuffer(q, "ALTER TABLE %s ",
12930                                           fmtId(tbinfo->dobj.name));
12931         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
12932                                           fmtId(tbinfo->attnames[adnum - 1]),
12933                                           adinfo->adef_expr);
12934
12935         /*
12936          * DROP must be fully qualified in case same name appears in pg_catalog
12937          */
12938         appendPQExpBuffer(delq, "ALTER TABLE %s.",
12939                                           fmtId(tbinfo->dobj.namespace->dobj.name));
12940         appendPQExpBuffer(delq, "%s ",
12941                                           fmtId(tbinfo->dobj.name));
12942         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
12943                                           fmtId(tbinfo->attnames[adnum - 1]));
12944
12945         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
12946                                  tbinfo->attnames[adnum - 1],
12947                                  tbinfo->dobj.namespace->dobj.name,
12948                                  NULL,
12949                                  tbinfo->rolname,
12950                                  false, "DEFAULT", SECTION_PRE_DATA,
12951                                  q->data, delq->data, NULL,
12952                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
12953                                  NULL, NULL);
12954
12955         destroyPQExpBuffer(q);
12956         destroyPQExpBuffer(delq);
12957 }
12958
12959 /*
12960  * getAttrName: extract the correct name for an attribute
12961  *
12962  * The array tblInfo->attnames[] only provides names of user attributes;
12963  * if a system attribute number is supplied, we have to fake it.
12964  * We also do a little bit of bounds checking for safety's sake.
12965  */
12966 static const char *
12967 getAttrName(int attrnum, TableInfo *tblInfo)
12968 {
12969         if (attrnum > 0 && attrnum <= tblInfo->numatts)
12970                 return tblInfo->attnames[attrnum - 1];
12971         switch (attrnum)
12972         {
12973                 case SelfItemPointerAttributeNumber:
12974                         return "ctid";
12975                 case ObjectIdAttributeNumber:
12976                         return "oid";
12977                 case MinTransactionIdAttributeNumber:
12978                         return "xmin";
12979                 case MinCommandIdAttributeNumber:
12980                         return "cmin";
12981                 case MaxTransactionIdAttributeNumber:
12982                         return "xmax";
12983                 case MaxCommandIdAttributeNumber:
12984                         return "cmax";
12985                 case TableOidAttributeNumber:
12986                         return "tableoid";
12987         }
12988         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
12989                           attrnum, tblInfo->dobj.name);
12990         exit_nicely();
12991         return NULL;                            /* keep compiler quiet */
12992 }
12993
12994 /*
12995  * dumpIndex
12996  *        write out to fout a user-defined index
12997  */
12998 static void
12999 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13000 {
13001         TableInfo  *tbinfo = indxinfo->indextable;
13002         PQExpBuffer q;
13003         PQExpBuffer delq;
13004         PQExpBuffer labelq;
13005
13006         if (dataOnly)
13007                 return;
13008
13009         q = createPQExpBuffer();
13010         delq = createPQExpBuffer();
13011         labelq = createPQExpBuffer();
13012
13013         appendPQExpBuffer(labelq, "INDEX %s",
13014                                           fmtId(indxinfo->dobj.name));
13015
13016         /*
13017          * If there's an associated constraint, don't dump the index per se, but
13018          * do dump any comment for it.  (This is safe because dependency ordering
13019          * will have ensured the constraint is emitted first.)
13020          */
13021         if (indxinfo->indexconstraint == 0)
13022         {
13023                 if (binary_upgrade)
13024                         binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
13025
13026                 /* Plain secondary index */
13027                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13028
13029                 /* If the index is clustered, we need to record that. */
13030                 if (indxinfo->indisclustered)
13031                 {
13032                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13033                                                           fmtId(tbinfo->dobj.name));
13034                         appendPQExpBuffer(q, " ON %s;\n",
13035                                                           fmtId(indxinfo->dobj.name));
13036                 }
13037
13038                 /*
13039                  * DROP must be fully qualified in case same name appears in
13040                  * pg_catalog
13041                  */
13042                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13043                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13044                 appendPQExpBuffer(delq, "%s;\n",
13045                                                   fmtId(indxinfo->dobj.name));
13046
13047                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13048                                          indxinfo->dobj.name,
13049                                          tbinfo->dobj.namespace->dobj.name,
13050                                          indxinfo->tablespace,
13051                                          tbinfo->rolname, false,
13052                                          "INDEX", SECTION_POST_DATA,
13053                                          q->data, delq->data, NULL,
13054                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
13055                                          NULL, NULL);
13056         }
13057
13058         /* Dump Index Comments */
13059         dumpComment(fout, labelq->data,
13060                                 tbinfo->dobj.namespace->dobj.name,
13061                                 tbinfo->rolname,
13062                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13063
13064         destroyPQExpBuffer(q);
13065         destroyPQExpBuffer(delq);
13066         destroyPQExpBuffer(labelq);
13067 }
13068
13069 /*
13070  * dumpConstraint
13071  *        write out to fout a user-defined constraint
13072  */
13073 static void
13074 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13075 {
13076         TableInfo  *tbinfo = coninfo->contable;
13077         PQExpBuffer q;
13078         PQExpBuffer delq;
13079
13080         /* Skip if not to be dumped */
13081         if (!coninfo->dobj.dump || dataOnly)
13082                 return;
13083
13084         q = createPQExpBuffer();
13085         delq = createPQExpBuffer();
13086
13087         if (coninfo->contype == 'p' ||
13088                 coninfo->contype == 'u' ||
13089                 coninfo->contype == 'x')
13090         {
13091                 /* Index-related constraint */
13092                 IndxInfo   *indxinfo;
13093                 int                     k;
13094
13095                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13096
13097                 if (indxinfo == NULL)
13098                 {
13099                         write_msg(NULL, "missing index for constraint \"%s\"\n",
13100                                           coninfo->dobj.name);
13101                         exit_nicely();
13102                 }
13103
13104                 if (binary_upgrade)
13105                         binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
13106
13107                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13108                                                   fmtId(tbinfo->dobj.name));
13109                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13110                                                   fmtId(coninfo->dobj.name));
13111
13112                 if (coninfo->condef)
13113                 {
13114                         /* pg_get_constraintdef should have provided everything */
13115                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13116                 }
13117                 else
13118                 {
13119                         appendPQExpBuffer(q, "%s (",
13120                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13121                         for (k = 0; k < indxinfo->indnkeys; k++)
13122                         {
13123                                 int                     indkey = (int) indxinfo->indkeys[k];
13124                                 const char *attname;
13125
13126                                 if (indkey == InvalidAttrNumber)
13127                                         break;
13128                                 attname = getAttrName(indkey, tbinfo);
13129
13130                                 appendPQExpBuffer(q, "%s%s",
13131                                                                   (k == 0) ? "" : ", ",
13132                                                                   fmtId(attname));
13133                         }
13134
13135                         appendPQExpBuffer(q, ")");
13136
13137                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13138                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13139
13140                         if (coninfo->condeferrable)
13141                         {
13142                                 appendPQExpBuffer(q, " DEFERRABLE");
13143                                 if (coninfo->condeferred)
13144                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13145                         }
13146
13147                         appendPQExpBuffer(q, ";\n");
13148                 }
13149
13150                 /* If the index is clustered, we need to record that. */
13151                 if (indxinfo->indisclustered)
13152                 {
13153                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13154                                                           fmtId(tbinfo->dobj.name));
13155                         appendPQExpBuffer(q, " ON %s;\n",
13156                                                           fmtId(indxinfo->dobj.name));
13157                 }
13158
13159                 /*
13160                  * DROP must be fully qualified in case same name appears in
13161                  * pg_catalog
13162                  */
13163                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13164                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13165                 appendPQExpBuffer(delq, "%s ",
13166                                                   fmtId(tbinfo->dobj.name));
13167                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13168                                                   fmtId(coninfo->dobj.name));
13169
13170                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13171                                          coninfo->dobj.name,
13172                                          tbinfo->dobj.namespace->dobj.name,
13173                                          indxinfo->tablespace,
13174                                          tbinfo->rolname, false,
13175                                          "CONSTRAINT", SECTION_POST_DATA,
13176                                          q->data, delq->data, NULL,
13177                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13178                                          NULL, NULL);
13179         }
13180         else if (coninfo->contype == 'f')
13181         {
13182                 /*
13183                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13184                  * current table data is not processed
13185                  */
13186                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13187                                                   fmtId(tbinfo->dobj.name));
13188                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13189                                                   fmtId(coninfo->dobj.name),
13190                                                   coninfo->condef);
13191
13192                 /*
13193                  * DROP must be fully qualified in case same name appears in
13194                  * pg_catalog
13195                  */
13196                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13197                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13198                 appendPQExpBuffer(delq, "%s ",
13199                                                   fmtId(tbinfo->dobj.name));
13200                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13201                                                   fmtId(coninfo->dobj.name));
13202
13203                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13204                                          coninfo->dobj.name,
13205                                          tbinfo->dobj.namespace->dobj.name,
13206                                          NULL,
13207                                          tbinfo->rolname, false,
13208                                          "FK CONSTRAINT", SECTION_POST_DATA,
13209                                          q->data, delq->data, NULL,
13210                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13211                                          NULL, NULL);
13212         }
13213         else if (coninfo->contype == 'c' && tbinfo)
13214         {
13215                 /* CHECK constraint on a table */
13216
13217                 /* Ignore if not to be dumped separately */
13218                 if (coninfo->separate)
13219                 {
13220                         /* add ONLY if we do not want it to propagate to children */
13221                         appendPQExpBuffer(q, "ALTER TABLE %s %s\n",
13222                                                          coninfo->conisonly ? "ONLY" : "", fmtId(tbinfo->dobj.name));
13223                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13224                                                           fmtId(coninfo->dobj.name),
13225                                                           coninfo->condef);
13226
13227                         /*
13228                          * DROP must be fully qualified in case same name appears in
13229                          * pg_catalog
13230                          */
13231                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13232                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13233                         appendPQExpBuffer(delq, "%s ",
13234                                                           fmtId(tbinfo->dobj.name));
13235                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13236                                                           fmtId(coninfo->dobj.name));
13237
13238                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13239                                                  coninfo->dobj.name,
13240                                                  tbinfo->dobj.namespace->dobj.name,
13241                                                  NULL,
13242                                                  tbinfo->rolname, false,
13243                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13244                                                  q->data, delq->data, NULL,
13245                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13246                                                  NULL, NULL);
13247                 }
13248         }
13249         else if (coninfo->contype == 'c' && tbinfo == NULL)
13250         {
13251                 /* CHECK constraint on a domain */
13252                 TypeInfo   *tyinfo = coninfo->condomain;
13253
13254                 /* Ignore if not to be dumped separately */
13255                 if (coninfo->separate)
13256                 {
13257                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13258                                                           fmtId(tyinfo->dobj.name));
13259                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13260                                                           fmtId(coninfo->dobj.name),
13261                                                           coninfo->condef);
13262
13263                         /*
13264                          * DROP must be fully qualified in case same name appears in
13265                          * pg_catalog
13266                          */
13267                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13268                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13269                         appendPQExpBuffer(delq, "%s ",
13270                                                           fmtId(tyinfo->dobj.name));
13271                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13272                                                           fmtId(coninfo->dobj.name));
13273
13274                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13275                                                  coninfo->dobj.name,
13276                                                  tyinfo->dobj.namespace->dobj.name,
13277                                                  NULL,
13278                                                  tyinfo->rolname, false,
13279                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13280                                                  q->data, delq->data, NULL,
13281                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13282                                                  NULL, NULL);
13283                 }
13284         }
13285         else
13286         {
13287                 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
13288                 exit_nicely();
13289         }
13290
13291         /* Dump Constraint Comments --- only works for table constraints */
13292         if (tbinfo && coninfo->separate)
13293                 dumpTableConstraintComment(fout, coninfo);
13294
13295         destroyPQExpBuffer(q);
13296         destroyPQExpBuffer(delq);
13297 }
13298
13299 /*
13300  * dumpTableConstraintComment --- dump a constraint's comment if any
13301  *
13302  * This is split out because we need the function in two different places
13303  * depending on whether the constraint is dumped as part of CREATE TABLE
13304  * or as a separate ALTER command.
13305  */
13306 static void
13307 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13308 {
13309         TableInfo  *tbinfo = coninfo->contable;
13310         PQExpBuffer labelq = createPQExpBuffer();
13311
13312         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13313                                           fmtId(coninfo->dobj.name));
13314         appendPQExpBuffer(labelq, "ON %s",
13315                                           fmtId(tbinfo->dobj.name));
13316         dumpComment(fout, labelq->data,
13317                                 tbinfo->dobj.namespace->dobj.name,
13318                                 tbinfo->rolname,
13319                                 coninfo->dobj.catId, 0,
13320                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13321
13322         destroyPQExpBuffer(labelq);
13323 }
13324
13325 /*
13326  * findLastBuiltInOid -
13327  * find the last built in oid
13328  *
13329  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13330  * pg_database entry for the current database
13331  */
13332 static Oid
13333 findLastBuiltinOid_V71(const char *dbname)
13334 {
13335         PGresult   *res;
13336         int                     ntups;
13337         Oid                     last_oid;
13338         PQExpBuffer query = createPQExpBuffer();
13339
13340         resetPQExpBuffer(query);
13341         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13342         appendStringLiteralAH(query, dbname, g_fout);
13343
13344         res = PQexec(g_conn, query->data);
13345         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13346
13347         ntups = PQntuples(res);
13348         if (ntups < 1)
13349         {
13350                 write_msg(NULL, "missing pg_database entry for this database\n");
13351                 exit_nicely();
13352         }
13353         if (ntups > 1)
13354         {
13355                 write_msg(NULL, "found more than one pg_database entry for this database\n");
13356                 exit_nicely();
13357         }
13358         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13359         PQclear(res);
13360         destroyPQExpBuffer(query);
13361         return last_oid;
13362 }
13363
13364 /*
13365  * findLastBuiltInOid -
13366  * find the last built in oid
13367  *
13368  * For 7.0, we do this by assuming that the last thing that initdb does is to
13369  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13370  * initdb won't be changing anymore, it'll do.
13371  */
13372 static Oid
13373 findLastBuiltinOid_V70(void)
13374 {
13375         PGresult   *res;
13376         int                     ntups;
13377         int                     last_oid;
13378
13379         res = PQexec(g_conn,
13380                                  "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13381         check_sql_result(res, g_conn,
13382                                          "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
13383                                          PGRES_TUPLES_OK);
13384         ntups = PQntuples(res);
13385         if (ntups < 1)
13386         {
13387                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
13388                 exit_nicely();
13389         }
13390         if (ntups > 1)
13391         {
13392                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
13393                 exit_nicely();
13394         }
13395         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13396         PQclear(res);
13397         return last_oid;
13398 }
13399
13400 static void
13401 dumpSequence(Archive *fout, TableInfo *tbinfo)
13402 {
13403         PGresult   *res;
13404         char       *startv,
13405                            *last,
13406                            *incby,
13407                            *maxv = NULL,
13408                            *minv = NULL,
13409                            *cache;
13410         char            bufm[100],
13411                                 bufx[100];
13412         bool            cycled,
13413                                 called;
13414         PQExpBuffer query = createPQExpBuffer();
13415         PQExpBuffer delqry = createPQExpBuffer();
13416         PQExpBuffer labelq = createPQExpBuffer();
13417
13418         /* Make sure we are in proper schema */
13419         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
13420
13421         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13422         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13423
13424         if (g_fout->remoteVersion >= 80400)
13425         {
13426                 appendPQExpBuffer(query,
13427                                                   "SELECT sequence_name, "
13428                                                   "start_value, last_value, increment_by, "
13429                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13430                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13431                                                   "     ELSE max_value "
13432                                                   "END AS max_value, "
13433                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13434                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13435                                                   "     ELSE min_value "
13436                                                   "END AS min_value, "
13437                                                   "cache_value, is_cycled, is_called from %s",
13438                                                   bufx, bufm,
13439                                                   fmtId(tbinfo->dobj.name));
13440         }
13441         else
13442         {
13443                 appendPQExpBuffer(query,
13444                                                   "SELECT sequence_name, "
13445                                                   "0 AS start_value, last_value, increment_by, "
13446                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13447                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13448                                                   "     ELSE max_value "
13449                                                   "END AS max_value, "
13450                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13451                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13452                                                   "     ELSE min_value "
13453                                                   "END AS min_value, "
13454                                                   "cache_value, is_cycled, is_called from %s",
13455                                                   bufx, bufm,
13456                                                   fmtId(tbinfo->dobj.name));
13457         }
13458
13459         res = PQexec(g_conn, query->data);
13460         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13461
13462         if (PQntuples(res) != 1)
13463         {
13464                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13465                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13466                                                                  PQntuples(res)),
13467                                   tbinfo->dobj.name, PQntuples(res));
13468                 exit_nicely();
13469         }
13470
13471         /* Disable this check: it fails if sequence has been renamed */
13472 #ifdef NOT_USED
13473         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13474         {
13475                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13476                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13477                 exit_nicely();
13478         }
13479 #endif
13480
13481         startv = PQgetvalue(res, 0, 1);
13482         last = PQgetvalue(res, 0, 2);
13483         incby = PQgetvalue(res, 0, 3);
13484         if (!PQgetisnull(res, 0, 4))
13485                 maxv = PQgetvalue(res, 0, 4);
13486         if (!PQgetisnull(res, 0, 5))
13487                 minv = PQgetvalue(res, 0, 5);
13488         cache = PQgetvalue(res, 0, 6);
13489         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
13490         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
13491
13492         /*
13493          * The logic we use for restoring sequences is as follows:
13494          *
13495          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
13496          * last_val for start if called is false, else use min_val for start_val).
13497          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
13498          * BY command for it.
13499          *
13500          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
13501          */
13502         if (!dataOnly)
13503         {
13504                 /*
13505                  * DROP must be fully qualified in case same name appears in
13506                  * pg_catalog
13507                  */
13508                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13509                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13510                 appendPQExpBuffer(delqry, "%s;\n",
13511                                                   fmtId(tbinfo->dobj.name));
13512
13513                 resetPQExpBuffer(query);
13514
13515                 if (binary_upgrade)
13516                 {
13517                         binary_upgrade_set_pg_class_oids(query, tbinfo->dobj.catId.oid, false);
13518                         binary_upgrade_set_type_oids_by_rel_oid(query, tbinfo->dobj.catId.oid);
13519                 }
13520
13521                 appendPQExpBuffer(query,
13522                                                   "CREATE SEQUENCE %s\n",
13523                                                   fmtId(tbinfo->dobj.name));
13524
13525                 if (g_fout->remoteVersion >= 80400)
13526                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
13527                 else
13528                 {
13529                         /*
13530                          * Versions before 8.4 did not remember the true start value.  If
13531                          * is_called is false then the sequence has never been incremented
13532                          * so we can use last_val.      Otherwise punt and let it default.
13533                          */
13534                         if (!called)
13535                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
13536                 }
13537
13538                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13539
13540                 if (minv)
13541                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13542                 else
13543                         appendPQExpBuffer(query, "    NO MINVALUE\n");
13544
13545                 if (maxv)
13546                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13547                 else
13548                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
13549
13550                 appendPQExpBuffer(query,
13551                                                   "    CACHE %s%s",
13552                                                   cache, (cycled ? "\n    CYCLE" : ""));
13553
13554                 appendPQExpBuffer(query, ";\n");
13555
13556                 appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13557
13558                 /* binary_upgrade:      no need to clear TOAST table oid */
13559
13560                 if (binary_upgrade)
13561                         binary_upgrade_extension_member(query, &tbinfo->dobj,
13562                                                                                         labelq->data);
13563
13564                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13565                                          tbinfo->dobj.name,
13566                                          tbinfo->dobj.namespace->dobj.name,
13567                                          NULL,
13568                                          tbinfo->rolname,
13569                                          false, "SEQUENCE", SECTION_PRE_DATA,
13570                                          query->data, delqry->data, NULL,
13571                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
13572                                          NULL, NULL);
13573
13574                 /*
13575                  * If the sequence is owned by a table column, emit the ALTER for it
13576                  * as a separate TOC entry immediately following the sequence's own
13577                  * entry.  It's OK to do this rather than using full sorting logic,
13578                  * because the dependency that tells us it's owned will have forced
13579                  * the table to be created first.  We can't just include the ALTER in
13580                  * the TOC entry because it will fail if we haven't reassigned the
13581                  * sequence owner to match the table's owner.
13582                  *
13583                  * We need not schema-qualify the table reference because both
13584                  * sequence and table must be in the same schema.
13585                  */
13586                 if (OidIsValid(tbinfo->owning_tab))
13587                 {
13588                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
13589
13590                         if (owning_tab && owning_tab->dobj.dump)
13591                         {
13592                                 resetPQExpBuffer(query);
13593                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
13594                                                                   fmtId(tbinfo->dobj.name));
13595                                 appendPQExpBuffer(query, " OWNED BY %s",
13596                                                                   fmtId(owning_tab->dobj.name));
13597                                 appendPQExpBuffer(query, ".%s;\n",
13598                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
13599
13600                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13601                                                          tbinfo->dobj.name,
13602                                                          tbinfo->dobj.namespace->dobj.name,
13603                                                          NULL,
13604                                                          tbinfo->rolname,
13605                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
13606                                                          query->data, "", NULL,
13607                                                          &(tbinfo->dobj.dumpId), 1,
13608                                                          NULL, NULL);
13609                         }
13610                 }
13611
13612                 /* Dump Sequence Comments and Security Labels */
13613                 dumpComment(fout, labelq->data,
13614                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13615                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13616                 dumpSecLabel(fout, labelq->data,
13617                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13618                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13619         }
13620
13621         if (!schemaOnly)
13622         {
13623                 resetPQExpBuffer(query);
13624                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
13625                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
13626                 appendPQExpBuffer(query, ", %s, %s);\n",
13627                                                   last, (called ? "true" : "false"));
13628
13629                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13630                                          tbinfo->dobj.name,
13631                                          tbinfo->dobj.namespace->dobj.name,
13632                                          NULL,
13633                                          tbinfo->rolname,
13634                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
13635                                          query->data, "", NULL,
13636                                          &(tbinfo->dobj.dumpId), 1,
13637                                          NULL, NULL);
13638         }
13639
13640         PQclear(res);
13641
13642         destroyPQExpBuffer(query);
13643         destroyPQExpBuffer(delqry);
13644         destroyPQExpBuffer(labelq);
13645 }
13646
13647 static void
13648 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
13649 {
13650         TableInfo  *tbinfo = tginfo->tgtable;
13651         PQExpBuffer query;
13652         PQExpBuffer delqry;
13653         PQExpBuffer labelq;
13654         char       *tgargs;
13655         size_t          lentgargs;
13656         const char *p;
13657         int                     findx;
13658
13659         if (dataOnly)
13660                 return;
13661
13662         query = createPQExpBuffer();
13663         delqry = createPQExpBuffer();
13664         labelq = createPQExpBuffer();
13665
13666         /*
13667          * DROP must be fully qualified in case same name appears in pg_catalog
13668          */
13669         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
13670                                           fmtId(tginfo->dobj.name));
13671         appendPQExpBuffer(delqry, "ON %s.",
13672                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13673         appendPQExpBuffer(delqry, "%s;\n",
13674                                           fmtId(tbinfo->dobj.name));
13675
13676         if (tginfo->tgdef)
13677         {
13678                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
13679         }
13680         else
13681         {
13682                 if (tginfo->tgisconstraint)
13683                 {
13684                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
13685                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
13686                 }
13687                 else
13688                 {
13689                         appendPQExpBuffer(query, "CREATE TRIGGER ");
13690                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
13691                 }
13692                 appendPQExpBuffer(query, "\n    ");
13693
13694                 /* Trigger type */
13695                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
13696                         appendPQExpBuffer(query, "BEFORE");
13697                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
13698                         appendPQExpBuffer(query, "AFTER");
13699                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
13700                         appendPQExpBuffer(query, "INSTEAD OF");
13701                 else
13702                 {
13703                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
13704                         exit_nicely();
13705                 }
13706
13707                 findx = 0;
13708                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
13709                 {
13710                         appendPQExpBuffer(query, " INSERT");
13711                         findx++;
13712                 }
13713                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
13714                 {
13715                         if (findx > 0)
13716                                 appendPQExpBuffer(query, " OR DELETE");
13717                         else
13718                                 appendPQExpBuffer(query, " DELETE");
13719                         findx++;
13720                 }
13721                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
13722                 {
13723                         if (findx > 0)
13724                                 appendPQExpBuffer(query, " OR UPDATE");
13725                         else
13726                                 appendPQExpBuffer(query, " UPDATE");
13727                         findx++;
13728                 }
13729                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
13730                 {
13731                         if (findx > 0)
13732                                 appendPQExpBuffer(query, " OR TRUNCATE");
13733                         else
13734                                 appendPQExpBuffer(query, " TRUNCATE");
13735                         findx++;
13736                 }
13737                 appendPQExpBuffer(query, " ON %s\n",
13738                                                   fmtId(tbinfo->dobj.name));
13739
13740                 if (tginfo->tgisconstraint)
13741                 {
13742                         if (OidIsValid(tginfo->tgconstrrelid))
13743                         {
13744                                 /* If we are using regclass, name is already quoted */
13745                                 if (g_fout->remoteVersion >= 70300)
13746                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13747                                                                           tginfo->tgconstrrelname);
13748                                 else
13749                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13750                                                                           fmtId(tginfo->tgconstrrelname));
13751                         }
13752                         if (!tginfo->tgdeferrable)
13753                                 appendPQExpBuffer(query, "NOT ");
13754                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
13755                         if (tginfo->tginitdeferred)
13756                                 appendPQExpBuffer(query, "DEFERRED\n");
13757                         else
13758                                 appendPQExpBuffer(query, "IMMEDIATE\n");
13759                 }
13760
13761                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
13762                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
13763                 else
13764                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
13765
13766                 /* In 7.3, result of regproc is already quoted */
13767                 if (g_fout->remoteVersion >= 70300)
13768                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13769                                                           tginfo->tgfname);
13770                 else
13771                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13772                                                           fmtId(tginfo->tgfname));
13773
13774                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
13775                                                                                   &lentgargs);
13776                 p = tgargs;
13777                 for (findx = 0; findx < tginfo->tgnargs; findx++)
13778                 {
13779                         /* find the embedded null that terminates this trigger argument */
13780                         size_t          tlen = strlen(p);
13781
13782                         if (p + tlen >= tgargs + lentgargs)
13783                         {
13784                                 /* hm, not found before end of bytea value... */
13785                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
13786                                                   tginfo->tgargs,
13787                                                   tginfo->dobj.name,
13788                                                   tbinfo->dobj.name);
13789                                 exit_nicely();
13790                         }
13791
13792                         if (findx > 0)
13793                                 appendPQExpBuffer(query, ", ");
13794                         appendStringLiteralAH(query, p, fout);
13795                         p += tlen + 1;
13796                 }
13797                 free(tgargs);
13798                 appendPQExpBuffer(query, ");\n");
13799         }
13800
13801         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
13802         {
13803                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
13804                                                   fmtId(tbinfo->dobj.name));
13805                 switch (tginfo->tgenabled)
13806                 {
13807                         case 'D':
13808                         case 'f':
13809                                 appendPQExpBuffer(query, "DISABLE");
13810                                 break;
13811                         case 'A':
13812                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
13813                                 break;
13814                         case 'R':
13815                                 appendPQExpBuffer(query, "ENABLE REPLICA");
13816                                 break;
13817                         default:
13818                                 appendPQExpBuffer(query, "ENABLE");
13819                                 break;
13820                 }
13821                 appendPQExpBuffer(query, " TRIGGER %s;\n",
13822                                                   fmtId(tginfo->dobj.name));
13823         }
13824
13825         appendPQExpBuffer(labelq, "TRIGGER %s ",
13826                                           fmtId(tginfo->dobj.name));
13827         appendPQExpBuffer(labelq, "ON %s",
13828                                           fmtId(tbinfo->dobj.name));
13829
13830         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
13831                                  tginfo->dobj.name,
13832                                  tbinfo->dobj.namespace->dobj.name,
13833                                  NULL,
13834                                  tbinfo->rolname, false,
13835                                  "TRIGGER", SECTION_POST_DATA,
13836                                  query->data, delqry->data, NULL,
13837                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
13838                                  NULL, NULL);
13839
13840         dumpComment(fout, labelq->data,
13841                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13842                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
13843
13844         destroyPQExpBuffer(query);
13845         destroyPQExpBuffer(delqry);
13846         destroyPQExpBuffer(labelq);
13847 }
13848
13849 /*
13850  * dumpRule
13851  *              Dump a rule
13852  */
13853 static void
13854 dumpRule(Archive *fout, RuleInfo *rinfo)
13855 {
13856         TableInfo  *tbinfo = rinfo->ruletable;
13857         PQExpBuffer query;
13858         PQExpBuffer cmd;
13859         PQExpBuffer delcmd;
13860         PQExpBuffer labelq;
13861         PGresult   *res;
13862
13863         /* Skip if not to be dumped */
13864         if (!rinfo->dobj.dump || dataOnly)
13865                 return;
13866
13867         /*
13868          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
13869          * we do not want to dump it as a separate object.
13870          */
13871         if (!rinfo->separate)
13872                 return;
13873
13874         /*
13875          * Make sure we are in proper schema.
13876          */
13877         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
13878
13879         query = createPQExpBuffer();
13880         cmd = createPQExpBuffer();
13881         delcmd = createPQExpBuffer();
13882         labelq = createPQExpBuffer();
13883
13884         if (g_fout->remoteVersion >= 70300)
13885         {
13886                 appendPQExpBuffer(query,
13887                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
13888                                                   rinfo->dobj.catId.oid);
13889         }
13890         else
13891         {
13892                 /* Rule name was unique before 7.3 ... */
13893                 appendPQExpBuffer(query,
13894                                                   "SELECT pg_get_ruledef('%s') AS definition",
13895                                                   rinfo->dobj.name);
13896         }
13897
13898         res = PQexec(g_conn, query->data);
13899         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13900
13901         if (PQntuples(res) != 1)
13902         {
13903                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
13904                                   rinfo->dobj.name, tbinfo->dobj.name);
13905                 exit_nicely();
13906         }
13907
13908         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
13909
13910         /*
13911          * Add the command to alter the rules replication firing semantics if it
13912          * differs from the default.
13913          */
13914         if (rinfo->ev_enabled != 'O')
13915         {
13916                 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
13917                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13918                 appendPQExpBuffer(cmd, "%s ",
13919                                                   fmtId(tbinfo->dobj.name));
13920                 switch (rinfo->ev_enabled)
13921                 {
13922                         case 'A':
13923                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
13924                                                                   fmtId(rinfo->dobj.name));
13925                                 break;
13926                         case 'R':
13927                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
13928                                                                   fmtId(rinfo->dobj.name));
13929                                 break;
13930                         case 'D':
13931                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
13932                                                                   fmtId(rinfo->dobj.name));
13933                                 break;
13934                 }
13935         }
13936
13937         /*
13938          * DROP must be fully qualified in case same name appears in pg_catalog
13939          */
13940         appendPQExpBuffer(delcmd, "DROP RULE %s ",
13941                                           fmtId(rinfo->dobj.name));
13942         appendPQExpBuffer(delcmd, "ON %s.",
13943                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13944         appendPQExpBuffer(delcmd, "%s;\n",
13945                                           fmtId(tbinfo->dobj.name));
13946
13947         appendPQExpBuffer(labelq, "RULE %s",
13948                                           fmtId(rinfo->dobj.name));
13949         appendPQExpBuffer(labelq, " ON %s",
13950                                           fmtId(tbinfo->dobj.name));
13951
13952         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
13953                                  rinfo->dobj.name,
13954                                  tbinfo->dobj.namespace->dobj.name,
13955                                  NULL,
13956                                  tbinfo->rolname, false,
13957                                  "RULE", SECTION_POST_DATA,
13958                                  cmd->data, delcmd->data, NULL,
13959                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
13960                                  NULL, NULL);
13961
13962         /* Dump rule comments */
13963         dumpComment(fout, labelq->data,
13964                                 tbinfo->dobj.namespace->dobj.name,
13965                                 tbinfo->rolname,
13966                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
13967
13968         PQclear(res);
13969
13970         destroyPQExpBuffer(query);
13971         destroyPQExpBuffer(cmd);
13972         destroyPQExpBuffer(delcmd);
13973         destroyPQExpBuffer(labelq);
13974 }
13975
13976 /*
13977  * getExtensionMembership --- obtain extension membership data
13978  */
13979 void
13980 getExtensionMembership(ExtensionInfo extinfo[], int numExtensions)
13981 {
13982         PQExpBuffer query;
13983         PGresult   *res;
13984         int                     ntups,
13985                                 i;
13986         int                     i_classid,
13987                                 i_objid,
13988                                 i_refclassid,
13989                                 i_refobjid;
13990         DumpableObject *dobj,
13991                            *refdobj;
13992
13993         /* Nothing to do if no extensions */
13994         if (numExtensions == 0)
13995                 return;
13996
13997         /* Make sure we are in proper schema */
13998         selectSourceSchema("pg_catalog");
13999
14000         query = createPQExpBuffer();
14001
14002         /* refclassid constraint is redundant but may speed the search */
14003         appendPQExpBuffer(query, "SELECT "
14004                                           "classid, objid, refclassid, refobjid "
14005                                           "FROM pg_depend "
14006                                           "WHERE refclassid = 'pg_extension'::regclass "
14007                                           "AND deptype = 'e' "
14008                                           "ORDER BY 3,4");
14009
14010         res = PQexec(g_conn, query->data);
14011         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
14012
14013         ntups = PQntuples(res);
14014
14015         i_classid = PQfnumber(res, "classid");
14016         i_objid = PQfnumber(res, "objid");
14017         i_refclassid = PQfnumber(res, "refclassid");
14018         i_refobjid = PQfnumber(res, "refobjid");
14019
14020         /*
14021          * Since we ordered the SELECT by referenced ID, we can expect that
14022          * multiple entries for the same extension will appear together; this
14023          * saves on searches.
14024          */
14025         refdobj = NULL;
14026
14027         for (i = 0; i < ntups; i++)
14028         {
14029                 CatalogId       objId;
14030                 CatalogId       refobjId;
14031
14032                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14033                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14034                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14035                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14036
14037                 if (refdobj == NULL ||
14038                         refdobj->catId.tableoid != refobjId.tableoid ||
14039                         refdobj->catId.oid != refobjId.oid)
14040                         refdobj = findObjectByCatalogId(refobjId);
14041
14042                 /*
14043                  * Failure to find objects mentioned in pg_depend is not unexpected,
14044                  * since for example we don't collect info about TOAST tables.
14045                  */
14046                 if (refdobj == NULL)
14047                 {
14048 #ifdef NOT_USED
14049                         fprintf(stderr, "no referenced object %u %u\n",
14050                                         refobjId.tableoid, refobjId.oid);
14051 #endif
14052                         continue;
14053                 }
14054
14055                 dobj = findObjectByCatalogId(objId);
14056
14057                 if (dobj == NULL)
14058                 {
14059 #ifdef NOT_USED
14060                         fprintf(stderr, "no referencing object %u %u\n",
14061                                         objId.tableoid, objId.oid);
14062 #endif
14063                         continue;
14064                 }
14065
14066                 /* Record dependency so that getDependencies needn't repeat this */
14067                 addObjectDependency(dobj, refdobj->dumpId);
14068
14069                 dobj->ext_member = true;
14070
14071                 /*
14072                  * Normally, mark the member object as not to be dumped.  But in
14073                  * binary upgrades, we still dump the members individually, since the
14074                  * idea is to exactly reproduce the database contents rather than
14075                  * replace the extension contents with something different.
14076                  */
14077                 if (!binary_upgrade)
14078                         dobj->dump = false;
14079                 else
14080                         dobj->dump = refdobj->dump;
14081         }
14082
14083         PQclear(res);
14084
14085         /*
14086          * Now identify extension configuration tables and create TableDataInfo
14087          * objects for them, ensuring their data will be dumped even though the
14088          * tables themselves won't be.
14089          *
14090          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14091          * user data in a configuration table is treated like schema data. This
14092          * seems appropriate since system data in a config table would get
14093          * reloaded by CREATE EXTENSION.
14094          */
14095         for (i = 0; i < numExtensions; i++)
14096         {
14097                 char       *extconfig = extinfo[i].extconfig;
14098                 char       *extcondition = extinfo[i].extcondition;
14099                 char      **extconfigarray = NULL;
14100                 char      **extconditionarray = NULL;
14101                 int                     nconfigitems;
14102                 int                     nconditionitems;
14103
14104                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14105                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14106                         nconfigitems == nconditionitems)
14107                 {
14108                         int                     j;
14109
14110                         for (j = 0; j < nconfigitems; j++)
14111                         {
14112                                 TableInfo  *configtbl;
14113
14114                                 configtbl = findTableByOid(atooid(extconfigarray[j]));
14115                                 if (configtbl && configtbl->dataObj == NULL)
14116                                 {
14117                                         /*
14118                                          * Note: config tables are dumped without OIDs regardless
14119                                          * of the --oids setting.  This is because row filtering
14120                                          * conditions aren't compatible with dumping OIDs.
14121                                          */
14122                                         makeTableDataInfo(configtbl, false);
14123                                         if (strlen(extconditionarray[j]) > 0)
14124                                                 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14125                                 }
14126                         }
14127                 }
14128                 if (extconfigarray)
14129                         free(extconfigarray);
14130                 if (extconditionarray)
14131                         free(extconditionarray);
14132         }
14133
14134         destroyPQExpBuffer(query);
14135 }
14136
14137 /*
14138  * getDependencies --- obtain available dependency data
14139  */
14140 static void
14141 getDependencies(void)
14142 {
14143         PQExpBuffer query;
14144         PGresult   *res;
14145         int                     ntups,
14146                                 i;
14147         int                     i_classid,
14148                                 i_objid,
14149                                 i_refclassid,
14150                                 i_refobjid,
14151                                 i_deptype;
14152         DumpableObject *dobj,
14153                            *refdobj;
14154
14155         /* No dependency info available before 7.3 */
14156         if (g_fout->remoteVersion < 70300)
14157                 return;
14158
14159         if (g_verbose)
14160                 write_msg(NULL, "reading dependency data\n");
14161
14162         /* Make sure we are in proper schema */
14163         selectSourceSchema("pg_catalog");
14164
14165         query = createPQExpBuffer();
14166
14167         /*
14168          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14169          * already processed by getExtensionMembership.
14170          */
14171         appendPQExpBuffer(query, "SELECT "
14172                                           "classid, objid, refclassid, refobjid, deptype "
14173                                           "FROM pg_depend "
14174                                           "WHERE deptype != 'p' AND deptype != 'e' "
14175                                           "ORDER BY 1,2");
14176
14177         res = PQexec(g_conn, query->data);
14178         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
14179
14180         ntups = PQntuples(res);
14181
14182         i_classid = PQfnumber(res, "classid");
14183         i_objid = PQfnumber(res, "objid");
14184         i_refclassid = PQfnumber(res, "refclassid");
14185         i_refobjid = PQfnumber(res, "refobjid");
14186         i_deptype = PQfnumber(res, "deptype");
14187
14188         /*
14189          * Since we ordered the SELECT by referencing ID, we can expect that
14190          * multiple entries for the same object will appear together; this saves
14191          * on searches.
14192          */
14193         dobj = NULL;
14194
14195         for (i = 0; i < ntups; i++)
14196         {
14197                 CatalogId       objId;
14198                 CatalogId       refobjId;
14199                 char            deptype;
14200
14201                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14202                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14203                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14204                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14205                 deptype = *(PQgetvalue(res, i, i_deptype));
14206
14207                 if (dobj == NULL ||
14208                         dobj->catId.tableoid != objId.tableoid ||
14209                         dobj->catId.oid != objId.oid)
14210                         dobj = findObjectByCatalogId(objId);
14211
14212                 /*
14213                  * Failure to find objects mentioned in pg_depend is not unexpected,
14214                  * since for example we don't collect info about TOAST tables.
14215                  */
14216                 if (dobj == NULL)
14217                 {
14218 #ifdef NOT_USED
14219                         fprintf(stderr, "no referencing object %u %u\n",
14220                                         objId.tableoid, objId.oid);
14221 #endif
14222                         continue;
14223                 }
14224
14225                 refdobj = findObjectByCatalogId(refobjId);
14226
14227                 if (refdobj == NULL)
14228                 {
14229 #ifdef NOT_USED
14230                         fprintf(stderr, "no referenced object %u %u\n",
14231                                         refobjId.tableoid, refobjId.oid);
14232 #endif
14233                         continue;
14234                 }
14235
14236                 /*
14237                  * Ordinarily, table rowtypes have implicit dependencies on their
14238                  * tables.      However, for a composite type the implicit dependency goes
14239                  * the other way in pg_depend; which is the right thing for DROP but
14240                  * it doesn't produce the dependency ordering we need. So in that one
14241                  * case, we reverse the direction of the dependency.
14242                  */
14243                 if (deptype == 'i' &&
14244                         dobj->objType == DO_TABLE &&
14245                         refdobj->objType == DO_TYPE)
14246                         addObjectDependency(refdobj, dobj->dumpId);
14247                 else
14248                         /* normal case */
14249                         addObjectDependency(dobj, refdobj->dumpId);
14250         }
14251
14252         PQclear(res);
14253
14254         destroyPQExpBuffer(query);
14255 }
14256
14257
14258 /*
14259  * selectSourceSchema - make the specified schema the active search path
14260  * in the source database.
14261  *
14262  * NB: pg_catalog is explicitly searched after the specified schema;
14263  * so user names are only qualified if they are cross-schema references,
14264  * and system names are only qualified if they conflict with a user name
14265  * in the current schema.
14266  *
14267  * Whenever the selected schema is not pg_catalog, be careful to qualify
14268  * references to system catalogs and types in our emitted commands!
14269  */
14270 static void
14271 selectSourceSchema(const char *schemaName)
14272 {
14273         static char *curSchemaName = NULL;
14274         PQExpBuffer query;
14275
14276         /* Not relevant if fetching from pre-7.3 DB */
14277         if (g_fout->remoteVersion < 70300)
14278                 return;
14279         /* Ignore null schema names */
14280         if (schemaName == NULL || *schemaName == '\0')
14281                 return;
14282         /* Optimize away repeated selection of same schema */
14283         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
14284                 return;
14285
14286         query = createPQExpBuffer();
14287         appendPQExpBuffer(query, "SET search_path = %s",
14288                                           fmtId(schemaName));
14289         if (strcmp(schemaName, "pg_catalog") != 0)
14290                 appendPQExpBuffer(query, ", pg_catalog");
14291
14292         do_sql_command(g_conn, query->data);
14293
14294         destroyPQExpBuffer(query);
14295         if (curSchemaName)
14296                 free(curSchemaName);
14297         curSchemaName = pg_strdup(schemaName);
14298 }
14299
14300 /*
14301  * getFormattedTypeName - retrieve a nicely-formatted type name for the
14302  * given type name.
14303  *
14304  * NB: in 7.3 and up the result may depend on the currently-selected
14305  * schema; this is why we don't try to cache the names.
14306  */
14307 static char *
14308 getFormattedTypeName(Oid oid, OidOptions opts)
14309 {
14310         char       *result;
14311         PQExpBuffer query;
14312         PGresult   *res;
14313         int                     ntups;
14314
14315         if (oid == 0)
14316         {
14317                 if ((opts & zeroAsOpaque) != 0)
14318                         return pg_strdup(g_opaque_type);
14319                 else if ((opts & zeroAsAny) != 0)
14320                         return pg_strdup("'any'");
14321                 else if ((opts & zeroAsStar) != 0)
14322                         return pg_strdup("*");
14323                 else if ((opts & zeroAsNone) != 0)
14324                         return pg_strdup("NONE");
14325         }
14326
14327         query = createPQExpBuffer();
14328         if (g_fout->remoteVersion >= 70300)
14329         {
14330                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
14331                                                   oid);
14332         }
14333         else if (g_fout->remoteVersion >= 70100)
14334         {
14335                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
14336                                                   oid);
14337         }
14338         else
14339         {
14340                 appendPQExpBuffer(query, "SELECT typname "
14341                                                   "FROM pg_type "
14342                                                   "WHERE oid = '%u'::oid",
14343                                                   oid);
14344         }
14345
14346         res = PQexec(g_conn, query->data);
14347         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
14348
14349         /* Expecting a single result only */
14350         ntups = PQntuples(res);
14351         if (ntups != 1)
14352         {
14353                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
14354                                                            "query returned %d rows instead of one: %s\n",
14355                                                                  ntups),
14356                                   ntups, query->data);
14357                 exit_nicely();
14358         }
14359
14360         if (g_fout->remoteVersion >= 70100)
14361         {
14362                 /* already quoted */
14363                 result = pg_strdup(PQgetvalue(res, 0, 0));
14364         }
14365         else
14366         {
14367                 /* may need to quote it */
14368                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
14369         }
14370
14371         PQclear(res);
14372         destroyPQExpBuffer(query);
14373
14374         return result;
14375 }
14376
14377 /*
14378  * myFormatType --- local implementation of format_type for use with 7.0.
14379  */
14380 static char *
14381 myFormatType(const char *typname, int32 typmod)
14382 {
14383         char       *result;
14384         bool            isarray = false;
14385         PQExpBuffer buf = createPQExpBuffer();
14386
14387         /* Handle array types */
14388         if (typname[0] == '_')
14389         {
14390                 isarray = true;
14391                 typname++;
14392         }
14393
14394         /* Show lengths on bpchar and varchar */
14395         if (strcmp(typname, "bpchar") == 0)
14396         {
14397                 int                     len = (typmod - VARHDRSZ);
14398
14399                 appendPQExpBuffer(buf, "character");
14400                 if (len > 1)
14401                         appendPQExpBuffer(buf, "(%d)",
14402                                                           typmod - VARHDRSZ);
14403         }
14404         else if (strcmp(typname, "varchar") == 0)
14405         {
14406                 appendPQExpBuffer(buf, "character varying");
14407                 if (typmod != -1)
14408                         appendPQExpBuffer(buf, "(%d)",
14409                                                           typmod - VARHDRSZ);
14410         }
14411         else if (strcmp(typname, "numeric") == 0)
14412         {
14413                 appendPQExpBuffer(buf, "numeric");
14414                 if (typmod != -1)
14415                 {
14416                         int32           tmp_typmod;
14417                         int                     precision;
14418                         int                     scale;
14419
14420                         tmp_typmod = typmod - VARHDRSZ;
14421                         precision = (tmp_typmod >> 16) & 0xffff;
14422                         scale = tmp_typmod & 0xffff;
14423                         appendPQExpBuffer(buf, "(%d,%d)",
14424                                                           precision, scale);
14425                 }
14426         }
14427
14428         /*
14429          * char is an internal single-byte data type; Let's make sure we force it
14430          * through with quotes. - thomas 1998-12-13
14431          */
14432         else if (strcmp(typname, "char") == 0)
14433                 appendPQExpBuffer(buf, "\"char\"");
14434         else
14435                 appendPQExpBuffer(buf, "%s", fmtId(typname));
14436
14437         /* Append array qualifier for array types */
14438         if (isarray)
14439                 appendPQExpBuffer(buf, "[]");
14440
14441         result = pg_strdup(buf->data);
14442         destroyPQExpBuffer(buf);
14443
14444         return result;
14445 }
14446
14447 /*
14448  * fmtQualifiedId - convert a qualified name to the proper format for
14449  * the source database.
14450  *
14451  * Like fmtId, use the result before calling again.
14452  */
14453 static const char *
14454 fmtQualifiedId(const char *schema, const char *id)
14455 {
14456         static PQExpBuffer id_return = NULL;
14457
14458         if (id_return)                          /* first time through? */
14459                 resetPQExpBuffer(id_return);
14460         else
14461                 id_return = createPQExpBuffer();
14462
14463         /* Suppress schema name if fetching from pre-7.3 DB */
14464         if (g_fout->remoteVersion >= 70300 && schema && *schema)
14465         {
14466                 appendPQExpBuffer(id_return, "%s.",
14467                                                   fmtId(schema));
14468         }
14469         appendPQExpBuffer(id_return, "%s",
14470                                           fmtId(id));
14471
14472         return id_return->data;
14473 }
14474
14475 /*
14476  * Return a column list clause for the given relation.
14477  *
14478  * Special case: if there are no undropped columns in the relation, return
14479  * "", not an invalid "()" column list.
14480  */
14481 static const char *
14482 fmtCopyColumnList(const TableInfo *ti)
14483 {
14484         static PQExpBuffer q = NULL;
14485         int                     numatts = ti->numatts;
14486         char      **attnames = ti->attnames;
14487         bool       *attisdropped = ti->attisdropped;
14488         bool            needComma;
14489         int                     i;
14490
14491         if (q)                                          /* first time through? */
14492                 resetPQExpBuffer(q);
14493         else
14494                 q = createPQExpBuffer();
14495
14496         appendPQExpBuffer(q, "(");
14497         needComma = false;
14498         for (i = 0; i < numatts; i++)
14499         {
14500                 if (attisdropped[i])
14501                         continue;
14502                 if (needComma)
14503                         appendPQExpBuffer(q, ", ");
14504                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
14505                 needComma = true;
14506         }
14507
14508         if (!needComma)
14509                 return "";                              /* no undropped columns */
14510
14511         appendPQExpBuffer(q, ")");
14512         return q->data;
14513 }
14514
14515 /*
14516  * Convenience subroutine to execute a SQL command and check for
14517  * COMMAND_OK status.
14518  */
14519 static void
14520 do_sql_command(PGconn *conn, const char *query)
14521 {
14522         PGresult   *res;
14523
14524         res = PQexec(conn, query);
14525         check_sql_result(res, conn, query, PGRES_COMMAND_OK);
14526         PQclear(res);
14527 }
14528
14529 /*
14530  * Convenience subroutine to verify a SQL command succeeded,
14531  * and exit with a useful error message if not.
14532  */
14533 static void
14534 check_sql_result(PGresult *res, PGconn *conn, const char *query,
14535                                  ExecStatusType expected)
14536 {
14537         const char *err;
14538
14539         if (res && PQresultStatus(res) == expected)
14540                 return;                                 /* A-OK */
14541
14542         write_msg(NULL, "SQL command failed\n");
14543         if (res)
14544                 err = PQresultErrorMessage(res);
14545         else
14546                 err = PQerrorMessage(conn);
14547         write_msg(NULL, "Error message from server: %s", err);
14548         write_msg(NULL, "The command was: %s\n", query);
14549         exit_nicely();
14550 }