]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
pg_dump: Add some const qualifiers
[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 "pg_backup_db.h"
61 #include "dumpmem.h"
62 #include "dumputils.h"
63
64 extern char *optarg;
65 extern int      optind,
66                         opterr;
67
68
69 typedef struct
70 {
71         const char *descr;                      /* comment for an object */
72         Oid                     classoid;               /* object class (catalog OID) */
73         Oid                     objoid;                 /* object OID */
74         int                     objsubid;               /* subobject (table column #) */
75 } CommentItem;
76
77 typedef struct
78 {
79         const char *provider;           /* label provider of this security label */
80         const char *label;                      /* security label for an object */
81         Oid                     classoid;               /* object class (catalog OID) */
82         Oid                     objoid;                 /* object OID */
83         int                     objsubid;               /* subobject (table column #) */
84 } SecLabelItem;
85
86 /* global decls */
87 bool            g_verbose;                      /* User wants verbose narration of our
88                                                                  * activities. */
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 void setup_connection(Archive *AH, const char *dumpencoding,
149                                  char *use_role);
150 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
151 static void expand_schema_name_patterns(Archive *fout,
152                                                         SimpleStringList *patterns,
153                                                         SimpleOidList *oids);
154 static void expand_table_name_patterns(Archive *fout,
155                                                    SimpleStringList *patterns,
156                                                    SimpleOidList *oids);
157 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
158 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
159 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
160 static void dumpComment(Archive *fout, const char *target,
161                         const char *namespace, const char *owner,
162                         CatalogId catalogId, int subid, DumpId dumpId);
163 static int findComments(Archive *fout, Oid classoid, Oid objoid,
164                          CommentItem **items);
165 static int      collectComments(Archive *fout, CommentItem **items);
166 static void dumpSecLabel(Archive *fout, const char *target,
167                          const char *namespace, const char *owner,
168                          CatalogId catalogId, int subid, DumpId dumpId);
169 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
170                           SecLabelItem **items);
171 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
172 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
173 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
174 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
175 static void dumpType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
180 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
181 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
182 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
183 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
184 static void dumpFunc(Archive *fout, FuncInfo *finfo);
185 static void dumpCast(Archive *fout, CastInfo *cast);
186 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
187 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
188 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
189 static void dumpCollation(Archive *fout, CollInfo *convinfo);
190 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
191 static void dumpRule(Archive *fout, RuleInfo *rinfo);
192 static void dumpAgg(Archive *fout, AggInfo *agginfo);
193 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
194 static void dumpTable(Archive *fout, TableInfo *tbinfo);
195 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
196 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
197 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
198 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
199 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
200 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
201 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
202 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
203 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
204 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
205 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
206 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
207 static void dumpUserMappings(Archive *fout,
208                                  const char *servername, const char *namespace,
209                                  const char *owner, CatalogId catalogId, DumpId dumpId);
210 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
211
212 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
213                 const char *type, const char *name, const char *subname,
214                 const char *tag, const char *nspname, const char *owner,
215                 const char *acls);
216
217 static void getDependencies(Archive *fout);
218 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
219 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
220 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
221 static void getTableDataFKConstraints(void);
222 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
223 static char *format_function_arguments_old(Archive *fout,
224                                                           FuncInfo *finfo, int nallargs,
225                                                           char **allargtypes,
226                                                           char **argmodes,
227                                                           char **argnames);
228 static char *format_function_signature(Archive *fout,
229                                                                            FuncInfo *finfo, bool honor_quotes);
230 static const char *convertRegProcReference(Archive *fout,
231                                                                                    const char *proc);
232 static const char *convertOperatorReference(Archive *fout, const char *opr);
233 static const char *convertTSFunction(Archive *fout, Oid funcOid);
234 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
235 static Oid      findLastBuiltinOid_V70(Archive *fout);
236 static void selectSourceSchema(Archive *fout, const char *schemaName);
237 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
238 static char *myFormatType(const char *typname, int32 typmod);
239 static const char *fmtQualifiedId(Archive *fout,
240                                                                   const char *schema, const char *id);
241 static void getBlobs(Archive *fout);
242 static void dumpBlob(Archive *fout, BlobInfo *binfo);
243 static int      dumpBlobs(Archive *fout, void *arg);
244 static void dumpDatabase(Archive *AH);
245 static void dumpEncoding(Archive *AH);
246 static void dumpStdStrings(Archive *AH);
247 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
248                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
249 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
250                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
251 static void binary_upgrade_set_pg_class_oids(Archive *fout,
252                                                                  PQExpBuffer upgrade_buffer,
253                                                                  Oid pg_class_oid, bool is_index);
254 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
255                                                                 DumpableObject *dobj,
256                                                                 const char *objlabel);
257 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
258 static const char *fmtCopyColumnList(const TableInfo *ti);
259
260 int
261 main(int argc, char **argv)
262 {
263         int                     c;
264         const char *filename = NULL;
265         const char *format = "p";
266         const char *dbname = NULL;
267         const char *pghost = NULL;
268         const char *pgport = NULL;
269         const char *username = NULL;
270         const char *dumpencoding = NULL;
271         bool            oids = false;
272         TableInfo  *tblinfo;
273         int                     numTables;
274         DumpableObject **dobjs;
275         int                     numObjs;
276         int                     i;
277         enum trivalue prompt_password = TRI_DEFAULT;
278         int                     compressLevel = -1;
279         int                     plainText = 0;
280         int                     outputClean = 0;
281         int                     outputCreateDB = 0;
282         bool            outputBlobs = false;
283         int                     outputNoOwner = 0;
284         char       *outputSuperuser = NULL;
285         char       *use_role = NULL;
286         int                     my_version;
287         int                     optindex;
288         RestoreOptions *ropt;
289         ArchiveFormat archiveFormat = archUnknown;
290         ArchiveMode archiveMode;
291         Archive    *fout;                               /* the script file */
292
293         static int      disable_triggers = 0;
294         static int      outputNoTablespaces = 0;
295         static int      use_setsessauth = 0;
296
297         static struct option long_options[] = {
298                 {"data-only", no_argument, NULL, 'a'},
299                 {"blobs", no_argument, NULL, 'b'},
300                 {"clean", no_argument, NULL, 'c'},
301                 {"create", no_argument, NULL, 'C'},
302                 {"file", required_argument, NULL, 'f'},
303                 {"format", required_argument, NULL, 'F'},
304                 {"host", required_argument, NULL, 'h'},
305                 {"ignore-version", no_argument, NULL, 'i'},
306                 {"no-reconnect", no_argument, NULL, 'R'},
307                 {"oids", no_argument, NULL, 'o'},
308                 {"no-owner", no_argument, NULL, 'O'},
309                 {"port", required_argument, NULL, 'p'},
310                 {"schema", required_argument, NULL, 'n'},
311                 {"exclude-schema", required_argument, NULL, 'N'},
312                 {"schema-only", no_argument, NULL, 's'},
313                 {"superuser", required_argument, NULL, 'S'},
314                 {"table", required_argument, NULL, 't'},
315                 {"exclude-table", required_argument, NULL, 'T'},
316                 {"no-password", no_argument, NULL, 'w'},
317                 {"password", no_argument, NULL, 'W'},
318                 {"username", required_argument, NULL, 'U'},
319                 {"verbose", no_argument, NULL, 'v'},
320                 {"no-privileges", no_argument, NULL, 'x'},
321                 {"no-acl", no_argument, NULL, 'x'},
322                 {"compress", required_argument, NULL, 'Z'},
323                 {"encoding", required_argument, NULL, 'E'},
324                 {"help", no_argument, NULL, '?'},
325                 {"version", no_argument, NULL, 'V'},
326
327                 /*
328                  * the following options don't have an equivalent short option letter
329                  */
330                 {"attribute-inserts", no_argument, &column_inserts, 1},
331                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
332                 {"column-inserts", no_argument, &column_inserts, 1},
333                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
334                 {"disable-triggers", no_argument, &disable_triggers, 1},
335                 {"exclude-table-data", required_argument, NULL, 4},
336                 {"inserts", no_argument, &dump_inserts, 1},
337                 {"lock-wait-timeout", required_argument, NULL, 2},
338                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
339                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
340                 {"role", required_argument, NULL, 3},
341                 {"section", required_argument, NULL, 5},
342                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
343                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
344                 {"no-security-labels", no_argument, &no_security_labels, 1},
345                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
346
347                 {NULL, 0, NULL, 0}
348         };
349
350         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
351
352         g_verbose = false;
353
354         strcpy(g_comment_start, "-- ");
355         g_comment_end[0] = '\0';
356         strcpy(g_opaque_type, "opaque");
357
358         dataOnly = schemaOnly = false;
359         dumpSections = DUMP_UNSECTIONED;
360         lockWaitTimeout = NULL;
361
362         progname = get_progname(argv[0]);
363
364         /* Set default options based on progname */
365         if (strcmp(progname, "pg_backup") == 0)
366                 format = "c";
367
368         if (argc > 1)
369         {
370                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
371                 {
372                         help(progname);
373                         exit(0);
374                 }
375                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
376                 {
377                         puts("pg_dump (PostgreSQL) " PG_VERSION);
378                         exit(0);
379                 }
380         }
381
382         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
383                                                         long_options, &optindex)) != -1)
384         {
385                 switch (c)
386                 {
387                         case 'a':                       /* Dump data only */
388                                 dataOnly = true;
389                                 break;
390
391                         case 'b':                       /* Dump blobs */
392                                 outputBlobs = true;
393                                 break;
394
395                         case 'c':                       /* clean (i.e., drop) schema prior to create */
396                                 outputClean = 1;
397                                 break;
398
399                         case 'C':                       /* Create DB */
400                                 outputCreateDB = 1;
401                                 break;
402
403                         case 'E':                       /* Dump encoding */
404                                 dumpencoding = optarg;
405                                 break;
406
407                         case 'f':
408                                 filename = optarg;
409                                 break;
410
411                         case 'F':
412                                 format = optarg;
413                                 break;
414
415                         case 'h':                       /* server host */
416                                 pghost = optarg;
417                                 break;
418
419                         case 'i':
420                                 /* ignored, deprecated option */
421                                 break;
422
423                         case 'n':                       /* include schema(s) */
424                                 simple_string_list_append(&schema_include_patterns, optarg);
425                                 include_everything = false;
426                                 break;
427
428                         case 'N':                       /* exclude schema(s) */
429                                 simple_string_list_append(&schema_exclude_patterns, optarg);
430                                 break;
431
432                         case 'o':                       /* Dump oids */
433                                 oids = true;
434                                 break;
435
436                         case 'O':                       /* Don't reconnect to match owner */
437                                 outputNoOwner = 1;
438                                 break;
439
440                         case 'p':                       /* server port */
441                                 pgport = optarg;
442                                 break;
443
444                         case 'R':
445                                 /* no-op, still accepted for backwards compatibility */
446                                 break;
447
448                         case 's':                       /* dump schema only */
449                                 schemaOnly = true;
450                                 break;
451
452                         case 'S':                       /* Username for superuser in plain text output */
453                                 outputSuperuser = pg_strdup(optarg);
454                                 break;
455
456                         case 't':                       /* include table(s) */
457                                 simple_string_list_append(&table_include_patterns, optarg);
458                                 include_everything = false;
459                                 break;
460
461                         case 'T':                       /* exclude table(s) */
462                                 simple_string_list_append(&table_exclude_patterns, optarg);
463                                 break;
464
465                         case 'U':
466                                 username = optarg;
467                                 break;
468
469                         case 'v':                       /* verbose */
470                                 g_verbose = true;
471                                 break;
472
473                         case 'w':
474                                 prompt_password = TRI_NO;
475                                 break;
476
477                         case 'W':
478                                 prompt_password = TRI_YES;
479                                 break;
480
481                         case 'x':                       /* skip ACL dump */
482                                 aclsSkip = true;
483                                 break;
484
485                         case 'Z':                       /* Compression Level */
486                                 compressLevel = atoi(optarg);
487                                 break;
488
489                         case 0:
490                                 /* This covers the long options. */
491                                 break;
492
493                         case 2:                         /* lock-wait-timeout */
494                                 lockWaitTimeout = optarg;
495                                 break;
496
497                         case 3:                         /* SET ROLE */
498                                 use_role = optarg;
499                                 break;
500
501                         case 4:                 /* exclude table(s) data */
502                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
503                                 break;
504
505                         case 5:                         /* section */
506                                 set_section(optarg, &dumpSections);
507                                 break;
508
509                         default:
510                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
511                                 exit(1);
512                 }
513         }
514
515         /* Get database name from command line */
516         if (optind < argc)
517                 dbname = argv[optind++];
518
519         /* Complain if any arguments remain */
520         if (optind < argc)
521         {
522                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
523                                 progname, argv[optind]);
524                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
525                                 progname);
526                 exit(1);
527         }
528
529         /* --column-inserts implies --inserts */
530         if (column_inserts)
531                 dump_inserts = 1;
532
533         if (dataOnly && schemaOnly)
534         {
535                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
536                 exit(1);
537         }
538
539         if ((dataOnly || schemaOnly) && dumpSections != DUMP_UNSECTIONED)
540         {
541                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used with --section\n");
542                 exit(1);
543         }
544
545         if (dataOnly)
546                 dumpSections = DUMP_DATA;
547         else if (schemaOnly)
548                 dumpSections = DUMP_PRE_DATA | DUMP_POST_DATA;
549         else if ( dumpSections != DUMP_UNSECTIONED)
550         {
551                 dataOnly = dumpSections == DUMP_DATA;
552                 schemaOnly = !(dumpSections & DUMP_DATA);
553         }
554
555         if (dataOnly && outputClean)
556         {
557                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
558                 exit(1);
559         }
560
561         if (dump_inserts && oids)
562         {
563                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
564                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
565                 exit(1);
566         }
567
568         /* Identify archive format to emit */
569         archiveFormat = parseArchiveFormat(format, &archiveMode);
570
571         /* archiveFormat specific setup */
572         if (archiveFormat == archNull)
573                 plainText = 1;
574
575         /* Custom and directory formats are compressed by default, others not */
576         if (compressLevel == -1)
577         {
578                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
579                         compressLevel = Z_DEFAULT_COMPRESSION;
580                 else
581                         compressLevel = 0;
582         }
583
584         /* Open the output file */
585         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
586
587         if (fout == NULL)
588         {
589                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
590                 exit(1);
591         }
592
593         /* Let the archiver know how noisy to be */
594         fout->verbose = g_verbose;
595
596         my_version = parse_version(PG_VERSION);
597         if (my_version < 0)
598         {
599                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
600                 exit(1);
601         }
602
603         /*
604          * We allow the server to be back to 7.0, and up to any minor release of
605          * our own major version.  (See also version check in pg_dumpall.c.)
606          */
607         fout->minRemoteVersion = 70000;
608         fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
609
610         /*
611          * Open the database using the Archiver, so it knows about it. Errors mean
612          * death.
613          */
614         g_conn = ConnectDatabase(fout, dbname, pghost, pgport,
615                                                          username, prompt_password);
616
617         setup_connection(fout, dumpencoding, use_role);
618
619         /*
620          * Disable security label support if server version < v9.1.x (prevents
621          * access to nonexistent pg_seclabel catalog)
622          */
623         if (fout->remoteVersion < 90100)
624                 no_security_labels = 1;
625
626         /*
627          * Start transaction-snapshot mode transaction to dump consistent data.
628          */
629         ExecuteSqlStatement(fout, "BEGIN");
630         if (fout->remoteVersion >= 90100)
631         {
632                 if (serializable_deferrable)
633                         ExecuteSqlStatement(fout,
634                                                                 "SET TRANSACTION ISOLATION LEVEL "
635                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
636                 else
637                         ExecuteSqlStatement(fout,
638                                                                 "SET TRANSACTION ISOLATION LEVEL "
639                                                                 "REPEATABLE READ");
640         }
641         else
642                 ExecuteSqlStatement(fout,
643                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
644
645         /* Select the appropriate subquery to convert user IDs to names */
646         if (fout->remoteVersion >= 80100)
647                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
648         else if (fout->remoteVersion >= 70300)
649                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
650         else
651                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
652
653         /* Find the last built-in OID, if needed */
654         if (fout->remoteVersion < 70300)
655         {
656                 if (fout->remoteVersion >= 70100)
657                         g_last_builtin_oid = findLastBuiltinOid_V71(fout, PQdb(g_conn));
658                 else
659                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
660                 if (g_verbose)
661                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
662         }
663
664         /* Expand schema selection patterns into OID lists */
665         if (schema_include_patterns.head != NULL)
666         {
667                 expand_schema_name_patterns(fout, &schema_include_patterns,
668                                                                         &schema_include_oids);
669                 if (schema_include_oids.head == NULL)
670                 {
671                         write_msg(NULL, "No matching schemas were found\n");
672                         exit_nicely();
673                 }
674         }
675         expand_schema_name_patterns(fout, &schema_exclude_patterns,
676                                                                 &schema_exclude_oids);
677         /* non-matching exclusion patterns aren't an error */
678
679         /* Expand table selection patterns into OID lists */
680         if (table_include_patterns.head != NULL)
681         {
682                 expand_table_name_patterns(fout, &table_include_patterns,
683                                                                    &table_include_oids);
684                 if (table_include_oids.head == NULL)
685                 {
686                         write_msg(NULL, "No matching tables were found\n");
687                         exit_nicely();
688                 }
689         }
690         expand_table_name_patterns(fout, &table_exclude_patterns,
691                                                            &table_exclude_oids);
692
693         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
694                                                            &tabledata_exclude_oids);
695
696         /* non-matching exclusion patterns aren't an error */
697
698         /*
699          * Dumping blobs is now default unless we saw an inclusion switch or -s
700          * ... but even if we did see one of these, -b turns it back on.
701          */
702         if (include_everything && !schemaOnly)
703                 outputBlobs = true;
704
705         /*
706          * Now scan the database and create DumpableObject structs for all the
707          * objects we intend to dump.
708          */
709         tblinfo = getSchemaData(fout, &numTables);
710
711         if (fout->remoteVersion < 80400)
712                 guessConstraintInheritance(tblinfo, numTables);
713
714         if (!schemaOnly)
715         {
716                 getTableData(tblinfo, numTables, oids);
717                 if (dataOnly)
718                         getTableDataFKConstraints();
719         }
720
721         if (outputBlobs)
722                 getBlobs(fout);
723
724         /*
725          * Collect dependency data to assist in ordering the objects.
726          */
727         getDependencies(fout);
728
729         /*
730          * Sort the objects into a safe dump order (no forward references).
731          *
732          * In 7.3 or later, we can rely on dependency information to help us
733          * determine a safe order, so the initial sort is mostly for cosmetic
734          * purposes: we sort by name to ensure that logically identical schemas
735          * will dump identically.  Before 7.3 we don't have dependencies and we
736          * use OID ordering as an (unreliable) guide to creation order.
737          */
738         getDumpableObjects(&dobjs, &numObjs);
739
740         if (fout->remoteVersion >= 70300)
741                 sortDumpableObjectsByTypeName(dobjs, numObjs);
742         else
743                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
744
745         sortDumpableObjects(dobjs, numObjs);
746
747         /*
748          * Create archive TOC entries for all the objects to be dumped, in a safe
749          * order.
750          */
751
752         /* First the special ENCODING and STDSTRINGS entries. */
753         dumpEncoding(fout);
754         dumpStdStrings(fout);
755
756         /* The database item is always next, unless we don't want it at all */
757         if (include_everything && !dataOnly)
758                 dumpDatabase(fout);
759
760         /* Now the rearrangeable objects. */
761         for (i = 0; i < numObjs; i++)
762                 dumpDumpableObject(fout, dobjs[i]);
763
764         /*
765          * And finally we can do the actual output.
766          */
767         if (plainText)
768         {
769                 ropt = NewRestoreOptions();
770                 ropt->filename = filename;
771                 ropt->dropSchema = outputClean;
772                 ropt->aclsSkip = aclsSkip;
773                 ropt->superuser = outputSuperuser;
774                 ropt->createDB = outputCreateDB;
775                 ropt->noOwner = outputNoOwner;
776                 ropt->noTablespace = outputNoTablespaces;
777                 ropt->disable_triggers = disable_triggers;
778                 ropt->use_setsessauth = use_setsessauth;
779                 ropt->dataOnly = dataOnly;
780
781                 if (compressLevel == -1)
782                         ropt->compression = 0;
783                 else
784                         ropt->compression = compressLevel;
785
786                 ropt->suppressDumpWarnings = true;              /* We've already shown them */
787
788                 RestoreArchive(fout, ropt);
789         }
790
791         CloseArchive(fout);
792
793         PQfinish(g_conn);
794
795         exit(0);
796 }
797
798
799 static void
800 help(const char *progname)
801 {
802         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
803         printf(_("Usage:\n"));
804         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
805
806         printf(_("\nGeneral options:\n"));
807         printf(_("  -f, --file=FILENAME         output file or directory name\n"));
808         printf(_("  -F, --format=c|d|t|p        output file format (custom, directory, tar,\n"
809                          "                              plain text (default))\n"));
810         printf(_("  -v, --verbose               verbose mode\n"));
811         printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
812         printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
813         printf(_("  --help                      show this help, then exit\n"));
814         printf(_("  --version                   output version information, then exit\n"));
815
816         printf(_("\nOptions controlling the output content:\n"));
817         printf(_("  -a, --data-only             dump only the data, not the schema\n"));
818         printf(_("  -b, --blobs                 include large objects in dump\n"));
819         printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
820         printf(_("  -C, --create                include commands to create database in dump\n"));
821         printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
822         printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
823         printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
824         printf(_("  -o, --oids                  include OIDs in dump\n"));
825         printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
826                          "                              plain-text format\n"));
827         printf(_("  -s, --schema-only           dump only the schema, no data\n"));
828         printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
829         printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
830         printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
831         printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
832         printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
833         printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
834         printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
835         printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
836         printf(_("  --exclude-table-data=TABLE  do NOT dump data for the named table(s)\n"));
837         printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
838         printf(_("  --no-security-labels        do not dump security label assignments\n"));
839         printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
840         printf(_("  --no-unlogged-table-data    do not dump unlogged table data\n"));
841         printf(_("  --quote-all-identifiers     quote all identifiers, even if not key words\n"));
842         printf(_("  --section=SECTION           dump named section (pre-data, data or post-data)\n"));
843         printf(_("  --serializable-deferrable   wait until the dump can run without anomalies\n"));
844         printf(_("  --use-set-session-authorization\n"
845                          "                              use SET SESSION AUTHORIZATION commands instead of\n"
846         "                              ALTER OWNER commands to set ownership\n"));
847
848         printf(_("\nConnection options:\n"));
849         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
850         printf(_("  -p, --port=PORT          database server port number\n"));
851         printf(_("  -U, --username=NAME      connect as specified database user\n"));
852         printf(_("  -w, --no-password        never prompt for password\n"));
853         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
854         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
855
856         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
857                          "variable value is used.\n\n"));
858         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
859 }
860
861 void
862 exit_nicely(void)
863 {
864         PQfinish(g_conn);
865         if (g_verbose)
866                 write_msg(NULL, "*** aborted because of error\n");
867         exit(1);
868 }
869
870 static void
871 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
872 {
873         const char *std_strings;
874
875         /* Set the client encoding if requested */
876         if (dumpencoding)
877         {
878                 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
879                 {
880                         write_msg(NULL, "invalid client encoding \"%s\" specified\n",
881                                           dumpencoding);
882                         exit(1);
883                 }
884         }
885
886         /*
887          * Get the active encoding and the standard_conforming_strings setting, so
888          * we know how to escape strings.
889          */
890         AH->encoding = PQclientEncoding(g_conn);
891
892         std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
893         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
894
895         /* Set the role if requested */
896         if (use_role && AH->remoteVersion >= 80100)
897         {
898                 PQExpBuffer query = createPQExpBuffer();
899
900                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
901                 ExecuteSqlStatement(AH, query->data);
902                 destroyPQExpBuffer(query);
903         }
904
905         /* Set the datestyle to ISO to ensure the dump's portability */
906         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
907
908         /* Likewise, avoid using sql_standard intervalstyle */
909         if (AH->remoteVersion >= 80400)
910                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
911
912         /*
913          * If supported, set extra_float_digits so that we can dump float data
914          * exactly (given correctly implemented float I/O code, anyway)
915          */
916         if (AH->remoteVersion >= 90000)
917                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
918         else if (AH->remoteVersion >= 70400)
919                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
920
921         /*
922          * If synchronized scanning is supported, disable it, to prevent
923          * unpredictable changes in row ordering across a dump and reload.
924          */
925         if (AH->remoteVersion >= 80300)
926                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
927
928         /*
929          * Disable timeouts if supported.
930          */
931         if (AH->remoteVersion >= 70300)
932                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
933
934         /*
935          * Quote all identifiers, if requested.
936          */
937         if (quote_all_identifiers && AH->remoteVersion >= 90100)
938                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
939 }
940
941 static ArchiveFormat
942 parseArchiveFormat(const char *format, ArchiveMode *mode)
943 {
944         ArchiveFormat archiveFormat;
945
946         *mode = archModeWrite;
947
948         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
949         {
950                 /* This is used by pg_dumpall, and is not documented */
951                 archiveFormat = archNull;
952                 *mode = archModeAppend;
953         }
954         else if (pg_strcasecmp(format, "c") == 0)
955                 archiveFormat = archCustom;
956         else if (pg_strcasecmp(format, "custom") == 0)
957                 archiveFormat = archCustom;
958         else if (pg_strcasecmp(format, "d") == 0)
959                 archiveFormat = archDirectory;
960         else if (pg_strcasecmp(format, "directory") == 0)
961                 archiveFormat = archDirectory;
962         else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
963
964                 /*
965                  * Dump files into the current directory; for demonstration only, not
966                  * documented.
967                  */
968                 archiveFormat = archFiles;
969         else if (pg_strcasecmp(format, "p") == 0)
970                 archiveFormat = archNull;
971         else if (pg_strcasecmp(format, "plain") == 0)
972                 archiveFormat = archNull;
973         else if (pg_strcasecmp(format, "t") == 0)
974                 archiveFormat = archTar;
975         else if (pg_strcasecmp(format, "tar") == 0)
976                 archiveFormat = archTar;
977         else
978         {
979                 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
980                 exit(1);
981         }
982         return archiveFormat;
983 }
984
985 /*
986  * Find the OIDs of all schemas matching the given list of patterns,
987  * and append them to the given OID list.
988  */
989 static void
990 expand_schema_name_patterns(Archive *fout,
991                                                         SimpleStringList *patterns,
992                                                         SimpleOidList *oids)
993 {
994         PQExpBuffer query;
995         PGresult   *res;
996         SimpleStringListCell *cell;
997         int                     i;
998
999         if (patterns->head == NULL)
1000                 return;                                 /* nothing to do */
1001
1002         if (fout->remoteVersion < 70300)
1003         {
1004                 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1005                 exit_nicely();
1006         }
1007
1008         query = createPQExpBuffer();
1009
1010         /*
1011          * We use UNION ALL rather than UNION; this might sometimes result in
1012          * duplicate entries in the OID list, but we don't care.
1013          */
1014
1015         for (cell = patterns->head; cell; cell = cell->next)
1016         {
1017                 if (cell != patterns->head)
1018                         appendPQExpBuffer(query, "UNION ALL\n");
1019                 appendPQExpBuffer(query,
1020                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1021                 processSQLNamePattern(g_conn, query, cell->val, false, false,
1022                                                           NULL, "n.nspname", NULL,
1023                                                           NULL);
1024         }
1025
1026         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1027
1028         for (i = 0; i < PQntuples(res); i++)
1029         {
1030                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1031         }
1032
1033         PQclear(res);
1034         destroyPQExpBuffer(query);
1035 }
1036
1037 /*
1038  * Find the OIDs of all tables matching the given list of patterns,
1039  * and append them to the given OID list.
1040  */
1041 static void
1042 expand_table_name_patterns(Archive *fout,
1043                                                    SimpleStringList *patterns, SimpleOidList *oids)
1044 {
1045         PQExpBuffer query;
1046         PGresult   *res;
1047         SimpleStringListCell *cell;
1048         int                     i;
1049
1050         if (patterns->head == NULL)
1051                 return;                                 /* nothing to do */
1052
1053         query = createPQExpBuffer();
1054
1055         /*
1056          * We use UNION ALL rather than UNION; this might sometimes result in
1057          * duplicate entries in the OID list, but we don't care.
1058          */
1059
1060         for (cell = patterns->head; cell; cell = cell->next)
1061         {
1062                 if (cell != patterns->head)
1063                         appendPQExpBuffer(query, "UNION ALL\n");
1064                 appendPQExpBuffer(query,
1065                                                   "SELECT c.oid"
1066                                                   "\nFROM pg_catalog.pg_class c"
1067                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1068                                                   "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
1069                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1070                                                   RELKIND_FOREIGN_TABLE);
1071                 processSQLNamePattern(g_conn, query, cell->val, true, false,
1072                                                           "n.nspname", "c.relname", NULL,
1073                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1074         }
1075
1076         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1077
1078         for (i = 0; i < PQntuples(res); i++)
1079         {
1080                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1081         }
1082
1083         PQclear(res);
1084         destroyPQExpBuffer(query);
1085 }
1086
1087 /*
1088  * selectDumpableNamespace: policy-setting subroutine
1089  *              Mark a namespace as to be dumped or not
1090  */
1091 static void
1092 selectDumpableNamespace(NamespaceInfo *nsinfo)
1093 {
1094         /*
1095          * If specific tables are being dumped, do not dump any complete
1096          * namespaces. If specific namespaces are being dumped, dump just those
1097          * namespaces. Otherwise, dump all non-system namespaces.
1098          */
1099         if (table_include_oids.head != NULL)
1100                 nsinfo->dobj.dump = false;
1101         else if (schema_include_oids.head != NULL)
1102                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1103                                                                                                    nsinfo->dobj.catId.oid);
1104         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1105                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1106                 nsinfo->dobj.dump = false;
1107         else
1108                 nsinfo->dobj.dump = true;
1109
1110         /*
1111          * In any case, a namespace can be excluded by an exclusion switch
1112          */
1113         if (nsinfo->dobj.dump &&
1114                 simple_oid_list_member(&schema_exclude_oids,
1115                                                            nsinfo->dobj.catId.oid))
1116                 nsinfo->dobj.dump = false;
1117 }
1118
1119 /*
1120  * selectDumpableTable: policy-setting subroutine
1121  *              Mark a table as to be dumped or not
1122  */
1123 static void
1124 selectDumpableTable(TableInfo *tbinfo)
1125 {
1126         /*
1127          * If specific tables are being dumped, dump just those tables; else, dump
1128          * according to the parent namespace's dump flag.
1129          */
1130         if (table_include_oids.head != NULL)
1131                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1132                                                                                                    tbinfo->dobj.catId.oid);
1133         else
1134                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1135
1136         /*
1137          * In any case, a table can be excluded by an exclusion switch
1138          */
1139         if (tbinfo->dobj.dump &&
1140                 simple_oid_list_member(&table_exclude_oids,
1141                                                            tbinfo->dobj.catId.oid))
1142                 tbinfo->dobj.dump = false;
1143
1144         /* If table is to be dumped, check that the data is not excluded */
1145         if (tbinfo->dobj.dump && !
1146                 simple_oid_list_member(&tabledata_exclude_oids,
1147                                                            tbinfo->dobj.catId.oid))
1148                 tbinfo->dobj.dumpdata = true;
1149         else
1150                 tbinfo->dobj.dumpdata = false;
1151
1152 }
1153
1154 /*
1155  * selectDumpableType: policy-setting subroutine
1156  *              Mark a type as to be dumped or not
1157  *
1158  * If it's a table's rowtype or an autogenerated array type, we also apply a
1159  * special type code to facilitate sorting into the desired order.      (We don't
1160  * want to consider those to be ordinary types because that would bring tables
1161  * up into the datatype part of the dump order.)  We still set the object's
1162  * dump flag; that's not going to cause the dummy type to be dumped, but we
1163  * need it so that casts involving such types will be dumped correctly -- see
1164  * dumpCast.  This means the flag should be set the same as for the underlying
1165  * object (the table or base type).
1166  */
1167 static void
1168 selectDumpableType(TypeInfo *tyinfo)
1169 {
1170         /* skip complex types, except for standalone composite types */
1171         if (OidIsValid(tyinfo->typrelid) &&
1172                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1173         {
1174                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1175
1176                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1177                 if (tytable != NULL)
1178                         tyinfo->dobj.dump = tytable->dobj.dump;
1179                 else
1180                         tyinfo->dobj.dump = false;
1181                 return;
1182         }
1183
1184         /* skip auto-generated array types */
1185         if (tyinfo->isArray)
1186         {
1187                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1188                 /*
1189                  * Fall through to set the dump flag; we assume that the subsequent
1190                  * rules will do the same thing as they would for the array's base
1191                  * type.  (We cannot reliably look up the base type here, since
1192                  * getTypes may not have processed it yet.)
1193                  */
1194         }
1195
1196         /* dump only types in dumpable namespaces */
1197         if (!tyinfo->dobj.namespace->dobj.dump)
1198                 tyinfo->dobj.dump = false;
1199
1200         /* skip undefined placeholder types */
1201         else if (!tyinfo->isDefined)
1202                 tyinfo->dobj.dump = false;
1203
1204         else
1205                 tyinfo->dobj.dump = true;
1206 }
1207
1208 /*
1209  * selectDumpableDefaultACL: policy-setting subroutine
1210  *              Mark a default ACL as to be dumped or not
1211  *
1212  * For per-schema default ACLs, dump if the schema is to be dumped.
1213  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1214  * and aclsSkip are checked separately.
1215  */
1216 static void
1217 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1218 {
1219         if (dinfo->dobj.namespace)
1220                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1221         else
1222                 dinfo->dobj.dump = include_everything;
1223 }
1224
1225 /*
1226  * selectDumpableExtension: policy-setting subroutine
1227  *              Mark an extension as to be dumped or not
1228  *
1229  * Normally, we dump all extensions, or none of them if include_everything
1230  * is false (i.e., a --schema or --table switch was given).  However, in
1231  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1232  * assume those will already be installed in the target database.  We identify
1233  * such extensions by their having OIDs in the range reserved for initdb.
1234  */
1235 static void
1236 selectDumpableExtension(ExtensionInfo *extinfo)
1237 {
1238         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1239                 extinfo->dobj.dump = false;
1240         else
1241                 extinfo->dobj.dump = include_everything;
1242 }
1243
1244 /*
1245  * selectDumpableObject: policy-setting subroutine
1246  *              Mark a generic dumpable object as to be dumped or not
1247  *
1248  * Use this only for object types without a special-case routine above.
1249  */
1250 static void
1251 selectDumpableObject(DumpableObject *dobj)
1252 {
1253         /*
1254          * Default policy is to dump if parent namespace is dumpable, or always
1255          * for non-namespace-associated items.
1256          */
1257         if (dobj->namespace)
1258                 dobj->dump = dobj->namespace->dobj.dump;
1259         else
1260                 dobj->dump = true;
1261 }
1262
1263 /*
1264  *      Dump a table's contents for loading using the COPY command
1265  *      - this routine is called by the Archiver when it wants the table
1266  *        to be dumped.
1267  */
1268
1269 static int
1270 dumpTableData_copy(Archive *fout, void *dcontext)
1271 {
1272         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1273         TableInfo  *tbinfo = tdinfo->tdtable;
1274         const char *classname = tbinfo->dobj.name;
1275         const bool      hasoids = tbinfo->hasoids;
1276         const bool      oids = tdinfo->oids;
1277         PQExpBuffer q = createPQExpBuffer();
1278         PGresult   *res;
1279         int                     ret;
1280         char       *copybuf;
1281         const char *column_list;
1282
1283         if (g_verbose)
1284                 write_msg(NULL, "dumping contents of table %s\n", classname);
1285
1286         /*
1287          * Make sure we are in proper schema.  We will qualify the table name
1288          * below anyway (in case its name conflicts with a pg_catalog table); but
1289          * this ensures reproducible results in case the table contains regproc,
1290          * regclass, etc columns.
1291          */
1292         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1293
1294         /*
1295          * If possible, specify the column list explicitly so that we have no
1296          * possibility of retrieving data in the wrong column order.  (The default
1297          * column ordering of COPY will not be what we want in certain corner
1298          * cases involving ADD COLUMN and inheritance.)
1299          */
1300         if (fout->remoteVersion >= 70300)
1301                 column_list = fmtCopyColumnList(tbinfo);
1302         else
1303                 column_list = "";               /* can't select columns in COPY */
1304
1305         if (oids && hasoids)
1306         {
1307                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1308                                                   fmtQualifiedId(fout,
1309                                                                                  tbinfo->dobj.namespace->dobj.name,
1310                                                                                  classname),
1311                                                   column_list);
1312         }
1313         else if (tdinfo->filtercond)
1314         {
1315                 /* Note: this syntax is only supported in 8.2 and up */
1316                 appendPQExpBufferStr(q, "COPY (SELECT ");
1317                 /* klugery to get rid of parens in column list */
1318                 if (strlen(column_list) > 2)
1319                 {
1320                         appendPQExpBufferStr(q, column_list + 1);
1321                         q->data[q->len - 1] = ' ';
1322                 }
1323                 else
1324                         appendPQExpBufferStr(q, "* ");
1325                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1326                                                   fmtQualifiedId(fout,
1327                                                                                  tbinfo->dobj.namespace->dobj.name,
1328                                                                                  classname),
1329                                                   tdinfo->filtercond);
1330         }
1331         else
1332         {
1333                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1334                                                   fmtQualifiedId(fout,
1335                                                                                  tbinfo->dobj.namespace->dobj.name,
1336                                                                                  classname),
1337                                                   column_list);
1338         }
1339         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1340         PQclear(res);
1341
1342         for (;;)
1343         {
1344                 ret = PQgetCopyData(g_conn, &copybuf, 0);
1345
1346                 if (ret < 0)
1347                         break;                          /* done or error */
1348
1349                 if (copybuf)
1350                 {
1351                         WriteData(fout, copybuf, ret);
1352                         PQfreemem(copybuf);
1353                 }
1354
1355                 /* ----------
1356                  * THROTTLE:
1357                  *
1358                  * There was considerable discussion in late July, 2000 regarding
1359                  * slowing down pg_dump when backing up large tables. Users with both
1360                  * slow & fast (multi-processor) machines experienced performance
1361                  * degradation when doing a backup.
1362                  *
1363                  * Initial attempts based on sleeping for a number of ms for each ms
1364                  * of work were deemed too complex, then a simple 'sleep in each loop'
1365                  * implementation was suggested. The latter failed because the loop
1366                  * was too tight. Finally, the following was implemented:
1367                  *
1368                  * If throttle is non-zero, then
1369                  *              See how long since the last sleep.
1370                  *              Work out how long to sleep (based on ratio).
1371                  *              If sleep is more than 100ms, then
1372                  *                      sleep
1373                  *                      reset timer
1374                  *              EndIf
1375                  * EndIf
1376                  *
1377                  * where the throttle value was the number of ms to sleep per ms of
1378                  * work. The calculation was done in each loop.
1379                  *
1380                  * Most of the hard work is done in the backend, and this solution
1381                  * still did not work particularly well: on slow machines, the ratio
1382                  * was 50:1, and on medium paced machines, 1:1, and on fast
1383                  * multi-processor machines, it had little or no effect, for reasons
1384                  * that were unclear.
1385                  *
1386                  * Further discussion ensued, and the proposal was dropped.
1387                  *
1388                  * For those people who want this feature, it can be implemented using
1389                  * gettimeofday in each loop, calculating the time since last sleep,
1390                  * multiplying that by the sleep ratio, then if the result is more
1391                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1392                  * function to sleep for a subsecond period ie.
1393                  *
1394                  * select(0, NULL, NULL, NULL, &tvi);
1395                  *
1396                  * This will return after the interval specified in the structure tvi.
1397                  * Finally, call gettimeofday again to save the 'last sleep time'.
1398                  * ----------
1399                  */
1400         }
1401         archprintf(fout, "\\.\n\n\n");
1402
1403         if (ret == -2)
1404         {
1405                 /* copy data transfer failed */
1406                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1407                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1408                 write_msg(NULL, "The command was: %s\n", q->data);
1409                 exit_nicely();
1410         }
1411
1412         /* Check command status and return to normal libpq state */
1413         res = PQgetResult(g_conn);
1414         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1415         {
1416                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1417                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1418                 write_msg(NULL, "The command was: %s\n", q->data);
1419                 exit_nicely();
1420         }
1421         PQclear(res);
1422
1423         destroyPQExpBuffer(q);
1424         return 1;
1425 }
1426
1427 /*
1428  * Dump table data using INSERT commands.
1429  *
1430  * Caution: when we restore from an archive file direct to database, the
1431  * INSERT commands emitted by this function have to be parsed by
1432  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1433  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1434  */
1435 static int
1436 dumpTableData_insert(Archive *fout, void *dcontext)
1437 {
1438         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1439         TableInfo  *tbinfo = tdinfo->tdtable;
1440         const char *classname = tbinfo->dobj.name;
1441         PQExpBuffer q = createPQExpBuffer();
1442         PGresult   *res;
1443         int                     tuple;
1444         int                     nfields;
1445         int                     field;
1446
1447         /*
1448          * Make sure we are in proper schema.  We will qualify the table name
1449          * below anyway (in case its name conflicts with a pg_catalog table); but
1450          * this ensures reproducible results in case the table contains regproc,
1451          * regclass, etc columns.
1452          */
1453         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1454
1455         if (fout->remoteVersion >= 70100)
1456         {
1457                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1458                                                   "SELECT * FROM ONLY %s",
1459                                                   fmtQualifiedId(fout,
1460                                                                                  tbinfo->dobj.namespace->dobj.name,
1461                                                                                  classname));
1462         }
1463         else
1464         {
1465                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1466                                                   "SELECT * FROM %s",
1467                                                   fmtQualifiedId(fout,
1468                                                                                  tbinfo->dobj.namespace->dobj.name,
1469                                                                                  classname));
1470         }
1471         if (tdinfo->filtercond)
1472                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1473
1474         ExecuteSqlStatement(fout, q->data);
1475
1476         while (1)
1477         {
1478                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1479                                                           PGRES_TUPLES_OK);
1480                 nfields = PQnfields(res);
1481                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1482                 {
1483                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1484                         if (nfields == 0)
1485                         {
1486                                 /* corner case for zero-column table */
1487                                 archprintf(fout, "DEFAULT VALUES;\n");
1488                                 continue;
1489                         }
1490                         if (column_inserts)
1491                         {
1492                                 resetPQExpBuffer(q);
1493                                 appendPQExpBuffer(q, "(");
1494                                 for (field = 0; field < nfields; field++)
1495                                 {
1496                                         if (field > 0)
1497                                                 appendPQExpBuffer(q, ", ");
1498                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1499                                 }
1500                                 appendPQExpBuffer(q, ") ");
1501                                 archputs(q->data, fout);
1502                         }
1503                         archprintf(fout, "VALUES (");
1504                         for (field = 0; field < nfields; field++)
1505                         {
1506                                 if (field > 0)
1507                                         archprintf(fout, ", ");
1508                                 if (PQgetisnull(res, tuple, field))
1509                                 {
1510                                         archprintf(fout, "NULL");
1511                                         continue;
1512                                 }
1513
1514                                 /* XXX This code is partially duplicated in ruleutils.c */
1515                                 switch (PQftype(res, field))
1516                                 {
1517                                         case INT2OID:
1518                                         case INT4OID:
1519                                         case INT8OID:
1520                                         case OIDOID:
1521                                         case FLOAT4OID:
1522                                         case FLOAT8OID:
1523                                         case NUMERICOID:
1524                                                 {
1525                                                         /*
1526                                                          * These types are printed without quotes unless
1527                                                          * they contain values that aren't accepted by the
1528                                                          * scanner unquoted (e.g., 'NaN').      Note that
1529                                                          * strtod() and friends might accept NaN, so we
1530                                                          * can't use that to test.
1531                                                          *
1532                                                          * In reality we only need to defend against
1533                                                          * infinity and NaN, so we need not get too crazy
1534                                                          * about pattern matching here.
1535                                                          */
1536                                                         const char *s = PQgetvalue(res, tuple, field);
1537
1538                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1539                                                                 archprintf(fout, "%s", s);
1540                                                         else
1541                                                                 archprintf(fout, "'%s'", s);
1542                                                 }
1543                                                 break;
1544
1545                                         case BITOID:
1546                                         case VARBITOID:
1547                                                 archprintf(fout, "B'%s'",
1548                                                                    PQgetvalue(res, tuple, field));
1549                                                 break;
1550
1551                                         case BOOLOID:
1552                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1553                                                         archprintf(fout, "true");
1554                                                 else
1555                                                         archprintf(fout, "false");
1556                                                 break;
1557
1558                                         default:
1559                                                 /* All other types are printed as string literals. */
1560                                                 resetPQExpBuffer(q);
1561                                                 appendStringLiteralAH(q,
1562                                                                                           PQgetvalue(res, tuple, field),
1563                                                                                           fout);
1564                                                 archputs(q->data, fout);
1565                                                 break;
1566                                 }
1567                         }
1568                         archprintf(fout, ");\n");
1569                 }
1570
1571                 if (PQntuples(res) <= 0)
1572                 {
1573                         PQclear(res);
1574                         break;
1575                 }
1576                 PQclear(res);
1577         }
1578
1579         archprintf(fout, "\n\n");
1580
1581         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1582
1583         destroyPQExpBuffer(q);
1584         return 1;
1585 }
1586
1587
1588 /*
1589  * dumpTableData -
1590  *        dump the contents of a single table
1591  *
1592  * Actually, this just makes an ArchiveEntry for the table contents.
1593  */
1594 static void
1595 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1596 {
1597         TableInfo  *tbinfo = tdinfo->tdtable;
1598         PQExpBuffer copyBuf = createPQExpBuffer();
1599         DataDumperPtr dumpFn;
1600         char       *copyStmt;
1601
1602         /* don't do anything if the data isn't wanted */
1603         if (!tbinfo->dobj.dumpdata)
1604                 return;
1605
1606         if (!dump_inserts)
1607         {
1608                 /* Dump/restore using COPY */
1609                 dumpFn = dumpTableData_copy;
1610                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1611                 appendPQExpBuffer(copyBuf, "COPY %s ",
1612                                                   fmtId(tbinfo->dobj.name));
1613                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1614                                                   fmtCopyColumnList(tbinfo),
1615                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1616                 copyStmt = copyBuf->data;
1617         }
1618         else
1619         {
1620                 /* Restore using INSERT */
1621                 dumpFn = dumpTableData_insert;
1622                 copyStmt = NULL;
1623         }
1624
1625         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1626                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1627                                  NULL, tbinfo->rolname,
1628                                  false, "TABLE DATA", SECTION_DATA,
1629                                  "", "", copyStmt,
1630                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1631                                  dumpFn, tdinfo);
1632
1633         destroyPQExpBuffer(copyBuf);
1634 }
1635
1636 /*
1637  * getTableData -
1638  *        set up dumpable objects representing the contents of tables
1639  */
1640 static void
1641 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1642 {
1643         int                     i;
1644
1645         for (i = 0; i < numTables; i++)
1646         {
1647                 /* Skip VIEWs (no data to dump) */
1648                 if (tblinfo[i].relkind == RELKIND_VIEW)
1649                         continue;
1650                 /* Skip SEQUENCEs (handled elsewhere) */
1651                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1652                         continue;
1653                 /* Skip FOREIGN TABLEs (no data to dump) */
1654                 if (tblinfo[i].relkind == RELKIND_FOREIGN_TABLE)
1655                         continue;
1656                 /* Skip unlogged tables if so requested */
1657                 if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED
1658                         && no_unlogged_table_data)
1659                         continue;
1660
1661                 if (tblinfo[i].dobj.dump && tblinfo[i].dataObj == NULL)
1662                         makeTableDataInfo(&(tblinfo[i]), oids);
1663         }
1664 }
1665
1666 /*
1667  * Make a dumpable object for the data of this specific table
1668  */
1669 static void
1670 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1671 {
1672         TableDataInfo *tdinfo;
1673
1674         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1675
1676         tdinfo->dobj.objType = DO_TABLE_DATA;
1677
1678         /*
1679          * Note: use tableoid 0 so that this object won't be mistaken for
1680          * something that pg_depend entries apply to.
1681          */
1682         tdinfo->dobj.catId.tableoid = 0;
1683         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1684         AssignDumpId(&tdinfo->dobj);
1685         tdinfo->dobj.name = tbinfo->dobj.name;
1686         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1687         tdinfo->tdtable = tbinfo;
1688         tdinfo->oids = oids;
1689         tdinfo->filtercond = NULL;      /* might get set later */
1690         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1691
1692         tbinfo->dataObj = tdinfo;
1693 }
1694
1695 /*
1696  * getTableDataFKConstraints -
1697  *        add dump-order dependencies reflecting foreign key constraints
1698  *
1699  * This code is executed only in a data-only dump --- in schema+data dumps
1700  * we handle foreign key issues by not creating the FK constraints until
1701  * after the data is loaded.  In a data-only dump, however, we want to
1702  * order the table data objects in such a way that a table's referenced
1703  * tables are restored first.  (In the presence of circular references or
1704  * self-references this may be impossible; we'll detect and complain about
1705  * that during the dependency sorting step.)
1706  */
1707 static void
1708 getTableDataFKConstraints(void)
1709 {
1710         DumpableObject **dobjs;
1711         int                     numObjs;
1712         int                     i;
1713
1714         /* Search through all the dumpable objects for FK constraints */
1715         getDumpableObjects(&dobjs, &numObjs);
1716         for (i = 0; i < numObjs; i++)
1717         {
1718                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1719                 {
1720                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1721                         TableInfo  *ftable;
1722
1723                         /* Not interesting unless both tables are to be dumped */
1724                         if (cinfo->contable == NULL ||
1725                                 cinfo->contable->dataObj == NULL)
1726                                 continue;
1727                         ftable = findTableByOid(cinfo->confrelid);
1728                         if (ftable == NULL ||
1729                                 ftable->dataObj == NULL)
1730                                 continue;
1731
1732                         /*
1733                          * Okay, make referencing table's TABLE_DATA object depend on the
1734                          * referenced table's TABLE_DATA object.
1735                          */
1736                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1737                                                                 ftable->dataObj->dobj.dumpId);
1738                 }
1739         }
1740         free(dobjs);
1741 }
1742
1743
1744 /*
1745  * guessConstraintInheritance:
1746  *      In pre-8.4 databases, we can't tell for certain which constraints
1747  *      are inherited.  We assume a CHECK constraint is inherited if its name
1748  *      matches the name of any constraint in the parent.  Originally this code
1749  *      tried to compare the expression texts, but that can fail for various
1750  *      reasons --- for example, if the parent and child tables are in different
1751  *      schemas, reverse-listing of function calls may produce different text
1752  *      (schema-qualified or not) depending on search path.
1753  *
1754  *      In 8.4 and up we can rely on the conislocal field to decide which
1755  *      constraints must be dumped; much safer.
1756  *
1757  *      This function assumes all conislocal flags were initialized to TRUE.
1758  *      It clears the flag on anything that seems to be inherited.
1759  */
1760 static void
1761 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1762 {
1763         int                     i,
1764                                 j,
1765                                 k;
1766
1767         for (i = 0; i < numTables; i++)
1768         {
1769                 TableInfo  *tbinfo = &(tblinfo[i]);
1770                 int                     numParents;
1771                 TableInfo **parents;
1772                 TableInfo  *parent;
1773
1774                 /* Sequences and views never have parents */
1775                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1776                         tbinfo->relkind == RELKIND_VIEW)
1777                         continue;
1778
1779                 /* Don't bother computing anything for non-target tables, either */
1780                 if (!tbinfo->dobj.dump)
1781                         continue;
1782
1783                 numParents = tbinfo->numParents;
1784                 parents = tbinfo->parents;
1785
1786                 if (numParents == 0)
1787                         continue;                       /* nothing to see here, move along */
1788
1789                 /* scan for inherited CHECK constraints */
1790                 for (j = 0; j < tbinfo->ncheck; j++)
1791                 {
1792                         ConstraintInfo *constr;
1793
1794                         constr = &(tbinfo->checkexprs[j]);
1795
1796                         for (k = 0; k < numParents; k++)
1797                         {
1798                                 int                     l;
1799
1800                                 parent = parents[k];
1801                                 for (l = 0; l < parent->ncheck; l++)
1802                                 {
1803                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1804
1805                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1806                                         {
1807                                                 constr->conislocal = false;
1808                                                 break;
1809                                         }
1810                                 }
1811                                 if (!constr->conislocal)
1812                                         break;
1813                         }
1814                 }
1815         }
1816 }
1817
1818
1819 /*
1820  * dumpDatabase:
1821  *      dump the database definition
1822  */
1823 static void
1824 dumpDatabase(Archive *fout)
1825 {
1826         PQExpBuffer dbQry = createPQExpBuffer();
1827         PQExpBuffer delQry = createPQExpBuffer();
1828         PQExpBuffer creaQry = createPQExpBuffer();
1829         PGresult   *res;
1830         int                     ntups;
1831         int                     i_tableoid,
1832                                 i_oid,
1833                                 i_dba,
1834                                 i_encoding,
1835                                 i_collate,
1836                                 i_ctype,
1837                                 i_frozenxid,
1838                                 i_tablespace;
1839         CatalogId       dbCatId;
1840         DumpId          dbDumpId;
1841         const char *datname,
1842                            *dba,
1843                            *encoding,
1844                            *collate,
1845                            *ctype,
1846                            *tablespace;
1847         uint32          frozenxid;
1848
1849         datname = PQdb(g_conn);
1850
1851         if (g_verbose)
1852                 write_msg(NULL, "saving database definition\n");
1853
1854         /* Make sure we are in proper schema */
1855         selectSourceSchema(fout, "pg_catalog");
1856
1857         /* Get the database owner and parameters from pg_database */
1858         if (fout->remoteVersion >= 80400)
1859         {
1860                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1861                                                   "(%s datdba) AS dba, "
1862                                                   "pg_encoding_to_char(encoding) AS encoding, "
1863                                                   "datcollate, datctype, datfrozenxid, "
1864                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1865                                           "shobj_description(oid, 'pg_database') AS description "
1866
1867                                                   "FROM pg_database "
1868                                                   "WHERE datname = ",
1869                                                   username_subquery);
1870                 appendStringLiteralAH(dbQry, datname, fout);
1871         }
1872         else if (fout->remoteVersion >= 80200)
1873         {
1874                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1875                                                   "(%s datdba) AS dba, "
1876                                                   "pg_encoding_to_char(encoding) AS encoding, "
1877                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1878                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1879                                           "shobj_description(oid, 'pg_database') AS description "
1880
1881                                                   "FROM pg_database "
1882                                                   "WHERE datname = ",
1883                                                   username_subquery);
1884                 appendStringLiteralAH(dbQry, datname, fout);
1885         }
1886         else if (fout->remoteVersion >= 80000)
1887         {
1888                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1889                                                   "(%s datdba) AS dba, "
1890                                                   "pg_encoding_to_char(encoding) AS encoding, "
1891                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1892                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1893                                                   "FROM pg_database "
1894                                                   "WHERE datname = ",
1895                                                   username_subquery);
1896                 appendStringLiteralAH(dbQry, datname, fout);
1897         }
1898         else if (fout->remoteVersion >= 70100)
1899         {
1900                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1901                                                   "(%s datdba) AS dba, "
1902                                                   "pg_encoding_to_char(encoding) AS encoding, "
1903                                                   "NULL AS datcollate, NULL AS datctype, "
1904                                                   "0 AS datfrozenxid, "
1905                                                   "NULL AS tablespace "
1906                                                   "FROM pg_database "
1907                                                   "WHERE datname = ",
1908                                                   username_subquery);
1909                 appendStringLiteralAH(dbQry, datname, fout);
1910         }
1911         else
1912         {
1913                 appendPQExpBuffer(dbQry, "SELECT "
1914                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1915                                                   "oid, "
1916                                                   "(%s datdba) AS dba, "
1917                                                   "pg_encoding_to_char(encoding) AS encoding, "
1918                                                   "NULL AS datcollate, NULL AS datctype, "
1919                                                   "0 AS datfrozenxid, "
1920                                                   "NULL AS tablespace "
1921                                                   "FROM pg_database "
1922                                                   "WHERE datname = ",
1923                                                   username_subquery);
1924                 appendStringLiteralAH(dbQry, datname, fout);
1925         }
1926
1927         res = ExecuteSqlQuery(fout, dbQry->data, PGRES_TUPLES_OK);
1928
1929         ntups = PQntuples(res);
1930
1931         if (ntups <= 0)
1932         {
1933                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1934                                   datname);
1935                 exit_nicely();
1936         }
1937
1938         if (ntups != 1)
1939         {
1940                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1941                                   ntups, datname);
1942                 exit_nicely();
1943         }
1944
1945         i_tableoid = PQfnumber(res, "tableoid");
1946         i_oid = PQfnumber(res, "oid");
1947         i_dba = PQfnumber(res, "dba");
1948         i_encoding = PQfnumber(res, "encoding");
1949         i_collate = PQfnumber(res, "datcollate");
1950         i_ctype = PQfnumber(res, "datctype");
1951         i_frozenxid = PQfnumber(res, "datfrozenxid");
1952         i_tablespace = PQfnumber(res, "tablespace");
1953
1954         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1955         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1956         dba = PQgetvalue(res, 0, i_dba);
1957         encoding = PQgetvalue(res, 0, i_encoding);
1958         collate = PQgetvalue(res, 0, i_collate);
1959         ctype = PQgetvalue(res, 0, i_ctype);
1960         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1961         tablespace = PQgetvalue(res, 0, i_tablespace);
1962
1963         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1964                                           fmtId(datname));
1965         if (strlen(encoding) > 0)
1966         {
1967                 appendPQExpBuffer(creaQry, " ENCODING = ");
1968                 appendStringLiteralAH(creaQry, encoding, fout);
1969         }
1970         if (strlen(collate) > 0)
1971         {
1972                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1973                 appendStringLiteralAH(creaQry, collate, fout);
1974         }
1975         if (strlen(ctype) > 0)
1976         {
1977                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1978                 appendStringLiteralAH(creaQry, ctype, fout);
1979         }
1980         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1981                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1982                                                   fmtId(tablespace));
1983         appendPQExpBuffer(creaQry, ";\n");
1984
1985         if (binary_upgrade)
1986         {
1987                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1988                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
1989                                                   "SET datfrozenxid = '%u'\n"
1990                                                   "WHERE        datname = ",
1991                                                   frozenxid);
1992                 appendStringLiteralAH(creaQry, datname, fout);
1993                 appendPQExpBuffer(creaQry, ";\n");
1994
1995         }
1996
1997         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1998                                           fmtId(datname));
1999
2000         dbDumpId = createDumpId();
2001
2002         ArchiveEntry(fout,
2003                                  dbCatId,               /* catalog ID */
2004                                  dbDumpId,              /* dump ID */
2005                                  datname,               /* Name */
2006                                  NULL,                  /* Namespace */
2007                                  NULL,                  /* Tablespace */
2008                                  dba,                   /* Owner */
2009                                  false,                 /* with oids */
2010                                  "DATABASE",    /* Desc */
2011                                  SECTION_PRE_DATA,              /* Section */
2012                                  creaQry->data, /* Create */
2013                                  delQry->data,  /* Del */
2014                                  NULL,                  /* Copy */
2015                                  NULL,                  /* Deps */
2016                                  0,                             /* # Deps */
2017                                  NULL,                  /* Dumper */
2018                                  NULL);                 /* Dumper Arg */
2019
2020         /*
2021          * pg_largeobject and pg_largeobject_metadata come from the old system
2022          * intact, so set their relfrozenxids.
2023          */
2024         if (binary_upgrade)
2025         {
2026                 PGresult   *lo_res;
2027                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2028                 PQExpBuffer loOutQry = createPQExpBuffer();
2029                 int                     i_relfrozenxid;
2030
2031                 /*
2032                  * pg_largeobject
2033                  */
2034                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2035                                                   "FROM pg_catalog.pg_class\n"
2036                                                   "WHERE oid = %u;\n",
2037                                                   LargeObjectRelationId);
2038
2039                 lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
2040
2041                 if (PQntuples(lo_res) != 1)
2042                 {
2043                         write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
2044                         exit_nicely();
2045                 }
2046
2047                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2048
2049                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2050                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2051                                                   "SET relfrozenxid = '%u'\n"
2052                                                   "WHERE oid = %u;\n",
2053                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2054                                                   LargeObjectRelationId);
2055                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2056                                          "pg_largeobject", NULL, NULL, "",
2057                                          false, "pg_largeobject", SECTION_PRE_DATA,
2058                                          loOutQry->data, "", NULL,
2059                                          NULL, 0,
2060                                          NULL, NULL);
2061
2062                 PQclear(lo_res);
2063
2064                 /*
2065                  * pg_largeobject_metadata
2066                  */
2067                 if (fout->remoteVersion >= 90000)
2068                 {
2069                         resetPQExpBuffer(loFrozenQry);
2070                         resetPQExpBuffer(loOutQry);
2071
2072                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2073                                                           "FROM pg_catalog.pg_class\n"
2074                                                           "WHERE oid = %u;\n",
2075                                                           LargeObjectMetadataRelationId);
2076
2077                         lo_res = ExecuteSqlQuery(fout, loFrozenQry->data, PGRES_TUPLES_OK);
2078
2079                         if (PQntuples(lo_res) != 1)
2080                         {
2081                                 write_msg(NULL, "dumpDatabase(): could not find pg_largeobject_metadata.relfrozenxid\n");
2082                                 exit_nicely();
2083                         }
2084
2085                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2086
2087                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2088                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2089                                                           "SET relfrozenxid = '%u'\n"
2090                                                           "WHERE oid = %u;\n",
2091                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2092                                                           LargeObjectMetadataRelationId);
2093                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2094                                                  "pg_largeobject_metadata", NULL, NULL, "",
2095                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2096                                                  loOutQry->data, "", NULL,
2097                                                  NULL, 0,
2098                                                  NULL, NULL);
2099
2100                         PQclear(lo_res);
2101                 }
2102
2103                 destroyPQExpBuffer(loFrozenQry);
2104                 destroyPQExpBuffer(loOutQry);
2105         }
2106
2107         /* Dump DB comment if any */
2108         if (fout->remoteVersion >= 80200)
2109         {
2110                 /*
2111                  * 8.2 keeps comments on shared objects in a shared table, so we
2112                  * cannot use the dumpComment used for other database objects.
2113                  */
2114                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2115
2116                 if (comment && strlen(comment))
2117                 {
2118                         resetPQExpBuffer(dbQry);
2119
2120                         /*
2121                          * Generates warning when loaded into a differently-named
2122                          * database.
2123                          */
2124                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2125                         appendStringLiteralAH(dbQry, comment, fout);
2126                         appendPQExpBuffer(dbQry, ";\n");
2127
2128                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2129                                                  dba, false, "COMMENT", SECTION_NONE,
2130                                                  dbQry->data, "", NULL,
2131                                                  &dbDumpId, 1, NULL, NULL);
2132                 }
2133         }
2134         else
2135         {
2136                 resetPQExpBuffer(dbQry);
2137                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2138                 dumpComment(fout, dbQry->data, NULL, "",
2139                                         dbCatId, 0, dbDumpId);
2140         }
2141
2142         PQclear(res);
2143
2144         /* Dump shared security label. */
2145         if (!no_security_labels && fout->remoteVersion >= 90200)
2146         {
2147                 PQExpBuffer seclabelQry = createPQExpBuffer();
2148
2149                 buildShSecLabelQuery(g_conn, "pg_database", dbCatId.oid, seclabelQry);
2150                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2151                 resetPQExpBuffer(seclabelQry);
2152                 emitShSecLabels(g_conn, res, seclabelQry, "DATABASE", datname);
2153                 if (strlen(seclabelQry->data))
2154                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2155                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2156                                                  seclabelQry->data, "", NULL,
2157                                                  &dbDumpId, 1, NULL, NULL);
2158                 destroyPQExpBuffer(seclabelQry);
2159         }
2160
2161         destroyPQExpBuffer(dbQry);
2162         destroyPQExpBuffer(delQry);
2163         destroyPQExpBuffer(creaQry);
2164 }
2165
2166
2167 /*
2168  * dumpEncoding: put the correct encoding into the archive
2169  */
2170 static void
2171 dumpEncoding(Archive *AH)
2172 {
2173         const char *encname = pg_encoding_to_char(AH->encoding);
2174         PQExpBuffer qry = createPQExpBuffer();
2175
2176         if (g_verbose)
2177                 write_msg(NULL, "saving encoding = %s\n", encname);
2178
2179         appendPQExpBuffer(qry, "SET client_encoding = ");
2180         appendStringLiteralAH(qry, encname, AH);
2181         appendPQExpBuffer(qry, ";\n");
2182
2183         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2184                                  "ENCODING", NULL, NULL, "",
2185                                  false, "ENCODING", SECTION_PRE_DATA,
2186                                  qry->data, "", NULL,
2187                                  NULL, 0,
2188                                  NULL, NULL);
2189
2190         destroyPQExpBuffer(qry);
2191 }
2192
2193
2194 /*
2195  * dumpStdStrings: put the correct escape string behavior into the archive
2196  */
2197 static void
2198 dumpStdStrings(Archive *AH)
2199 {
2200         const char *stdstrings = AH->std_strings ? "on" : "off";
2201         PQExpBuffer qry = createPQExpBuffer();
2202
2203         if (g_verbose)
2204                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2205                                   stdstrings);
2206
2207         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2208                                           stdstrings);
2209
2210         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2211                                  "STDSTRINGS", NULL, NULL, "",
2212                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2213                                  qry->data, "", NULL,
2214                                  NULL, 0,
2215                                  NULL, NULL);
2216
2217         destroyPQExpBuffer(qry);
2218 }
2219
2220
2221 /*
2222  * getBlobs:
2223  *      Collect schema-level data about large objects
2224  */
2225 static void
2226 getBlobs(Archive *fout)
2227 {
2228         PQExpBuffer blobQry = createPQExpBuffer();
2229         BlobInfo   *binfo;
2230         DumpableObject *bdata;
2231         PGresult   *res;
2232         int                     ntups;
2233         int                     i;
2234
2235         /* Verbose message */
2236         if (g_verbose)
2237                 write_msg(NULL, "reading large objects\n");
2238
2239         /* Make sure we are in proper schema */
2240         selectSourceSchema(fout, "pg_catalog");
2241
2242         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2243         if (fout->remoteVersion >= 90000)
2244                 appendPQExpBuffer(blobQry,
2245                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2246                                                   " FROM pg_largeobject_metadata",
2247                                                   username_subquery);
2248         else if (fout->remoteVersion >= 70100)
2249                 appendPQExpBuffer(blobQry,
2250                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2251                                                   " FROM pg_largeobject");
2252         else
2253                 appendPQExpBuffer(blobQry,
2254                                                   "SELECT oid, NULL::oid, NULL::oid"
2255                                                   " FROM pg_class WHERE relkind = 'l'");
2256
2257         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2258
2259         ntups = PQntuples(res);
2260         if (ntups > 0)
2261         {
2262                 /*
2263                  * Each large object has its own BLOB archive entry.
2264                  */
2265                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2266
2267                 for (i = 0; i < ntups; i++)
2268                 {
2269                         binfo[i].dobj.objType = DO_BLOB;
2270                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2271                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2272                         AssignDumpId(&binfo[i].dobj);
2273
2274                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2275                         if (!PQgetisnull(res, i, 1))
2276                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2277                         else
2278                                 binfo[i].rolname = "";
2279                         if (!PQgetisnull(res, i, 2))
2280                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2281                         else
2282                                 binfo[i].blobacl = NULL;
2283                 }
2284
2285                 /*
2286                  * If we have any large objects, a "BLOBS" archive entry is needed.
2287                  * This is just a placeholder for sorting; it carries no data now.
2288                  */
2289                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2290                 bdata->objType = DO_BLOB_DATA;
2291                 bdata->catId = nilCatalogId;
2292                 AssignDumpId(bdata);
2293                 bdata->name = pg_strdup("BLOBS");
2294         }
2295
2296         PQclear(res);
2297         destroyPQExpBuffer(blobQry);
2298 }
2299
2300 /*
2301  * dumpBlob
2302  *
2303  * dump the definition (metadata) of the given large object
2304  */
2305 static void
2306 dumpBlob(Archive *fout, BlobInfo *binfo)
2307 {
2308         PQExpBuffer cquery = createPQExpBuffer();
2309         PQExpBuffer dquery = createPQExpBuffer();
2310
2311         appendPQExpBuffer(cquery,
2312                                           "SELECT pg_catalog.lo_create('%s');\n",
2313                                           binfo->dobj.name);
2314
2315         appendPQExpBuffer(dquery,
2316                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2317                                           binfo->dobj.name);
2318
2319         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2320                                  binfo->dobj.name,
2321                                  NULL, NULL,
2322                                  binfo->rolname, false,
2323                                  "BLOB", SECTION_PRE_DATA,
2324                                  cquery->data, dquery->data, NULL,
2325                                  binfo->dobj.dependencies, binfo->dobj.nDeps,
2326                                  NULL, NULL);
2327
2328         /* set up tag for comment and/or ACL */
2329         resetPQExpBuffer(cquery);
2330         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2331
2332         /* Dump comment if any */
2333         dumpComment(fout, cquery->data,
2334                                 NULL, binfo->rolname,
2335                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2336
2337         /* Dump security label if any */
2338         dumpSecLabel(fout, cquery->data,
2339                                  NULL, binfo->rolname,
2340                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2341
2342         /* Dump ACL if any */
2343         if (binfo->blobacl)
2344                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2345                                 binfo->dobj.name, NULL, cquery->data,
2346                                 NULL, binfo->rolname, binfo->blobacl);
2347
2348         destroyPQExpBuffer(cquery);
2349         destroyPQExpBuffer(dquery);
2350 }
2351
2352 /*
2353  * dumpBlobs:
2354  *      dump the data contents of all large objects
2355  */
2356 static int
2357 dumpBlobs(Archive *fout, void *arg)
2358 {
2359         const char *blobQry;
2360         const char *blobFetchQry;
2361         PGresult   *res;
2362         char            buf[LOBBUFSIZE];
2363         int                     ntups;
2364         int                     i;
2365         int                     cnt;
2366
2367         if (g_verbose)
2368                 write_msg(NULL, "saving large objects\n");
2369
2370         /* Make sure we are in proper schema */
2371         selectSourceSchema(fout, "pg_catalog");
2372
2373         /*
2374          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2375          * the already-in-memory dumpable objects instead...
2376          */
2377         if (fout->remoteVersion >= 90000)
2378                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2379         else if (fout->remoteVersion >= 70100)
2380                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2381         else
2382                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2383
2384         ExecuteSqlStatement(fout, blobQry);
2385
2386         /* Command to fetch from cursor */
2387         blobFetchQry = "FETCH 1000 IN bloboid";
2388
2389         do
2390         {
2391                 /* Do a fetch */
2392                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2393
2394                 /* Process the tuples, if any */
2395                 ntups = PQntuples(res);
2396                 for (i = 0; i < ntups; i++)
2397                 {
2398                         Oid                     blobOid;
2399                         int                     loFd;
2400
2401                         blobOid = atooid(PQgetvalue(res, i, 0));
2402                         /* Open the BLOB */
2403                         loFd = lo_open(g_conn, blobOid, INV_READ);
2404                         if (loFd == -1)
2405                         {
2406                                 write_msg(NULL, "could not open large object %u: %s",
2407                                                   blobOid, PQerrorMessage(g_conn));
2408                                 exit_nicely();
2409                         }
2410
2411                         StartBlob(fout, blobOid);
2412
2413                         /* Now read it in chunks, sending data to archive */
2414                         do
2415                         {
2416                                 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
2417                                 if (cnt < 0)
2418                                 {
2419                                         write_msg(NULL, "error reading large object %u: %s",
2420                                                           blobOid, PQerrorMessage(g_conn));
2421                                         exit_nicely();
2422                                 }
2423
2424                                 WriteData(fout, buf, cnt);
2425                         } while (cnt > 0);
2426
2427                         lo_close(g_conn, loFd);
2428
2429                         EndBlob(fout, blobOid);
2430                 }
2431
2432                 PQclear(res);
2433         } while (ntups > 0);
2434
2435         PQclear(res);
2436
2437         return 1;
2438 }
2439
2440 static void
2441 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2442                                                                                  PQExpBuffer upgrade_buffer,
2443                                                                                  Oid pg_type_oid)
2444 {
2445         PQExpBuffer upgrade_query = createPQExpBuffer();
2446         int                     ntups;
2447         PGresult   *upgrade_res;
2448         Oid                     pg_type_array_oid;
2449
2450         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2451         appendPQExpBuffer(upgrade_buffer,
2452          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2453                                           pg_type_oid);
2454
2455         /* we only support old >= 8.3 for binary upgrades */
2456         appendPQExpBuffer(upgrade_query,
2457                                           "SELECT typarray "
2458                                           "FROM pg_catalog.pg_type "
2459                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2460                                           pg_type_oid);
2461
2462         upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
2463
2464         /* Expecting a single result only */
2465         ntups = PQntuples(upgrade_res);
2466         if (ntups != 1)
2467         {
2468                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2469                                                            "query returned %d rows instead of one: %s\n",
2470                                                                  ntups),
2471                                   ntups, upgrade_query->data);
2472                 exit_nicely();
2473         }
2474
2475         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2476
2477         if (OidIsValid(pg_type_array_oid))
2478         {
2479                 appendPQExpBuffer(upgrade_buffer,
2480                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2481                 appendPQExpBuffer(upgrade_buffer,
2482                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2483                                                   pg_type_array_oid);
2484         }
2485
2486         PQclear(upgrade_res);
2487         destroyPQExpBuffer(upgrade_query);
2488 }
2489
2490 static bool
2491 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2492                                                                                 PQExpBuffer upgrade_buffer,
2493                                                                                 Oid pg_rel_oid)
2494 {
2495         PQExpBuffer upgrade_query = createPQExpBuffer();
2496         int                     ntups;
2497         PGresult   *upgrade_res;
2498         Oid                     pg_type_oid;
2499         bool            toast_set = false;
2500
2501         /* we only support old >= 8.3 for binary upgrades */
2502         appendPQExpBuffer(upgrade_query,
2503                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2504                                           "FROM pg_catalog.pg_class c "
2505                                           "LEFT JOIN pg_catalog.pg_class t ON "
2506                                           "  (c.reltoastrelid = t.oid) "
2507                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2508                                           pg_rel_oid);
2509
2510         upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
2511
2512         /* Expecting a single result only */
2513         ntups = PQntuples(upgrade_res);
2514         if (ntups != 1)
2515         {
2516                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2517                                                            "query returned %d rows instead of one: %s\n",
2518                                                                  ntups),
2519                                   ntups, upgrade_query->data);
2520                 exit_nicely();
2521         }
2522
2523         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2524
2525         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2526                                                                                          pg_type_oid);
2527
2528         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2529         {
2530                 /* Toast tables do not have pg_type array rows */
2531                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2532                                                                                         PQfnumber(upgrade_res, "trel")));
2533
2534                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2535                 appendPQExpBuffer(upgrade_buffer,
2536                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2537                                                   pg_type_toast_oid);
2538
2539                 toast_set = true;
2540         }
2541
2542         PQclear(upgrade_res);
2543         destroyPQExpBuffer(upgrade_query);
2544
2545         return toast_set;
2546 }
2547
2548 static void
2549 binary_upgrade_set_pg_class_oids(Archive *fout,
2550                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2551                                                                  bool is_index)
2552 {
2553         PQExpBuffer upgrade_query = createPQExpBuffer();
2554         int                     ntups;
2555         PGresult   *upgrade_res;
2556         Oid                     pg_class_reltoastrelid;
2557         Oid                     pg_class_reltoastidxid;
2558
2559         appendPQExpBuffer(upgrade_query,
2560                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2561                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2562                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2563                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2564                                           pg_class_oid);
2565
2566         upgrade_res = ExecuteSqlQuery(fout, upgrade_query->data, PGRES_TUPLES_OK);
2567
2568         /* Expecting a single result only */
2569         ntups = PQntuples(upgrade_res);
2570         if (ntups != 1)
2571         {
2572                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2573                                                            "query returned %d rows instead of one: %s\n",
2574                                                                  ntups),
2575                                   ntups, upgrade_query->data);
2576                 exit_nicely();
2577         }
2578
2579         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2580         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2581
2582         appendPQExpBuffer(upgrade_buffer,
2583                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2584
2585         if (!is_index)
2586         {
2587                 appendPQExpBuffer(upgrade_buffer,
2588                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2589                                                   pg_class_oid);
2590                 /* only tables have toast tables, not indexes */
2591                 if (OidIsValid(pg_class_reltoastrelid))
2592                 {
2593                         /*
2594                          * One complexity is that the table definition might not require
2595                          * the creation of a TOAST table, and the TOAST table might have
2596                          * been created long after table creation, when the table was
2597                          * loaded with wide data.  By setting the TOAST oid we force
2598                          * creation of the TOAST heap and TOAST index by the backend so we
2599                          * can cleanly copy the files during binary upgrade.
2600                          */
2601
2602                         appendPQExpBuffer(upgrade_buffer,
2603                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2604                                                           pg_class_reltoastrelid);
2605
2606                         /* every toast table has an index */
2607                         appendPQExpBuffer(upgrade_buffer,
2608                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2609                                                           pg_class_reltoastidxid);
2610                 }
2611         }
2612         else
2613                 appendPQExpBuffer(upgrade_buffer,
2614                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2615                                                   pg_class_oid);
2616
2617         appendPQExpBuffer(upgrade_buffer, "\n");
2618
2619         PQclear(upgrade_res);
2620         destroyPQExpBuffer(upgrade_query);
2621 }
2622
2623 /*
2624  * If the DumpableObject is a member of an extension, add a suitable
2625  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2626  */
2627 static void
2628 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2629                                                                 DumpableObject *dobj,
2630                                                                 const char *objlabel)
2631 {
2632         DumpableObject *extobj = NULL;
2633         int                     i;
2634
2635         if (!dobj->ext_member)
2636                 return;
2637
2638         /*
2639          * Find the parent extension.  We could avoid this search if we wanted to
2640          * add a link field to DumpableObject, but the space costs of that would
2641          * be considerable.  We assume that member objects could only have a
2642          * direct dependency on their own extension, not any others.
2643          */
2644         for (i = 0; i < dobj->nDeps; i++)
2645         {
2646                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2647                 if (extobj && extobj->objType == DO_EXTENSION)
2648                         break;
2649                 extobj = NULL;
2650         }
2651         if (extobj == NULL)
2652         {
2653                 write_msg(NULL, "could not find parent extension for %s", objlabel);
2654                 exit_nicely();
2655         }
2656
2657         appendPQExpBuffer(upgrade_buffer,
2658           "\n-- For binary upgrade, handle extension membership the hard way\n");
2659         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2660                                           fmtId(extobj->name),
2661                                           objlabel);
2662 }
2663
2664 /*
2665  * getNamespaces:
2666  *        read all namespaces in the system catalogs and return them in the
2667  * NamespaceInfo* structure
2668  *
2669  *      numNamespaces is set to the number of namespaces read in
2670  */
2671 NamespaceInfo *
2672 getNamespaces(Archive *fout, int *numNamespaces)
2673 {
2674         PGresult   *res;
2675         int                     ntups;
2676         int                     i;
2677         PQExpBuffer query;
2678         NamespaceInfo *nsinfo;
2679         int                     i_tableoid;
2680         int                     i_oid;
2681         int                     i_nspname;
2682         int                     i_rolname;
2683         int                     i_nspacl;
2684
2685         /*
2686          * Before 7.3, there are no real namespaces; create two dummy entries, one
2687          * for user stuff and one for system stuff.
2688          */
2689         if (fout->remoteVersion < 70300)
2690         {
2691                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2692
2693                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2694                 nsinfo[0].dobj.catId.tableoid = 0;
2695                 nsinfo[0].dobj.catId.oid = 0;
2696                 AssignDumpId(&nsinfo[0].dobj);
2697                 nsinfo[0].dobj.name = pg_strdup("public");
2698                 nsinfo[0].rolname = pg_strdup("");
2699                 nsinfo[0].nspacl = pg_strdup("");
2700
2701                 selectDumpableNamespace(&nsinfo[0]);
2702
2703                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2704                 nsinfo[1].dobj.catId.tableoid = 0;
2705                 nsinfo[1].dobj.catId.oid = 1;
2706                 AssignDumpId(&nsinfo[1].dobj);
2707                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2708                 nsinfo[1].rolname = pg_strdup("");
2709                 nsinfo[1].nspacl = pg_strdup("");
2710
2711                 selectDumpableNamespace(&nsinfo[1]);
2712
2713                 g_namespaces = nsinfo;
2714                 g_numNamespaces = *numNamespaces = 2;
2715
2716                 return nsinfo;
2717         }
2718
2719         query = createPQExpBuffer();
2720
2721         /* Make sure we are in proper schema */
2722         selectSourceSchema(fout, "pg_catalog");
2723
2724         /*
2725          * we fetch all namespaces including system ones, so that every object we
2726          * read in can be linked to a containing namespace.
2727          */
2728         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2729                                           "(%s nspowner) AS rolname, "
2730                                           "nspacl FROM pg_namespace",
2731                                           username_subquery);
2732
2733         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2734
2735         ntups = PQntuples(res);
2736
2737         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2738
2739         i_tableoid = PQfnumber(res, "tableoid");
2740         i_oid = PQfnumber(res, "oid");
2741         i_nspname = PQfnumber(res, "nspname");
2742         i_rolname = PQfnumber(res, "rolname");
2743         i_nspacl = PQfnumber(res, "nspacl");
2744
2745         for (i = 0; i < ntups; i++)
2746         {
2747                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2748                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2749                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2750                 AssignDumpId(&nsinfo[i].dobj);
2751                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2752                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2753                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2754
2755                 /* Decide whether to dump this namespace */
2756                 selectDumpableNamespace(&nsinfo[i]);
2757
2758                 if (strlen(nsinfo[i].rolname) == 0)
2759                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2760                                           nsinfo[i].dobj.name);
2761         }
2762
2763         PQclear(res);
2764         destroyPQExpBuffer(query);
2765
2766         g_namespaces = nsinfo;
2767         g_numNamespaces = *numNamespaces = ntups;
2768
2769         return nsinfo;
2770 }
2771
2772 /*
2773  * findNamespace:
2774  *              given a namespace OID and an object OID, look up the info read by
2775  *              getNamespaces
2776  *
2777  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2778  * a system object or not.      In 7.3 and later there is no guessing.
2779  */
2780 static NamespaceInfo *
2781 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2782 {
2783         int                     i;
2784
2785         if (fout->remoteVersion >= 70300)
2786         {
2787                 for (i = 0; i < g_numNamespaces; i++)
2788                 {
2789                         NamespaceInfo *nsinfo = &g_namespaces[i];
2790
2791                         if (nsoid == nsinfo->dobj.catId.oid)
2792                                 return nsinfo;
2793                 }
2794                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2795                 exit_nicely();
2796         }
2797         else
2798         {
2799                 /* This code depends on the layout set up by getNamespaces. */
2800                 if (objoid > g_last_builtin_oid)
2801                         i = 0;                          /* user object */
2802                 else
2803                         i = 1;                          /* system object */
2804                 return &g_namespaces[i];
2805         }
2806
2807         return NULL;                            /* keep compiler quiet */
2808 }
2809
2810 /*
2811  * getExtensions:
2812  *        read all extensions in the system catalogs and return them in the
2813  * ExtensionInfo* structure
2814  *
2815  *      numExtensions is set to the number of extensions read in
2816  */
2817 ExtensionInfo *
2818 getExtensions(Archive *fout, int *numExtensions)
2819 {
2820         PGresult   *res;
2821         int                     ntups;
2822         int                     i;
2823         PQExpBuffer query;
2824         ExtensionInfo *extinfo;
2825         int                     i_tableoid;
2826         int                     i_oid;
2827         int                     i_extname;
2828         int                     i_nspname;
2829         int                     i_extrelocatable;
2830         int                     i_extversion;
2831         int                     i_extconfig;
2832         int                     i_extcondition;
2833
2834         /*
2835          * Before 9.1, there are no extensions.
2836          */
2837         if (fout->remoteVersion < 90100)
2838         {
2839                 *numExtensions = 0;
2840                 return NULL;
2841         }
2842
2843         query = createPQExpBuffer();
2844
2845         /* Make sure we are in proper schema */
2846         selectSourceSchema(fout, "pg_catalog");
2847
2848         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
2849                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
2850                                           "FROM pg_extension x "
2851                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
2852
2853         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2854
2855         ntups = PQntuples(res);
2856
2857         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
2858
2859         i_tableoid = PQfnumber(res, "tableoid");
2860         i_oid = PQfnumber(res, "oid");
2861         i_extname = PQfnumber(res, "extname");
2862         i_nspname = PQfnumber(res, "nspname");
2863         i_extrelocatable = PQfnumber(res, "extrelocatable");
2864         i_extversion = PQfnumber(res, "extversion");
2865         i_extconfig = PQfnumber(res, "extconfig");
2866         i_extcondition = PQfnumber(res, "extcondition");
2867
2868         for (i = 0; i < ntups; i++)
2869         {
2870                 extinfo[i].dobj.objType = DO_EXTENSION;
2871                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2872                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2873                 AssignDumpId(&extinfo[i].dobj);
2874                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
2875                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
2876                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
2877                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
2878                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
2879                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
2880
2881                 /* Decide whether we want to dump it */
2882                 selectDumpableExtension(&(extinfo[i]));
2883         }
2884
2885         PQclear(res);
2886         destroyPQExpBuffer(query);
2887
2888         *numExtensions = ntups;
2889
2890         return extinfo;
2891 }
2892
2893 /*
2894  * getTypes:
2895  *        read all types in the system catalogs and return them in the
2896  * TypeInfo* structure
2897  *
2898  *      numTypes is set to the number of types read in
2899  *
2900  * NB: this must run after getFuncs() because we assume we can do
2901  * findFuncByOid().
2902  */
2903 TypeInfo *
2904 getTypes(Archive *fout, int *numTypes)
2905 {
2906         PGresult   *res;
2907         int                     ntups;
2908         int                     i;
2909         PQExpBuffer query = createPQExpBuffer();
2910         TypeInfo   *tyinfo;
2911         ShellTypeInfo *stinfo;
2912         int                     i_tableoid;
2913         int                     i_oid;
2914         int                     i_typname;
2915         int                     i_typnamespace;
2916         int                     i_rolname;
2917         int                     i_typinput;
2918         int                     i_typoutput;
2919         int                     i_typelem;
2920         int                     i_typrelid;
2921         int                     i_typrelkind;
2922         int                     i_typtype;
2923         int                     i_typisdefined;
2924         int                     i_isarray;
2925
2926         /*
2927          * we include even the built-in types because those may be used as array
2928          * elements by user-defined types
2929          *
2930          * we filter out the built-in types when we dump out the types
2931          *
2932          * same approach for undefined (shell) types and array types
2933          *
2934          * Note: as of 8.3 we can reliably detect whether a type is an
2935          * auto-generated array type by checking the element type's typarray.
2936          * (Before that the test is capable of generating false positives.) We
2937          * still check for name beginning with '_', though, so as to avoid the
2938          * cost of the subselect probe for all standard types.  This would have to
2939          * be revisited if the backend ever allows renaming of array types.
2940          */
2941
2942         /* Make sure we are in proper schema */
2943         selectSourceSchema(fout, "pg_catalog");
2944
2945         if (fout->remoteVersion >= 80300)
2946         {
2947                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2948                                                   "typnamespace, "
2949                                                   "(%s typowner) AS rolname, "
2950                                                   "typinput::oid AS typinput, "
2951                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2952                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2953                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2954                                                   "typtype, typisdefined, "
2955                                                   "typname[0] = '_' AND typelem != 0 AND "
2956                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2957                                                   "FROM pg_type",
2958                                                   username_subquery);
2959         }
2960         else if (fout->remoteVersion >= 70300)
2961         {
2962                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2963                                                   "typnamespace, "
2964                                                   "(%s typowner) AS rolname, "
2965                                                   "typinput::oid AS typinput, "
2966                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2967                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2968                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2969                                                   "typtype, typisdefined, "
2970                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2971                                                   "FROM pg_type",
2972                                                   username_subquery);
2973         }
2974         else if (fout->remoteVersion >= 70100)
2975         {
2976                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2977                                                   "0::oid AS typnamespace, "
2978                                                   "(%s typowner) AS rolname, "
2979                                                   "typinput::oid AS typinput, "
2980                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2981                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2982                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2983                                                   "typtype, typisdefined, "
2984                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2985                                                   "FROM pg_type",
2986                                                   username_subquery);
2987         }
2988         else
2989         {
2990                 appendPQExpBuffer(query, "SELECT "
2991                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2992                                                   "oid, typname, "
2993                                                   "0::oid AS typnamespace, "
2994                                                   "(%s typowner) AS rolname, "
2995                                                   "typinput::oid AS typinput, "
2996                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2997                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2998                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2999                                                   "typtype, typisdefined, "
3000                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3001                                                   "FROM pg_type",
3002                                                   username_subquery);
3003         }
3004
3005         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3006
3007         ntups = PQntuples(res);
3008
3009         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3010
3011         i_tableoid = PQfnumber(res, "tableoid");
3012         i_oid = PQfnumber(res, "oid");
3013         i_typname = PQfnumber(res, "typname");
3014         i_typnamespace = PQfnumber(res, "typnamespace");
3015         i_rolname = PQfnumber(res, "rolname");
3016         i_typinput = PQfnumber(res, "typinput");
3017         i_typoutput = PQfnumber(res, "typoutput");
3018         i_typelem = PQfnumber(res, "typelem");
3019         i_typrelid = PQfnumber(res, "typrelid");
3020         i_typrelkind = PQfnumber(res, "typrelkind");
3021         i_typtype = PQfnumber(res, "typtype");
3022         i_typisdefined = PQfnumber(res, "typisdefined");
3023         i_isarray = PQfnumber(res, "isarray");
3024
3025         for (i = 0; i < ntups; i++)
3026         {
3027                 tyinfo[i].dobj.objType = DO_TYPE;
3028                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3029                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3030                 AssignDumpId(&tyinfo[i].dobj);
3031                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3032                 tyinfo[i].dobj.namespace =
3033                         findNamespace(fout,
3034                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3035                                                   tyinfo[i].dobj.catId.oid);
3036                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3037                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3038                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3039                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3040                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3041                 tyinfo[i].shellType = NULL;
3042
3043                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3044                         tyinfo[i].isDefined = true;
3045                 else
3046                         tyinfo[i].isDefined = false;
3047
3048                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3049                         tyinfo[i].isArray = true;
3050                 else
3051                         tyinfo[i].isArray = false;
3052
3053                 /* Decide whether we want to dump it */
3054                 selectDumpableType(&tyinfo[i]);
3055
3056                 /*
3057                  * If it's a domain, fetch info about its constraints, if any
3058                  */
3059                 tyinfo[i].nDomChecks = 0;
3060                 tyinfo[i].domChecks = NULL;
3061                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3062                         getDomainConstraints(fout, &(tyinfo[i]));
3063
3064                 /*
3065                  * If it's a base type, make a DumpableObject representing a shell
3066                  * definition of the type.      We will need to dump that ahead of the I/O
3067                  * functions for the type.  Similarly, range types need a shell
3068                  * definition in case they have a canonicalize function.
3069                  *
3070                  * Note: the shell type doesn't have a catId.  You might think it
3071                  * should copy the base type's catId, but then it might capture the
3072                  * pg_depend entries for the type, which we don't want.
3073                  */
3074                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3075                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3076                 {
3077                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3078                         stinfo->dobj.objType = DO_SHELL_TYPE;
3079                         stinfo->dobj.catId = nilCatalogId;
3080                         AssignDumpId(&stinfo->dobj);
3081                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3082                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3083                         stinfo->baseType = &(tyinfo[i]);
3084                         tyinfo[i].shellType = stinfo;
3085
3086                         /*
3087                          * Initially mark the shell type as not to be dumped.  We'll only
3088                          * dump it if the I/O or canonicalize functions need to be dumped;
3089                          * this is taken care of while sorting dependencies.
3090                          */
3091                         stinfo->dobj.dump = false;
3092
3093                         /*
3094                          * However, if dumping from pre-7.3, there will be no dependency
3095                          * info so we have to fake it here.  We only need to worry about
3096                          * typinput and typoutput since the other functions only exist
3097                          * post-7.3.
3098                          */
3099                         if (fout->remoteVersion < 70300)
3100                         {
3101                                 Oid                     typinput;
3102                                 Oid                     typoutput;
3103                                 FuncInfo   *funcInfo;
3104
3105                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3106                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3107
3108                                 funcInfo = findFuncByOid(typinput);
3109                                 if (funcInfo && funcInfo->dobj.dump)
3110                                 {
3111                                         /* base type depends on function */
3112                                         addObjectDependency(&tyinfo[i].dobj,
3113                                                                                 funcInfo->dobj.dumpId);
3114                                         /* function depends on shell type */
3115                                         addObjectDependency(&funcInfo->dobj,
3116                                                                                 stinfo->dobj.dumpId);
3117                                         /* mark shell type as to be dumped */
3118                                         stinfo->dobj.dump = true;
3119                                 }
3120
3121                                 funcInfo = findFuncByOid(typoutput);
3122                                 if (funcInfo && funcInfo->dobj.dump)
3123                                 {
3124                                         /* base type depends on function */
3125                                         addObjectDependency(&tyinfo[i].dobj,
3126                                                                                 funcInfo->dobj.dumpId);
3127                                         /* function depends on shell type */
3128                                         addObjectDependency(&funcInfo->dobj,
3129                                                                                 stinfo->dobj.dumpId);
3130                                         /* mark shell type as to be dumped */
3131                                         stinfo->dobj.dump = true;
3132                                 }
3133                         }
3134                 }
3135
3136                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3137                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3138                                           tyinfo[i].dobj.name);
3139         }
3140
3141         *numTypes = ntups;
3142
3143         PQclear(res);
3144
3145         destroyPQExpBuffer(query);
3146
3147         return tyinfo;
3148 }
3149
3150 /*
3151  * getOperators:
3152  *        read all operators in the system catalogs and return them in the
3153  * OprInfo* structure
3154  *
3155  *      numOprs is set to the number of operators read in
3156  */
3157 OprInfo *
3158 getOperators(Archive *fout, int *numOprs)
3159 {
3160         PGresult   *res;
3161         int                     ntups;
3162         int                     i;
3163         PQExpBuffer query = createPQExpBuffer();
3164         OprInfo    *oprinfo;
3165         int                     i_tableoid;
3166         int                     i_oid;
3167         int                     i_oprname;
3168         int                     i_oprnamespace;
3169         int                     i_rolname;
3170         int                     i_oprkind;
3171         int                     i_oprcode;
3172
3173         /*
3174          * find all operators, including builtin operators; we filter out
3175          * system-defined operators at dump-out time.
3176          */
3177
3178         /* Make sure we are in proper schema */
3179         selectSourceSchema(fout, "pg_catalog");
3180
3181         if (fout->remoteVersion >= 70300)
3182         {
3183                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3184                                                   "oprnamespace, "
3185                                                   "(%s oprowner) AS rolname, "
3186                                                   "oprkind, "
3187                                                   "oprcode::oid AS oprcode "
3188                                                   "FROM pg_operator",
3189                                                   username_subquery);
3190         }
3191         else if (fout->remoteVersion >= 70100)
3192         {
3193                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3194                                                   "0::oid AS oprnamespace, "
3195                                                   "(%s oprowner) AS rolname, "
3196                                                   "oprkind, "
3197                                                   "oprcode::oid AS oprcode "
3198                                                   "FROM pg_operator",
3199                                                   username_subquery);
3200         }
3201         else
3202         {
3203                 appendPQExpBuffer(query, "SELECT "
3204                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3205                                                   "oid, oprname, "
3206                                                   "0::oid AS oprnamespace, "
3207                                                   "(%s oprowner) AS rolname, "
3208                                                   "oprkind, "
3209                                                   "oprcode::oid AS oprcode "
3210                                                   "FROM pg_operator",
3211                                                   username_subquery);
3212         }
3213
3214         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3215
3216         ntups = PQntuples(res);
3217         *numOprs = ntups;
3218
3219         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3220
3221         i_tableoid = PQfnumber(res, "tableoid");
3222         i_oid = PQfnumber(res, "oid");
3223         i_oprname = PQfnumber(res, "oprname");
3224         i_oprnamespace = PQfnumber(res, "oprnamespace");
3225         i_rolname = PQfnumber(res, "rolname");
3226         i_oprkind = PQfnumber(res, "oprkind");
3227         i_oprcode = PQfnumber(res, "oprcode");
3228
3229         for (i = 0; i < ntups; i++)
3230         {
3231                 oprinfo[i].dobj.objType = DO_OPERATOR;
3232                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3233                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3234                 AssignDumpId(&oprinfo[i].dobj);
3235                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3236                 oprinfo[i].dobj.namespace =
3237                         findNamespace(fout,
3238                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3239                                                   oprinfo[i].dobj.catId.oid);
3240                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3241                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3242                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3243
3244                 /* Decide whether we want to dump it */
3245                 selectDumpableObject(&(oprinfo[i].dobj));
3246
3247                 if (strlen(oprinfo[i].rolname) == 0)
3248                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3249                                           oprinfo[i].dobj.name);
3250         }
3251
3252         PQclear(res);
3253
3254         destroyPQExpBuffer(query);
3255
3256         return oprinfo;
3257 }
3258
3259 /*
3260  * getCollations:
3261  *        read all collations in the system catalogs and return them in the
3262  * CollInfo* structure
3263  *
3264  *      numCollations is set to the number of collations read in
3265  */
3266 CollInfo *
3267 getCollations(Archive *fout, int *numCollations)
3268 {
3269         PGresult   *res;
3270         int                     ntups;
3271         int                     i;
3272         PQExpBuffer query = createPQExpBuffer();
3273         CollInfo   *collinfo;
3274         int                     i_tableoid;
3275         int                     i_oid;
3276         int                     i_collname;
3277         int                     i_collnamespace;
3278         int                     i_rolname;
3279
3280         /* Collations didn't exist pre-9.1 */
3281         if (fout->remoteVersion < 90100)
3282         {
3283                 *numCollations = 0;
3284                 return NULL;
3285         }
3286
3287         /*
3288          * find all collations, including builtin collations; we filter out
3289          * system-defined collations at dump-out time.
3290          */
3291
3292         /* Make sure we are in proper schema */
3293         selectSourceSchema(fout, "pg_catalog");
3294
3295         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3296                                           "collnamespace, "
3297                                           "(%s collowner) AS rolname "
3298                                           "FROM pg_collation",
3299                                           username_subquery);
3300
3301         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3302
3303         ntups = PQntuples(res);
3304         *numCollations = ntups;
3305
3306         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3307
3308         i_tableoid = PQfnumber(res, "tableoid");
3309         i_oid = PQfnumber(res, "oid");
3310         i_collname = PQfnumber(res, "collname");
3311         i_collnamespace = PQfnumber(res, "collnamespace");
3312         i_rolname = PQfnumber(res, "rolname");
3313
3314         for (i = 0; i < ntups; i++)
3315         {
3316                 collinfo[i].dobj.objType = DO_COLLATION;
3317                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3318                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3319                 AssignDumpId(&collinfo[i].dobj);
3320                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3321                 collinfo[i].dobj.namespace =
3322                         findNamespace(fout,
3323                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3324                                                   collinfo[i].dobj.catId.oid);
3325                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3326
3327                 /* Decide whether we want to dump it */
3328                 selectDumpableObject(&(collinfo[i].dobj));
3329         }
3330
3331         PQclear(res);
3332
3333         destroyPQExpBuffer(query);
3334
3335         return collinfo;
3336 }
3337
3338 /*
3339  * getConversions:
3340  *        read all conversions in the system catalogs and return them in the
3341  * ConvInfo* structure
3342  *
3343  *      numConversions is set to the number of conversions read in
3344  */
3345 ConvInfo *
3346 getConversions(Archive *fout, int *numConversions)
3347 {
3348         PGresult   *res;
3349         int                     ntups;
3350         int                     i;
3351         PQExpBuffer query = createPQExpBuffer();
3352         ConvInfo   *convinfo;
3353         int                     i_tableoid;
3354         int                     i_oid;
3355         int                     i_conname;
3356         int                     i_connamespace;
3357         int                     i_rolname;
3358
3359         /* Conversions didn't exist pre-7.3 */
3360         if (fout->remoteVersion < 70300)
3361         {
3362                 *numConversions = 0;
3363                 return NULL;
3364         }
3365
3366         /*
3367          * find all conversions, including builtin conversions; we filter out
3368          * system-defined conversions at dump-out time.
3369          */
3370
3371         /* Make sure we are in proper schema */
3372         selectSourceSchema(fout, "pg_catalog");
3373
3374         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3375                                           "connamespace, "
3376                                           "(%s conowner) AS rolname "
3377                                           "FROM pg_conversion",
3378                                           username_subquery);
3379
3380         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3381
3382         ntups = PQntuples(res);
3383         *numConversions = ntups;
3384
3385         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3386
3387         i_tableoid = PQfnumber(res, "tableoid");
3388         i_oid = PQfnumber(res, "oid");
3389         i_conname = PQfnumber(res, "conname");
3390         i_connamespace = PQfnumber(res, "connamespace");
3391         i_rolname = PQfnumber(res, "rolname");
3392
3393         for (i = 0; i < ntups; i++)
3394         {
3395                 convinfo[i].dobj.objType = DO_CONVERSION;
3396                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3397                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3398                 AssignDumpId(&convinfo[i].dobj);
3399                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3400                 convinfo[i].dobj.namespace =
3401                         findNamespace(fout,
3402                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3403                                                   convinfo[i].dobj.catId.oid);
3404                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3405
3406                 /* Decide whether we want to dump it */
3407                 selectDumpableObject(&(convinfo[i].dobj));
3408         }
3409
3410         PQclear(res);
3411
3412         destroyPQExpBuffer(query);
3413
3414         return convinfo;
3415 }
3416
3417 /*
3418  * getOpclasses:
3419  *        read all opclasses in the system catalogs and return them in the
3420  * OpclassInfo* structure
3421  *
3422  *      numOpclasses is set to the number of opclasses read in
3423  */
3424 OpclassInfo *
3425 getOpclasses(Archive *fout, int *numOpclasses)
3426 {
3427         PGresult   *res;
3428         int                     ntups;
3429         int                     i;
3430         PQExpBuffer query = createPQExpBuffer();
3431         OpclassInfo *opcinfo;
3432         int                     i_tableoid;
3433         int                     i_oid;
3434         int                     i_opcname;
3435         int                     i_opcnamespace;
3436         int                     i_rolname;
3437
3438         /*
3439          * find all opclasses, including builtin opclasses; we filter out
3440          * system-defined opclasses at dump-out time.
3441          */
3442
3443         /* Make sure we are in proper schema */
3444         selectSourceSchema(fout, "pg_catalog");
3445
3446         if (fout->remoteVersion >= 70300)
3447         {
3448                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3449                                                   "opcnamespace, "
3450                                                   "(%s opcowner) AS rolname "
3451                                                   "FROM pg_opclass",
3452                                                   username_subquery);
3453         }
3454         else if (fout->remoteVersion >= 70100)
3455         {
3456                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3457                                                   "0::oid AS opcnamespace, "
3458                                                   "''::name AS rolname "
3459                                                   "FROM pg_opclass");
3460         }
3461         else
3462         {
3463                 appendPQExpBuffer(query, "SELECT "
3464                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3465                                                   "oid, opcname, "
3466                                                   "0::oid AS opcnamespace, "
3467                                                   "''::name AS rolname "
3468                                                   "FROM pg_opclass");
3469         }
3470
3471         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3472
3473         ntups = PQntuples(res);
3474         *numOpclasses = ntups;
3475
3476         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3477
3478         i_tableoid = PQfnumber(res, "tableoid");
3479         i_oid = PQfnumber(res, "oid");
3480         i_opcname = PQfnumber(res, "opcname");
3481         i_opcnamespace = PQfnumber(res, "opcnamespace");
3482         i_rolname = PQfnumber(res, "rolname");
3483
3484         for (i = 0; i < ntups; i++)
3485         {
3486                 opcinfo[i].dobj.objType = DO_OPCLASS;
3487                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3488                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3489                 AssignDumpId(&opcinfo[i].dobj);
3490                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3491                 opcinfo[i].dobj.namespace =
3492                         findNamespace(fout,
3493                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3494                                                   opcinfo[i].dobj.catId.oid);
3495                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3496
3497                 /* Decide whether we want to dump it */
3498                 selectDumpableObject(&(opcinfo[i].dobj));
3499
3500                 if (fout->remoteVersion >= 70300)
3501                 {
3502                         if (strlen(opcinfo[i].rolname) == 0)
3503                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3504                                                   opcinfo[i].dobj.name);
3505                 }
3506         }
3507
3508         PQclear(res);
3509
3510         destroyPQExpBuffer(query);
3511
3512         return opcinfo;
3513 }
3514
3515 /*
3516  * getOpfamilies:
3517  *        read all opfamilies in the system catalogs and return them in the
3518  * OpfamilyInfo* structure
3519  *
3520  *      numOpfamilies is set to the number of opfamilies read in
3521  */
3522 OpfamilyInfo *
3523 getOpfamilies(Archive *fout, int *numOpfamilies)
3524 {
3525         PGresult   *res;
3526         int                     ntups;
3527         int                     i;
3528         PQExpBuffer query;
3529         OpfamilyInfo *opfinfo;
3530         int                     i_tableoid;
3531         int                     i_oid;
3532         int                     i_opfname;
3533         int                     i_opfnamespace;
3534         int                     i_rolname;
3535
3536         /* Before 8.3, there is no separate concept of opfamilies */
3537         if (fout->remoteVersion < 80300)
3538         {
3539                 *numOpfamilies = 0;
3540                 return NULL;
3541         }
3542
3543         query = createPQExpBuffer();
3544
3545         /*
3546          * find all opfamilies, including builtin opfamilies; we filter out
3547          * system-defined opfamilies at dump-out time.
3548          */
3549
3550         /* Make sure we are in proper schema */
3551         selectSourceSchema(fout, "pg_catalog");
3552
3553         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3554                                           "opfnamespace, "
3555                                           "(%s opfowner) AS rolname "
3556                                           "FROM pg_opfamily",
3557                                           username_subquery);
3558
3559         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3560
3561         ntups = PQntuples(res);
3562         *numOpfamilies = ntups;
3563
3564         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3565
3566         i_tableoid = PQfnumber(res, "tableoid");
3567         i_oid = PQfnumber(res, "oid");
3568         i_opfname = PQfnumber(res, "opfname");
3569         i_opfnamespace = PQfnumber(res, "opfnamespace");
3570         i_rolname = PQfnumber(res, "rolname");
3571
3572         for (i = 0; i < ntups; i++)
3573         {
3574                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3575                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3576                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3577                 AssignDumpId(&opfinfo[i].dobj);
3578                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3579                 opfinfo[i].dobj.namespace =
3580                         findNamespace(fout,
3581                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3582                                                   opfinfo[i].dobj.catId.oid);
3583                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3584
3585                 /* Decide whether we want to dump it */
3586                 selectDumpableObject(&(opfinfo[i].dobj));
3587
3588                 if (fout->remoteVersion >= 70300)
3589                 {
3590                         if (strlen(opfinfo[i].rolname) == 0)
3591                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3592                                                   opfinfo[i].dobj.name);
3593                 }
3594         }
3595
3596         PQclear(res);
3597
3598         destroyPQExpBuffer(query);
3599
3600         return opfinfo;
3601 }
3602
3603 /*
3604  * getAggregates:
3605  *        read all the user-defined aggregates in the system catalogs and
3606  * return them in the AggInfo* structure
3607  *
3608  * numAggs is set to the number of aggregates read in
3609  */
3610 AggInfo *
3611 getAggregates(Archive *fout, int *numAggs)
3612 {
3613         PGresult   *res;
3614         int                     ntups;
3615         int                     i;
3616         PQExpBuffer query = createPQExpBuffer();
3617         AggInfo    *agginfo;
3618         int                     i_tableoid;
3619         int                     i_oid;
3620         int                     i_aggname;
3621         int                     i_aggnamespace;
3622         int                     i_pronargs;
3623         int                     i_proargtypes;
3624         int                     i_rolname;
3625         int                     i_aggacl;
3626
3627         /* Make sure we are in proper schema */
3628         selectSourceSchema(fout, "pg_catalog");
3629
3630         /*
3631          * Find all user-defined aggregates.  See comment in getFuncs() for the
3632          * rationale behind the filtering logic.
3633          */
3634
3635         if (fout->remoteVersion >= 80200)
3636         {
3637                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3638                                                   "pronamespace AS aggnamespace, "
3639                                                   "pronargs, proargtypes, "
3640                                                   "(%s proowner) AS rolname, "
3641                                                   "proacl AS aggacl "
3642                                                   "FROM pg_proc p "
3643                                                   "WHERE proisagg AND ("
3644                                                   "pronamespace != "
3645                                                   "(SELECT oid FROM pg_namespace "
3646                                                   "WHERE nspname = 'pg_catalog')",
3647                                                   username_subquery);
3648                 if (binary_upgrade && fout->remoteVersion >= 90100)
3649                         appendPQExpBuffer(query,
3650                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3651                                                           "classid = 'pg_proc'::regclass AND "
3652                                                           "objid = p.oid AND "
3653                                                           "refclassid = 'pg_extension'::regclass AND "
3654                                                           "deptype = 'e')");
3655                 appendPQExpBuffer(query, ")");
3656         }
3657         else if (fout->remoteVersion >= 70300)
3658         {
3659                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3660                                                   "pronamespace AS aggnamespace, "
3661                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3662                                                   "proargtypes, "
3663                                                   "(%s proowner) AS rolname, "
3664                                                   "proacl AS aggacl "
3665                                                   "FROM pg_proc "
3666                                                   "WHERE proisagg "
3667                                                   "AND pronamespace != "
3668                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3669                                                   username_subquery);
3670         }
3671         else if (fout->remoteVersion >= 70100)
3672         {
3673                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3674                                                   "0::oid AS aggnamespace, "
3675                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3676                                                   "aggbasetype AS proargtypes, "
3677                                                   "(%s aggowner) AS rolname, "
3678                                                   "'{=X}' AS aggacl "
3679                                                   "FROM pg_aggregate "
3680                                                   "where oid > '%u'::oid",
3681                                                   username_subquery,
3682                                                   g_last_builtin_oid);
3683         }
3684         else
3685         {
3686                 appendPQExpBuffer(query, "SELECT "
3687                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3688                                                   "oid, aggname, "
3689                                                   "0::oid AS aggnamespace, "
3690                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3691                                                   "aggbasetype AS proargtypes, "
3692                                                   "(%s aggowner) AS rolname, "
3693                                                   "'{=X}' AS aggacl "
3694                                                   "FROM pg_aggregate "
3695                                                   "where oid > '%u'::oid",
3696                                                   username_subquery,
3697                                                   g_last_builtin_oid);
3698         }
3699
3700         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3701
3702         ntups = PQntuples(res);
3703         *numAggs = ntups;
3704
3705         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3706
3707         i_tableoid = PQfnumber(res, "tableoid");
3708         i_oid = PQfnumber(res, "oid");
3709         i_aggname = PQfnumber(res, "aggname");
3710         i_aggnamespace = PQfnumber(res, "aggnamespace");
3711         i_pronargs = PQfnumber(res, "pronargs");
3712         i_proargtypes = PQfnumber(res, "proargtypes");
3713         i_rolname = PQfnumber(res, "rolname");
3714         i_aggacl = PQfnumber(res, "aggacl");
3715
3716         for (i = 0; i < ntups; i++)
3717         {
3718                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3719                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3720                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3721                 AssignDumpId(&agginfo[i].aggfn.dobj);
3722                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3723                 agginfo[i].aggfn.dobj.namespace =
3724                         findNamespace(fout,
3725                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3726                                                   agginfo[i].aggfn.dobj.catId.oid);
3727                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3728                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3729                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3730                                           agginfo[i].aggfn.dobj.name);
3731                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3732                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3733                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3734                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3735                 if (agginfo[i].aggfn.nargs == 0)
3736                         agginfo[i].aggfn.argtypes = NULL;
3737                 else
3738                 {
3739                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3740                         if (fout->remoteVersion >= 70300)
3741                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3742                                                           agginfo[i].aggfn.argtypes,
3743                                                           agginfo[i].aggfn.nargs);
3744                         else
3745                                 /* it's just aggbasetype */
3746                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3747                 }
3748
3749                 /* Decide whether we want to dump it */
3750                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3751         }
3752
3753         PQclear(res);
3754
3755         destroyPQExpBuffer(query);
3756
3757         return agginfo;
3758 }
3759
3760 /*
3761  * getFuncs:
3762  *        read all the user-defined functions in the system catalogs and
3763  * return them in the FuncInfo* structure
3764  *
3765  * numFuncs is set to the number of functions read in
3766  */
3767 FuncInfo *
3768 getFuncs(Archive *fout, int *numFuncs)
3769 {
3770         PGresult   *res;
3771         int                     ntups;
3772         int                     i;
3773         PQExpBuffer query = createPQExpBuffer();
3774         FuncInfo   *finfo;
3775         int                     i_tableoid;
3776         int                     i_oid;
3777         int                     i_proname;
3778         int                     i_pronamespace;
3779         int                     i_rolname;
3780         int                     i_prolang;
3781         int                     i_pronargs;
3782         int                     i_proargtypes;
3783         int                     i_prorettype;
3784         int                     i_proacl;
3785
3786         /* Make sure we are in proper schema */
3787         selectSourceSchema(fout, "pg_catalog");
3788
3789         /*
3790          * Find all user-defined functions.  Normally we can exclude functions in
3791          * pg_catalog, which is worth doing since there are several thousand of
3792          * 'em.  However, there are some extensions that create functions in
3793          * pg_catalog.  In normal dumps we can still ignore those --- but in
3794          * binary-upgrade mode, we must dump the member objects of the extension,
3795          * so be sure to fetch any such functions.
3796          *
3797          * Also, in 9.2 and up, exclude functions that are internally dependent on
3798          * something else, since presumably those will be created as a result of
3799          * creating the something else.  This currently only acts to suppress
3800          * constructor functions for range types.  Note that this is OK only
3801          * because the constructors don't have any dependencies the range type
3802          * doesn't have; otherwise we might not get creation ordering correct.
3803          */
3804
3805         if (fout->remoteVersion >= 70300)
3806         {
3807                 appendPQExpBuffer(query,
3808                                                   "SELECT tableoid, oid, proname, prolang, "
3809                                                   "pronargs, proargtypes, prorettype, proacl, "
3810                                                   "pronamespace, "
3811                                                   "(%s proowner) AS rolname "
3812                                                   "FROM pg_proc p "
3813                                                   "WHERE NOT proisagg AND ("
3814                                                   "pronamespace != "
3815                                                   "(SELECT oid FROM pg_namespace "
3816                                                   "WHERE nspname = 'pg_catalog')",
3817                                                   username_subquery);
3818                 if (fout->remoteVersion >= 90200)
3819                         appendPQExpBuffer(query,
3820                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
3821                                                           "WHERE classid = 'pg_proc'::regclass AND "
3822                                                           "objid = p.oid AND deptype = 'i')");
3823                 if (binary_upgrade && fout->remoteVersion >= 90100)
3824                         appendPQExpBuffer(query,
3825                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3826                                                           "classid = 'pg_proc'::regclass AND "
3827                                                           "objid = p.oid AND "
3828                                                           "refclassid = 'pg_extension'::regclass AND "
3829                                                           "deptype = 'e')");
3830                 appendPQExpBuffer(query, ")");
3831         }
3832         else if (fout->remoteVersion >= 70100)
3833         {
3834                 appendPQExpBuffer(query,
3835                                                   "SELECT tableoid, oid, proname, prolang, "
3836                                                   "pronargs, proargtypes, prorettype, "
3837                                                   "'{=X}' AS proacl, "
3838                                                   "0::oid AS pronamespace, "
3839                                                   "(%s proowner) AS rolname "
3840                                                   "FROM pg_proc "
3841                                                   "WHERE pg_proc.oid > '%u'::oid",
3842                                                   username_subquery,
3843                                                   g_last_builtin_oid);
3844         }
3845         else
3846         {
3847                 appendPQExpBuffer(query,
3848                                                   "SELECT "
3849                                                   "(SELECT oid FROM pg_class "
3850                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3851                                                   "oid, proname, prolang, "
3852                                                   "pronargs, proargtypes, prorettype, "
3853                                                   "'{=X}' AS proacl, "
3854                                                   "0::oid AS pronamespace, "
3855                                                   "(%s proowner) AS rolname "
3856                                                   "FROM pg_proc "
3857                                                   "where pg_proc.oid > '%u'::oid",
3858                                                   username_subquery,
3859                                                   g_last_builtin_oid);
3860         }
3861
3862         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3863
3864         ntups = PQntuples(res);
3865
3866         *numFuncs = ntups;
3867
3868         finfo = (FuncInfo *) pg_calloc(ntups, sizeof(FuncInfo));
3869
3870         i_tableoid = PQfnumber(res, "tableoid");
3871         i_oid = PQfnumber(res, "oid");
3872         i_proname = PQfnumber(res, "proname");
3873         i_pronamespace = PQfnumber(res, "pronamespace");
3874         i_rolname = PQfnumber(res, "rolname");
3875         i_prolang = PQfnumber(res, "prolang");
3876         i_pronargs = PQfnumber(res, "pronargs");
3877         i_proargtypes = PQfnumber(res, "proargtypes");
3878         i_prorettype = PQfnumber(res, "prorettype");
3879         i_proacl = PQfnumber(res, "proacl");
3880
3881         for (i = 0; i < ntups; i++)
3882         {
3883                 finfo[i].dobj.objType = DO_FUNC;
3884                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3885                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3886                 AssignDumpId(&finfo[i].dobj);
3887                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
3888                 finfo[i].dobj.namespace =
3889                         findNamespace(fout,
3890                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
3891                                                   finfo[i].dobj.catId.oid);
3892                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3893                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3894                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3895                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
3896                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3897                 if (finfo[i].nargs == 0)
3898                         finfo[i].argtypes = NULL;
3899                 else
3900                 {
3901                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
3902                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3903                                                   finfo[i].argtypes, finfo[i].nargs);
3904                 }
3905
3906                 /* Decide whether we want to dump it */
3907                 selectDumpableObject(&(finfo[i].dobj));
3908
3909                 if (strlen(finfo[i].rolname) == 0)
3910                         write_msg(NULL,
3911                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3912                                           finfo[i].dobj.name);
3913         }
3914
3915         PQclear(res);
3916
3917         destroyPQExpBuffer(query);
3918
3919         return finfo;
3920 }
3921
3922 /*
3923  * getTables
3924  *        read all the user-defined tables (no indexes, no catalogs)
3925  * in the system catalogs return them in the TableInfo* structure
3926  *
3927  * numTables is set to the number of tables read in
3928  */
3929 TableInfo *
3930 getTables(Archive *fout, int *numTables)
3931 {
3932         PGresult   *res;
3933         int                     ntups;
3934         int                     i;
3935         PQExpBuffer query = createPQExpBuffer();
3936         TableInfo  *tblinfo;
3937         int                     i_reltableoid;
3938         int                     i_reloid;
3939         int                     i_relname;
3940         int                     i_relnamespace;
3941         int                     i_relkind;
3942         int                     i_relacl;
3943         int                     i_rolname;
3944         int                     i_relchecks;
3945         int                     i_relhastriggers;
3946         int                     i_relhasindex;
3947         int                     i_relhasrules;
3948         int                     i_relhasoids;
3949         int                     i_relfrozenxid;
3950         int                     i_toastoid;
3951         int                     i_toastfrozenxid;
3952         int                     i_relpersistence;
3953         int                     i_owning_tab;
3954         int                     i_owning_col;
3955         int                     i_reltablespace;
3956         int                     i_reloptions;
3957         int                     i_toastreloptions;
3958         int                     i_reloftype;
3959
3960         /* Make sure we are in proper schema */
3961         selectSourceSchema(fout, "pg_catalog");
3962
3963         /*
3964          * Find all the tables (including views and sequences).
3965          *
3966          * We include system catalogs, so that we can work if a user table is
3967          * defined to inherit from a system catalog (pretty weird, but...)
3968          *
3969          * We ignore tables that are not type 'r' (ordinary relation), 'S'
3970          * (sequence), 'v' (view), or 'c' (composite type).
3971          *
3972          * Composite-type table entries won't be dumped as such, but we have to
3973          * make a DumpableObject for them so that we can track dependencies of the
3974          * composite type (pg_depend entries for columns of the composite type
3975          * link to the pg_class entry not the pg_type entry).
3976          *
3977          * Note: in this phase we should collect only a minimal amount of
3978          * information about each table, basically just enough to decide if it is
3979          * interesting. We must fetch all tables in this phase because otherwise
3980          * we cannot correctly identify inherited columns, owned sequences, etc.
3981          */
3982
3983         if (fout->remoteVersion >= 90100)
3984         {
3985                 /*
3986                  * Left join to pick up dependency info linking sequences to their
3987                  * owning column, if any (note this dependency is AUTO as of 8.2)
3988                  */
3989                 appendPQExpBuffer(query,
3990                                                   "SELECT c.tableoid, c.oid, c.relname, "
3991                                                   "c.relacl, c.relkind, c.relnamespace, "
3992                                                   "(%s c.relowner) AS rolname, "
3993                                                   "c.relchecks, c.relhastriggers, "
3994                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3995                                                   "c.relfrozenxid, tc.oid AS toid, "
3996                                                   "tc.relfrozenxid AS tfrozenxid, "
3997                                                   "c.relpersistence, "
3998                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3999                                                   "d.refobjid AS owning_tab, "
4000                                                   "d.refobjsubid AS owning_col, "
4001                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4002                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4003                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4004                                                   "FROM pg_class c "
4005                                                   "LEFT JOIN pg_depend d ON "
4006                                                   "(c.relkind = '%c' AND "
4007                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4008                                                   "d.objsubid = 0 AND "
4009                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4010                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4011                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
4012                                                   "ORDER BY c.oid",
4013                                                   username_subquery,
4014                                                   RELKIND_SEQUENCE,
4015                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4016                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4017                                                   RELKIND_FOREIGN_TABLE);
4018         }
4019         else if (fout->remoteVersion >= 90000)
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                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END 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 (fout->remoteVersion >= 80400)
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.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                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') 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 (fout->remoteVersion >= 80200)
4090         {
4091                 /*
4092                  * Left join to pick up dependency info linking sequences to their
4093                  * owning column, if any (note this dependency is AUTO as of 8.2)
4094                  */
4095                 appendPQExpBuffer(query,
4096                                                   "SELECT c.tableoid, c.oid, c.relname, "
4097                                                   "c.relacl, c.relkind, c.relnamespace, "
4098                                                   "(%s c.relowner) AS rolname, "
4099                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4100                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4101                                                   "c.relfrozenxid, tc.oid AS toid, "
4102                                                   "tc.relfrozenxid AS tfrozenxid, "
4103                                                   "'p' AS relpersistence, "
4104                                                   "NULL AS reloftype, "
4105                                                   "d.refobjid AS owning_tab, "
4106                                                   "d.refobjsubid AS owning_col, "
4107                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4108                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4109                                                   "NULL AS toast_reloptions "
4110                                                   "FROM pg_class c "
4111                                                   "LEFT JOIN pg_depend d ON "
4112                                                   "(c.relkind = '%c' AND "
4113                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4114                                                   "d.objsubid = 0 AND "
4115                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4116                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4117                                                   "WHERE c.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 (fout->remoteVersion >= 80000)
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                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) 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 (fout->remoteVersion >= 70300)
4160         {
4161                 /*
4162                  * Left join to pick up dependency info linking sequences to their
4163                  * owning column, if any
4164                  */
4165                 appendPQExpBuffer(query,
4166                                                   "SELECT c.tableoid, c.oid, relname, "
4167                                                   "relacl, relkind, relnamespace, "
4168                                                   "(%s relowner) AS rolname, "
4169                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4170                                                   "relhasindex, relhasrules, relhasoids, "
4171                                                   "0 AS relfrozenxid, "
4172                                                   "0 AS toid, "
4173                                                   "0 AS tfrozenxid, "
4174                                                   "'p' AS relpersistence, "
4175                                                   "NULL AS reloftype, "
4176                                                   "d.refobjid AS owning_tab, "
4177                                                   "d.refobjsubid AS owning_col, "
4178                                                   "NULL AS reltablespace, "
4179                                                   "NULL AS reloptions, "
4180                                                   "NULL AS toast_reloptions "
4181                                                   "FROM pg_class c "
4182                                                   "LEFT JOIN pg_depend d ON "
4183                                                   "(c.relkind = '%c' AND "
4184                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4185                                                   "d.objsubid = 0 AND "
4186                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4187                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4188                                                   "ORDER BY c.oid",
4189                                                   username_subquery,
4190                                                   RELKIND_SEQUENCE,
4191                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4192                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4193         }
4194         else if (fout->remoteVersion >= 70200)
4195         {
4196                 appendPQExpBuffer(query,
4197                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4198                                                   "0::oid AS relnamespace, "
4199                                                   "(%s relowner) AS rolname, "
4200                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4201                                                   "relhasindex, relhasrules, relhasoids, "
4202                                                   "0 AS relfrozenxid, "
4203                                                   "0 AS toid, "
4204                                                   "0 AS tfrozenxid, "
4205                                                   "'p' AS relpersistence, "
4206                                                   "NULL AS reloftype, "
4207                                                   "NULL::oid AS owning_tab, "
4208                                                   "NULL::int4 AS owning_col, "
4209                                                   "NULL AS reltablespace, "
4210                                                   "NULL AS reloptions, "
4211                                                   "NULL AS toast_reloptions "
4212                                                   "FROM pg_class "
4213                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4214                                                   "ORDER BY oid",
4215                                                   username_subquery,
4216                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4217         }
4218         else if (fout->remoteVersion >= 70100)
4219         {
4220                 /* all tables have oids in 7.1 */
4221                 appendPQExpBuffer(query,
4222                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4223                                                   "0::oid AS relnamespace, "
4224                                                   "(%s relowner) AS rolname, "
4225                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4226                                                   "relhasindex, relhasrules, "
4227                                                   "'t'::bool AS relhasoids, "
4228                                                   "0 AS relfrozenxid, "
4229                                                   "0 AS toid, "
4230                                                   "0 AS tfrozenxid, "
4231                                                   "'p' AS relpersistence, "
4232                                                   "NULL AS reloftype, "
4233                                                   "NULL::oid AS owning_tab, "
4234                                                   "NULL::int4 AS owning_col, "
4235                                                   "NULL AS reltablespace, "
4236                                                   "NULL AS reloptions, "
4237                                                   "NULL AS toast_reloptions "
4238                                                   "FROM pg_class "
4239                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4240                                                   "ORDER BY oid",
4241                                                   username_subquery,
4242                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4243         }
4244         else
4245         {
4246                 /*
4247                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4248                  * have a view by looking for a rule in pg_rewrite.
4249                  */
4250                 appendPQExpBuffer(query,
4251                                                   "SELECT "
4252                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4253                                                   "oid, relname, relacl, "
4254                                                   "CASE WHEN relhasrules and relkind = 'r' "
4255                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4256                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4257                                                   "THEN '%c'::\"char\" "
4258                                                   "ELSE relkind END AS relkind,"
4259                                                   "0::oid AS relnamespace, "
4260                                                   "(%s relowner) AS rolname, "
4261                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4262                                                   "relhasindex, relhasrules, "
4263                                                   "'t'::bool AS relhasoids, "
4264                                                   "0 as relfrozenxid, "
4265                                                   "0 AS toid, "
4266                                                   "0 AS tfrozenxid, "
4267                                                   "'p' AS relpersistence, "
4268                                                   "NULL AS reloftype, "
4269                                                   "NULL::oid AS owning_tab, "
4270                                                   "NULL::int4 AS owning_col, "
4271                                                   "NULL AS reltablespace, "
4272                                                   "NULL AS reloptions, "
4273                                                   "NULL AS toast_reloptions "
4274                                                   "FROM pg_class c "
4275                                                   "WHERE relkind IN ('%c', '%c') "
4276                                                   "ORDER BY oid",
4277                                                   RELKIND_VIEW,
4278                                                   username_subquery,
4279                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4280         }
4281
4282         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4283
4284         ntups = PQntuples(res);
4285
4286         *numTables = ntups;
4287
4288         /*
4289          * Extract data from result and lock dumpable tables.  We do the locking
4290          * before anything else, to minimize the window wherein a table could
4291          * disappear under us.
4292          *
4293          * Note that we have to save info about all tables here, even when dumping
4294          * only one, because we don't yet know which tables might be inheritance
4295          * ancestors of the target table.
4296          */
4297         tblinfo = (TableInfo *) pg_calloc(ntups, sizeof(TableInfo));
4298
4299         i_reltableoid = PQfnumber(res, "tableoid");
4300         i_reloid = PQfnumber(res, "oid");
4301         i_relname = PQfnumber(res, "relname");
4302         i_relnamespace = PQfnumber(res, "relnamespace");
4303         i_relacl = PQfnumber(res, "relacl");
4304         i_relkind = PQfnumber(res, "relkind");
4305         i_rolname = PQfnumber(res, "rolname");
4306         i_relchecks = PQfnumber(res, "relchecks");
4307         i_relhastriggers = PQfnumber(res, "relhastriggers");
4308         i_relhasindex = PQfnumber(res, "relhasindex");
4309         i_relhasrules = PQfnumber(res, "relhasrules");
4310         i_relhasoids = PQfnumber(res, "relhasoids");
4311         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4312         i_toastoid = PQfnumber(res, "toid");
4313         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4314         i_relpersistence = PQfnumber(res, "relpersistence");
4315         i_owning_tab = PQfnumber(res, "owning_tab");
4316         i_owning_col = PQfnumber(res, "owning_col");
4317         i_reltablespace = PQfnumber(res, "reltablespace");
4318         i_reloptions = PQfnumber(res, "reloptions");
4319         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4320         i_reloftype = PQfnumber(res, "reloftype");
4321
4322         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4323         {
4324                 /*
4325                  * Arrange to fail instead of waiting forever for a table lock.
4326                  *
4327                  * NB: this coding assumes that the only queries issued within the
4328                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4329                  * applied to other things too.
4330                  */
4331                 resetPQExpBuffer(query);
4332                 appendPQExpBuffer(query, "SET statement_timeout = ");
4333                 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
4334                 ExecuteSqlStatement(fout, query->data);
4335         }
4336
4337         for (i = 0; i < ntups; i++)
4338         {
4339                 tblinfo[i].dobj.objType = DO_TABLE;
4340                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4341                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4342                 AssignDumpId(&tblinfo[i].dobj);
4343                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4344                 tblinfo[i].dobj.namespace =
4345                         findNamespace(fout,
4346                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4347                                                   tblinfo[i].dobj.catId.oid);
4348                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4349                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4350                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4351                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4352                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4353                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4354                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4355                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4356                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4357                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4358                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4359                 if (PQgetisnull(res, i, i_reloftype))
4360                         tblinfo[i].reloftype = NULL;
4361                 else
4362                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4363                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4364                 if (PQgetisnull(res, i, i_owning_tab))
4365                 {
4366                         tblinfo[i].owning_tab = InvalidOid;
4367                         tblinfo[i].owning_col = 0;
4368                 }
4369                 else
4370                 {
4371                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4372                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4373                 }
4374                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4375                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4376                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4377
4378                 /* other fields were zeroed above */
4379
4380                 /*
4381                  * Decide whether we want to dump this table.
4382                  */
4383                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4384                         tblinfo[i].dobj.dump = false;
4385                 else
4386                         selectDumpableTable(&tblinfo[i]);
4387                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4388
4389                 /*
4390                  * Read-lock target tables to make sure they aren't DROPPED or altered
4391                  * in schema before we get around to dumping them.
4392                  *
4393                  * Note that we don't explicitly lock parents of the target tables; we
4394                  * assume our lock on the child is enough to prevent schema
4395                  * alterations to parent tables.
4396                  *
4397                  * NOTE: it'd be kinda nice to lock other relations too, not only
4398                  * plain tables, but the backend doesn't presently allow that.
4399                  */
4400                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4401                 {
4402                         resetPQExpBuffer(query);
4403                         appendPQExpBuffer(query,
4404                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4405                                                  fmtQualifiedId(fout,
4406                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4407                                                                                 tblinfo[i].dobj.name));
4408                         ExecuteSqlStatement(fout, query->data);
4409                 }
4410
4411                 /* Emit notice if join for owner failed */
4412                 if (strlen(tblinfo[i].rolname) == 0)
4413                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4414                                           tblinfo[i].dobj.name);
4415         }
4416
4417         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4418         {
4419                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4420         }
4421
4422         PQclear(res);
4423
4424         /*
4425          * Force sequences that are "owned" by table columns to be dumped whenever
4426          * their owning table is being dumped.
4427          */
4428         for (i = 0; i < ntups; i++)
4429         {
4430                 TableInfo  *seqinfo = &tblinfo[i];
4431                 int                     j;
4432
4433                 if (!OidIsValid(seqinfo->owning_tab))
4434                         continue;                       /* not an owned sequence */
4435                 if (seqinfo->dobj.dump)
4436                         continue;                       /* no need to search */
4437
4438                 /* can't use findTableByOid yet, unfortunately */
4439                 for (j = 0; j < ntups; j++)
4440                 {
4441                         if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
4442                         {
4443                                 if (tblinfo[j].dobj.dump)
4444                                 {
4445                                         seqinfo->interesting = true;
4446                                         seqinfo->dobj.dump = true;
4447                                 }
4448                                 break;
4449                         }
4450                 }
4451         }
4452
4453         destroyPQExpBuffer(query);
4454
4455         return tblinfo;
4456 }
4457
4458 /*
4459  * getInherits
4460  *        read all the inheritance information
4461  * from the system catalogs return them in the InhInfo* structure
4462  *
4463  * numInherits is set to the number of pairs read in
4464  */
4465 InhInfo *
4466 getInherits(Archive *fout, int *numInherits)
4467 {
4468         PGresult   *res;
4469         int                     ntups;
4470         int                     i;
4471         PQExpBuffer query = createPQExpBuffer();
4472         InhInfo    *inhinfo;
4473
4474         int                     i_inhrelid;
4475         int                     i_inhparent;
4476
4477         /* Make sure we are in proper schema */
4478         selectSourceSchema(fout, "pg_catalog");
4479
4480         /* find all the inheritance information */
4481
4482         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4483
4484         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4485
4486         ntups = PQntuples(res);
4487
4488         *numInherits = ntups;
4489
4490         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4491
4492         i_inhrelid = PQfnumber(res, "inhrelid");
4493         i_inhparent = PQfnumber(res, "inhparent");
4494
4495         for (i = 0; i < ntups; i++)
4496         {
4497                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4498                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4499         }
4500
4501         PQclear(res);
4502
4503         destroyPQExpBuffer(query);
4504
4505         return inhinfo;
4506 }
4507
4508 /*
4509  * getIndexes
4510  *        get information about every index on a dumpable table
4511  *
4512  * Note: index data is not returned directly to the caller, but it
4513  * does get entered into the DumpableObject tables.
4514  */
4515 void
4516 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4517 {
4518         int                     i,
4519                                 j;
4520         PQExpBuffer query = createPQExpBuffer();
4521         PGresult   *res;
4522         IndxInfo   *indxinfo;
4523         ConstraintInfo *constrinfo;
4524         int                     i_tableoid,
4525                                 i_oid,
4526                                 i_indexname,
4527                                 i_indexdef,
4528                                 i_indnkeys,
4529                                 i_indkey,
4530                                 i_indisclustered,
4531                                 i_contype,
4532                                 i_conname,
4533                                 i_condeferrable,
4534                                 i_condeferred,
4535                                 i_contableoid,
4536                                 i_conoid,
4537                                 i_condef,
4538                                 i_tablespace,
4539                                 i_options;
4540         int                     ntups;
4541
4542         for (i = 0; i < numTables; i++)
4543         {
4544                 TableInfo  *tbinfo = &tblinfo[i];
4545
4546                 /* Only plain tables have indexes */
4547                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
4548                         continue;
4549
4550                 /* Ignore indexes of tables not to be dumped */
4551                 if (!tbinfo->dobj.dump)
4552                         continue;
4553
4554                 if (g_verbose)
4555                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4556                                           tbinfo->dobj.name);
4557
4558                 /* Make sure we are in proper schema so indexdef is right */
4559                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4560
4561                 /*
4562                  * The point of the messy-looking outer join is to find a constraint
4563                  * that is related by an internal dependency link to the index. If we
4564                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4565                  * assume an index won't have more than one internal dependency.
4566                  *
4567                  * As of 9.0 we don't need to look at pg_depend but can check for a
4568                  * match to pg_constraint.conindid.  The check on conrelid is
4569                  * redundant but useful because that column is indexed while conindid
4570                  * is not.
4571                  */
4572                 resetPQExpBuffer(query);
4573                 if (fout->remoteVersion >= 90000)
4574                 {
4575                         appendPQExpBuffer(query,
4576                                                           "SELECT t.tableoid, t.oid, "
4577                                                           "t.relname AS indexname, "
4578                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4579                                                           "t.relnatts AS indnkeys, "
4580                                                           "i.indkey, i.indisclustered, "
4581                                                           "c.contype, c.conname, "
4582                                                           "c.condeferrable, c.condeferred, "
4583                                                           "c.tableoid AS contableoid, "
4584                                                           "c.oid AS conoid, "
4585                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4586                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4587                                                         "array_to_string(t.reloptions, ', ') AS options "
4588                                                           "FROM pg_catalog.pg_index i "
4589                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4590                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4591                                                           "ON (i.indrelid = c.conrelid AND "
4592                                                           "i.indexrelid = c.conindid AND "
4593                                                           "c.contype IN ('p','u','x')) "
4594                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4595                                                           "ORDER BY indexname",
4596                                                           tbinfo->dobj.catId.oid);
4597                 }
4598                 else if (fout->remoteVersion >= 80200)
4599                 {
4600                         appendPQExpBuffer(query,
4601                                                           "SELECT t.tableoid, t.oid, "
4602                                                           "t.relname AS indexname, "
4603                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4604                                                           "t.relnatts AS indnkeys, "
4605                                                           "i.indkey, i.indisclustered, "
4606                                                           "c.contype, c.conname, "
4607                                                           "c.condeferrable, c.condeferred, "
4608                                                           "c.tableoid AS contableoid, "
4609                                                           "c.oid AS conoid, "
4610                                                           "null AS condef, "
4611                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4612                                                         "array_to_string(t.reloptions, ', ') AS options "
4613                                                           "FROM pg_catalog.pg_index i "
4614                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4615                                                           "LEFT JOIN pg_catalog.pg_depend d "
4616                                                           "ON (d.classid = t.tableoid "
4617                                                           "AND d.objid = t.oid "
4618                                                           "AND d.deptype = 'i') "
4619                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4620                                                           "ON (d.refclassid = c.tableoid "
4621                                                           "AND d.refobjid = c.oid) "
4622                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4623                                                           "ORDER BY indexname",
4624                                                           tbinfo->dobj.catId.oid);
4625                 }
4626                 else if (fout->remoteVersion >= 80000)
4627                 {
4628                         appendPQExpBuffer(query,
4629                                                           "SELECT t.tableoid, t.oid, "
4630                                                           "t.relname AS indexname, "
4631                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4632                                                           "t.relnatts AS indnkeys, "
4633                                                           "i.indkey, i.indisclustered, "
4634                                                           "c.contype, c.conname, "
4635                                                           "c.condeferrable, c.condeferred, "
4636                                                           "c.tableoid AS contableoid, "
4637                                                           "c.oid AS conoid, "
4638                                                           "null AS condef, "
4639                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4640                                                           "null AS options "
4641                                                           "FROM pg_catalog.pg_index i "
4642                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4643                                                           "LEFT JOIN pg_catalog.pg_depend d "
4644                                                           "ON (d.classid = t.tableoid "
4645                                                           "AND d.objid = t.oid "
4646                                                           "AND d.deptype = 'i') "
4647                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4648                                                           "ON (d.refclassid = c.tableoid "
4649                                                           "AND d.refobjid = c.oid) "
4650                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4651                                                           "ORDER BY indexname",
4652                                                           tbinfo->dobj.catId.oid);
4653                 }
4654                 else if (fout->remoteVersion >= 70300)
4655                 {
4656                         appendPQExpBuffer(query,
4657                                                           "SELECT t.tableoid, t.oid, "
4658                                                           "t.relname AS indexname, "
4659                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4660                                                           "t.relnatts AS indnkeys, "
4661                                                           "i.indkey, i.indisclustered, "
4662                                                           "c.contype, c.conname, "
4663                                                           "c.condeferrable, c.condeferred, "
4664                                                           "c.tableoid AS contableoid, "
4665                                                           "c.oid AS conoid, "
4666                                                           "null AS condef, "
4667                                                           "NULL AS tablespace, "
4668                                                           "null AS options "
4669                                                           "FROM pg_catalog.pg_index i "
4670                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4671                                                           "LEFT JOIN pg_catalog.pg_depend d "
4672                                                           "ON (d.classid = t.tableoid "
4673                                                           "AND d.objid = t.oid "
4674                                                           "AND d.deptype = 'i') "
4675                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4676                                                           "ON (d.refclassid = c.tableoid "
4677                                                           "AND d.refobjid = c.oid) "
4678                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4679                                                           "ORDER BY indexname",
4680                                                           tbinfo->dobj.catId.oid);
4681                 }
4682                 else if (fout->remoteVersion >= 70100)
4683                 {
4684                         appendPQExpBuffer(query,
4685                                                           "SELECT t.tableoid, t.oid, "
4686                                                           "t.relname AS indexname, "
4687                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4688                                                           "t.relnatts AS indnkeys, "
4689                                                           "i.indkey, false AS indisclustered, "
4690                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4691                                                           "ELSE '0'::char END AS contype, "
4692                                                           "t.relname AS conname, "
4693                                                           "false AS condeferrable, "
4694                                                           "false AS condeferred, "
4695                                                           "0::oid AS contableoid, "
4696                                                           "t.oid AS conoid, "
4697                                                           "null AS condef, "
4698                                                           "NULL AS tablespace, "
4699                                                           "null AS options "
4700                                                           "FROM pg_index i, pg_class t "
4701                                                           "WHERE t.oid = i.indexrelid "
4702                                                           "AND i.indrelid = '%u'::oid "
4703                                                           "ORDER BY indexname",
4704                                                           tbinfo->dobj.catId.oid);
4705                 }
4706                 else
4707                 {
4708                         appendPQExpBuffer(query,
4709                                                           "SELECT "
4710                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4711                                                           "t.oid, "
4712                                                           "t.relname AS indexname, "
4713                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4714                                                           "t.relnatts AS indnkeys, "
4715                                                           "i.indkey, false AS indisclustered, "
4716                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4717                                                           "ELSE '0'::char END AS contype, "
4718                                                           "t.relname AS conname, "
4719                                                           "false AS condeferrable, "
4720                                                           "false AS condeferred, "
4721                                                           "0::oid AS contableoid, "
4722                                                           "t.oid AS conoid, "
4723                                                           "null AS condef, "
4724                                                           "NULL AS tablespace, "
4725                                                           "null AS options "
4726                                                           "FROM pg_index i, pg_class t "
4727                                                           "WHERE t.oid = i.indexrelid "
4728                                                           "AND i.indrelid = '%u'::oid "
4729                                                           "ORDER BY indexname",
4730                                                           tbinfo->dobj.catId.oid);
4731                 }
4732
4733                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4734
4735                 ntups = PQntuples(res);
4736
4737                 i_tableoid = PQfnumber(res, "tableoid");
4738                 i_oid = PQfnumber(res, "oid");
4739                 i_indexname = PQfnumber(res, "indexname");
4740                 i_indexdef = PQfnumber(res, "indexdef");
4741                 i_indnkeys = PQfnumber(res, "indnkeys");
4742                 i_indkey = PQfnumber(res, "indkey");
4743                 i_indisclustered = PQfnumber(res, "indisclustered");
4744                 i_contype = PQfnumber(res, "contype");
4745                 i_conname = PQfnumber(res, "conname");
4746                 i_condeferrable = PQfnumber(res, "condeferrable");
4747                 i_condeferred = PQfnumber(res, "condeferred");
4748                 i_contableoid = PQfnumber(res, "contableoid");
4749                 i_conoid = PQfnumber(res, "conoid");
4750                 i_condef = PQfnumber(res, "condef");
4751                 i_tablespace = PQfnumber(res, "tablespace");
4752                 i_options = PQfnumber(res, "options");
4753
4754                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
4755                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4756
4757                 for (j = 0; j < ntups; j++)
4758                 {
4759                         char            contype;
4760
4761                         indxinfo[j].dobj.objType = DO_INDEX;
4762                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4763                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4764                         AssignDumpId(&indxinfo[j].dobj);
4765                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
4766                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4767                         indxinfo[j].indextable = tbinfo;
4768                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
4769                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
4770                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
4771                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
4772
4773                         /*
4774                          * In pre-7.4 releases, indkeys may contain more entries than
4775                          * indnkeys says (since indnkeys will be 1 for a functional
4776                          * index).      We don't actually care about this case since we don't
4777                          * examine indkeys except for indexes associated with PRIMARY and
4778                          * UNIQUE constraints, which are never functional indexes. But we
4779                          * have to allocate enough space to keep parseOidArray from
4780                          * complaining.
4781                          */
4782                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
4783                         parseOidArray(PQgetvalue(res, j, i_indkey),
4784                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
4785                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4786                         contype = *(PQgetvalue(res, j, i_contype));
4787
4788                         if (contype == 'p' || contype == 'u' || contype == 'x')
4789                         {
4790                                 /*
4791                                  * If we found a constraint matching the index, create an
4792                                  * entry for it.
4793                                  *
4794                                  * In a pre-7.3 database, we take this path iff the index was
4795                                  * marked indisprimary.
4796                                  */
4797                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
4798                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4799                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4800                                 AssignDumpId(&constrinfo[j].dobj);
4801                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4802                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4803                                 constrinfo[j].contable = tbinfo;
4804                                 constrinfo[j].condomain = NULL;
4805                                 constrinfo[j].contype = contype;
4806                                 if (contype == 'x')
4807                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4808                                 else
4809                                         constrinfo[j].condef = NULL;
4810                                 constrinfo[j].confrelid = InvalidOid;
4811                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
4812                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
4813                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
4814                                 constrinfo[j].conislocal = true;
4815                                 constrinfo[j].separate = true;
4816
4817                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
4818
4819                                 /* If pre-7.3 DB, better make sure table comes first */
4820                                 addObjectDependency(&constrinfo[j].dobj,
4821                                                                         tbinfo->dobj.dumpId);
4822                         }
4823                         else
4824                         {
4825                                 /* Plain secondary index */
4826                                 indxinfo[j].indexconstraint = 0;
4827                         }
4828                 }
4829
4830                 PQclear(res);
4831         }
4832
4833         destroyPQExpBuffer(query);
4834 }
4835
4836 /*
4837  * getConstraints
4838  *
4839  * Get info about constraints on dumpable tables.
4840  *
4841  * Currently handles foreign keys only.
4842  * Unique and primary key constraints are handled with indexes,
4843  * while check constraints are processed in getTableAttrs().
4844  */
4845 void
4846 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
4847 {
4848         int                     i,
4849                                 j;
4850         ConstraintInfo *constrinfo;
4851         PQExpBuffer query;
4852         PGresult   *res;
4853         int                     i_contableoid,
4854                                 i_conoid,
4855                                 i_conname,
4856                                 i_confrelid,
4857                                 i_condef;
4858         int                     ntups;
4859
4860         /* pg_constraint was created in 7.3, so nothing to do if older */
4861         if (fout->remoteVersion < 70300)
4862                 return;
4863
4864         query = createPQExpBuffer();
4865
4866         for (i = 0; i < numTables; i++)
4867         {
4868                 TableInfo  *tbinfo = &tblinfo[i];
4869
4870                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4871                         continue;
4872
4873                 if (g_verbose)
4874                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
4875                                           tbinfo->dobj.name);
4876
4877                 /*
4878                  * select table schema to ensure constraint expr is qualified if
4879                  * needed
4880                  */
4881                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4882
4883                 resetPQExpBuffer(query);
4884                 appendPQExpBuffer(query,
4885                                                   "SELECT tableoid, oid, conname, confrelid, "
4886                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
4887                                                   "FROM pg_catalog.pg_constraint "
4888                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4889                                                   "AND contype = 'f'",
4890                                                   tbinfo->dobj.catId.oid);
4891                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4892
4893                 ntups = PQntuples(res);
4894
4895                 i_contableoid = PQfnumber(res, "tableoid");
4896                 i_conoid = PQfnumber(res, "oid");
4897                 i_conname = PQfnumber(res, "conname");
4898                 i_confrelid = PQfnumber(res, "confrelid");
4899                 i_condef = PQfnumber(res, "condef");
4900
4901                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4902
4903                 for (j = 0; j < ntups; j++)
4904                 {
4905                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
4906                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4907                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4908                         AssignDumpId(&constrinfo[j].dobj);
4909                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4910                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4911                         constrinfo[j].contable = tbinfo;
4912                         constrinfo[j].condomain = NULL;
4913                         constrinfo[j].contype = 'f';
4914                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4915                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
4916                         constrinfo[j].conindex = 0;
4917                         constrinfo[j].condeferrable = false;
4918                         constrinfo[j].condeferred = false;
4919                         constrinfo[j].conislocal = true;
4920                         constrinfo[j].separate = true;
4921                 }
4922
4923                 PQclear(res);
4924         }
4925
4926         destroyPQExpBuffer(query);
4927 }
4928
4929 /*
4930  * getDomainConstraints
4931  *
4932  * Get info about constraints on a domain.
4933  */
4934 static void
4935 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
4936 {
4937         int                     i;
4938         ConstraintInfo *constrinfo;
4939         PQExpBuffer query;
4940         PGresult   *res;
4941         int                     i_tableoid,
4942                                 i_oid,
4943                                 i_conname,
4944                                 i_consrc;
4945         int                     ntups;
4946
4947         /* pg_constraint was created in 7.3, so nothing to do if older */
4948         if (fout->remoteVersion < 70300)
4949                 return;
4950
4951         /*
4952          * select appropriate schema to ensure names in constraint are properly
4953          * qualified
4954          */
4955         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
4956
4957         query = createPQExpBuffer();
4958
4959         if (fout->remoteVersion >= 90100)
4960                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4961                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4962                                                   "convalidated "
4963                                                   "FROM pg_catalog.pg_constraint "
4964                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4965                                                   "ORDER BY conname",
4966                                                   tyinfo->dobj.catId.oid);
4967
4968         else if (fout->remoteVersion >= 70400)
4969                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4970                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4971                                                   "true as convalidated "
4972                                                   "FROM pg_catalog.pg_constraint "
4973                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4974                                                   "ORDER BY conname",
4975                                                   tyinfo->dobj.catId.oid);
4976         else
4977                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4978                                                   "'CHECK (' || consrc || ')' AS consrc, "
4979                                                   "true as convalidated "
4980                                                   "FROM pg_catalog.pg_constraint "
4981                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4982                                                   "ORDER BY conname",
4983                                                   tyinfo->dobj.catId.oid);
4984
4985         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4986
4987         ntups = PQntuples(res);
4988
4989         i_tableoid = PQfnumber(res, "tableoid");
4990         i_oid = PQfnumber(res, "oid");
4991         i_conname = PQfnumber(res, "conname");
4992         i_consrc = PQfnumber(res, "consrc");
4993
4994         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4995
4996         tyinfo->nDomChecks = ntups;
4997         tyinfo->domChecks = constrinfo;
4998
4999         for (i = 0; i < ntups; i++)
5000         {
5001                 bool    validated = PQgetvalue(res, i, 4)[0] == 't';
5002
5003                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5004                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5005                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5006                 AssignDumpId(&constrinfo[i].dobj);
5007                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5008                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5009                 constrinfo[i].contable = NULL;
5010                 constrinfo[i].condomain = tyinfo;
5011                 constrinfo[i].contype = 'c';
5012                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5013                 constrinfo[i].confrelid = InvalidOid;
5014                 constrinfo[i].conindex = 0;
5015                 constrinfo[i].condeferrable = false;
5016                 constrinfo[i].condeferred = false;
5017                 constrinfo[i].conislocal = true;
5018
5019                 constrinfo[i].separate = !validated;
5020
5021                 /*
5022                  * Make the domain depend on the constraint, ensuring it won't be
5023                  * output till any constraint dependencies are OK.  If the constraint
5024                  * has not been validated, it's going to be dumped after the domain
5025                  * anyway, so this doesn't matter.
5026                  */
5027                 if (validated)
5028                         addObjectDependency(&tyinfo->dobj,
5029                                                                 constrinfo[i].dobj.dumpId);
5030         }
5031
5032         PQclear(res);
5033
5034         destroyPQExpBuffer(query);
5035 }
5036
5037 /*
5038  * getRules
5039  *        get basic information about every rule in the system
5040  *
5041  * numRules is set to the number of rules read in
5042  */
5043 RuleInfo *
5044 getRules(Archive *fout, int *numRules)
5045 {
5046         PGresult   *res;
5047         int                     ntups;
5048         int                     i;
5049         PQExpBuffer query = createPQExpBuffer();
5050         RuleInfo   *ruleinfo;
5051         int                     i_tableoid;
5052         int                     i_oid;
5053         int                     i_rulename;
5054         int                     i_ruletable;
5055         int                     i_ev_type;
5056         int                     i_is_instead;
5057         int                     i_ev_enabled;
5058
5059         /* Make sure we are in proper schema */
5060         selectSourceSchema(fout, "pg_catalog");
5061
5062         if (fout->remoteVersion >= 80300)
5063         {
5064                 appendPQExpBuffer(query, "SELECT "
5065                                                   "tableoid, oid, rulename, "
5066                                                   "ev_class AS ruletable, ev_type, is_instead, "
5067                                                   "ev_enabled "
5068                                                   "FROM pg_rewrite "
5069                                                   "ORDER BY oid");
5070         }
5071         else if (fout->remoteVersion >= 70100)
5072         {
5073                 appendPQExpBuffer(query, "SELECT "
5074                                                   "tableoid, oid, rulename, "
5075                                                   "ev_class AS ruletable, ev_type, is_instead, "
5076                                                   "'O'::char AS ev_enabled "
5077                                                   "FROM pg_rewrite "
5078                                                   "ORDER BY oid");
5079         }
5080         else
5081         {
5082                 appendPQExpBuffer(query, "SELECT "
5083                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5084                                                   "oid, rulename, "
5085                                                   "ev_class AS ruletable, ev_type, is_instead, "
5086                                                   "'O'::char AS ev_enabled "
5087                                                   "FROM pg_rewrite "
5088                                                   "ORDER BY oid");
5089         }
5090
5091         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5092
5093         ntups = PQntuples(res);
5094
5095         *numRules = ntups;
5096
5097         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5098
5099         i_tableoid = PQfnumber(res, "tableoid");
5100         i_oid = PQfnumber(res, "oid");
5101         i_rulename = PQfnumber(res, "rulename");
5102         i_ruletable = PQfnumber(res, "ruletable");
5103         i_ev_type = PQfnumber(res, "ev_type");
5104         i_is_instead = PQfnumber(res, "is_instead");
5105         i_ev_enabled = PQfnumber(res, "ev_enabled");
5106
5107         for (i = 0; i < ntups; i++)
5108         {
5109                 Oid                     ruletableoid;
5110
5111                 ruleinfo[i].dobj.objType = DO_RULE;
5112                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5113                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5114                 AssignDumpId(&ruleinfo[i].dobj);
5115                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5116                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5117                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5118                 if (ruleinfo[i].ruletable == NULL)
5119                 {
5120                         write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5121                                           ruletableoid,
5122                                           ruleinfo[i].dobj.catId.oid);
5123                         exit_nicely();
5124                 }
5125                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5126                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5127                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5128                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5129                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5130                 if (ruleinfo[i].ruletable)
5131                 {
5132                         /*
5133                          * If the table is a view, force its ON SELECT rule to be sorted
5134                          * before the view itself --- this ensures that any dependencies
5135                          * for the rule affect the table's positioning. Other rules are
5136                          * forced to appear after their table.
5137                          */
5138                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
5139                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5140                         {
5141                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5142                                                                         ruleinfo[i].dobj.dumpId);
5143                                 /* We'll merge the rule into CREATE VIEW, if possible */
5144                                 ruleinfo[i].separate = false;
5145                         }
5146                         else
5147                         {
5148                                 addObjectDependency(&ruleinfo[i].dobj,
5149                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5150                                 ruleinfo[i].separate = true;
5151                         }
5152                 }
5153                 else
5154                         ruleinfo[i].separate = true;
5155         }
5156
5157         PQclear(res);
5158
5159         destroyPQExpBuffer(query);
5160
5161         return ruleinfo;
5162 }
5163
5164 /*
5165  * getTriggers
5166  *        get information about every trigger on a dumpable table
5167  *
5168  * Note: trigger data is not returned directly to the caller, but it
5169  * does get entered into the DumpableObject tables.
5170  */
5171 void
5172 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5173 {
5174         int                     i,
5175                                 j;
5176         PQExpBuffer query = createPQExpBuffer();
5177         PGresult   *res;
5178         TriggerInfo *tginfo;
5179         int                     i_tableoid,
5180                                 i_oid,
5181                                 i_tgname,
5182                                 i_tgfname,
5183                                 i_tgtype,
5184                                 i_tgnargs,
5185                                 i_tgargs,
5186                                 i_tgisconstraint,
5187                                 i_tgconstrname,
5188                                 i_tgconstrrelid,
5189                                 i_tgconstrrelname,
5190                                 i_tgenabled,
5191                                 i_tgdeferrable,
5192                                 i_tginitdeferred,
5193                                 i_tgdef;
5194         int                     ntups;
5195
5196         for (i = 0; i < numTables; i++)
5197         {
5198                 TableInfo  *tbinfo = &tblinfo[i];
5199
5200                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5201                         continue;
5202
5203                 if (g_verbose)
5204                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5205                                           tbinfo->dobj.name);
5206
5207                 /*
5208                  * select table schema to ensure regproc name is qualified if needed
5209                  */
5210                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5211
5212                 resetPQExpBuffer(query);
5213                 if (fout->remoteVersion >= 90000)
5214                 {
5215                         /*
5216                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5217                          * could result in non-forward-compatible dumps of WHEN clauses
5218                          * due to under-parenthesization.
5219                          */
5220                         appendPQExpBuffer(query,
5221                                                           "SELECT tgname, "
5222                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5223                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5224                                                           "tgenabled, tableoid, oid "
5225                                                           "FROM pg_catalog.pg_trigger t "
5226                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5227                                                           "AND NOT tgisinternal",
5228                                                           tbinfo->dobj.catId.oid);
5229                 }
5230                 else if (fout->remoteVersion >= 80300)
5231                 {
5232                         /*
5233                          * We ignore triggers that are tied to a foreign-key constraint
5234                          */
5235                         appendPQExpBuffer(query,
5236                                                           "SELECT tgname, "
5237                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5238                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5239                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5240                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5241                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5242                                                           "FROM pg_catalog.pg_trigger t "
5243                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5244                                                           "AND tgconstraint = 0",
5245                                                           tbinfo->dobj.catId.oid);
5246                 }
5247                 else if (fout->remoteVersion >= 70300)
5248                 {
5249                         /*
5250                          * We ignore triggers that are tied to a foreign-key constraint,
5251                          * but in these versions we have to grovel through pg_constraint
5252                          * to find out
5253                          */
5254                         appendPQExpBuffer(query,
5255                                                           "SELECT tgname, "
5256                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5257                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5258                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5259                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5260                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5261                                                           "FROM pg_catalog.pg_trigger t "
5262                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5263                                                           "AND (NOT tgisconstraint "
5264                                                           " OR NOT EXISTS"
5265                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5266                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5267                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5268                                                           tbinfo->dobj.catId.oid);
5269                 }
5270                 else if (fout->remoteVersion >= 70100)
5271                 {
5272                         appendPQExpBuffer(query,
5273                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5274                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5275                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5276                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5277                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5278                                                           "             AS tgconstrrelname "
5279                                                           "FROM pg_trigger "
5280                                                           "WHERE tgrelid = '%u'::oid",
5281                                                           tbinfo->dobj.catId.oid);
5282                 }
5283                 else
5284                 {
5285                         appendPQExpBuffer(query,
5286                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5287                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5288                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5289                                                           "tgconstrrelid, tginitdeferred, "
5290                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5291                                                           "oid, "
5292                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5293                                                           "             AS tgconstrrelname "
5294                                                           "FROM pg_trigger "
5295                                                           "WHERE tgrelid = '%u'::oid",
5296                                                           tbinfo->dobj.catId.oid);
5297                 }
5298                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5299
5300                 ntups = PQntuples(res);
5301
5302                 i_tableoid = PQfnumber(res, "tableoid");
5303                 i_oid = PQfnumber(res, "oid");
5304                 i_tgname = PQfnumber(res, "tgname");
5305                 i_tgfname = PQfnumber(res, "tgfname");
5306                 i_tgtype = PQfnumber(res, "tgtype");
5307                 i_tgnargs = PQfnumber(res, "tgnargs");
5308                 i_tgargs = PQfnumber(res, "tgargs");
5309                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5310                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5311                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5312                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5313                 i_tgenabled = PQfnumber(res, "tgenabled");
5314                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5315                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5316                 i_tgdef = PQfnumber(res, "tgdef");
5317
5318                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5319
5320                 for (j = 0; j < ntups; j++)
5321                 {
5322                         tginfo[j].dobj.objType = DO_TRIGGER;
5323                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5324                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5325                         AssignDumpId(&tginfo[j].dobj);
5326                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5327                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5328                         tginfo[j].tgtable = tbinfo;
5329                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5330                         if (i_tgdef >= 0)
5331                         {
5332                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5333
5334                                 /* remaining fields are not valid if we have tgdef */
5335                                 tginfo[j].tgfname = NULL;
5336                                 tginfo[j].tgtype = 0;
5337                                 tginfo[j].tgnargs = 0;
5338                                 tginfo[j].tgargs = NULL;
5339                                 tginfo[j].tgisconstraint = false;
5340                                 tginfo[j].tgdeferrable = false;
5341                                 tginfo[j].tginitdeferred = false;
5342                                 tginfo[j].tgconstrname = NULL;
5343                                 tginfo[j].tgconstrrelid = InvalidOid;
5344                                 tginfo[j].tgconstrrelname = NULL;
5345                         }
5346                         else
5347                         {
5348                                 tginfo[j].tgdef = NULL;
5349
5350                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5351                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5352                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5353                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5354                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5355                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5356                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5357
5358                                 if (tginfo[j].tgisconstraint)
5359                                 {
5360                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5361                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5362                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5363                                         {
5364                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5365                                                 {
5366                                                         write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5367                                                                           tginfo[j].dobj.name, tbinfo->dobj.name,
5368                                                                           tginfo[j].tgconstrrelid);
5369                                                         exit_nicely();
5370                                                 }
5371                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5372                                         }
5373                                         else
5374                                                 tginfo[j].tgconstrrelname = NULL;
5375                                 }
5376                                 else
5377                                 {
5378                                         tginfo[j].tgconstrname = NULL;
5379                                         tginfo[j].tgconstrrelid = InvalidOid;
5380                                         tginfo[j].tgconstrrelname = NULL;
5381                                 }
5382                         }
5383                 }
5384
5385                 PQclear(res);
5386         }
5387
5388         destroyPQExpBuffer(query);
5389 }
5390
5391 /*
5392  * getProcLangs
5393  *        get basic information about every procedural language in the system
5394  *
5395  * numProcLangs is set to the number of langs read in
5396  *
5397  * NB: this must run after getFuncs() because we assume we can do
5398  * findFuncByOid().
5399  */
5400 ProcLangInfo *
5401 getProcLangs(Archive *fout, int *numProcLangs)
5402 {
5403         PGresult   *res;
5404         int                     ntups;
5405         int                     i;
5406         PQExpBuffer query = createPQExpBuffer();
5407         ProcLangInfo *planginfo;
5408         int                     i_tableoid;
5409         int                     i_oid;
5410         int                     i_lanname;
5411         int                     i_lanpltrusted;
5412         int                     i_lanplcallfoid;
5413         int                     i_laninline;
5414         int                     i_lanvalidator;
5415         int                     i_lanacl;
5416         int                     i_lanowner;
5417
5418         /* Make sure we are in proper schema */
5419         selectSourceSchema(fout, "pg_catalog");
5420
5421         if (fout->remoteVersion >= 90000)
5422         {
5423                 /* pg_language has a laninline column */
5424                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5425                                                   "lanname, lanpltrusted, lanplcallfoid, "
5426                                                   "laninline, lanvalidator,  lanacl, "
5427                                                   "(%s lanowner) AS lanowner "
5428                                                   "FROM pg_language "
5429                                                   "WHERE lanispl "
5430                                                   "ORDER BY oid",
5431                                                   username_subquery);
5432         }
5433         else if (fout->remoteVersion >= 80300)
5434         {
5435                 /* pg_language has a lanowner column */
5436                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5437                                                   "lanname, lanpltrusted, lanplcallfoid, "
5438                                                   "lanvalidator,  lanacl, "
5439                                                   "(%s lanowner) AS lanowner "
5440                                                   "FROM pg_language "
5441                                                   "WHERE lanispl "
5442                                                   "ORDER BY oid",
5443                                                   username_subquery);
5444         }
5445         else if (fout->remoteVersion >= 80100)
5446         {
5447                 /* Languages are owned by the bootstrap superuser, OID 10 */
5448                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5449                                                   "(%s '10') AS lanowner "
5450                                                   "FROM pg_language "
5451                                                   "WHERE lanispl "
5452                                                   "ORDER BY oid",
5453                                                   username_subquery);
5454         }
5455         else if (fout->remoteVersion >= 70400)
5456         {
5457                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5458                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5459                                                   "(%s '1') AS lanowner "
5460                                                   "FROM pg_language "
5461                                                   "WHERE lanispl "
5462                                                   "ORDER BY oid",
5463                                                   username_subquery);
5464         }
5465         else if (fout->remoteVersion >= 70100)
5466         {
5467                 /* No clear notion of an owner at all before 7.4 ... */
5468                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5469                                                   "WHERE lanispl "
5470                                                   "ORDER BY oid");
5471         }
5472         else
5473         {
5474                 appendPQExpBuffer(query, "SELECT "
5475                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5476                                                   "oid, * FROM pg_language "
5477                                                   "WHERE lanispl "
5478                                                   "ORDER BY oid");
5479         }
5480
5481         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5482
5483         ntups = PQntuples(res);
5484
5485         *numProcLangs = ntups;
5486
5487         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5488
5489         i_tableoid = PQfnumber(res, "tableoid");
5490         i_oid = PQfnumber(res, "oid");
5491         i_lanname = PQfnumber(res, "lanname");
5492         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5493         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5494         /* these may fail and return -1: */
5495         i_laninline = PQfnumber(res, "laninline");
5496         i_lanvalidator = PQfnumber(res, "lanvalidator");
5497         i_lanacl = PQfnumber(res, "lanacl");
5498         i_lanowner = PQfnumber(res, "lanowner");
5499
5500         for (i = 0; i < ntups; i++)
5501         {
5502                 planginfo[i].dobj.objType = DO_PROCLANG;
5503                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5504                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5505                 AssignDumpId(&planginfo[i].dobj);
5506
5507                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5508                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5509                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5510                 if (i_laninline >= 0)
5511                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5512                 else
5513                         planginfo[i].laninline = InvalidOid;
5514                 if (i_lanvalidator >= 0)
5515                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5516                 else
5517                         planginfo[i].lanvalidator = InvalidOid;
5518                 if (i_lanacl >= 0)
5519                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5520                 else
5521                         planginfo[i].lanacl = pg_strdup("{=U}");
5522                 if (i_lanowner >= 0)
5523                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5524                 else
5525                         planginfo[i].lanowner = pg_strdup("");
5526
5527                 if (fout->remoteVersion < 70300)
5528                 {
5529                         /*
5530                          * We need to make a dependency to ensure the function will be
5531                          * dumped first.  (In 7.3 and later the regular dependency
5532                          * mechanism will handle this for us.)
5533                          */
5534                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5535
5536                         if (funcInfo)
5537                                 addObjectDependency(&planginfo[i].dobj,
5538                                                                         funcInfo->dobj.dumpId);
5539                 }
5540         }
5541
5542         PQclear(res);
5543
5544         destroyPQExpBuffer(query);
5545
5546         return planginfo;
5547 }
5548
5549 /*
5550  * getCasts
5551  *        get basic information about every cast in the system
5552  *
5553  * numCasts is set to the number of casts read in
5554  */
5555 CastInfo *
5556 getCasts(Archive *fout, int *numCasts)
5557 {
5558         PGresult   *res;
5559         int                     ntups;
5560         int                     i;
5561         PQExpBuffer query = createPQExpBuffer();
5562         CastInfo   *castinfo;
5563         int                     i_tableoid;
5564         int                     i_oid;
5565         int                     i_castsource;
5566         int                     i_casttarget;
5567         int                     i_castfunc;
5568         int                     i_castcontext;
5569         int                     i_castmethod;
5570
5571         /* Make sure we are in proper schema */
5572         selectSourceSchema(fout, "pg_catalog");
5573
5574         if (fout->remoteVersion >= 80400)
5575         {
5576                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5577                                                   "castsource, casttarget, castfunc, castcontext, "
5578                                                   "castmethod "
5579                                                   "FROM pg_cast ORDER BY 3,4");
5580         }
5581         else if (fout->remoteVersion >= 70300)
5582         {
5583                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5584                                                   "castsource, casttarget, castfunc, castcontext, "
5585                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
5586                                                   "FROM pg_cast ORDER BY 3,4");
5587         }
5588         else
5589         {
5590                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
5591                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
5592                                                   "p.oid AS castfunc, 'e' AS castcontext, "
5593                                                   "'f' AS castmethod "
5594                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
5595                                                   "WHERE p.pronargs = 1 AND "
5596                                                   "p.proargtypes[0] = t1.oid AND "
5597                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
5598                                                   "ORDER BY 3,4");
5599         }
5600
5601         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5602
5603         ntups = PQntuples(res);
5604
5605         *numCasts = ntups;
5606
5607         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
5608
5609         i_tableoid = PQfnumber(res, "tableoid");
5610         i_oid = PQfnumber(res, "oid");
5611         i_castsource = PQfnumber(res, "castsource");
5612         i_casttarget = PQfnumber(res, "casttarget");
5613         i_castfunc = PQfnumber(res, "castfunc");
5614         i_castcontext = PQfnumber(res, "castcontext");
5615         i_castmethod = PQfnumber(res, "castmethod");
5616
5617         for (i = 0; i < ntups; i++)
5618         {
5619                 PQExpBufferData namebuf;
5620                 TypeInfo   *sTypeInfo;
5621                 TypeInfo   *tTypeInfo;
5622
5623                 castinfo[i].dobj.objType = DO_CAST;
5624                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5625                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5626                 AssignDumpId(&castinfo[i].dobj);
5627                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
5628                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
5629                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
5630                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
5631                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
5632
5633                 /*
5634                  * Try to name cast as concatenation of typnames.  This is only used
5635                  * for purposes of sorting.  If we fail to find either type, the name
5636                  * will be an empty string.
5637                  */
5638                 initPQExpBuffer(&namebuf);
5639                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
5640                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
5641                 if (sTypeInfo && tTypeInfo)
5642                         appendPQExpBuffer(&namebuf, "%s %s",
5643                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
5644                 castinfo[i].dobj.name = namebuf.data;
5645
5646                 if (OidIsValid(castinfo[i].castfunc))
5647                 {
5648                         /*
5649                          * We need to make a dependency to ensure the function will be
5650                          * dumped first.  (In 7.3 and later the regular dependency
5651                          * mechanism will handle this for us.)
5652                          */
5653                         FuncInfo   *funcInfo;
5654
5655                         funcInfo = findFuncByOid(castinfo[i].castfunc);
5656                         if (funcInfo)
5657                                 addObjectDependency(&castinfo[i].dobj,
5658                                                                         funcInfo->dobj.dumpId);
5659                 }
5660         }
5661
5662         PQclear(res);
5663
5664         destroyPQExpBuffer(query);
5665
5666         return castinfo;
5667 }
5668
5669 /*
5670  * getTableAttrs -
5671  *        for each interesting table, read info about its attributes
5672  *        (names, types, default values, CHECK constraints, etc)
5673  *
5674  * This is implemented in a very inefficient way right now, looping
5675  * through the tblinfo and doing a join per table to find the attrs and their
5676  * types.  However, because we want type names and so forth to be named
5677  * relative to the schema of each table, we couldn't do it in just one
5678  * query.  (Maybe one query per schema?)
5679  *
5680  *      modifies tblinfo
5681  */
5682 void
5683 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
5684 {
5685         int                     i,
5686                                 j;
5687         PQExpBuffer q = createPQExpBuffer();
5688         int                     i_attnum;
5689         int                     i_attname;
5690         int                     i_atttypname;
5691         int                     i_atttypmod;
5692         int                     i_attstattarget;
5693         int                     i_attstorage;
5694         int                     i_typstorage;
5695         int                     i_attnotnull;
5696         int                     i_atthasdef;
5697         int                     i_attisdropped;
5698         int                     i_attlen;
5699         int                     i_attalign;
5700         int                     i_attislocal;
5701         int                     i_attoptions;
5702         int                     i_attcollation;
5703         int                     i_attfdwoptions;
5704         PGresult   *res;
5705         int                     ntups;
5706         bool            hasdefaults;
5707
5708         for (i = 0; i < numTables; i++)
5709         {
5710                 TableInfo  *tbinfo = &tblinfo[i];
5711
5712                 /* Don't bother to collect info for sequences */
5713                 if (tbinfo->relkind == RELKIND_SEQUENCE)
5714                         continue;
5715
5716                 /* Don't bother with uninteresting tables, either */
5717                 if (!tbinfo->interesting)
5718                         continue;
5719
5720                 /*
5721                  * Make sure we are in proper schema for this table; this allows
5722                  * correct retrieval of formatted type names and default exprs
5723                  */
5724                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5725
5726                 /* find all the user attributes and their types */
5727
5728                 /*
5729                  * we must read the attribute names in attribute number order! because
5730                  * we will use the attnum to index into the attnames array later.  We
5731                  * actually ask to order by "attrelid, attnum" because (at least up to
5732                  * 7.3) the planner is not smart enough to realize it needn't re-sort
5733                  * the output of an indexscan on pg_attribute_relid_attnum_index.
5734                  */
5735                 if (g_verbose)
5736                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
5737                                           tbinfo->dobj.name);
5738
5739                 resetPQExpBuffer(q);
5740
5741                 if (fout->remoteVersion >= 90200)
5742                 {
5743                         /*
5744                          * attfdwoptions is new in 9.2.
5745                          */
5746                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5747                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5748                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5749                                                           "a.attlen, a.attalign, a.attislocal, "
5750                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5751                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5752                                                           "CASE WHEN a.attcollation <> t.typcollation "
5753                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5754                                                           "pg_catalog.array_to_string(ARRAY("
5755                                                           "SELECT pg_catalog.quote_ident(option_name) || "
5756                                                           "' ' || pg_catalog.quote_literal(option_value) "
5757                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
5758                                                           "ORDER BY option_name"
5759                                                           "), E',\n    ') AS attfdwoptions "
5760                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5761                                                           "ON a.atttypid = t.oid "
5762                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5763                                                           "AND a.attnum > 0::pg_catalog.int2 "
5764                                                           "ORDER BY a.attrelid, a.attnum",
5765                                                           tbinfo->dobj.catId.oid);
5766                 }
5767                 else if (fout->remoteVersion >= 90100)
5768                 {
5769                         /*
5770                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
5771                          * clauses for attributes whose collation is different from their
5772                          * type's default, we use a CASE here to suppress uninteresting
5773                          * attcollations cheaply.
5774                          */
5775                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5776                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5777                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5778                                                           "a.attlen, a.attalign, a.attislocal, "
5779                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5780                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5781                                                           "CASE WHEN a.attcollation <> t.typcollation "
5782                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5783                                                           "NULL AS attfdwoptions "
5784                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5785                                                           "ON a.atttypid = t.oid "
5786                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5787                                                           "AND a.attnum > 0::pg_catalog.int2 "
5788                                                           "ORDER BY a.attrelid, a.attnum",
5789                                                           tbinfo->dobj.catId.oid);
5790                 }
5791                 else if (fout->remoteVersion >= 90000)
5792                 {
5793                         /* attoptions is new in 9.0 */
5794                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5795                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5796                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5797                                                           "a.attlen, a.attalign, a.attislocal, "
5798                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5799                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5800                                                           "0 AS attcollation, "
5801                                                           "NULL AS attfdwoptions "
5802                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5803                                                           "ON a.atttypid = t.oid "
5804                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5805                                                           "AND a.attnum > 0::pg_catalog.int2 "
5806                                                           "ORDER BY a.attrelid, a.attnum",
5807                                                           tbinfo->dobj.catId.oid);
5808                 }
5809                 else if (fout->remoteVersion >= 70300)
5810                 {
5811                         /* need left join here to not fail on dropped columns ... */
5812                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5813                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5814                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5815                                                           "a.attlen, a.attalign, a.attislocal, "
5816                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5817                                                           "'' AS attoptions, 0 AS attcollation, "
5818                                                           "NULL AS attfdwoptions "
5819                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5820                                                           "ON a.atttypid = t.oid "
5821                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5822                                                           "AND a.attnum > 0::pg_catalog.int2 "
5823                                                           "ORDER BY a.attrelid, a.attnum",
5824                                                           tbinfo->dobj.catId.oid);
5825                 }
5826                 else if (fout->remoteVersion >= 70100)
5827                 {
5828                         /*
5829                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
5830                          * we don't dump it because we can't tell whether it's been
5831                          * explicitly set or was just a default.
5832                          */
5833                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5834                                                           "-1 AS attstattarget, a.attstorage, "
5835                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
5836                                                           "false AS attisdropped, a.attlen, "
5837                                                           "a.attalign, false AS attislocal, "
5838                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
5839                                                           "'' AS attoptions, 0 AS attcollation, "
5840                                                           "NULL AS attfdwoptions "
5841                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
5842                                                           "ON a.atttypid = t.oid "
5843                                                           "WHERE a.attrelid = '%u'::oid "
5844                                                           "AND a.attnum > 0::int2 "
5845                                                           "ORDER BY a.attrelid, a.attnum",
5846                                                           tbinfo->dobj.catId.oid);
5847                 }
5848                 else
5849                 {
5850                         /* format_type not available before 7.1 */
5851                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
5852                                                           "-1 AS attstattarget, "
5853                                                           "attstorage, attstorage AS typstorage, "
5854                                                           "attnotnull, atthasdef, false AS attisdropped, "
5855                                                           "attlen, attalign, "
5856                                                           "false AS attislocal, "
5857                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
5858                                                           "'' AS attoptions, 0 AS attcollation, "
5859                                                           "NULL AS attfdwoptions "
5860                                                           "FROM pg_attribute a "
5861                                                           "WHERE attrelid = '%u'::oid "
5862                                                           "AND attnum > 0::int2 "
5863                                                           "ORDER BY attrelid, attnum",
5864                                                           tbinfo->dobj.catId.oid);
5865                 }
5866
5867                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
5868
5869                 ntups = PQntuples(res);
5870
5871                 i_attnum = PQfnumber(res, "attnum");
5872                 i_attname = PQfnumber(res, "attname");
5873                 i_atttypname = PQfnumber(res, "atttypname");
5874                 i_atttypmod = PQfnumber(res, "atttypmod");
5875                 i_attstattarget = PQfnumber(res, "attstattarget");
5876                 i_attstorage = PQfnumber(res, "attstorage");
5877                 i_typstorage = PQfnumber(res, "typstorage");
5878                 i_attnotnull = PQfnumber(res, "attnotnull");
5879                 i_atthasdef = PQfnumber(res, "atthasdef");
5880                 i_attisdropped = PQfnumber(res, "attisdropped");
5881                 i_attlen = PQfnumber(res, "attlen");
5882                 i_attalign = PQfnumber(res, "attalign");
5883                 i_attislocal = PQfnumber(res, "attislocal");
5884                 i_attoptions = PQfnumber(res, "attoptions");
5885                 i_attcollation = PQfnumber(res, "attcollation");
5886                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
5887
5888                 tbinfo->numatts = ntups;
5889                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
5890                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
5891                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
5892                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
5893                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
5894                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
5895                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
5896                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
5897                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
5898                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
5899                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
5900                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
5901                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
5902                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
5903                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
5904                 tbinfo->inhAttrs = (bool *) pg_malloc(ntups * sizeof(bool));
5905                 tbinfo->inhAttrDef = (bool *) pg_malloc(ntups * sizeof(bool));
5906                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
5907                 hasdefaults = false;
5908
5909                 for (j = 0; j < ntups; j++)
5910                 {
5911                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
5912                         {
5913                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
5914                                                   tbinfo->dobj.name);
5915                                 exit_nicely();
5916                         }
5917                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
5918                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
5919                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
5920                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
5921                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
5922                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
5923                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
5924                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
5925                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
5926                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
5927                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
5928                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
5929                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
5930                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
5931                         tbinfo->attrdefs[j] = NULL; /* fix below */
5932                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
5933                                 hasdefaults = true;
5934                         /* these flags will be set in flagInhAttrs() */
5935                         tbinfo->inhAttrs[j] = false;
5936                         tbinfo->inhAttrDef[j] = false;
5937                         tbinfo->inhNotNull[j] = false;
5938                 }
5939
5940                 PQclear(res);
5941
5942                 /*
5943                  * Get info about column defaults
5944                  */
5945                 if (hasdefaults)
5946                 {
5947                         AttrDefInfo *attrdefs;
5948                         int                     numDefaults;
5949
5950                         if (g_verbose)
5951                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
5952                                                   tbinfo->dobj.name);
5953
5954                         resetPQExpBuffer(q);
5955                         if (fout->remoteVersion >= 70300)
5956                         {
5957                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
5958                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
5959                                                                   "FROM pg_catalog.pg_attrdef "
5960                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
5961                                                                   tbinfo->dobj.catId.oid);
5962                         }
5963                         else if (fout->remoteVersion >= 70200)
5964                         {
5965                                 /* 7.2 did not have OIDs in pg_attrdef */
5966                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
5967                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
5968                                                                   "FROM pg_attrdef "
5969                                                                   "WHERE adrelid = '%u'::oid",
5970                                                                   tbinfo->dobj.catId.oid);
5971                         }
5972                         else if (fout->remoteVersion >= 70100)
5973                         {
5974                                 /* no pg_get_expr, so must rely on adsrc */
5975                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
5976                                                                   "FROM pg_attrdef "
5977                                                                   "WHERE adrelid = '%u'::oid",
5978                                                                   tbinfo->dobj.catId.oid);
5979                         }
5980                         else
5981                         {
5982                                 /* no pg_get_expr, no tableoid either */
5983                                 appendPQExpBuffer(q, "SELECT "
5984                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
5985                                                                   "oid, adnum, adsrc "
5986                                                                   "FROM pg_attrdef "
5987                                                                   "WHERE adrelid = '%u'::oid",
5988                                                                   tbinfo->dobj.catId.oid);
5989                         }
5990                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
5991
5992                         numDefaults = PQntuples(res);
5993                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
5994
5995                         for (j = 0; j < numDefaults; j++)
5996                         {
5997                                 int                     adnum;
5998
5999                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6000                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6001                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6002                                 AssignDumpId(&attrdefs[j].dobj);
6003                                 attrdefs[j].adtable = tbinfo;
6004                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
6005                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6006
6007                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6008                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6009
6010                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6011
6012                                 /*
6013                                  * Defaults on a VIEW must always be dumped as separate ALTER
6014                                  * TABLE commands.      Defaults on regular tables are dumped as
6015                                  * part of the CREATE TABLE if possible.  To check if it's
6016                                  * safe, we mark the default as needing to appear before the
6017                                  * CREATE.
6018                                  */
6019                                 if (tbinfo->relkind == RELKIND_VIEW)
6020                                 {
6021                                         attrdefs[j].separate = true;
6022                                         /* needed in case pre-7.3 DB: */
6023                                         addObjectDependency(&attrdefs[j].dobj,
6024                                                                                 tbinfo->dobj.dumpId);
6025                                 }
6026                                 else
6027                                 {
6028                                         attrdefs[j].separate = false;
6029                                         addObjectDependency(&tbinfo->dobj,
6030                                                                                 attrdefs[j].dobj.dumpId);
6031                                 }
6032
6033                                 if (adnum <= 0 || adnum > ntups)
6034                                 {
6035                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
6036                                                           adnum, tbinfo->dobj.name);
6037                                         exit_nicely();
6038                                 }
6039                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6040                         }
6041                         PQclear(res);
6042                 }
6043
6044                 /*
6045                  * Get info about table CHECK constraints
6046                  */
6047                 if (tbinfo->ncheck > 0)
6048                 {
6049                         ConstraintInfo *constrs;
6050                         int                     numConstrs;
6051
6052                         if (g_verbose)
6053                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6054                                                   tbinfo->dobj.name);
6055
6056                         resetPQExpBuffer(q);
6057                         if (fout->remoteVersion >= 90200)
6058                         {
6059                                 /*
6060                                  * conisonly and convalidated are new in 9.2 (actually, the latter
6061                                  * is there in 9.1, but it wasn't ever false for check constraints
6062                                  * until 9.2).
6063                                  */
6064                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6065                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6066                                                                   "conislocal, convalidated, conisonly "
6067                                                                   "FROM pg_catalog.pg_constraint "
6068                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6069                                                                   "   AND contype = 'c' "
6070                                                                   "ORDER BY conname",
6071                                                                   tbinfo->dobj.catId.oid);
6072                         }
6073                         else if (fout->remoteVersion >= 80400)
6074                         {
6075                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6076                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6077                                                                   "conislocal, true AS convalidated, "
6078                                                                   "false as conisonly "
6079                                                                   "FROM pg_catalog.pg_constraint "
6080                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6081                                                                   "   AND contype = 'c' "
6082                                                                   "ORDER BY conname",
6083                                                                   tbinfo->dobj.catId.oid);
6084                         }
6085                         else if (fout->remoteVersion >= 70400)
6086                         {
6087                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6088                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6089                                                                   "true AS conislocal, true AS convalidated, "
6090                                                                   "false as conisonly "
6091                                                                   "FROM pg_catalog.pg_constraint "
6092                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6093                                                                   "   AND contype = 'c' "
6094                                                                   "ORDER BY conname",
6095                                                                   tbinfo->dobj.catId.oid);
6096                         }
6097                         else if (fout->remoteVersion >= 70300)
6098                         {
6099                                 /* no pg_get_constraintdef, must use consrc */
6100                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6101                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6102                                                                   "true AS conislocal, true AS convalidated, "
6103                                                                   "false as conisonly "
6104                                                                   "FROM pg_catalog.pg_constraint "
6105                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6106                                                                   "   AND contype = 'c' "
6107                                                                   "ORDER BY conname",
6108                                                                   tbinfo->dobj.catId.oid);
6109                         }
6110                         else if (fout->remoteVersion >= 70200)
6111                         {
6112                                 /* 7.2 did not have OIDs in pg_relcheck */
6113                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6114                                                                   "rcname AS conname, "
6115                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6116                                                                   "true AS conislocal, true AS convalidated, "
6117                                                                   "false as conisonly "
6118                                                                   "FROM pg_relcheck "
6119                                                                   "WHERE rcrelid = '%u'::oid "
6120                                                                   "ORDER BY rcname",
6121                                                                   tbinfo->dobj.catId.oid);
6122                         }
6123                         else if (fout->remoteVersion >= 70100)
6124                         {
6125                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6126                                                                   "rcname AS conname, "
6127                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6128                                                                   "true AS conislocal, true AS convalidated, "
6129                                                                   "false as conisonly "
6130                                                                   "FROM pg_relcheck "
6131                                                                   "WHERE rcrelid = '%u'::oid "
6132                                                                   "ORDER BY rcname",
6133                                                                   tbinfo->dobj.catId.oid);
6134                         }
6135                         else
6136                         {
6137                                 /* no tableoid in 7.0 */
6138                                 appendPQExpBuffer(q, "SELECT "
6139                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6140                                                                   "oid, rcname AS conname, "
6141                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6142                                                                   "true AS conislocal, true AS convalidated, "
6143                                                                   "false as conisonly "
6144                                                                   "FROM pg_relcheck "
6145                                                                   "WHERE rcrelid = '%u'::oid "
6146                                                                   "ORDER BY rcname",
6147                                                                   tbinfo->dobj.catId.oid);
6148                         }
6149                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6150
6151                         numConstrs = PQntuples(res);
6152                         if (numConstrs != tbinfo->ncheck)
6153                         {
6154                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6155                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6156                                                                                  tbinfo->ncheck),
6157                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6158                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6159                                 exit_nicely();
6160                         }
6161
6162                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6163                         tbinfo->checkexprs = constrs;
6164
6165                         for (j = 0; j < numConstrs; j++)
6166                         {
6167                                 bool    validated = PQgetvalue(res, j, 5)[0] == 't';
6168                                 bool    isonly = PQgetvalue(res, j, 6)[0] == 't';
6169
6170                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6171                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6172                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6173                                 AssignDumpId(&constrs[j].dobj);
6174                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6175                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6176                                 constrs[j].contable = tbinfo;
6177                                 constrs[j].condomain = NULL;
6178                                 constrs[j].contype = 'c';
6179                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6180                                 constrs[j].confrelid = InvalidOid;
6181                                 constrs[j].conindex = 0;
6182                                 constrs[j].condeferrable = false;
6183                                 constrs[j].condeferred = false;
6184                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6185                                 constrs[j].conisonly = isonly;
6186                                 /*
6187                                  * An unvalidated constraint needs to be dumped separately, so
6188                                  * that potentially-violating existing data is loaded before
6189                                  * the constraint.  An ONLY constraint needs to be dumped
6190                                  * separately too.
6191                                  */
6192                                 constrs[j].separate = !validated || isonly;
6193
6194                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6195
6196                                 /*
6197                                  * Mark the constraint as needing to appear before the table
6198                                  * --- this is so that any other dependencies of the
6199                                  * constraint will be emitted before we try to create the
6200                                  * table.  If the constraint is to be dumped separately, it will be
6201                                  * dumped after data is loaded anyway, so don't do it.  (There's
6202                                  * an automatic dependency in the opposite direction anyway, so
6203                                  * don't need to add one manually here.)
6204                                  */
6205                                 if (!constrs[j].separate)
6206                                         addObjectDependency(&tbinfo->dobj,
6207                                                                                 constrs[j].dobj.dumpId);
6208
6209                                 /*
6210                                  * If the constraint is inherited, this will be detected later
6211                                  * (in pre-8.4 databases).      We also detect later if the
6212                                  * constraint must be split out from the table definition.
6213                                  */
6214                         }
6215                         PQclear(res);
6216                 }
6217         }
6218
6219         destroyPQExpBuffer(q);
6220 }
6221
6222
6223 /*
6224  * getTSParsers:
6225  *        read all text search parsers in the system catalogs and return them
6226  *        in the TSParserInfo* structure
6227  *
6228  *      numTSParsers is set to the number of parsers read in
6229  */
6230 TSParserInfo *
6231 getTSParsers(Archive *fout, int *numTSParsers)
6232 {
6233         PGresult   *res;
6234         int                     ntups;
6235         int                     i;
6236         PQExpBuffer query = createPQExpBuffer();
6237         TSParserInfo *prsinfo;
6238         int                     i_tableoid;
6239         int                     i_oid;
6240         int                     i_prsname;
6241         int                     i_prsnamespace;
6242         int                     i_prsstart;
6243         int                     i_prstoken;
6244         int                     i_prsend;
6245         int                     i_prsheadline;
6246         int                     i_prslextype;
6247
6248         /* Before 8.3, there is no built-in text search support */
6249         if (fout->remoteVersion < 80300)
6250         {
6251                 *numTSParsers = 0;
6252                 return NULL;
6253         }
6254
6255         /*
6256          * find all text search objects, including builtin ones; we filter out
6257          * system-defined objects at dump-out time.
6258          */
6259
6260         /* Make sure we are in proper schema */
6261         selectSourceSchema(fout, "pg_catalog");
6262
6263         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6264                                           "prsstart::oid, prstoken::oid, "
6265                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6266                                           "FROM pg_ts_parser");
6267
6268         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6269
6270         ntups = PQntuples(res);
6271         *numTSParsers = ntups;
6272
6273         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6274
6275         i_tableoid = PQfnumber(res, "tableoid");
6276         i_oid = PQfnumber(res, "oid");
6277         i_prsname = PQfnumber(res, "prsname");
6278         i_prsnamespace = PQfnumber(res, "prsnamespace");
6279         i_prsstart = PQfnumber(res, "prsstart");
6280         i_prstoken = PQfnumber(res, "prstoken");
6281         i_prsend = PQfnumber(res, "prsend");
6282         i_prsheadline = PQfnumber(res, "prsheadline");
6283         i_prslextype = PQfnumber(res, "prslextype");
6284
6285         for (i = 0; i < ntups; i++)
6286         {
6287                 prsinfo[i].dobj.objType = DO_TSPARSER;
6288                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6289                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6290                 AssignDumpId(&prsinfo[i].dobj);
6291                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6292                 prsinfo[i].dobj.namespace =
6293                         findNamespace(fout,
6294                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6295                                                   prsinfo[i].dobj.catId.oid);
6296                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6297                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6298                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6299                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6300                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6301
6302                 /* Decide whether we want to dump it */
6303                 selectDumpableObject(&(prsinfo[i].dobj));
6304         }
6305
6306         PQclear(res);
6307
6308         destroyPQExpBuffer(query);
6309
6310         return prsinfo;
6311 }
6312
6313 /*
6314  * getTSDictionaries:
6315  *        read all text search dictionaries in the system catalogs and return them
6316  *        in the TSDictInfo* structure
6317  *
6318  *      numTSDicts is set to the number of dictionaries read in
6319  */
6320 TSDictInfo *
6321 getTSDictionaries(Archive *fout, int *numTSDicts)
6322 {
6323         PGresult   *res;
6324         int                     ntups;
6325         int                     i;
6326         PQExpBuffer query = createPQExpBuffer();
6327         TSDictInfo *dictinfo;
6328         int                     i_tableoid;
6329         int                     i_oid;
6330         int                     i_dictname;
6331         int                     i_dictnamespace;
6332         int                     i_rolname;
6333         int                     i_dicttemplate;
6334         int                     i_dictinitoption;
6335
6336         /* Before 8.3, there is no built-in text search support */
6337         if (fout->remoteVersion < 80300)
6338         {
6339                 *numTSDicts = 0;
6340                 return NULL;
6341         }
6342
6343         /* Make sure we are in proper schema */
6344         selectSourceSchema(fout, "pg_catalog");
6345
6346         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6347                                           "dictnamespace, (%s dictowner) AS rolname, "
6348                                           "dicttemplate, dictinitoption "
6349                                           "FROM pg_ts_dict",
6350                                           username_subquery);
6351
6352         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6353
6354         ntups = PQntuples(res);
6355         *numTSDicts = ntups;
6356
6357         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6358
6359         i_tableoid = PQfnumber(res, "tableoid");
6360         i_oid = PQfnumber(res, "oid");
6361         i_dictname = PQfnumber(res, "dictname");
6362         i_dictnamespace = PQfnumber(res, "dictnamespace");
6363         i_rolname = PQfnumber(res, "rolname");
6364         i_dictinitoption = PQfnumber(res, "dictinitoption");
6365         i_dicttemplate = PQfnumber(res, "dicttemplate");
6366
6367         for (i = 0; i < ntups; i++)
6368         {
6369                 dictinfo[i].dobj.objType = DO_TSDICT;
6370                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6371                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6372                 AssignDumpId(&dictinfo[i].dobj);
6373                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6374                 dictinfo[i].dobj.namespace =
6375                         findNamespace(fout,
6376                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6377                                                   dictinfo[i].dobj.catId.oid);
6378                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6379                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6380                 if (PQgetisnull(res, i, i_dictinitoption))
6381                         dictinfo[i].dictinitoption = NULL;
6382                 else
6383                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6384
6385                 /* Decide whether we want to dump it */
6386                 selectDumpableObject(&(dictinfo[i].dobj));
6387         }
6388
6389         PQclear(res);
6390
6391         destroyPQExpBuffer(query);
6392
6393         return dictinfo;
6394 }
6395
6396 /*
6397  * getTSTemplates:
6398  *        read all text search templates in the system catalogs and return them
6399  *        in the TSTemplateInfo* structure
6400  *
6401  *      numTSTemplates is set to the number of templates read in
6402  */
6403 TSTemplateInfo *
6404 getTSTemplates(Archive *fout, int *numTSTemplates)
6405 {
6406         PGresult   *res;
6407         int                     ntups;
6408         int                     i;
6409         PQExpBuffer query = createPQExpBuffer();
6410         TSTemplateInfo *tmplinfo;
6411         int                     i_tableoid;
6412         int                     i_oid;
6413         int                     i_tmplname;
6414         int                     i_tmplnamespace;
6415         int                     i_tmplinit;
6416         int                     i_tmpllexize;
6417
6418         /* Before 8.3, there is no built-in text search support */
6419         if (fout->remoteVersion < 80300)
6420         {
6421                 *numTSTemplates = 0;
6422                 return NULL;
6423         }
6424
6425         /* Make sure we are in proper schema */
6426         selectSourceSchema(fout, "pg_catalog");
6427
6428         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6429                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6430                                           "FROM pg_ts_template");
6431
6432         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6433
6434         ntups = PQntuples(res);
6435         *numTSTemplates = ntups;
6436
6437         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6438
6439         i_tableoid = PQfnumber(res, "tableoid");
6440         i_oid = PQfnumber(res, "oid");
6441         i_tmplname = PQfnumber(res, "tmplname");
6442         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6443         i_tmplinit = PQfnumber(res, "tmplinit");
6444         i_tmpllexize = PQfnumber(res, "tmpllexize");
6445
6446         for (i = 0; i < ntups; i++)
6447         {
6448                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6449                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6450                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6451                 AssignDumpId(&tmplinfo[i].dobj);
6452                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6453                 tmplinfo[i].dobj.namespace =
6454                         findNamespace(fout,
6455                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
6456                                                   tmplinfo[i].dobj.catId.oid);
6457                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6458                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6459
6460                 /* Decide whether we want to dump it */
6461                 selectDumpableObject(&(tmplinfo[i].dobj));
6462         }
6463
6464         PQclear(res);
6465
6466         destroyPQExpBuffer(query);
6467
6468         return tmplinfo;
6469 }
6470
6471 /*
6472  * getTSConfigurations:
6473  *        read all text search configurations in the system catalogs and return
6474  *        them in the TSConfigInfo* structure
6475  *
6476  *      numTSConfigs is set to the number of configurations read in
6477  */
6478 TSConfigInfo *
6479 getTSConfigurations(Archive *fout, int *numTSConfigs)
6480 {
6481         PGresult   *res;
6482         int                     ntups;
6483         int                     i;
6484         PQExpBuffer query = createPQExpBuffer();
6485         TSConfigInfo *cfginfo;
6486         int                     i_tableoid;
6487         int                     i_oid;
6488         int                     i_cfgname;
6489         int                     i_cfgnamespace;
6490         int                     i_rolname;
6491         int                     i_cfgparser;
6492
6493         /* Before 8.3, there is no built-in text search support */
6494         if (fout->remoteVersion < 80300)
6495         {
6496                 *numTSConfigs = 0;
6497                 return NULL;
6498         }
6499
6500         /* Make sure we are in proper schema */
6501         selectSourceSchema(fout, "pg_catalog");
6502
6503         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6504                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6505                                           "FROM pg_ts_config",
6506                                           username_subquery);
6507
6508         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6509
6510         ntups = PQntuples(res);
6511         *numTSConfigs = ntups;
6512
6513         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6514
6515         i_tableoid = PQfnumber(res, "tableoid");
6516         i_oid = PQfnumber(res, "oid");
6517         i_cfgname = PQfnumber(res, "cfgname");
6518         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6519         i_rolname = PQfnumber(res, "rolname");
6520         i_cfgparser = PQfnumber(res, "cfgparser");
6521
6522         for (i = 0; i < ntups; i++)
6523         {
6524                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6525                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6526                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6527                 AssignDumpId(&cfginfo[i].dobj);
6528                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
6529                 cfginfo[i].dobj.namespace =
6530                         findNamespace(fout,
6531                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
6532                                                   cfginfo[i].dobj.catId.oid);
6533                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6534                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
6535
6536                 /* Decide whether we want to dump it */
6537                 selectDumpableObject(&(cfginfo[i].dobj));
6538         }
6539
6540         PQclear(res);
6541
6542         destroyPQExpBuffer(query);
6543
6544         return cfginfo;
6545 }
6546
6547 /*
6548  * getForeignDataWrappers:
6549  *        read all foreign-data wrappers in the system catalogs and return
6550  *        them in the FdwInfo* structure
6551  *
6552  *      numForeignDataWrappers is set to the number of fdws read in
6553  */
6554 FdwInfo *
6555 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
6556 {
6557         PGresult   *res;
6558         int                     ntups;
6559         int                     i;
6560         PQExpBuffer query = createPQExpBuffer();
6561         FdwInfo    *fdwinfo;
6562         int                     i_tableoid;
6563         int                     i_oid;
6564         int                     i_fdwname;
6565         int                     i_rolname;
6566         int                     i_fdwhandler;
6567         int                     i_fdwvalidator;
6568         int                     i_fdwacl;
6569         int                     i_fdwoptions;
6570
6571         /* Before 8.4, there are no foreign-data wrappers */
6572         if (fout->remoteVersion < 80400)
6573         {
6574                 *numForeignDataWrappers = 0;
6575                 return NULL;
6576         }
6577
6578         /* Make sure we are in proper schema */
6579         selectSourceSchema(fout, "pg_catalog");
6580
6581         if (fout->remoteVersion >= 90100)
6582         {
6583                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6584                                                   "(%s fdwowner) AS rolname, "
6585                                                   "fdwhandler::pg_catalog.regproc, "
6586                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6587                                                   "array_to_string(ARRAY("
6588                                                   "SELECT quote_ident(option_name) || ' ' || "
6589                                                   "quote_literal(option_value) "
6590                                                   "FROM pg_options_to_table(fdwoptions) "
6591                                                   "ORDER BY option_name"
6592                                                   "), E',\n    ') AS fdwoptions "
6593                                                   "FROM pg_foreign_data_wrapper",
6594                                                   username_subquery);
6595         }
6596         else
6597         {
6598                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6599                                                   "(%s fdwowner) AS rolname, "
6600                                                   "'-' AS fdwhandler, "
6601                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6602                                                   "array_to_string(ARRAY("
6603                                                   "SELECT quote_ident(option_name) || ' ' || "
6604                                                   "quote_literal(option_value) "
6605                                                   "FROM pg_options_to_table(fdwoptions) "
6606                                                   "ORDER BY option_name"
6607                                                   "), E',\n    ') AS fdwoptions "
6608                                                   "FROM pg_foreign_data_wrapper",
6609                                                   username_subquery);
6610         }
6611
6612         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6613
6614         ntups = PQntuples(res);
6615         *numForeignDataWrappers = ntups;
6616
6617         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
6618
6619         i_tableoid = PQfnumber(res, "tableoid");
6620         i_oid = PQfnumber(res, "oid");
6621         i_fdwname = PQfnumber(res, "fdwname");
6622         i_rolname = PQfnumber(res, "rolname");
6623         i_fdwhandler = PQfnumber(res, "fdwhandler");
6624         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6625         i_fdwacl = PQfnumber(res, "fdwacl");
6626         i_fdwoptions = PQfnumber(res, "fdwoptions");
6627
6628         for (i = 0; i < ntups; i++)
6629         {
6630                 fdwinfo[i].dobj.objType = DO_FDW;
6631                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6632                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6633                 AssignDumpId(&fdwinfo[i].dobj);
6634                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6635                 fdwinfo[i].dobj.namespace = NULL;
6636                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6637                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
6638                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
6639                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
6640                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
6641
6642                 /* Decide whether we want to dump it */
6643                 selectDumpableObject(&(fdwinfo[i].dobj));
6644         }
6645
6646         PQclear(res);
6647
6648         destroyPQExpBuffer(query);
6649
6650         return fdwinfo;
6651 }
6652
6653 /*
6654  * getForeignServers:
6655  *        read all foreign servers in the system catalogs and return
6656  *        them in the ForeignServerInfo * structure
6657  *
6658  *      numForeignServers is set to the number of servers read in
6659  */
6660 ForeignServerInfo *
6661 getForeignServers(Archive *fout, int *numForeignServers)
6662 {
6663         PGresult   *res;
6664         int                     ntups;
6665         int                     i;
6666         PQExpBuffer query = createPQExpBuffer();
6667         ForeignServerInfo *srvinfo;
6668         int                     i_tableoid;
6669         int                     i_oid;
6670         int                     i_srvname;
6671         int                     i_rolname;
6672         int                     i_srvfdw;
6673         int                     i_srvtype;
6674         int                     i_srvversion;
6675         int                     i_srvacl;
6676         int                     i_srvoptions;
6677
6678         /* Before 8.4, there are no foreign servers */
6679         if (fout->remoteVersion < 80400)
6680         {
6681                 *numForeignServers = 0;
6682                 return NULL;
6683         }
6684
6685         /* Make sure we are in proper schema */
6686         selectSourceSchema(fout,"pg_catalog");
6687
6688         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
6689                                           "(%s srvowner) AS rolname, "
6690                                           "srvfdw, srvtype, srvversion, srvacl,"
6691                                           "array_to_string(ARRAY("
6692                                           "SELECT quote_ident(option_name) || ' ' || "
6693                                           "quote_literal(option_value) "
6694                                           "FROM pg_options_to_table(srvoptions) "
6695                                           "ORDER BY option_name"
6696                                           "), E',\n    ') AS srvoptions "
6697                                           "FROM pg_foreign_server",
6698                                           username_subquery);
6699
6700         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6701
6702         ntups = PQntuples(res);
6703         *numForeignServers = ntups;
6704
6705         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
6706
6707         i_tableoid = PQfnumber(res, "tableoid");
6708         i_oid = PQfnumber(res, "oid");
6709         i_srvname = PQfnumber(res, "srvname");
6710         i_rolname = PQfnumber(res, "rolname");
6711         i_srvfdw = PQfnumber(res, "srvfdw");
6712         i_srvtype = PQfnumber(res, "srvtype");
6713         i_srvversion = PQfnumber(res, "srvversion");
6714         i_srvacl = PQfnumber(res, "srvacl");
6715         i_srvoptions = PQfnumber(res, "srvoptions");
6716
6717         for (i = 0; i < ntups; i++)
6718         {
6719                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
6720                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6721                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6722                 AssignDumpId(&srvinfo[i].dobj);
6723                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6724                 srvinfo[i].dobj.namespace = NULL;
6725                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6726                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
6727                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
6728                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
6729                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
6730                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
6731
6732                 /* Decide whether we want to dump it */
6733                 selectDumpableObject(&(srvinfo[i].dobj));
6734         }
6735
6736         PQclear(res);
6737
6738         destroyPQExpBuffer(query);
6739
6740         return srvinfo;
6741 }
6742
6743 /*
6744  * getDefaultACLs:
6745  *        read all default ACL information in the system catalogs and return
6746  *        them in the DefaultACLInfo structure
6747  *
6748  *      numDefaultACLs is set to the number of ACLs read in
6749  */
6750 DefaultACLInfo *
6751 getDefaultACLs(Archive *fout, int *numDefaultACLs)
6752 {
6753         DefaultACLInfo *daclinfo;
6754         PQExpBuffer query;
6755         PGresult   *res;
6756         int                     i_oid;
6757         int                     i_tableoid;
6758         int                     i_defaclrole;
6759         int                     i_defaclnamespace;
6760         int                     i_defaclobjtype;
6761         int                     i_defaclacl;
6762         int                     i,
6763                                 ntups;
6764
6765         if (fout->remoteVersion < 90000)
6766         {
6767                 *numDefaultACLs = 0;
6768                 return NULL;
6769         }
6770
6771         query = createPQExpBuffer();
6772
6773         /* Make sure we are in proper schema */
6774         selectSourceSchema(fout, "pg_catalog");
6775
6776         appendPQExpBuffer(query, "SELECT oid, tableoid, "
6777                                           "(%s defaclrole) AS defaclrole, "
6778                                           "defaclnamespace, "
6779                                           "defaclobjtype, "
6780                                           "defaclacl "
6781                                           "FROM pg_default_acl",
6782                                           username_subquery);
6783
6784         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6785
6786         ntups = PQntuples(res);
6787         *numDefaultACLs = ntups;
6788
6789         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
6790
6791         i_oid = PQfnumber(res, "oid");
6792         i_tableoid = PQfnumber(res, "tableoid");
6793         i_defaclrole = PQfnumber(res, "defaclrole");
6794         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
6795         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
6796         i_defaclacl = PQfnumber(res, "defaclacl");
6797
6798         for (i = 0; i < ntups; i++)
6799         {
6800                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
6801
6802                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
6803                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6804                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6805                 AssignDumpId(&daclinfo[i].dobj);
6806                 /* cheesy ... is it worth coming up with a better object name? */
6807                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
6808
6809                 if (nspid != InvalidOid)
6810                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
6811                                                                                                  daclinfo[i].dobj.catId.oid);
6812                 else
6813                         daclinfo[i].dobj.namespace = NULL;
6814
6815                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
6816                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
6817                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
6818
6819                 /* Decide whether we want to dump it */
6820                 selectDumpableDefaultACL(&(daclinfo[i]));
6821         }
6822
6823         PQclear(res);
6824
6825         destroyPQExpBuffer(query);
6826
6827         return daclinfo;
6828 }
6829
6830 /*
6831  * dumpComment --
6832  *
6833  * This routine is used to dump any comments associated with the
6834  * object handed to this routine. The routine takes a constant character
6835  * string for the target part of the comment-creation command, plus
6836  * the namespace and owner of the object (for labeling the ArchiveEntry),
6837  * plus catalog ID and subid which are the lookup key for pg_description,
6838  * plus the dump ID for the object (for setting a dependency).
6839  * If a matching pg_description entry is found, it is dumped.
6840  *
6841  * Note: although this routine takes a dumpId for dependency purposes,
6842  * that purpose is just to mark the dependency in the emitted dump file
6843  * for possible future use by pg_restore.  We do NOT use it for determining
6844  * ordering of the comment in the dump file, because this routine is called
6845  * after dependency sorting occurs.  This routine should be called just after
6846  * calling ArchiveEntry() for the specified object.
6847  */
6848 static void
6849 dumpComment(Archive *fout, const char *target,
6850                         const char *namespace, const char *owner,
6851                         CatalogId catalogId, int subid, DumpId dumpId)
6852 {
6853         CommentItem *comments;
6854         int                     ncomments;
6855
6856         /* Comments are schema not data ... except blob comments are data */
6857         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
6858         {
6859                 if (dataOnly)
6860                         return;
6861         }
6862         else
6863         {
6864                 if (schemaOnly)
6865                         return;
6866         }
6867
6868         /* Search for comments associated with catalogId, using table */
6869         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
6870                                                          &comments);
6871
6872         /* Is there one matching the subid? */
6873         while (ncomments > 0)
6874         {
6875                 if (comments->objsubid == subid)
6876                         break;
6877                 comments++;
6878                 ncomments--;
6879         }
6880
6881         /* If a comment exists, build COMMENT ON statement */
6882         if (ncomments > 0)
6883         {
6884                 PQExpBuffer query = createPQExpBuffer();
6885
6886                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
6887                 appendStringLiteralAH(query, comments->descr, fout);
6888                 appendPQExpBuffer(query, ";\n");
6889
6890                 /*
6891                  * We mark comments as SECTION_NONE because they really belong in the
6892                  * same section as their parent, whether that is pre-data or
6893                  * post-data.
6894                  */
6895                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
6896                                          target, namespace, NULL, owner,
6897                                          false, "COMMENT", SECTION_NONE,
6898                                          query->data, "", NULL,
6899                                          &(dumpId), 1,
6900                                          NULL, NULL);
6901
6902                 destroyPQExpBuffer(query);
6903         }
6904 }
6905
6906 /*
6907  * dumpTableComment --
6908  *
6909  * As above, but dump comments for both the specified table (or view)
6910  * and its columns.
6911  */
6912 static void
6913 dumpTableComment(Archive *fout, TableInfo *tbinfo,
6914                                  const char *reltypename)
6915 {
6916         CommentItem *comments;
6917         int                     ncomments;
6918         PQExpBuffer query;
6919         PQExpBuffer target;
6920
6921         /* Comments are SCHEMA not data */
6922         if (dataOnly)
6923                 return;
6924
6925         /* Search for comments associated with relation, using table */
6926         ncomments = findComments(fout,
6927                                                          tbinfo->dobj.catId.tableoid,
6928                                                          tbinfo->dobj.catId.oid,
6929                                                          &comments);
6930
6931         /* If comments exist, build COMMENT ON statements */
6932         if (ncomments <= 0)
6933                 return;
6934
6935         query = createPQExpBuffer();
6936         target = createPQExpBuffer();
6937
6938         while (ncomments > 0)
6939         {
6940                 const char *descr = comments->descr;
6941                 int                     objsubid = comments->objsubid;
6942
6943                 if (objsubid == 0)
6944                 {
6945                         resetPQExpBuffer(target);
6946                         appendPQExpBuffer(target, "%s %s", reltypename,
6947                                                           fmtId(tbinfo->dobj.name));
6948
6949                         resetPQExpBuffer(query);
6950                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6951                         appendStringLiteralAH(query, descr, fout);
6952                         appendPQExpBuffer(query, ";\n");
6953
6954                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6955                                                  target->data,
6956                                                  tbinfo->dobj.namespace->dobj.name,
6957                                                  NULL, tbinfo->rolname,
6958                                                  false, "COMMENT", SECTION_NONE,
6959                                                  query->data, "", NULL,
6960                                                  &(tbinfo->dobj.dumpId), 1,
6961                                                  NULL, NULL);
6962                 }
6963                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
6964                 {
6965                         resetPQExpBuffer(target);
6966                         appendPQExpBuffer(target, "COLUMN %s.",
6967                                                           fmtId(tbinfo->dobj.name));
6968                         appendPQExpBuffer(target, "%s",
6969                                                           fmtId(tbinfo->attnames[objsubid - 1]));
6970
6971                         resetPQExpBuffer(query);
6972                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6973                         appendStringLiteralAH(query, descr, fout);
6974                         appendPQExpBuffer(query, ";\n");
6975
6976                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6977                                                  target->data,
6978                                                  tbinfo->dobj.namespace->dobj.name,
6979                                                  NULL, tbinfo->rolname,
6980                                                  false, "COMMENT", SECTION_NONE,
6981                                                  query->data, "", NULL,
6982                                                  &(tbinfo->dobj.dumpId), 1,
6983                                                  NULL, NULL);
6984                 }
6985
6986                 comments++;
6987                 ncomments--;
6988         }
6989
6990         destroyPQExpBuffer(query);
6991         destroyPQExpBuffer(target);
6992 }
6993
6994 /*
6995  * findComments --
6996  *
6997  * Find the comment(s), if any, associated with the given object.  All the
6998  * objsubid values associated with the given classoid/objoid are found with
6999  * one search.
7000  */
7001 static int
7002 findComments(Archive *fout, Oid classoid, Oid objoid,
7003                          CommentItem **items)
7004 {
7005         /* static storage for table of comments */
7006         static CommentItem *comments = NULL;
7007         static int      ncomments = -1;
7008
7009         CommentItem *middle = NULL;
7010         CommentItem *low;
7011         CommentItem *high;
7012         int                     nmatch;
7013
7014         /* Get comments if we didn't already */
7015         if (ncomments < 0)
7016                 ncomments = collectComments(fout, &comments);
7017
7018         /*
7019          * Pre-7.2, pg_description does not contain classoid, so collectComments
7020          * just stores a zero.  If there's a collision on object OID, well, you
7021          * get duplicate comments.
7022          */
7023         if (fout->remoteVersion < 70200)
7024                 classoid = 0;
7025
7026         /*
7027          * Do binary search to find some item matching the object.
7028          */
7029         low = &comments[0];
7030         high = &comments[ncomments - 1];
7031         while (low <= high)
7032         {
7033                 middle = low + (high - low) / 2;
7034
7035                 if (classoid < middle->classoid)
7036                         high = middle - 1;
7037                 else if (classoid > middle->classoid)
7038                         low = middle + 1;
7039                 else if (objoid < middle->objoid)
7040                         high = middle - 1;
7041                 else if (objoid > middle->objoid)
7042                         low = middle + 1;
7043                 else
7044                         break;                          /* found a match */
7045         }
7046
7047         if (low > high)                         /* no matches */
7048         {
7049                 *items = NULL;
7050                 return 0;
7051         }
7052
7053         /*
7054          * Now determine how many items match the object.  The search loop
7055          * invariant still holds: only items between low and high inclusive could
7056          * match.
7057          */
7058         nmatch = 1;
7059         while (middle > low)
7060         {
7061                 if (classoid != middle[-1].classoid ||
7062                         objoid != middle[-1].objoid)
7063                         break;
7064                 middle--;
7065                 nmatch++;
7066         }
7067
7068         *items = middle;
7069
7070         middle += nmatch;
7071         while (middle <= high)
7072         {
7073                 if (classoid != middle->classoid ||
7074                         objoid != middle->objoid)
7075                         break;
7076                 middle++;
7077                 nmatch++;
7078         }
7079
7080         return nmatch;
7081 }
7082
7083 /*
7084  * collectComments --
7085  *
7086  * Construct a table of all comments available for database objects.
7087  * We used to do per-object queries for the comments, but it's much faster
7088  * to pull them all over at once, and on most databases the memory cost
7089  * isn't high.
7090  *
7091  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7092  */
7093 static int
7094 collectComments(Archive *fout, CommentItem **items)
7095 {
7096         PGresult   *res;
7097         PQExpBuffer query;
7098         int                     i_description;
7099         int                     i_classoid;
7100         int                     i_objoid;
7101         int                     i_objsubid;
7102         int                     ntups;
7103         int                     i;
7104         CommentItem *comments;
7105
7106         /*
7107          * Note we do NOT change source schema here; preserve the caller's
7108          * setting, instead.
7109          */
7110
7111         query = createPQExpBuffer();
7112
7113         if (fout->remoteVersion >= 70300)
7114         {
7115                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7116                                                   "FROM pg_catalog.pg_description "
7117                                                   "ORDER BY classoid, objoid, objsubid");
7118         }
7119         else if (fout->remoteVersion >= 70200)
7120         {
7121                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7122                                                   "FROM pg_description "
7123                                                   "ORDER BY classoid, objoid, objsubid");
7124         }
7125         else
7126         {
7127                 /* Note: this will fail to find attribute comments in pre-7.2... */
7128                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7129                                                   "FROM pg_description "
7130                                                   "ORDER BY objoid");
7131         }
7132
7133         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7134
7135         /* Construct lookup table containing OIDs in numeric form */
7136
7137         i_description = PQfnumber(res, "description");
7138         i_classoid = PQfnumber(res, "classoid");
7139         i_objoid = PQfnumber(res, "objoid");
7140         i_objsubid = PQfnumber(res, "objsubid");
7141
7142         ntups = PQntuples(res);
7143
7144         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7145
7146         for (i = 0; i < ntups; i++)
7147         {
7148                 comments[i].descr = PQgetvalue(res, i, i_description);
7149                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7150                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7151                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7152         }
7153
7154         /* Do NOT free the PGresult since we are keeping pointers into it */
7155         destroyPQExpBuffer(query);
7156
7157         *items = comments;
7158         return ntups;
7159 }
7160
7161 /*
7162  * dumpDumpableObject
7163  *
7164  * This routine and its subsidiaries are responsible for creating
7165  * ArchiveEntries (TOC objects) for each object to be dumped.
7166  */
7167 static void
7168 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7169 {
7170
7171         bool skip = false;
7172
7173         switch (dobj->objType)
7174         {
7175                 case DO_INDEX:
7176                 case DO_TRIGGER:
7177                 case DO_CONSTRAINT:
7178                 case DO_FK_CONSTRAINT:
7179                 case DO_RULE:
7180                         skip = !(dumpSections & DUMP_POST_DATA);
7181                         break;
7182                 case DO_TABLE_DATA:
7183                         skip = !(dumpSections & DUMP_DATA);
7184                         break;
7185                 default:
7186                         skip = !(dumpSections & DUMP_PRE_DATA);
7187         }
7188
7189         if (skip)
7190                 return;
7191
7192         switch (dobj->objType)
7193         {
7194                 case DO_NAMESPACE:
7195                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7196                         break;
7197                 case DO_EXTENSION:
7198                         dumpExtension(fout, (ExtensionInfo *) dobj);
7199                         break;
7200                 case DO_TYPE:
7201                         dumpType(fout, (TypeInfo *) dobj);
7202                         break;
7203                 case DO_SHELL_TYPE:
7204                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7205                         break;
7206                 case DO_FUNC:
7207                         dumpFunc(fout, (FuncInfo *) dobj);
7208                         break;
7209                 case DO_AGG:
7210                         dumpAgg(fout, (AggInfo *) dobj);
7211                         break;
7212                 case DO_OPERATOR:
7213                         dumpOpr(fout, (OprInfo *) dobj);
7214                         break;
7215                 case DO_OPCLASS:
7216                         dumpOpclass(fout, (OpclassInfo *) dobj);
7217                         break;
7218                 case DO_OPFAMILY:
7219                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7220                         break;
7221                 case DO_COLLATION:
7222                         dumpCollation(fout, (CollInfo *) dobj);
7223                         break;
7224                 case DO_CONVERSION:
7225                         dumpConversion(fout, (ConvInfo *) dobj);
7226                         break;
7227                 case DO_TABLE:
7228                         dumpTable(fout, (TableInfo *) dobj);
7229                         break;
7230                 case DO_ATTRDEF:
7231                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7232                         break;
7233                 case DO_INDEX:
7234                         dumpIndex(fout, (IndxInfo *) dobj);
7235                         break;
7236                 case DO_RULE:
7237                         dumpRule(fout, (RuleInfo *) dobj);
7238                         break;
7239                 case DO_TRIGGER:
7240                         dumpTrigger(fout, (TriggerInfo *) dobj);
7241                         break;
7242                 case DO_CONSTRAINT:
7243                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7244                         break;
7245                 case DO_FK_CONSTRAINT:
7246                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7247                         break;
7248                 case DO_PROCLANG:
7249                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7250                         break;
7251                 case DO_CAST:
7252                         dumpCast(fout, (CastInfo *) dobj);
7253                         break;
7254                 case DO_TABLE_DATA:
7255                         dumpTableData(fout, (TableDataInfo *) dobj);
7256                         break;
7257                 case DO_DUMMY_TYPE:
7258                         /* table rowtypes and array types are never dumped separately */
7259                         break;
7260                 case DO_TSPARSER:
7261                         dumpTSParser(fout, (TSParserInfo *) dobj);
7262                         break;
7263                 case DO_TSDICT:
7264                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7265                         break;
7266                 case DO_TSTEMPLATE:
7267                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7268                         break;
7269                 case DO_TSCONFIG:
7270                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7271                         break;
7272                 case DO_FDW:
7273                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7274                         break;
7275                 case DO_FOREIGN_SERVER:
7276                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7277                         break;
7278                 case DO_DEFAULT_ACL:
7279                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7280                         break;
7281                 case DO_BLOB:
7282                         dumpBlob(fout, (BlobInfo *) dobj);
7283                         break;
7284                 case DO_BLOB_DATA:
7285                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7286                                                  dobj->name, NULL, NULL, "",
7287                                                  false, "BLOBS", SECTION_DATA,
7288                                                  "", "", NULL,
7289                                                  dobj->dependencies, dobj->nDeps,
7290                                                  dumpBlobs, NULL);
7291                         break;
7292         }
7293 }
7294
7295 /*
7296  * dumpNamespace
7297  *        writes out to fout the queries to recreate a user-defined namespace
7298  */
7299 static void
7300 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7301 {
7302         PQExpBuffer q;
7303         PQExpBuffer delq;
7304         PQExpBuffer labelq;
7305         char       *qnspname;
7306
7307         /* Skip if not to be dumped */
7308         if (!nspinfo->dobj.dump || dataOnly)
7309                 return;
7310
7311         /* don't dump dummy namespace from pre-7.3 source */
7312         if (strlen(nspinfo->dobj.name) == 0)
7313                 return;
7314
7315         q = createPQExpBuffer();
7316         delq = createPQExpBuffer();
7317         labelq = createPQExpBuffer();
7318
7319         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7320
7321         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7322
7323         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7324
7325         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7326
7327         if (binary_upgrade)
7328                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7329
7330         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7331                                  nspinfo->dobj.name,
7332                                  NULL, NULL,
7333                                  nspinfo->rolname,
7334                                  false, "SCHEMA", SECTION_PRE_DATA,
7335                                  q->data, delq->data, NULL,
7336                                  nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
7337                                  NULL, NULL);
7338
7339         /* Dump Schema Comments and Security Labels */
7340         dumpComment(fout, labelq->data,
7341                                 NULL, nspinfo->rolname,
7342                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7343         dumpSecLabel(fout, labelq->data,
7344                                  NULL, nspinfo->rolname,
7345                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7346
7347         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7348                         qnspname, NULL, nspinfo->dobj.name, NULL,
7349                         nspinfo->rolname, nspinfo->nspacl);
7350
7351         free(qnspname);
7352
7353         destroyPQExpBuffer(q);
7354         destroyPQExpBuffer(delq);
7355         destroyPQExpBuffer(labelq);
7356 }
7357
7358 /*
7359  * dumpExtension
7360  *        writes out to fout the queries to recreate an extension
7361  */
7362 static void
7363 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7364 {
7365         PQExpBuffer q;
7366         PQExpBuffer delq;
7367         PQExpBuffer labelq;
7368         char       *qextname;
7369
7370         /* Skip if not to be dumped */
7371         if (!extinfo->dobj.dump || dataOnly)
7372                 return;
7373
7374         q = createPQExpBuffer();
7375         delq = createPQExpBuffer();
7376         labelq = createPQExpBuffer();
7377
7378         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7379
7380         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7381
7382         if (!binary_upgrade)
7383         {
7384                 /*
7385                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7386                  * problem if the extension already exists in the target database;
7387                  * this is essential for installed-by-default extensions such as
7388                  * plpgsql.
7389                  *
7390                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7391                  * built-in extensions based on their OIDs; see
7392                  * selectDumpableExtension.
7393                  */
7394                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7395                                                   qextname, fmtId(extinfo->namespace));
7396         }
7397         else
7398         {
7399                 int                     i;
7400                 int                     n;
7401
7402                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7403                 appendPQExpBuffer(q,
7404                                                   "SELECT binary_upgrade.create_empty_extension(");
7405                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7406                 appendPQExpBuffer(q, ", ");
7407                 appendStringLiteralAH(q, extinfo->namespace, fout);
7408                 appendPQExpBuffer(q, ", ");
7409                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7410                 appendStringLiteralAH(q, extinfo->extversion, fout);
7411                 appendPQExpBuffer(q, ", ");
7412
7413                 /*
7414                  * Note that we're pushing extconfig (an OID array) back into
7415                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7416                  * preserved in binary upgrade.
7417                  */
7418                 if (strlen(extinfo->extconfig) > 2)
7419                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7420                 else
7421                         appendPQExpBuffer(q, "NULL");
7422                 appendPQExpBuffer(q, ", ");
7423                 if (strlen(extinfo->extcondition) > 2)
7424                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7425                 else
7426                         appendPQExpBuffer(q, "NULL");
7427                 appendPQExpBuffer(q, ", ");
7428                 appendPQExpBuffer(q, "ARRAY[");
7429                 n = 0;
7430                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7431                 {
7432                         DumpableObject *extobj;
7433
7434                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7435                         if (extobj && extobj->objType == DO_EXTENSION)
7436                         {
7437                                 if (n++ > 0)
7438                                         appendPQExpBuffer(q, ",");
7439                                 appendStringLiteralAH(q, extobj->name, fout);
7440                         }
7441                 }
7442                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7443                 appendPQExpBuffer(q, ");\n");
7444         }
7445
7446         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7447
7448         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7449                                  extinfo->dobj.name,
7450                                  NULL, NULL,
7451                                  "",
7452                                  false, "EXTENSION", SECTION_PRE_DATA,
7453                                  q->data, delq->data, NULL,
7454                                  extinfo->dobj.dependencies, extinfo->dobj.nDeps,
7455                                  NULL, NULL);
7456
7457         /* Dump Extension Comments and Security Labels */
7458         dumpComment(fout, labelq->data,
7459                                 NULL, "",
7460                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7461         dumpSecLabel(fout, labelq->data,
7462                                  NULL, "",
7463                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7464
7465         free(qextname);
7466
7467         destroyPQExpBuffer(q);
7468         destroyPQExpBuffer(delq);
7469         destroyPQExpBuffer(labelq);
7470 }
7471
7472 /*
7473  * dumpType
7474  *        writes out to fout the queries to recreate a user-defined type
7475  */
7476 static void
7477 dumpType(Archive *fout, TypeInfo *tyinfo)
7478 {
7479         /* Skip if not to be dumped */
7480         if (!tyinfo->dobj.dump || dataOnly)
7481                 return;
7482
7483         /* Dump out in proper style */
7484         if (tyinfo->typtype == TYPTYPE_BASE)
7485                 dumpBaseType(fout, tyinfo);
7486         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7487                 dumpDomain(fout, tyinfo);
7488         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7489                 dumpCompositeType(fout, tyinfo);
7490         else if (tyinfo->typtype == TYPTYPE_ENUM)
7491                 dumpEnumType(fout, tyinfo);
7492         else if (tyinfo->typtype == TYPTYPE_RANGE)
7493                 dumpRangeType(fout, tyinfo);
7494         else
7495                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7496                                   tyinfo->dobj.name);
7497 }
7498
7499 /*
7500  * dumpEnumType
7501  *        writes out to fout the queries to recreate a user-defined enum type
7502  */
7503 static void
7504 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7505 {
7506         PQExpBuffer q = createPQExpBuffer();
7507         PQExpBuffer delq = createPQExpBuffer();
7508         PQExpBuffer labelq = createPQExpBuffer();
7509         PQExpBuffer query = createPQExpBuffer();
7510         PGresult   *res;
7511         int                     num,
7512                                 i;
7513         Oid                     enum_oid;
7514         char       *label;
7515
7516         /* Set proper schema search path */
7517         selectSourceSchema(fout, "pg_catalog");
7518
7519         if (fout->remoteVersion >= 90100)
7520                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7521                                                   "FROM pg_catalog.pg_enum "
7522                                                   "WHERE enumtypid = '%u'"
7523                                                   "ORDER BY enumsortorder",
7524                                                   tyinfo->dobj.catId.oid);
7525         else
7526                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7527                                                   "FROM pg_catalog.pg_enum "
7528                                                   "WHERE enumtypid = '%u'"
7529                                                   "ORDER BY oid",
7530                                                   tyinfo->dobj.catId.oid);
7531
7532         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7533
7534         num = PQntuples(res);
7535
7536         /*
7537          * DROP must be fully qualified in case same name appears in pg_catalog.
7538          * CASCADE shouldn't be required here as for normal types since the I/O
7539          * functions are generic and do not get dropped.
7540          */
7541         appendPQExpBuffer(delq, "DROP TYPE %s.",
7542                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7543         appendPQExpBuffer(delq, "%s;\n",
7544                                           fmtId(tyinfo->dobj.name));
7545
7546         if (binary_upgrade)
7547                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
7548                                                                                                  tyinfo->dobj.catId.oid);
7549
7550         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
7551                                           fmtId(tyinfo->dobj.name));
7552
7553         if (!binary_upgrade)
7554         {
7555                 /* Labels with server-assigned oids */
7556                 for (i = 0; i < num; i++)
7557                 {
7558                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7559                         if (i > 0)
7560                                 appendPQExpBuffer(q, ",");
7561                         appendPQExpBuffer(q, "\n    ");
7562                         appendStringLiteralAH(q, label, fout);
7563                 }
7564         }
7565
7566         appendPQExpBuffer(q, "\n);\n");
7567
7568         if (binary_upgrade)
7569         {
7570                 /* Labels with dump-assigned (preserved) oids */
7571                 for (i = 0; i < num; i++)
7572                 {
7573                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
7574                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7575
7576                         if (i == 0)
7577                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
7578                         appendPQExpBuffer(q,
7579                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
7580                                                           enum_oid);
7581                         appendPQExpBuffer(q, "ALTER TYPE %s.",
7582                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7583                         appendPQExpBuffer(q, "%s ADD VALUE ",
7584                                                           fmtId(tyinfo->dobj.name));
7585                         appendStringLiteralAH(q, label, fout);
7586                         appendPQExpBuffer(q, ";\n\n");
7587                 }
7588         }
7589
7590         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7591
7592         if (binary_upgrade)
7593                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7594
7595         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7596                                  tyinfo->dobj.name,
7597                                  tyinfo->dobj.namespace->dobj.name,
7598                                  NULL,
7599                                  tyinfo->rolname, false,
7600                                  "TYPE", SECTION_PRE_DATA,
7601                                  q->data, delq->data, NULL,
7602                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7603                                  NULL, NULL);
7604
7605         /* Dump Type Comments and Security Labels */
7606         dumpComment(fout, labelq->data,
7607                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7608                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7609         dumpSecLabel(fout, labelq->data,
7610                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7611                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7612
7613         PQclear(res);
7614         destroyPQExpBuffer(q);
7615         destroyPQExpBuffer(delq);
7616         destroyPQExpBuffer(labelq);
7617         destroyPQExpBuffer(query);
7618 }
7619
7620 /*
7621  * dumpRangeType
7622  *        writes out to fout the queries to recreate a user-defined range type
7623  */
7624 static void
7625 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
7626 {
7627         PQExpBuffer q = createPQExpBuffer();
7628         PQExpBuffer delq = createPQExpBuffer();
7629         PQExpBuffer labelq = createPQExpBuffer();
7630         PQExpBuffer query = createPQExpBuffer();
7631         PGresult   *res;
7632         Oid                     collationOid;
7633         char       *procname;
7634
7635         /*
7636          * select appropriate schema to ensure names in CREATE are properly
7637          * qualified
7638          */
7639         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
7640
7641         appendPQExpBuffer(query,
7642                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
7643                                           "opc.opcname AS opcname, "
7644                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
7645                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
7646                                           "opc.opcdefault, "
7647                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
7648                                           "     ELSE rngcollation END AS collation, "
7649                                           "rngcanonical, rngsubdiff "
7650                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
7651                                           "     pg_catalog.pg_opclass opc "
7652                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
7653                                           "rngtypid = '%u'",
7654                                           tyinfo->dobj.catId.oid);
7655
7656         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7657         if (PQntuples(res) != 1)
7658         {
7659                 write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
7660                                   PQntuples(res), tyinfo->dobj.name);
7661                 exit_nicely();
7662         }
7663
7664         /*
7665          * DROP must be fully qualified in case same name appears in pg_catalog.
7666          * CASCADE shouldn't be required here as for normal types since the I/O
7667          * functions are generic and do not get dropped.
7668          */
7669         appendPQExpBuffer(delq, "DROP TYPE %s.",
7670                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7671         appendPQExpBuffer(delq, "%s;\n",
7672                                           fmtId(tyinfo->dobj.name));
7673
7674         if (binary_upgrade)
7675                 binary_upgrade_set_type_oids_by_type_oid(fout,
7676                                                                                                  q, tyinfo->dobj.catId.oid);
7677
7678         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
7679                                           fmtId(tyinfo->dobj.name));
7680
7681         appendPQExpBuffer(q, "\n    subtype = %s",
7682                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
7683
7684         /* print subtype_opclass only if not default for subtype */
7685         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
7686         {
7687                 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
7688                 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
7689
7690                 /* always schema-qualify, don't try to be smart */
7691                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
7692                                                   fmtId(nspname));
7693                 appendPQExpBuffer(q, "%s", fmtId(opcname));
7694         }
7695
7696         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
7697         if (OidIsValid(collationOid))
7698         {
7699                 CollInfo   *coll = findCollationByOid(collationOid);
7700
7701                 if (coll)
7702                 {
7703                         /* always schema-qualify, don't try to be smart */
7704                         appendPQExpBuffer(q, ",\n    collation = %s.",
7705                                                           fmtId(coll->dobj.namespace->dobj.name));
7706                         appendPQExpBuffer(q, "%s",
7707                                                           fmtId(coll->dobj.name));
7708                 }
7709         }
7710
7711         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
7712         if (strcmp(procname, "-") != 0)
7713                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
7714
7715         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
7716         if (strcmp(procname, "-") != 0)
7717                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
7718
7719         appendPQExpBuffer(q, "\n);\n");
7720
7721         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7722
7723         if (binary_upgrade)
7724                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7725
7726         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7727                                  tyinfo->dobj.name,
7728                                  tyinfo->dobj.namespace->dobj.name,
7729                                  NULL,
7730                                  tyinfo->rolname, false,
7731                                  "TYPE", SECTION_PRE_DATA,
7732                                  q->data, delq->data, NULL,
7733                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7734                                  NULL, NULL);
7735
7736         /* Dump Type Comments and Security Labels */
7737         dumpComment(fout, labelq->data,
7738                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7739                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7740         dumpSecLabel(fout, labelq->data,
7741                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7742                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7743
7744         PQclear(res);
7745         destroyPQExpBuffer(q);
7746         destroyPQExpBuffer(delq);
7747         destroyPQExpBuffer(labelq);
7748         destroyPQExpBuffer(query);
7749 }
7750
7751 /*
7752  * dumpBaseType
7753  *        writes out to fout the queries to recreate a user-defined base type
7754  */
7755 static void
7756 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
7757 {
7758         PQExpBuffer q = createPQExpBuffer();
7759         PQExpBuffer delq = createPQExpBuffer();
7760         PQExpBuffer labelq = createPQExpBuffer();
7761         PQExpBuffer query = createPQExpBuffer();
7762         PGresult   *res;
7763         int                     ntups;
7764         char       *typlen;
7765         char       *typinput;
7766         char       *typoutput;
7767         char       *typreceive;
7768         char       *typsend;
7769         char       *typmodin;
7770         char       *typmodout;
7771         char       *typanalyze;
7772         Oid                     typreceiveoid;
7773         Oid                     typsendoid;
7774         Oid                     typmodinoid;
7775         Oid                     typmodoutoid;
7776         Oid                     typanalyzeoid;
7777         char       *typcategory;
7778         char       *typispreferred;
7779         char       *typdelim;
7780         char       *typbyval;
7781         char       *typalign;
7782         char       *typstorage;
7783         char       *typcollatable;
7784         char       *typdefault;
7785         bool            typdefault_is_literal = false;
7786
7787         /* Set proper schema search path so regproc references list correctly */
7788         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
7789
7790         /* Fetch type-specific details */
7791         if (fout->remoteVersion >= 90100)
7792         {
7793                 appendPQExpBuffer(query, "SELECT typlen, "
7794                                                   "typinput, typoutput, typreceive, typsend, "
7795                                                   "typmodin, typmodout, typanalyze, "
7796                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7797                                                   "typsend::pg_catalog.oid AS typsendoid, "
7798                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7799                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7800                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7801                                                   "typcategory, typispreferred, "
7802                                                   "typdelim, typbyval, typalign, typstorage, "
7803                                                   "(typcollation <> 0) AS typcollatable, "
7804                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7805                                                   "FROM pg_catalog.pg_type "
7806                                                   "WHERE oid = '%u'::pg_catalog.oid",
7807                                                   tyinfo->dobj.catId.oid);
7808         }
7809         else if (fout->remoteVersion >= 80400)
7810         {
7811                 appendPQExpBuffer(query, "SELECT typlen, "
7812                                                   "typinput, typoutput, typreceive, typsend, "
7813                                                   "typmodin, typmodout, typanalyze, "
7814                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7815                                                   "typsend::pg_catalog.oid AS typsendoid, "
7816                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7817                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7818                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7819                                                   "typcategory, typispreferred, "
7820                                                   "typdelim, typbyval, typalign, typstorage, "
7821                                                   "false AS typcollatable, "
7822                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7823                                                   "FROM pg_catalog.pg_type "
7824                                                   "WHERE oid = '%u'::pg_catalog.oid",
7825                                                   tyinfo->dobj.catId.oid);
7826         }
7827         else if (fout->remoteVersion >= 80300)
7828         {
7829                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
7830                 appendPQExpBuffer(query, "SELECT typlen, "
7831                                                   "typinput, typoutput, typreceive, typsend, "
7832                                                   "typmodin, typmodout, typanalyze, "
7833                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7834                                                   "typsend::pg_catalog.oid AS typsendoid, "
7835                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7836                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7837                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7838                                                   "'U' AS typcategory, false AS typispreferred, "
7839                                                   "typdelim, typbyval, typalign, typstorage, "
7840                                                   "false AS typcollatable, "
7841                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7842                                                   "FROM pg_catalog.pg_type "
7843                                                   "WHERE oid = '%u'::pg_catalog.oid",
7844                                                   tyinfo->dobj.catId.oid);
7845         }
7846         else if (fout->remoteVersion >= 80000)
7847         {
7848                 appendPQExpBuffer(query, "SELECT typlen, "
7849                                                   "typinput, typoutput, typreceive, typsend, "
7850                                                   "'-' AS typmodin, '-' AS typmodout, "
7851                                                   "typanalyze, "
7852                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7853                                                   "typsend::pg_catalog.oid AS typsendoid, "
7854                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7855                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7856                                                   "'U' AS typcategory, false AS typispreferred, "
7857                                                   "typdelim, typbyval, typalign, typstorage, "
7858                                                   "false AS typcollatable, "
7859                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7860                                                   "FROM pg_catalog.pg_type "
7861                                                   "WHERE oid = '%u'::pg_catalog.oid",
7862                                                   tyinfo->dobj.catId.oid);
7863         }
7864         else if (fout->remoteVersion >= 70400)
7865         {
7866                 appendPQExpBuffer(query, "SELECT typlen, "
7867                                                   "typinput, typoutput, typreceive, typsend, "
7868                                                   "'-' AS typmodin, '-' AS typmodout, "
7869                                                   "'-' AS typanalyze, "
7870                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7871                                                   "typsend::pg_catalog.oid AS typsendoid, "
7872                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7873                                                   "0 AS typanalyzeoid, "
7874                                                   "'U' AS typcategory, false AS typispreferred, "
7875                                                   "typdelim, typbyval, typalign, typstorage, "
7876                                                   "false AS typcollatable, "
7877                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7878                                                   "FROM pg_catalog.pg_type "
7879                                                   "WHERE oid = '%u'::pg_catalog.oid",
7880                                                   tyinfo->dobj.catId.oid);
7881         }
7882         else if (fout->remoteVersion >= 70300)
7883         {
7884                 appendPQExpBuffer(query, "SELECT typlen, "
7885                                                   "typinput, typoutput, "
7886                                                   "'-' AS typreceive, '-' AS typsend, "
7887                                                   "'-' AS typmodin, '-' AS typmodout, "
7888                                                   "'-' AS typanalyze, "
7889                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7890                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7891                                                   "0 AS typanalyzeoid, "
7892                                                   "'U' AS typcategory, false AS typispreferred, "
7893                                                   "typdelim, typbyval, typalign, typstorage, "
7894                                                   "false AS typcollatable, "
7895                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7896                                                   "FROM pg_catalog.pg_type "
7897                                                   "WHERE oid = '%u'::pg_catalog.oid",
7898                                                   tyinfo->dobj.catId.oid);
7899         }
7900         else if (fout->remoteVersion >= 70200)
7901         {
7902                 /*
7903                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
7904                  * ignore them because they are not right.
7905                  */
7906                 appendPQExpBuffer(query, "SELECT typlen, "
7907                                                   "typinput, typoutput, "
7908                                                   "'-' AS typreceive, '-' AS typsend, "
7909                                                   "'-' AS typmodin, '-' AS typmodout, "
7910                                                   "'-' AS typanalyze, "
7911                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7912                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7913                                                   "0 AS typanalyzeoid, "
7914                                                   "'U' AS typcategory, false AS typispreferred, "
7915                                                   "typdelim, typbyval, typalign, typstorage, "
7916                                                   "false AS typcollatable, "
7917                                                   "NULL AS typdefaultbin, typdefault "
7918                                                   "FROM pg_type "
7919                                                   "WHERE oid = '%u'::oid",
7920                                                   tyinfo->dobj.catId.oid);
7921         }
7922         else if (fout->remoteVersion >= 70100)
7923         {
7924                 /*
7925                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
7926                  * representation.
7927                  */
7928                 appendPQExpBuffer(query, "SELECT typlen, "
7929                                                   "typinput, typoutput, "
7930                                                   "'-' AS typreceive, '-' AS typsend, "
7931                                                   "'-' AS typmodin, '-' AS typmodout, "
7932                                                   "'-' AS typanalyze, "
7933                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7934                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7935                                                   "0 AS typanalyzeoid, "
7936                                                   "'U' AS typcategory, false AS typispreferred, "
7937                                                   "typdelim, typbyval, typalign, typstorage, "
7938                                                   "false AS typcollatable, "
7939                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7940                                                   "FROM pg_type "
7941                                                   "WHERE oid = '%u'::oid",
7942                                                   tyinfo->dobj.catId.oid);
7943         }
7944         else
7945         {
7946                 appendPQExpBuffer(query, "SELECT typlen, "
7947                                                   "typinput, typoutput, "
7948                                                   "'-' AS typreceive, '-' AS typsend, "
7949                                                   "'-' AS typmodin, '-' AS typmodout, "
7950                                                   "'-' AS typanalyze, "
7951                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7952                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7953                                                   "0 AS typanalyzeoid, "
7954                                                   "'U' AS typcategory, false AS typispreferred, "
7955                                                   "typdelim, typbyval, typalign, "
7956                                                   "'p'::char AS typstorage, "
7957                                                   "false AS typcollatable, "
7958                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7959                                                   "FROM pg_type "
7960                                                   "WHERE oid = '%u'::oid",
7961                                                   tyinfo->dobj.catId.oid);
7962         }
7963
7964         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7965
7966         /* Expecting a single result only */
7967         ntups = PQntuples(res);
7968         if (ntups != 1)
7969         {
7970                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7971                                                            "query returned %d rows instead of one: %s\n",
7972                                                                  ntups),
7973                                   ntups, query->data);
7974                 exit_nicely();
7975         }
7976
7977         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
7978         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
7979         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7980         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
7981         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
7982         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
7983         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7984         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
7985         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
7986         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
7987         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
7988         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7989         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
7990         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
7991         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
7992         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
7993         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
7994         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
7995         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
7996         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
7997         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
7998                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
7999         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8000         {
8001                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8002                 typdefault_is_literal = true;   /* it needs quotes */
8003         }
8004         else
8005                 typdefault = NULL;
8006
8007         /*
8008          * DROP must be fully qualified in case same name appears in pg_catalog.
8009          * The reason we include CASCADE is that the circular dependency between
8010          * the type and its I/O functions makes it impossible to drop the type any
8011          * other way.
8012          */
8013         appendPQExpBuffer(delq, "DROP TYPE %s.",
8014                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8015         appendPQExpBuffer(delq, "%s CASCADE;\n",
8016                                           fmtId(tyinfo->dobj.name));
8017
8018         /* We might already have a shell type, but setting pg_type_oid is harmless */
8019         if (binary_upgrade)
8020                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8021                                                                                                  tyinfo->dobj.catId.oid);
8022
8023         appendPQExpBuffer(q,
8024                                           "CREATE TYPE %s (\n"
8025                                           "    INTERNALLENGTH = %s",
8026                                           fmtId(tyinfo->dobj.name),
8027                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8028
8029         if (fout->remoteVersion >= 70300)
8030         {
8031                 /* regproc result is correctly quoted as of 7.3 */
8032                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8033                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8034                 if (OidIsValid(typreceiveoid))
8035                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8036                 if (OidIsValid(typsendoid))
8037                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8038                 if (OidIsValid(typmodinoid))
8039                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8040                 if (OidIsValid(typmodoutoid))
8041                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8042                 if (OidIsValid(typanalyzeoid))
8043                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8044         }
8045         else
8046         {
8047                 /* regproc delivers an unquoted name before 7.3 */
8048                 /* cannot combine these because fmtId uses static result area */
8049                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8050                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8051                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8052         }
8053
8054         if (strcmp(typcollatable, "t") == 0)
8055                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8056
8057         if (typdefault != NULL)
8058         {
8059                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8060                 if (typdefault_is_literal)
8061                         appendStringLiteralAH(q, typdefault, fout);
8062                 else
8063                         appendPQExpBufferStr(q, typdefault);
8064         }
8065
8066         if (OidIsValid(tyinfo->typelem))
8067         {
8068                 char       *elemType;
8069
8070                 /* reselect schema in case changed by function dump */
8071                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8072                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8073                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8074                 free(elemType);
8075         }
8076
8077         if (strcmp(typcategory, "U") != 0)
8078         {
8079                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8080                 appendStringLiteralAH(q, typcategory, fout);
8081         }
8082
8083         if (strcmp(typispreferred, "t") == 0)
8084                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8085
8086         if (typdelim && strcmp(typdelim, ",") != 0)
8087         {
8088                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8089                 appendStringLiteralAH(q, typdelim, fout);
8090         }
8091
8092         if (strcmp(typalign, "c") == 0)
8093                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8094         else if (strcmp(typalign, "s") == 0)
8095                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8096         else if (strcmp(typalign, "i") == 0)
8097                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8098         else if (strcmp(typalign, "d") == 0)
8099                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8100
8101         if (strcmp(typstorage, "p") == 0)
8102                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8103         else if (strcmp(typstorage, "e") == 0)
8104                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8105         else if (strcmp(typstorage, "x") == 0)
8106                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8107         else if (strcmp(typstorage, "m") == 0)
8108                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8109
8110         if (strcmp(typbyval, "t") == 0)
8111                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8112
8113         appendPQExpBuffer(q, "\n);\n");
8114
8115         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8116
8117         if (binary_upgrade)
8118                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8119
8120         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8121                                  tyinfo->dobj.name,
8122                                  tyinfo->dobj.namespace->dobj.name,
8123                                  NULL,
8124                                  tyinfo->rolname, false,
8125                                  "TYPE", SECTION_PRE_DATA,
8126                                  q->data, delq->data, NULL,
8127                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8128                                  NULL, NULL);
8129
8130         /* Dump Type Comments and Security Labels */
8131         dumpComment(fout, labelq->data,
8132                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8133                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8134         dumpSecLabel(fout, labelq->data,
8135                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8136                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8137
8138         PQclear(res);
8139         destroyPQExpBuffer(q);
8140         destroyPQExpBuffer(delq);
8141         destroyPQExpBuffer(labelq);
8142         destroyPQExpBuffer(query);
8143 }
8144
8145 /*
8146  * dumpDomain
8147  *        writes out to fout the queries to recreate a user-defined domain
8148  */
8149 static void
8150 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8151 {
8152         PQExpBuffer q = createPQExpBuffer();
8153         PQExpBuffer delq = createPQExpBuffer();
8154         PQExpBuffer labelq = createPQExpBuffer();
8155         PQExpBuffer query = createPQExpBuffer();
8156         PGresult   *res;
8157         int                     ntups;
8158         int                     i;
8159         char       *typnotnull;
8160         char       *typdefn;
8161         char       *typdefault;
8162         Oid                     typcollation;
8163         bool            typdefault_is_literal = false;
8164
8165         /* Set proper schema search path so type references list correctly */
8166         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8167
8168         /* Fetch domain specific details */
8169         if (fout->remoteVersion >= 90100)
8170         {
8171                 /* typcollation is new in 9.1 */
8172                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8173                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8174                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8175                                                   "t.typdefault, "
8176                                                   "CASE WHEN t.typcollation <> u.typcollation "
8177                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8178                                                   "FROM pg_catalog.pg_type t "
8179                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8180                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8181                                                   tyinfo->dobj.catId.oid);
8182         }
8183         else
8184         {
8185                 /* We assume here that remoteVersion must be at least 70300 */
8186                 appendPQExpBuffer(query, "SELECT typnotnull, "
8187                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8188                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8189                                                   "typdefault, 0 AS typcollation "
8190                                                   "FROM pg_catalog.pg_type "
8191                                                   "WHERE oid = '%u'::pg_catalog.oid",
8192                                                   tyinfo->dobj.catId.oid);
8193         }
8194
8195         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8196
8197         /* Expecting a single result only */
8198         ntups = PQntuples(res);
8199         if (ntups != 1)
8200         {
8201                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8202                                                            "query returned %d rows instead of one: %s\n",
8203                                                                  ntups),
8204                                   ntups, query->data);
8205                 exit_nicely();
8206         }
8207
8208         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8209         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8210         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8211                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8212         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8213         {
8214                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8215                 typdefault_is_literal = true;   /* it needs quotes */
8216         }
8217         else
8218                 typdefault = NULL;
8219         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8220
8221         if (binary_upgrade)
8222                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8223                                                                                                  tyinfo->dobj.catId.oid);
8224
8225         appendPQExpBuffer(q,
8226                                           "CREATE DOMAIN %s AS %s",
8227                                           fmtId(tyinfo->dobj.name),
8228                                           typdefn);
8229
8230         /* Print collation only if different from base type's collation */
8231         if (OidIsValid(typcollation))
8232         {
8233                 CollInfo   *coll;
8234
8235                 coll = findCollationByOid(typcollation);
8236                 if (coll)
8237                 {
8238                         /* always schema-qualify, don't try to be smart */
8239                         appendPQExpBuffer(q, " COLLATE %s.",
8240                                                           fmtId(coll->dobj.namespace->dobj.name));
8241                         appendPQExpBuffer(q, "%s",
8242                                                           fmtId(coll->dobj.name));
8243                 }
8244         }
8245
8246         if (typnotnull[0] == 't')
8247                 appendPQExpBuffer(q, " NOT NULL");
8248
8249         if (typdefault != NULL)
8250         {
8251                 appendPQExpBuffer(q, " DEFAULT ");
8252                 if (typdefault_is_literal)
8253                         appendStringLiteralAH(q, typdefault, fout);
8254                 else
8255                         appendPQExpBufferStr(q, typdefault);
8256         }
8257
8258         PQclear(res);
8259
8260         /*
8261          * Add any CHECK constraints for the domain
8262          */
8263         for (i = 0; i < tyinfo->nDomChecks; i++)
8264         {
8265                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8266
8267                 if (!domcheck->separate)
8268                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8269                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8270         }
8271
8272         appendPQExpBuffer(q, ";\n");
8273
8274         /*
8275          * DROP must be fully qualified in case same name appears in pg_catalog
8276          */
8277         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8278                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8279         appendPQExpBuffer(delq, "%s;\n",
8280                                           fmtId(tyinfo->dobj.name));
8281
8282         appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
8283
8284         if (binary_upgrade)
8285                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8286
8287         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8288                                  tyinfo->dobj.name,
8289                                  tyinfo->dobj.namespace->dobj.name,
8290                                  NULL,
8291                                  tyinfo->rolname, false,
8292                                  "DOMAIN", SECTION_PRE_DATA,
8293                                  q->data, delq->data, NULL,
8294                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8295                                  NULL, NULL);
8296
8297         /* Dump Domain Comments and Security Labels */
8298         dumpComment(fout, labelq->data,
8299                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8300                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8301         dumpSecLabel(fout, labelq->data,
8302                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8303                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8304
8305         destroyPQExpBuffer(q);
8306         destroyPQExpBuffer(delq);
8307         destroyPQExpBuffer(labelq);
8308         destroyPQExpBuffer(query);
8309 }
8310
8311 /*
8312  * dumpCompositeType
8313  *        writes out to fout the queries to recreate a user-defined stand-alone
8314  *        composite type
8315  */
8316 static void
8317 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8318 {
8319         PQExpBuffer q = createPQExpBuffer();
8320         PQExpBuffer dropped = createPQExpBuffer();
8321         PQExpBuffer delq = createPQExpBuffer();
8322         PQExpBuffer labelq = createPQExpBuffer();
8323         PQExpBuffer query = createPQExpBuffer();
8324         PGresult   *res;
8325         int                     ntups;
8326         int                     i_attname;
8327         int                     i_atttypdefn;
8328         int                     i_attlen;
8329         int                     i_attalign;
8330         int                     i_attisdropped;
8331         int                     i_attcollation;
8332         int                     i_typrelid;
8333         int                     i;
8334         int                     actual_atts;
8335
8336         /* Set proper schema search path so type references list correctly */
8337         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8338
8339         /* Fetch type specific details */
8340         if (fout->remoteVersion >= 90100)
8341         {
8342                 /*
8343                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8344                  * clauses for attributes whose collation is different from their
8345                  * type's default, we use a CASE here to suppress uninteresting
8346                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8347                  * collation does not matter for those.
8348                  */
8349                 appendPQExpBuffer(query, "SELECT a.attname, "
8350                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8351                                                   "a.attlen, a.attalign, a.attisdropped, "
8352                                                   "CASE WHEN a.attcollation <> at.typcollation "
8353                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8354                                                   "ct.typrelid "
8355                                                   "FROM pg_catalog.pg_type ct "
8356                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8357                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8358                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8359                                                   "ORDER BY a.attnum ",
8360                                                   tyinfo->dobj.catId.oid);
8361         }
8362         else
8363         {
8364                 /*
8365                  * We assume here that remoteVersion must be at least 70300.  Since
8366                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8367                  * always be false.
8368                  */
8369                 appendPQExpBuffer(query, "SELECT a.attname, "
8370                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8371                                                   "a.attlen, a.attalign, a.attisdropped, "
8372                                                   "0 AS attcollation, "
8373                                                   "ct.typrelid "
8374                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8375                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8376                                                   "AND a.attrelid = ct.typrelid "
8377                                                   "ORDER BY a.attnum ",
8378                                                   tyinfo->dobj.catId.oid);
8379         }
8380
8381         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8382
8383         ntups = PQntuples(res);
8384
8385         i_attname = PQfnumber(res, "attname");
8386         i_atttypdefn = PQfnumber(res, "atttypdefn");
8387         i_attlen = PQfnumber(res, "attlen");
8388         i_attalign = PQfnumber(res, "attalign");
8389         i_attisdropped = PQfnumber(res, "attisdropped");
8390         i_attcollation = PQfnumber(res, "attcollation");
8391         i_typrelid = PQfnumber(res, "typrelid");
8392
8393         if (binary_upgrade)
8394         {
8395                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8396
8397                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8398                                                                                                  tyinfo->dobj.catId.oid);
8399                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8400         }
8401
8402         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8403                                           fmtId(tyinfo->dobj.name));
8404
8405         actual_atts = 0;
8406         for (i = 0; i < ntups; i++)
8407         {
8408                 char       *attname;
8409                 char       *atttypdefn;
8410                 char       *attlen;
8411                 char       *attalign;
8412                 bool            attisdropped;
8413                 Oid                     attcollation;
8414
8415                 attname = PQgetvalue(res, i, i_attname);
8416                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8417                 attlen = PQgetvalue(res, i, i_attlen);
8418                 attalign = PQgetvalue(res, i, i_attalign);
8419                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8420                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8421
8422                 if (attisdropped && !binary_upgrade)
8423                         continue;
8424
8425                 /* Format properly if not first attr */
8426                 if (actual_atts++ > 0)
8427                         appendPQExpBuffer(q, ",");
8428                 appendPQExpBuffer(q, "\n\t");
8429
8430                 if (!attisdropped)
8431                 {
8432                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8433
8434                         /* Add collation if not default for the column type */
8435                         if (OidIsValid(attcollation))
8436                         {
8437                                 CollInfo   *coll;
8438
8439                                 coll = findCollationByOid(attcollation);
8440                                 if (coll)
8441                                 {
8442                                         /* always schema-qualify, don't try to be smart */
8443                                         appendPQExpBuffer(q, " COLLATE %s.",
8444                                                                           fmtId(coll->dobj.namespace->dobj.name));
8445                                         appendPQExpBuffer(q, "%s",
8446                                                                           fmtId(coll->dobj.name));
8447                                 }
8448                         }
8449                 }
8450                 else
8451                 {
8452                         /*
8453                          * This is a dropped attribute and we're in binary_upgrade mode.
8454                          * Insert a placeholder for it in the CREATE TYPE command, and set
8455                          * length and alignment with direct UPDATE to the catalogs
8456                          * afterwards. See similar code in dumpTableSchema().
8457                          */
8458                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8459
8460                         /* stash separately for insertion after the CREATE TYPE */
8461                         appendPQExpBuffer(dropped,
8462                                           "\n-- For binary upgrade, recreate dropped column.\n");
8463                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8464                                                           "SET attlen = %s, "
8465                                                           "attalign = '%s', attbyval = false\n"
8466                                                           "WHERE attname = ", attlen, attalign);
8467                         appendStringLiteralAH(dropped, attname, fout);
8468                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8469                         appendStringLiteralAH(dropped, fmtId(tyinfo->dobj.name), fout);
8470                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8471
8472                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8473                                                           fmtId(tyinfo->dobj.name));
8474                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8475                                                           fmtId(attname));
8476                 }
8477         }
8478         appendPQExpBuffer(q, "\n);\n");
8479         appendPQExpBufferStr(q, dropped->data);
8480
8481         /*
8482          * DROP must be fully qualified in case same name appears in pg_catalog
8483          */
8484         appendPQExpBuffer(delq, "DROP TYPE %s.",
8485                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8486         appendPQExpBuffer(delq, "%s;\n",
8487                                           fmtId(tyinfo->dobj.name));
8488
8489         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8490
8491         if (binary_upgrade)
8492                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8493
8494         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8495                                  tyinfo->dobj.name,
8496                                  tyinfo->dobj.namespace->dobj.name,
8497                                  NULL,
8498                                  tyinfo->rolname, false,
8499                                  "TYPE", SECTION_PRE_DATA,
8500                                  q->data, delq->data, NULL,
8501                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8502                                  NULL, NULL);
8503
8504
8505         /* Dump Type Comments and Security Labels */
8506         dumpComment(fout, labelq->data,
8507                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8508                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8509         dumpSecLabel(fout, labelq->data,
8510                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8511                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8512
8513         PQclear(res);
8514         destroyPQExpBuffer(q);
8515         destroyPQExpBuffer(dropped);
8516         destroyPQExpBuffer(delq);
8517         destroyPQExpBuffer(labelq);
8518         destroyPQExpBuffer(query);
8519
8520         /* Dump any per-column comments */
8521         dumpCompositeTypeColComments(fout, tyinfo);
8522 }
8523
8524 /*
8525  * dumpCompositeTypeColComments
8526  *        writes out to fout the queries to recreate comments on the columns of
8527  *        a user-defined stand-alone composite type
8528  */
8529 static void
8530 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
8531 {
8532         CommentItem *comments;
8533         int                     ncomments;
8534         PGresult   *res;
8535         PQExpBuffer query;
8536         PQExpBuffer target;
8537         Oid                     pgClassOid;
8538         int                     i;
8539         int                     ntups;
8540         int                     i_attname;
8541         int                     i_attnum;
8542
8543         query = createPQExpBuffer();
8544
8545         /* We assume here that remoteVersion must be at least 70300 */
8546         appendPQExpBuffer(query,
8547                                           "SELECT c.tableoid, a.attname, a.attnum "
8548                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
8549                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
8550                                           "  AND NOT a.attisdropped "
8551                                           "ORDER BY a.attnum ",
8552                                           tyinfo->typrelid);
8553
8554         /* Fetch column attnames */
8555         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8556
8557         ntups = PQntuples(res);
8558         if (ntups < 1)
8559         {
8560                 PQclear(res);
8561                 destroyPQExpBuffer(query);
8562                 return;
8563         }
8564
8565         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
8566
8567         /* Search for comments associated with type's pg_class OID */
8568         ncomments = findComments(fout,
8569                                                          pgClassOid,
8570                                                          tyinfo->typrelid,
8571                                                          &comments);
8572
8573         /* If no comments exist, we're done */
8574         if (ncomments <= 0)
8575         {
8576                 PQclear(res);
8577                 destroyPQExpBuffer(query);
8578                 return;
8579         }
8580
8581         /* Build COMMENT ON statements */
8582         target = createPQExpBuffer();
8583
8584         i_attnum = PQfnumber(res, "attnum");
8585         i_attname = PQfnumber(res, "attname");
8586         while (ncomments > 0)
8587         {
8588                 const char *attname;
8589
8590                 attname = NULL;
8591                 for (i = 0; i < ntups; i++)
8592                 {
8593                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
8594                         {
8595                                 attname = PQgetvalue(res, i, i_attname);
8596                                 break;
8597                         }
8598                 }
8599                 if (attname)                    /* just in case we don't find it */
8600                 {
8601                         const char *descr = comments->descr;
8602
8603                         resetPQExpBuffer(target);
8604                         appendPQExpBuffer(target, "COLUMN %s.",
8605                                                           fmtId(tyinfo->dobj.name));
8606                         appendPQExpBuffer(target, "%s",
8607                                                           fmtId(attname));
8608
8609                         resetPQExpBuffer(query);
8610                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
8611                         appendStringLiteralAH(query, descr, fout);
8612                         appendPQExpBuffer(query, ";\n");
8613
8614                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
8615                                                  target->data,
8616                                                  tyinfo->dobj.namespace->dobj.name,
8617                                                  NULL, tyinfo->rolname,
8618                                                  false, "COMMENT", SECTION_NONE,
8619                                                  query->data, "", NULL,
8620                                                  &(tyinfo->dobj.dumpId), 1,
8621                                                  NULL, NULL);
8622                 }
8623
8624                 comments++;
8625                 ncomments--;
8626         }
8627
8628         PQclear(res);
8629         destroyPQExpBuffer(query);
8630         destroyPQExpBuffer(target);
8631 }
8632
8633 /*
8634  * dumpShellType
8635  *        writes out to fout the queries to create a shell type
8636  *
8637  * We dump a shell definition in advance of the I/O functions for the type.
8638  */
8639 static void
8640 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
8641 {
8642         PQExpBuffer q;
8643
8644         /* Skip if not to be dumped */
8645         if (!stinfo->dobj.dump || dataOnly)
8646                 return;
8647
8648         q = createPQExpBuffer();
8649
8650         /*
8651          * Note the lack of a DROP command for the shell type; any required DROP
8652          * is driven off the base type entry, instead.  This interacts with
8653          * _printTocEntry()'s use of the presence of a DROP command to decide
8654          * whether an entry needs an ALTER OWNER command.  We don't want to alter
8655          * the shell type's owner immediately on creation; that should happen only
8656          * after it's filled in, otherwise the backend complains.
8657          */
8658
8659         if (binary_upgrade)
8660                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8661                                                                                    stinfo->baseType->dobj.catId.oid);
8662
8663         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
8664                                           fmtId(stinfo->dobj.name));
8665
8666         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
8667                                  stinfo->dobj.name,
8668                                  stinfo->dobj.namespace->dobj.name,
8669                                  NULL,
8670                                  stinfo->baseType->rolname, false,
8671                                  "SHELL TYPE", SECTION_PRE_DATA,
8672                                  q->data, "", NULL,
8673                                  stinfo->dobj.dependencies, stinfo->dobj.nDeps,
8674                                  NULL, NULL);
8675
8676         destroyPQExpBuffer(q);
8677 }
8678
8679 /*
8680  * Determine whether we want to dump definitions for procedural languages.
8681  * Since the languages themselves don't have schemas, we can't rely on
8682  * the normal schema-based selection mechanism.  We choose to dump them
8683  * whenever neither --schema nor --table was given.  (Before 8.1, we used
8684  * the dump flag of the PL's call handler function, but in 8.1 this will
8685  * probably always be false since call handlers are created in pg_catalog.)
8686  *
8687  * For some backwards compatibility with the older behavior, we forcibly
8688  * dump a PL if its handler function (and validator if any) are in a
8689  * dumpable namespace.  That case is not checked here.
8690  *
8691  * Also, if the PL belongs to an extension, we do not use this heuristic.
8692  * That case isn't checked here either.
8693  */
8694 static bool
8695 shouldDumpProcLangs(void)
8696 {
8697         if (!include_everything)
8698                 return false;
8699         /* And they're schema not data */
8700         if (dataOnly)
8701                 return false;
8702         return true;
8703 }
8704
8705 /*
8706  * dumpProcLang
8707  *                writes out to fout the queries to recreate a user-defined
8708  *                procedural language
8709  */
8710 static void
8711 dumpProcLang(Archive *fout, ProcLangInfo *plang)
8712 {
8713         PQExpBuffer defqry;
8714         PQExpBuffer delqry;
8715         PQExpBuffer labelq;
8716         bool            useParams;
8717         char       *qlanname;
8718         char       *lanschema;
8719         FuncInfo   *funcInfo;
8720         FuncInfo   *inlineInfo = NULL;
8721         FuncInfo   *validatorInfo = NULL;
8722
8723         /* Skip if not to be dumped */
8724         if (!plang->dobj.dump || dataOnly)
8725                 return;
8726
8727         /*
8728          * Try to find the support function(s).  It is not an error if we don't
8729          * find them --- if the functions are in the pg_catalog schema, as is
8730          * standard in 8.1 and up, then we won't have loaded them. (In this case
8731          * we will emit a parameterless CREATE LANGUAGE command, which will
8732          * require PL template knowledge in the backend to reload.)
8733          */
8734
8735         funcInfo = findFuncByOid(plang->lanplcallfoid);
8736         if (funcInfo != NULL && !funcInfo->dobj.dump)
8737                 funcInfo = NULL;                /* treat not-dumped same as not-found */
8738
8739         if (OidIsValid(plang->laninline))
8740         {
8741                 inlineInfo = findFuncByOid(plang->laninline);
8742                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
8743                         inlineInfo = NULL;
8744         }
8745
8746         if (OidIsValid(plang->lanvalidator))
8747         {
8748                 validatorInfo = findFuncByOid(plang->lanvalidator);
8749                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
8750                         validatorInfo = NULL;
8751         }
8752
8753         /*
8754          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
8755          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
8756          * dump it.
8757          *
8758          * However, for a language that belongs to an extension, we must not use
8759          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
8760          * told to (via dobj.dump).  Generally the support functions will belong
8761          * to the same extension and so have the same dump flags ... if they
8762          * don't, this might not work terribly nicely.
8763          */
8764         useParams = (funcInfo != NULL &&
8765                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
8766                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
8767
8768         if (!plang->dobj.ext_member)
8769         {
8770                 if (!useParams && !shouldDumpProcLangs())
8771                         return;
8772         }
8773
8774         defqry = createPQExpBuffer();
8775         delqry = createPQExpBuffer();
8776         labelq = createPQExpBuffer();
8777
8778         qlanname = pg_strdup(fmtId(plang->dobj.name));
8779
8780         /*
8781          * If dumping a HANDLER clause, treat the language as being in the handler
8782          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
8783          * it doesn't really have a schema.
8784          */
8785         if (useParams)
8786                 lanschema = funcInfo->dobj.namespace->dobj.name;
8787         else
8788                 lanschema = NULL;
8789
8790         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
8791                                           qlanname);
8792
8793         if (useParams)
8794         {
8795                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
8796                                                   plang->lanpltrusted ? "TRUSTED " : "",
8797                                                   qlanname);
8798                 appendPQExpBuffer(defqry, " HANDLER %s",
8799                                                   fmtId(funcInfo->dobj.name));
8800                 if (OidIsValid(plang->laninline))
8801                 {
8802                         appendPQExpBuffer(defqry, " INLINE ");
8803                         /* Cope with possibility that inline is in different schema */
8804                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
8805                                 appendPQExpBuffer(defqry, "%s.",
8806                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
8807                         appendPQExpBuffer(defqry, "%s",
8808                                                           fmtId(inlineInfo->dobj.name));
8809                 }
8810                 if (OidIsValid(plang->lanvalidator))
8811                 {
8812                         appendPQExpBuffer(defqry, " VALIDATOR ");
8813                         /* Cope with possibility that validator is in different schema */
8814                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
8815                                 appendPQExpBuffer(defqry, "%s.",
8816                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
8817                         appendPQExpBuffer(defqry, "%s",
8818                                                           fmtId(validatorInfo->dobj.name));
8819                 }
8820         }
8821         else
8822         {
8823                 /*
8824                  * If not dumping parameters, then use CREATE OR REPLACE so that the
8825                  * command will not fail if the language is preinstalled in the target
8826                  * database.  We restrict the use of REPLACE to this case so as to
8827                  * eliminate the risk of replacing a language with incompatible
8828                  * parameter settings: this command will only succeed at all if there
8829                  * is a pg_pltemplate entry, and if there is one, the existing entry
8830                  * must match it too.
8831                  */
8832                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
8833                                                   qlanname);
8834         }
8835         appendPQExpBuffer(defqry, ";\n");
8836
8837         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
8838
8839         if (binary_upgrade)
8840                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
8841
8842         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
8843                                  plang->dobj.name,
8844                                  lanschema, NULL, plang->lanowner,
8845                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
8846                                  defqry->data, delqry->data, NULL,
8847                                  plang->dobj.dependencies, plang->dobj.nDeps,
8848                                  NULL, NULL);
8849
8850         /* Dump Proc Lang Comments and Security Labels */
8851         dumpComment(fout, labelq->data,
8852                                 NULL, "",
8853                                 plang->dobj.catId, 0, plang->dobj.dumpId);
8854         dumpSecLabel(fout, labelq->data,
8855                                  NULL, "",
8856                                  plang->dobj.catId, 0, plang->dobj.dumpId);
8857
8858         if (plang->lanpltrusted)
8859                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
8860                                 qlanname, NULL, plang->dobj.name,
8861                                 lanschema,
8862                                 plang->lanowner, plang->lanacl);
8863
8864         free(qlanname);
8865
8866         destroyPQExpBuffer(defqry);
8867         destroyPQExpBuffer(delqry);
8868         destroyPQExpBuffer(labelq);
8869 }
8870
8871 /*
8872  * format_function_arguments: generate function name and argument list
8873  *
8874  * This is used when we can rely on pg_get_function_arguments to format
8875  * the argument list.
8876  */
8877 static char *
8878 format_function_arguments(FuncInfo *finfo, char *funcargs)
8879 {
8880         PQExpBufferData fn;
8881
8882         initPQExpBuffer(&fn);
8883         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
8884         return fn.data;
8885 }
8886
8887 /*
8888  * format_function_arguments_old: generate function name and argument list
8889  *
8890  * The argument type names are qualified if needed.  The function name
8891  * is never qualified.
8892  *
8893  * This is used only with pre-8.4 servers, so we aren't expecting to see
8894  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
8895  *
8896  * Any or all of allargtypes, argmodes, argnames may be NULL.
8897  */
8898 static char *
8899 format_function_arguments_old(Archive *fout,
8900                                                           FuncInfo *finfo, int nallargs,
8901                                                           char **allargtypes,
8902                                                           char **argmodes,
8903                                                           char **argnames)
8904 {
8905         PQExpBufferData fn;
8906         int                     j;
8907
8908         initPQExpBuffer(&fn);
8909         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8910         for (j = 0; j < nallargs; j++)
8911         {
8912                 Oid                     typid;
8913                 char       *typname;
8914                 const char *argmode;
8915                 const char *argname;
8916
8917                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
8918                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
8919
8920                 if (argmodes)
8921                 {
8922                         switch (argmodes[j][0])
8923                         {
8924                                 case PROARGMODE_IN:
8925                                         argmode = "";
8926                                         break;
8927                                 case PROARGMODE_OUT:
8928                                         argmode = "OUT ";
8929                                         break;
8930                                 case PROARGMODE_INOUT:
8931                                         argmode = "INOUT ";
8932                                         break;
8933                                 default:
8934                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
8935                                         argmode = "";
8936                                         break;
8937                         }
8938                 }
8939                 else
8940                         argmode = "";
8941
8942                 argname = argnames ? argnames[j] : (char *) NULL;
8943                 if (argname && argname[0] == '\0')
8944                         argname = NULL;
8945
8946                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
8947                                                   (j > 0) ? ", " : "",
8948                                                   argmode,
8949                                                   argname ? fmtId(argname) : "",
8950                                                   argname ? " " : "",
8951                                                   typname);
8952                 free(typname);
8953         }
8954         appendPQExpBuffer(&fn, ")");
8955         return fn.data;
8956 }
8957
8958 /*
8959  * format_function_signature: generate function name and argument list
8960  *
8961  * This is like format_function_arguments_old except that only a minimal
8962  * list of input argument types is generated; this is sufficient to
8963  * reference the function, but not to define it.
8964  *
8965  * If honor_quotes is false then the function name is never quoted.
8966  * This is appropriate for use in TOC tags, but not in SQL commands.
8967  */
8968 static char *
8969 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
8970 {
8971         PQExpBufferData fn;
8972         int                     j;
8973
8974         initPQExpBuffer(&fn);
8975         if (honor_quotes)
8976                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8977         else
8978                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
8979         for (j = 0; j < finfo->nargs; j++)
8980         {
8981                 char       *typname;
8982
8983                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
8984                                                                            zeroAsOpaque);
8985
8986                 appendPQExpBuffer(&fn, "%s%s",
8987                                                   (j > 0) ? ", " : "",
8988                                                   typname);
8989                 free(typname);
8990         }
8991         appendPQExpBuffer(&fn, ")");
8992         return fn.data;
8993 }
8994
8995
8996 /*
8997  * dumpFunc:
8998  *        dump out one function
8999  */
9000 static void
9001 dumpFunc(Archive *fout, FuncInfo *finfo)
9002 {
9003         PQExpBuffer query;
9004         PQExpBuffer q;
9005         PQExpBuffer delqry;
9006         PQExpBuffer labelq;
9007         PQExpBuffer asPart;
9008         PGresult   *res;
9009         char       *funcsig;            /* identity signature */
9010         char       *funcfullsig;        /* full signature */
9011         char       *funcsig_tag;
9012         int                     ntups;
9013         char       *proretset;
9014         char       *prosrc;
9015         char       *probin;
9016         char       *funcargs;
9017         char       *funciargs;
9018         char       *funcresult;
9019         char       *proallargtypes;
9020         char       *proargmodes;
9021         char       *proargnames;
9022         char       *proiswindow;
9023         char       *provolatile;
9024         char       *proisstrict;
9025         char       *prosecdef;
9026         char       *proconfig;
9027         char       *procost;
9028         char       *prorows;
9029         char       *lanname;
9030         char       *rettypename;
9031         int                     nallargs;
9032         char      **allargtypes = NULL;
9033         char      **argmodes = NULL;
9034         char      **argnames = NULL;
9035         char      **configitems = NULL;
9036         int                     nconfigitems = 0;
9037         int                     i;
9038
9039         /* Skip if not to be dumped */
9040         if (!finfo->dobj.dump || dataOnly)
9041                 return;
9042
9043         query = createPQExpBuffer();
9044         q = createPQExpBuffer();
9045         delqry = createPQExpBuffer();
9046         labelq = createPQExpBuffer();
9047         asPart = createPQExpBuffer();
9048
9049         /* Set proper schema search path so type references list correctly */
9050         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9051
9052         /* Fetch function-specific details */
9053         if (fout->remoteVersion >= 80400)
9054         {
9055                 /*
9056                  * In 8.4 and up we rely on pg_get_function_arguments and
9057                  * pg_get_function_result instead of examining proallargtypes etc.
9058                  */
9059                 appendPQExpBuffer(query,
9060                                                   "SELECT proretset, prosrc, probin, "
9061                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9062                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9063                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9064                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9065                                                   "proconfig, procost, prorows, "
9066                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9067                                                   "FROM pg_catalog.pg_proc "
9068                                                   "WHERE oid = '%u'::pg_catalog.oid",
9069                                                   finfo->dobj.catId.oid);
9070         }
9071         else if (fout->remoteVersion >= 80300)
9072         {
9073                 appendPQExpBuffer(query,
9074                                                   "SELECT proretset, prosrc, probin, "
9075                                                   "proallargtypes, proargmodes, proargnames, "
9076                                                   "false AS proiswindow, "
9077                                                   "provolatile, proisstrict, prosecdef, "
9078                                                   "proconfig, procost, prorows, "
9079                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9080                                                   "FROM pg_catalog.pg_proc "
9081                                                   "WHERE oid = '%u'::pg_catalog.oid",
9082                                                   finfo->dobj.catId.oid);
9083         }
9084         else if (fout->remoteVersion >= 80100)
9085         {
9086                 appendPQExpBuffer(query,
9087                                                   "SELECT proretset, prosrc, probin, "
9088                                                   "proallargtypes, proargmodes, proargnames, "
9089                                                   "false AS proiswindow, "
9090                                                   "provolatile, proisstrict, prosecdef, "
9091                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9092                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9093                                                   "FROM pg_catalog.pg_proc "
9094                                                   "WHERE oid = '%u'::pg_catalog.oid",
9095                                                   finfo->dobj.catId.oid);
9096         }
9097         else if (fout->remoteVersion >= 80000)
9098         {
9099                 appendPQExpBuffer(query,
9100                                                   "SELECT proretset, prosrc, probin, "
9101                                                   "null AS proallargtypes, "
9102                                                   "null AS proargmodes, "
9103                                                   "proargnames, "
9104                                                   "false AS proiswindow, "
9105                                                   "provolatile, proisstrict, prosecdef, "
9106                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9107                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9108                                                   "FROM pg_catalog.pg_proc "
9109                                                   "WHERE oid = '%u'::pg_catalog.oid",
9110                                                   finfo->dobj.catId.oid);
9111         }
9112         else if (fout->remoteVersion >= 70300)
9113         {
9114                 appendPQExpBuffer(query,
9115                                                   "SELECT proretset, prosrc, probin, "
9116                                                   "null AS proallargtypes, "
9117                                                   "null AS proargmodes, "
9118                                                   "null AS proargnames, "
9119                                                   "false AS proiswindow, "
9120                                                   "provolatile, proisstrict, prosecdef, "
9121                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9122                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9123                                                   "FROM pg_catalog.pg_proc "
9124                                                   "WHERE oid = '%u'::pg_catalog.oid",
9125                                                   finfo->dobj.catId.oid);
9126         }
9127         else if (fout->remoteVersion >= 70100)
9128         {
9129                 appendPQExpBuffer(query,
9130                                                   "SELECT proretset, prosrc, probin, "
9131                                                   "null AS proallargtypes, "
9132                                                   "null AS proargmodes, "
9133                                                   "null AS proargnames, "
9134                                                   "false AS proiswindow, "
9135                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9136                                                   "proisstrict, "
9137                                                   "false AS prosecdef, "
9138                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9139                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9140                                                   "FROM pg_proc "
9141                                                   "WHERE oid = '%u'::oid",
9142                                                   finfo->dobj.catId.oid);
9143         }
9144         else
9145         {
9146                 appendPQExpBuffer(query,
9147                                                   "SELECT proretset, prosrc, probin, "
9148                                                   "null AS proallargtypes, "
9149                                                   "null AS proargmodes, "
9150                                                   "null AS proargnames, "
9151                                                   "false AS proiswindow, "
9152                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9153                                                   "false AS proisstrict, "
9154                                                   "false AS prosecdef, "
9155                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9156                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9157                                                   "FROM pg_proc "
9158                                                   "WHERE oid = '%u'::oid",
9159                                                   finfo->dobj.catId.oid);
9160         }
9161
9162         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9163
9164         /* Expecting a single result only */
9165         ntups = PQntuples(res);
9166         if (ntups != 1)
9167         {
9168                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9169                                                            "query returned %d rows instead of one: %s\n",
9170                                                                  ntups),
9171                                   ntups, query->data);
9172                 exit_nicely();
9173         }
9174
9175         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9176         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9177         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9178         if (fout->remoteVersion >= 80400)
9179         {
9180                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9181                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9182                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9183                 proallargtypes = proargmodes = proargnames = NULL;
9184         }
9185         else
9186         {
9187                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9188                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9189                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9190                 funcargs = funciargs = funcresult = NULL;
9191         }
9192         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9193         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9194         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9195         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9196         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9197         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9198         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9199         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9200
9201         /*
9202          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9203          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9204          * versions would set it to "-".  There are no known cases in which prosrc
9205          * is unused, so the tests below for "-" are probably useless.
9206          */
9207         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9208         {
9209                 appendPQExpBuffer(asPart, "AS ");
9210                 appendStringLiteralAH(asPart, probin, fout);
9211                 if (strcmp(prosrc, "-") != 0)
9212                 {
9213                         appendPQExpBuffer(asPart, ", ");
9214
9215                         /*
9216                          * where we have bin, use dollar quoting if allowed and src
9217                          * contains quote or backslash; else use regular quoting.
9218                          */
9219                         if (disable_dollar_quoting ||
9220                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9221                                 appendStringLiteralAH(asPart, prosrc, fout);
9222                         else
9223                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9224                 }
9225         }
9226         else
9227         {
9228                 if (strcmp(prosrc, "-") != 0)
9229                 {
9230                         appendPQExpBuffer(asPart, "AS ");
9231                         /* with no bin, dollar quote src unconditionally if allowed */
9232                         if (disable_dollar_quoting)
9233                                 appendStringLiteralAH(asPart, prosrc, fout);
9234                         else
9235                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9236                 }
9237         }
9238
9239         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9240
9241         if (proallargtypes && *proallargtypes)
9242         {
9243                 int                     nitems = 0;
9244
9245                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9246                         nitems < finfo->nargs)
9247                 {
9248                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9249                         if (allargtypes)
9250                                 free(allargtypes);
9251                         allargtypes = NULL;
9252                 }
9253                 else
9254                         nallargs = nitems;
9255         }
9256
9257         if (proargmodes && *proargmodes)
9258         {
9259                 int                     nitems = 0;
9260
9261                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9262                         nitems != nallargs)
9263                 {
9264                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9265                         if (argmodes)
9266                                 free(argmodes);
9267                         argmodes = NULL;
9268                 }
9269         }
9270
9271         if (proargnames && *proargnames)
9272         {
9273                 int                     nitems = 0;
9274
9275                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9276                         nitems != nallargs)
9277                 {
9278                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9279                         if (argnames)
9280                                 free(argnames);
9281                         argnames = NULL;
9282                 }
9283         }
9284
9285         if (proconfig && *proconfig)
9286         {
9287                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9288                 {
9289                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9290                         if (configitems)
9291                                 free(configitems);
9292                         configitems = NULL;
9293                         nconfigitems = 0;
9294                 }
9295         }
9296
9297         if (funcargs)
9298         {
9299                 /* 8.4 or later; we rely on server-side code for most of the work */
9300                 funcfullsig = format_function_arguments(finfo, funcargs);
9301                 funcsig = format_function_arguments(finfo, funciargs);
9302         }
9303         else
9304         {
9305                 /* pre-8.4, do it ourselves */
9306                 funcsig = format_function_arguments_old(fout,
9307                                                                                                 finfo, nallargs, allargtypes,
9308                                                                                                 argmodes, argnames);
9309                 funcfullsig = funcsig;
9310         }
9311
9312         funcsig_tag = format_function_signature(fout, finfo, false);
9313
9314         /*
9315          * DROP must be fully qualified in case same name appears in pg_catalog
9316          */
9317         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9318                                           fmtId(finfo->dobj.namespace->dobj.name),
9319                                           funcsig);
9320
9321         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9322         if (funcresult)
9323                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9324         else
9325         {
9326                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9327                                                                                    zeroAsOpaque);
9328                 appendPQExpBuffer(q, "RETURNS %s%s",
9329                                                   (proretset[0] == 't') ? "SETOF " : "",
9330                                                   rettypename);
9331                 free(rettypename);
9332         }
9333
9334         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9335
9336         if (proiswindow[0] == 't')
9337                 appendPQExpBuffer(q, " WINDOW");
9338
9339         if (provolatile[0] != PROVOLATILE_VOLATILE)
9340         {
9341                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9342                         appendPQExpBuffer(q, " IMMUTABLE");
9343                 else if (provolatile[0] == PROVOLATILE_STABLE)
9344                         appendPQExpBuffer(q, " STABLE");
9345                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9346                 {
9347                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
9348                                           finfo->dobj.name);
9349                         exit_nicely();
9350                 }
9351         }
9352
9353         if (proisstrict[0] == 't')
9354                 appendPQExpBuffer(q, " STRICT");
9355
9356         if (prosecdef[0] == 't')
9357                 appendPQExpBuffer(q, " SECURITY DEFINER");
9358
9359         /*
9360          * COST and ROWS are emitted only if present and not default, so as not to
9361          * break backwards-compatibility of the dump without need.      Keep this code
9362          * in sync with the defaults in functioncmds.c.
9363          */
9364         if (strcmp(procost, "0") != 0)
9365         {
9366                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9367                 {
9368                         /* default cost is 1 */
9369                         if (strcmp(procost, "1") != 0)
9370                                 appendPQExpBuffer(q, " COST %s", procost);
9371                 }
9372                 else
9373                 {
9374                         /* default cost is 100 */
9375                         if (strcmp(procost, "100") != 0)
9376                                 appendPQExpBuffer(q, " COST %s", procost);
9377                 }
9378         }
9379         if (proretset[0] == 't' &&
9380                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9381                 appendPQExpBuffer(q, " ROWS %s", prorows);
9382
9383         for (i = 0; i < nconfigitems; i++)
9384         {
9385                 /* we feel free to scribble on configitems[] here */
9386                 char       *configitem = configitems[i];
9387                 char       *pos;
9388
9389                 pos = strchr(configitem, '=');
9390                 if (pos == NULL)
9391                         continue;
9392                 *pos++ = '\0';
9393                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9394
9395                 /*
9396                  * Some GUC variable names are 'LIST' type and hence must not be
9397                  * quoted.
9398                  */
9399                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9400                         || pg_strcasecmp(configitem, "search_path") == 0)
9401                         appendPQExpBuffer(q, "%s", pos);
9402                 else
9403                         appendStringLiteralAH(q, pos, fout);
9404         }
9405
9406         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9407
9408         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9409
9410         if (binary_upgrade)
9411                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9412
9413         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9414                                  funcsig_tag,
9415                                  finfo->dobj.namespace->dobj.name,
9416                                  NULL,
9417                                  finfo->rolname, false,
9418                                  "FUNCTION", SECTION_PRE_DATA,
9419                                  q->data, delqry->data, NULL,
9420                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
9421                                  NULL, NULL);
9422
9423         /* Dump Function Comments and Security Labels */
9424         dumpComment(fout, labelq->data,
9425                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9426                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9427         dumpSecLabel(fout, labelq->data,
9428                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9429                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9430
9431         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9432                         funcsig, NULL, funcsig_tag,
9433                         finfo->dobj.namespace->dobj.name,
9434                         finfo->rolname, finfo->proacl);
9435
9436         PQclear(res);
9437
9438         destroyPQExpBuffer(query);
9439         destroyPQExpBuffer(q);
9440         destroyPQExpBuffer(delqry);
9441         destroyPQExpBuffer(labelq);
9442         destroyPQExpBuffer(asPart);
9443         free(funcsig);
9444         free(funcsig_tag);
9445         if (allargtypes)
9446                 free(allargtypes);
9447         if (argmodes)
9448                 free(argmodes);
9449         if (argnames)
9450                 free(argnames);
9451         if (configitems)
9452                 free(configitems);
9453 }
9454
9455
9456 /*
9457  * Dump a user-defined cast
9458  */
9459 static void
9460 dumpCast(Archive *fout, CastInfo *cast)
9461 {
9462         PQExpBuffer defqry;
9463         PQExpBuffer delqry;
9464         PQExpBuffer labelq;
9465         FuncInfo   *funcInfo = NULL;
9466
9467         /* Skip if not to be dumped */
9468         if (!cast->dobj.dump || dataOnly)
9469                 return;
9470
9471         /* Cannot dump if we don't have the cast function's info */
9472         if (OidIsValid(cast->castfunc))
9473         {
9474                 funcInfo = findFuncByOid(cast->castfunc);
9475                 if (funcInfo == NULL)
9476                         return;
9477         }
9478
9479         /*
9480          * As per discussion we dump casts if one or more of the underlying
9481          * objects (the conversion function and the two data types) are not
9482          * builtin AND if all of the non-builtin objects are included in the dump.
9483          * Builtin meaning, the namespace name does not start with "pg_".
9484          *
9485          * However, for a cast that belongs to an extension, we must not use this
9486          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9487          */
9488         if (!cast->dobj.ext_member)
9489         {
9490                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9491                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9492
9493                 if (sourceInfo == NULL || targetInfo == NULL)
9494                         return;
9495
9496                 /*
9497                  * Skip this cast if all objects are from pg_
9498                  */
9499                 if ((funcInfo == NULL ||
9500                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9501                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
9502                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
9503                         return;
9504
9505                 /*
9506                  * Skip cast if function isn't from pg_ and is not to be dumped.
9507                  */
9508                 if (funcInfo &&
9509                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9510                         !funcInfo->dobj.dump)
9511                         return;
9512
9513                 /*
9514                  * Same for the source type
9515                  */
9516                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9517                         !sourceInfo->dobj.dump)
9518                         return;
9519
9520                 /*
9521                  * and the target type.
9522                  */
9523                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9524                         !targetInfo->dobj.dump)
9525                         return;
9526         }
9527
9528         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
9529         selectSourceSchema(fout, "pg_catalog");
9530
9531         defqry = createPQExpBuffer();
9532         delqry = createPQExpBuffer();
9533         labelq = createPQExpBuffer();
9534
9535         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
9536                                   getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9537                                   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9538
9539         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
9540                                   getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9541                                   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9542
9543         switch (cast->castmethod)
9544         {
9545                 case COERCION_METHOD_BINARY:
9546                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
9547                         break;
9548                 case COERCION_METHOD_INOUT:
9549                         appendPQExpBuffer(defqry, "WITH INOUT");
9550                         break;
9551                 case COERCION_METHOD_FUNCTION:
9552
9553                         /*
9554                          * Always qualify the function name, in case it is not in
9555                          * pg_catalog schema (format_function_signature won't qualify it).
9556                          */
9557                         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
9558                                                           fmtId(funcInfo->dobj.namespace->dobj.name));
9559                         appendPQExpBuffer(defqry, "%s",
9560                                                   format_function_signature(fout, funcInfo, true));
9561                         break;
9562                 default:
9563                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
9564         }
9565
9566         if (cast->castcontext == 'a')
9567                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
9568         else if (cast->castcontext == 'i')
9569                 appendPQExpBuffer(defqry, " AS IMPLICIT");
9570         appendPQExpBuffer(defqry, ";\n");
9571
9572         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
9573                                   getFormattedTypeName(fout, cast->castsource, zeroAsNone),
9574                                   getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
9575
9576         if (binary_upgrade)
9577                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
9578
9579         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
9580                                  labelq->data,
9581                                  "pg_catalog", NULL, "",
9582                                  false, "CAST", SECTION_PRE_DATA,
9583                                  defqry->data, delqry->data, NULL,
9584                                  cast->dobj.dependencies, cast->dobj.nDeps,
9585                                  NULL, NULL);
9586
9587         /* Dump Cast Comments */
9588         dumpComment(fout, labelq->data,
9589                                 NULL, "",
9590                                 cast->dobj.catId, 0, cast->dobj.dumpId);
9591
9592         destroyPQExpBuffer(defqry);
9593         destroyPQExpBuffer(delqry);
9594         destroyPQExpBuffer(labelq);
9595 }
9596
9597 /*
9598  * dumpOpr
9599  *        write out a single operator definition
9600  */
9601 static void
9602 dumpOpr(Archive *fout, OprInfo *oprinfo)
9603 {
9604         PQExpBuffer query;
9605         PQExpBuffer q;
9606         PQExpBuffer delq;
9607         PQExpBuffer labelq;
9608         PQExpBuffer oprid;
9609         PQExpBuffer details;
9610         const char *name;
9611         PGresult   *res;
9612         int                     ntups;
9613         int                     i_oprkind;
9614         int                     i_oprcode;
9615         int                     i_oprleft;
9616         int                     i_oprright;
9617         int                     i_oprcom;
9618         int                     i_oprnegate;
9619         int                     i_oprrest;
9620         int                     i_oprjoin;
9621         int                     i_oprcanmerge;
9622         int                     i_oprcanhash;
9623         char       *oprkind;
9624         char       *oprcode;
9625         char       *oprleft;
9626         char       *oprright;
9627         char       *oprcom;
9628         char       *oprnegate;
9629         char       *oprrest;
9630         char       *oprjoin;
9631         char       *oprcanmerge;
9632         char       *oprcanhash;
9633
9634         /* Skip if not to be dumped */
9635         if (!oprinfo->dobj.dump || dataOnly)
9636                 return;
9637
9638         /*
9639          * some operators are invalid because they were the result of user
9640          * defining operators before commutators exist
9641          */
9642         if (!OidIsValid(oprinfo->oprcode))
9643                 return;
9644
9645         query = createPQExpBuffer();
9646         q = createPQExpBuffer();
9647         delq = createPQExpBuffer();
9648         labelq = createPQExpBuffer();
9649         oprid = createPQExpBuffer();
9650         details = createPQExpBuffer();
9651
9652         /* Make sure we are in proper schema so regoperator works correctly */
9653         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
9654
9655         if (fout->remoteVersion >= 80300)
9656         {
9657                 appendPQExpBuffer(query, "SELECT oprkind, "
9658                                                   "oprcode::pg_catalog.regprocedure, "
9659                                                   "oprleft::pg_catalog.regtype, "
9660                                                   "oprright::pg_catalog.regtype, "
9661                                                   "oprcom::pg_catalog.regoperator, "
9662                                                   "oprnegate::pg_catalog.regoperator, "
9663                                                   "oprrest::pg_catalog.regprocedure, "
9664                                                   "oprjoin::pg_catalog.regprocedure, "
9665                                                   "oprcanmerge, oprcanhash "
9666                                                   "FROM pg_catalog.pg_operator "
9667                                                   "WHERE oid = '%u'::pg_catalog.oid",
9668                                                   oprinfo->dobj.catId.oid);
9669         }
9670         else if (fout->remoteVersion >= 70300)
9671         {
9672                 appendPQExpBuffer(query, "SELECT oprkind, "
9673                                                   "oprcode::pg_catalog.regprocedure, "
9674                                                   "oprleft::pg_catalog.regtype, "
9675                                                   "oprright::pg_catalog.regtype, "
9676                                                   "oprcom::pg_catalog.regoperator, "
9677                                                   "oprnegate::pg_catalog.regoperator, "
9678                                                   "oprrest::pg_catalog.regprocedure, "
9679                                                   "oprjoin::pg_catalog.regprocedure, "
9680                                                   "(oprlsortop != 0) AS oprcanmerge, "
9681                                                   "oprcanhash "
9682                                                   "FROM pg_catalog.pg_operator "
9683                                                   "WHERE oid = '%u'::pg_catalog.oid",
9684                                                   oprinfo->dobj.catId.oid);
9685         }
9686         else if (fout->remoteVersion >= 70100)
9687         {
9688                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9689                                                   "CASE WHEN oprleft = 0 THEN '-' "
9690                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
9691                                                   "CASE WHEN oprright = 0 THEN '-' "
9692                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
9693                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9694                                                   "(oprlsortop != 0) AS oprcanmerge, "
9695                                                   "oprcanhash "
9696                                                   "FROM pg_operator "
9697                                                   "WHERE oid = '%u'::oid",
9698                                                   oprinfo->dobj.catId.oid);
9699         }
9700         else
9701         {
9702                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9703                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
9704                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
9705                                                   "CASE WHEN oprright = 0 THEN '-'::name "
9706                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
9707                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9708                                                   "(oprlsortop != 0) AS oprcanmerge, "
9709                                                   "oprcanhash "
9710                                                   "FROM pg_operator "
9711                                                   "WHERE oid = '%u'::oid",
9712                                                   oprinfo->dobj.catId.oid);
9713         }
9714
9715         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9716
9717         /* Expecting a single result only */
9718         ntups = PQntuples(res);
9719         if (ntups != 1)
9720         {
9721                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9722                                                            "query returned %d rows instead of one: %s\n",
9723                                                                  ntups),
9724                                   ntups, query->data);
9725                 exit_nicely();
9726         }
9727
9728         i_oprkind = PQfnumber(res, "oprkind");
9729         i_oprcode = PQfnumber(res, "oprcode");
9730         i_oprleft = PQfnumber(res, "oprleft");
9731         i_oprright = PQfnumber(res, "oprright");
9732         i_oprcom = PQfnumber(res, "oprcom");
9733         i_oprnegate = PQfnumber(res, "oprnegate");
9734         i_oprrest = PQfnumber(res, "oprrest");
9735         i_oprjoin = PQfnumber(res, "oprjoin");
9736         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
9737         i_oprcanhash = PQfnumber(res, "oprcanhash");
9738
9739         oprkind = PQgetvalue(res, 0, i_oprkind);
9740         oprcode = PQgetvalue(res, 0, i_oprcode);
9741         oprleft = PQgetvalue(res, 0, i_oprleft);
9742         oprright = PQgetvalue(res, 0, i_oprright);
9743         oprcom = PQgetvalue(res, 0, i_oprcom);
9744         oprnegate = PQgetvalue(res, 0, i_oprnegate);
9745         oprrest = PQgetvalue(res, 0, i_oprrest);
9746         oprjoin = PQgetvalue(res, 0, i_oprjoin);
9747         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
9748         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
9749
9750         appendPQExpBuffer(details, "    PROCEDURE = %s",
9751                                           convertRegProcReference(fout, oprcode));
9752
9753         appendPQExpBuffer(oprid, "%s (",
9754                                           oprinfo->dobj.name);
9755
9756         /*
9757          * right unary means there's a left arg and left unary means there's a
9758          * right arg
9759          */
9760         if (strcmp(oprkind, "r") == 0 ||
9761                 strcmp(oprkind, "b") == 0)
9762         {
9763                 if (fout->remoteVersion >= 70100)
9764                         name = oprleft;
9765                 else
9766                         name = fmtId(oprleft);
9767                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
9768                 appendPQExpBuffer(oprid, "%s", name);
9769         }
9770         else
9771                 appendPQExpBuffer(oprid, "NONE");
9772
9773         if (strcmp(oprkind, "l") == 0 ||
9774                 strcmp(oprkind, "b") == 0)
9775         {
9776                 if (fout->remoteVersion >= 70100)
9777                         name = oprright;
9778                 else
9779                         name = fmtId(oprright);
9780                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
9781                 appendPQExpBuffer(oprid, ", %s)", name);
9782         }
9783         else
9784                 appendPQExpBuffer(oprid, ", NONE)");
9785
9786         name = convertOperatorReference(fout, oprcom);
9787         if (name)
9788                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
9789
9790         name = convertOperatorReference(fout, oprnegate);
9791         if (name)
9792                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
9793
9794         if (strcmp(oprcanmerge, "t") == 0)
9795                 appendPQExpBuffer(details, ",\n    MERGES");
9796
9797         if (strcmp(oprcanhash, "t") == 0)
9798                 appendPQExpBuffer(details, ",\n    HASHES");
9799
9800         name = convertRegProcReference(fout, oprrest);
9801         if (name)
9802                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
9803
9804         name = convertRegProcReference(fout, oprjoin);
9805         if (name)
9806                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
9807
9808         /*
9809          * DROP must be fully qualified in case same name appears in pg_catalog
9810          */
9811         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
9812                                           fmtId(oprinfo->dobj.namespace->dobj.name),
9813                                           oprid->data);
9814
9815         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
9816                                           oprinfo->dobj.name, details->data);
9817
9818         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
9819
9820         if (binary_upgrade)
9821                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
9822
9823         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
9824                                  oprinfo->dobj.name,
9825                                  oprinfo->dobj.namespace->dobj.name,
9826                                  NULL,
9827                                  oprinfo->rolname,
9828                                  false, "OPERATOR", SECTION_PRE_DATA,
9829                                  q->data, delq->data, NULL,
9830                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
9831                                  NULL, NULL);
9832
9833         /* Dump Operator Comments */
9834         dumpComment(fout, labelq->data,
9835                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
9836                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
9837
9838         PQclear(res);
9839
9840         destroyPQExpBuffer(query);
9841         destroyPQExpBuffer(q);
9842         destroyPQExpBuffer(delq);
9843         destroyPQExpBuffer(labelq);
9844         destroyPQExpBuffer(oprid);
9845         destroyPQExpBuffer(details);
9846 }
9847
9848 /*
9849  * Convert a function reference obtained from pg_operator
9850  *
9851  * Returns what to print, or NULL if function references is InvalidOid
9852  *
9853  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
9854  * argument-types part.  In prior versions, the input is a REGPROC display.
9855  */
9856 static const char *
9857 convertRegProcReference(Archive *fout, const char *proc)
9858 {
9859         /* In all cases "-" means a null reference */
9860         if (strcmp(proc, "-") == 0)
9861                 return NULL;
9862
9863         if (fout->remoteVersion >= 70300)
9864         {
9865                 char       *name;
9866                 char       *paren;
9867                 bool            inquote;
9868
9869                 name = pg_strdup(proc);
9870                 /* find non-double-quoted left paren */
9871                 inquote = false;
9872                 for (paren = name; *paren; paren++)
9873                 {
9874                         if (*paren == '(' && !inquote)
9875                         {
9876                                 *paren = '\0';
9877                                 break;
9878                         }
9879                         if (*paren == '"')
9880                                 inquote = !inquote;
9881                 }
9882                 return name;
9883         }
9884
9885         /* REGPROC before 7.3 does not quote its result */
9886         return fmtId(proc);
9887 }
9888
9889 /*
9890  * Convert an operator cross-reference obtained from pg_operator
9891  *
9892  * Returns what to print, or NULL to print nothing
9893  *
9894  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
9895  * argument-types part, and add OPERATOR() decoration if the name is
9896  * schema-qualified.  In older versions, the input is just a numeric OID,
9897  * which we search our operator list for.
9898  */
9899 static const char *
9900 convertOperatorReference(Archive *fout, const char *opr)
9901 {
9902         OprInfo    *oprInfo;
9903
9904         /* In all cases "0" means a null reference */
9905         if (strcmp(opr, "0") == 0)
9906                 return NULL;
9907
9908         if (fout->remoteVersion >= 70300)
9909         {
9910                 char       *name;
9911                 char       *oname;
9912                 char       *ptr;
9913                 bool            inquote;
9914                 bool            sawdot;
9915
9916                 name = pg_strdup(opr);
9917                 /* find non-double-quoted left paren, and check for non-quoted dot */
9918                 inquote = false;
9919                 sawdot = false;
9920                 for (ptr = name; *ptr; ptr++)
9921                 {
9922                         if (*ptr == '"')
9923                                 inquote = !inquote;
9924                         else if (*ptr == '.' && !inquote)
9925                                 sawdot = true;
9926                         else if (*ptr == '(' && !inquote)
9927                         {
9928                                 *ptr = '\0';
9929                                 break;
9930                         }
9931                 }
9932                 /* If not schema-qualified, don't need to add OPERATOR() */
9933                 if (!sawdot)
9934                         return name;
9935                 oname = pg_malloc(strlen(name) + 11);
9936                 sprintf(oname, "OPERATOR(%s)", name);
9937                 free(name);
9938                 return oname;
9939         }
9940
9941         oprInfo = findOprByOid(atooid(opr));
9942         if (oprInfo == NULL)
9943         {
9944                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
9945                                   opr);
9946                 return NULL;
9947         }
9948         return oprInfo->dobj.name;
9949 }
9950
9951 /*
9952  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
9953  *
9954  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
9955  * argument lists of these functions are predetermined.  Note that the
9956  * caller should ensure we are in the proper schema, because the results
9957  * are search path dependent!
9958  */
9959 static const char *
9960 convertTSFunction(Archive *fout, Oid funcOid)
9961 {
9962         char       *result;
9963         char            query[128];
9964         PGresult   *res;
9965         int                     ntups;
9966
9967         snprintf(query, sizeof(query),
9968                          "SELECT '%u'::pg_catalog.regproc", funcOid);
9969         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
9970
9971         ntups = PQntuples(res);
9972         if (ntups != 1)
9973         {
9974                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9975                                                            "query returned %d rows instead of one: %s\n",
9976                                                                  ntups),
9977                                   ntups, query);
9978                 exit_nicely();
9979         }
9980
9981         result = pg_strdup(PQgetvalue(res, 0, 0));
9982
9983         PQclear(res);
9984
9985         return result;
9986 }
9987
9988
9989 /*
9990  * dumpOpclass
9991  *        write out a single operator class definition
9992  */
9993 static void
9994 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
9995 {
9996         PQExpBuffer query;
9997         PQExpBuffer q;
9998         PQExpBuffer delq;
9999         PQExpBuffer labelq;
10000         PGresult   *res;
10001         int                     ntups;
10002         int                     i_opcintype;
10003         int                     i_opckeytype;
10004         int                     i_opcdefault;
10005         int                     i_opcfamily;
10006         int                     i_opcfamilyname;
10007         int                     i_opcfamilynsp;
10008         int                     i_amname;
10009         int                     i_amopstrategy;
10010         int                     i_amopreqcheck;
10011         int                     i_amopopr;
10012         int                     i_sortfamily;
10013         int                     i_sortfamilynsp;
10014         int                     i_amprocnum;
10015         int                     i_amproc;
10016         int                     i_amproclefttype;
10017         int                     i_amprocrighttype;
10018         char       *opcintype;
10019         char       *opckeytype;
10020         char       *opcdefault;
10021         char       *opcfamily;
10022         char       *opcfamilyname;
10023         char       *opcfamilynsp;
10024         char       *amname;
10025         char       *amopstrategy;
10026         char       *amopreqcheck;
10027         char       *amopopr;
10028         char       *sortfamily;
10029         char       *sortfamilynsp;
10030         char       *amprocnum;
10031         char       *amproc;
10032         char       *amproclefttype;
10033         char       *amprocrighttype;
10034         bool            needComma;
10035         int                     i;
10036
10037         /* Skip if not to be dumped */
10038         if (!opcinfo->dobj.dump || dataOnly)
10039                 return;
10040
10041         /*
10042          * XXX currently we do not implement dumping of operator classes from
10043          * pre-7.3 databases.  This could be done but it seems not worth the
10044          * trouble.
10045          */
10046         if (fout->remoteVersion < 70300)
10047                 return;
10048
10049         query = createPQExpBuffer();
10050         q = createPQExpBuffer();
10051         delq = createPQExpBuffer();
10052         labelq = createPQExpBuffer();
10053
10054         /* Make sure we are in proper schema so regoperator works correctly */
10055         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10056
10057         /* Get additional fields from the pg_opclass row */
10058         if (fout->remoteVersion >= 80300)
10059         {
10060                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10061                                                   "opckeytype::pg_catalog.regtype, "
10062                                                   "opcdefault, opcfamily, "
10063                                                   "opfname AS opcfamilyname, "
10064                                                   "nspname AS opcfamilynsp, "
10065                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10066                                                   "FROM pg_catalog.pg_opclass c "
10067                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10068                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10069                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10070                                                   opcinfo->dobj.catId.oid);
10071         }
10072         else
10073         {
10074                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10075                                                   "opckeytype::pg_catalog.regtype, "
10076                                                   "opcdefault, NULL AS opcfamily, "
10077                                                   "NULL AS opcfamilyname, "
10078                                                   "NULL AS opcfamilynsp, "
10079                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10080                                                   "FROM pg_catalog.pg_opclass "
10081                                                   "WHERE oid = '%u'::pg_catalog.oid",
10082                                                   opcinfo->dobj.catId.oid);
10083         }
10084
10085         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10086
10087         /* Expecting a single result only */
10088         ntups = PQntuples(res);
10089         if (ntups != 1)
10090         {
10091                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10092                                                            "query returned %d rows instead of one: %s\n",
10093                                                                  ntups),
10094                                   ntups, query->data);
10095                 exit_nicely();
10096         }
10097
10098         i_opcintype = PQfnumber(res, "opcintype");
10099         i_opckeytype = PQfnumber(res, "opckeytype");
10100         i_opcdefault = PQfnumber(res, "opcdefault");
10101         i_opcfamily = PQfnumber(res, "opcfamily");
10102         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10103         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10104         i_amname = PQfnumber(res, "amname");
10105
10106         opcintype = PQgetvalue(res, 0, i_opcintype);
10107         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10108         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10109         /* opcfamily will still be needed after we PQclear res */
10110         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10111         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10112         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10113         /* amname will still be needed after we PQclear res */
10114         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10115
10116         /*
10117          * DROP must be fully qualified in case same name appears in pg_catalog
10118          */
10119         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10120                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10121         appendPQExpBuffer(delq, ".%s",
10122                                           fmtId(opcinfo->dobj.name));
10123         appendPQExpBuffer(delq, " USING %s;\n",
10124                                           fmtId(amname));
10125
10126         /* Build the fixed portion of the CREATE command */
10127         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10128                                           fmtId(opcinfo->dobj.name));
10129         if (strcmp(opcdefault, "t") == 0)
10130                 appendPQExpBuffer(q, "DEFAULT ");
10131         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10132                                           opcintype,
10133                                           fmtId(amname));
10134         if (strlen(opcfamilyname) > 0 &&
10135                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10136                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10137         {
10138                 appendPQExpBuffer(q, " FAMILY ");
10139                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10140                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10141                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10142         }
10143         appendPQExpBuffer(q, " AS\n    ");
10144
10145         needComma = false;
10146
10147         if (strcmp(opckeytype, "-") != 0)
10148         {
10149                 appendPQExpBuffer(q, "STORAGE %s",
10150                                                   opckeytype);
10151                 needComma = true;
10152         }
10153
10154         PQclear(res);
10155
10156         /*
10157          * Now fetch and print the OPERATOR entries (pg_amop rows).
10158          *
10159          * Print only those opfamily members that are tied to the opclass by
10160          * pg_depend entries.
10161          *
10162          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10163          * older server's opclass in which it is used.  This is to avoid
10164          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10165          * older server and then reload into that old version.  This can go away
10166          * once 8.3 is so old as to not be of interest to anyone.
10167          */
10168         resetPQExpBuffer(query);
10169
10170         if (fout->remoteVersion >= 90100)
10171         {
10172                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10173                                                   "amopopr::pg_catalog.regoperator, "
10174                                                   "opfname AS sortfamily, "
10175                                                   "nspname AS sortfamilynsp "
10176                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10177                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10178                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10179                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10180                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10181                                                   "AND refobjid = '%u'::pg_catalog.oid "
10182                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10183                                                   "ORDER BY amopstrategy",
10184                                                   opcinfo->dobj.catId.oid,
10185                                                   opcfamily);
10186         }
10187         else if (fout->remoteVersion >= 80400)
10188         {
10189                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10190                                                   "amopopr::pg_catalog.regoperator, "
10191                                                   "NULL AS sortfamily, "
10192                                                   "NULL AS sortfamilynsp "
10193                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10194                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10195                                                   "AND refobjid = '%u'::pg_catalog.oid "
10196                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10197                                                   "AND objid = ao.oid "
10198                                                   "ORDER BY amopstrategy",
10199                                                   opcinfo->dobj.catId.oid);
10200         }
10201         else if (fout->remoteVersion >= 80300)
10202         {
10203                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10204                                                   "amopopr::pg_catalog.regoperator, "
10205                                                   "NULL AS sortfamily, "
10206                                                   "NULL AS sortfamilynsp "
10207                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10208                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10209                                                   "AND refobjid = '%u'::pg_catalog.oid "
10210                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10211                                                   "AND objid = ao.oid "
10212                                                   "ORDER BY amopstrategy",
10213                                                   opcinfo->dobj.catId.oid);
10214         }
10215         else
10216         {
10217                 /*
10218                  * Here, we print all entries since there are no opfamilies and hence
10219                  * no loose operators to worry about.
10220                  */
10221                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10222                                                   "amopopr::pg_catalog.regoperator, "
10223                                                   "NULL AS sortfamily, "
10224                                                   "NULL AS sortfamilynsp "
10225                                                   "FROM pg_catalog.pg_amop "
10226                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10227                                                   "ORDER BY amopstrategy",
10228                                                   opcinfo->dobj.catId.oid);
10229         }
10230
10231         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10232
10233         ntups = PQntuples(res);
10234
10235         i_amopstrategy = PQfnumber(res, "amopstrategy");
10236         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10237         i_amopopr = PQfnumber(res, "amopopr");
10238         i_sortfamily = PQfnumber(res, "sortfamily");
10239         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10240
10241         for (i = 0; i < ntups; i++)
10242         {
10243                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10244                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10245                 amopopr = PQgetvalue(res, i, i_amopopr);
10246                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10247                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10248
10249                 if (needComma)
10250                         appendPQExpBuffer(q, " ,\n    ");
10251
10252                 appendPQExpBuffer(q, "OPERATOR %s %s",
10253                                                   amopstrategy, amopopr);
10254
10255                 if (strlen(sortfamily) > 0)
10256                 {
10257                         appendPQExpBuffer(q, " FOR ORDER BY ");
10258                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10259                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10260                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10261                 }
10262
10263                 if (strcmp(amopreqcheck, "t") == 0)
10264                         appendPQExpBuffer(q, " RECHECK");
10265
10266                 needComma = true;
10267         }
10268
10269         PQclear(res);
10270
10271         /*
10272          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10273          *
10274          * Print only those opfamily members that are tied to the opclass by
10275          * pg_depend entries.
10276          *
10277          * We print the amproclefttype/amprocrighttype even though in most cases
10278          * the backend could deduce the right values, because of the corner case
10279          * of a btree sort support function for a cross-type comparison.  That's
10280          * only allowed in 9.2 and later, but for simplicity print them in all
10281          * versions that have the columns.
10282          */
10283         resetPQExpBuffer(query);
10284
10285         if (fout->remoteVersion >= 80300)
10286         {
10287                 appendPQExpBuffer(query, "SELECT amprocnum, "
10288                                                   "amproc::pg_catalog.regprocedure, "
10289                                                   "amproclefttype::pg_catalog.regtype, "
10290                                                   "amprocrighttype::pg_catalog.regtype "
10291                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10292                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10293                                                   "AND refobjid = '%u'::pg_catalog.oid "
10294                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10295                                                   "AND objid = ap.oid "
10296                                                   "ORDER BY amprocnum",
10297                                                   opcinfo->dobj.catId.oid);
10298         }
10299         else
10300         {
10301                 appendPQExpBuffer(query, "SELECT amprocnum, "
10302                                                   "amproc::pg_catalog.regprocedure, "
10303                                                   "'' AS amproclefttype, "
10304                                                   "'' AS amprocrighttype "
10305                                                   "FROM pg_catalog.pg_amproc "
10306                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10307                                                   "ORDER BY amprocnum",
10308                                                   opcinfo->dobj.catId.oid);
10309         }
10310
10311         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10312
10313         ntups = PQntuples(res);
10314
10315         i_amprocnum = PQfnumber(res, "amprocnum");
10316         i_amproc = PQfnumber(res, "amproc");
10317         i_amproclefttype = PQfnumber(res, "amproclefttype");
10318         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10319
10320         for (i = 0; i < ntups; i++)
10321         {
10322                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10323                 amproc = PQgetvalue(res, i, i_amproc);
10324                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10325                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10326
10327                 if (needComma)
10328                         appendPQExpBuffer(q, " ,\n    ");
10329
10330                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10331
10332                 if (*amproclefttype && *amprocrighttype)
10333                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10334
10335                 appendPQExpBuffer(q, " %s", amproc);
10336
10337                 needComma = true;
10338         }
10339
10340         PQclear(res);
10341
10342         appendPQExpBuffer(q, ";\n");
10343
10344         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10345                                           fmtId(opcinfo->dobj.name));
10346         appendPQExpBuffer(labelq, " USING %s",
10347                                           fmtId(amname));
10348
10349         if (binary_upgrade)
10350                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10351
10352         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10353                                  opcinfo->dobj.name,
10354                                  opcinfo->dobj.namespace->dobj.name,
10355                                  NULL,
10356                                  opcinfo->rolname,
10357                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10358                                  q->data, delq->data, NULL,
10359                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
10360                                  NULL, NULL);
10361
10362         /* Dump Operator Class Comments */
10363         dumpComment(fout, labelq->data,
10364                                 NULL, opcinfo->rolname,
10365                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10366
10367         free(amname);
10368         destroyPQExpBuffer(query);
10369         destroyPQExpBuffer(q);
10370         destroyPQExpBuffer(delq);
10371         destroyPQExpBuffer(labelq);
10372 }
10373
10374 /*
10375  * dumpOpfamily
10376  *        write out a single operator family definition
10377  *
10378  * Note: this also dumps any "loose" operator members that aren't bound to a
10379  * specific opclass within the opfamily.
10380  */
10381 static void
10382 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10383 {
10384         PQExpBuffer query;
10385         PQExpBuffer q;
10386         PQExpBuffer delq;
10387         PQExpBuffer labelq;
10388         PGresult   *res;
10389         PGresult   *res_ops;
10390         PGresult   *res_procs;
10391         int                     ntups;
10392         int                     i_amname;
10393         int                     i_amopstrategy;
10394         int                     i_amopreqcheck;
10395         int                     i_amopopr;
10396         int                     i_sortfamily;
10397         int                     i_sortfamilynsp;
10398         int                     i_amprocnum;
10399         int                     i_amproc;
10400         int                     i_amproclefttype;
10401         int                     i_amprocrighttype;
10402         char       *amname;
10403         char       *amopstrategy;
10404         char       *amopreqcheck;
10405         char       *amopopr;
10406         char       *sortfamily;
10407         char       *sortfamilynsp;
10408         char       *amprocnum;
10409         char       *amproc;
10410         char       *amproclefttype;
10411         char       *amprocrighttype;
10412         bool            needComma;
10413         int                     i;
10414
10415         /* Skip if not to be dumped */
10416         if (!opfinfo->dobj.dump || dataOnly)
10417                 return;
10418
10419         /*
10420          * We want to dump the opfamily only if (1) it contains "loose" operators
10421          * or functions, or (2) it contains an opclass with a different name or
10422          * owner.  Otherwise it's sufficient to let it be created during creation
10423          * of the contained opclass, and not dumping it improves portability of
10424          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10425          * that first.
10426          */
10427
10428         query = createPQExpBuffer();
10429         q = createPQExpBuffer();
10430         delq = createPQExpBuffer();
10431         labelq = createPQExpBuffer();
10432
10433         /* Make sure we are in proper schema so regoperator works correctly */
10434         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10435
10436         /*
10437          * Fetch only those opfamily members that are tied directly to the
10438          * opfamily by pg_depend entries.
10439          *
10440          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10441          * older server's opclass in which it is used.  This is to avoid
10442          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10443          * older server and then reload into that old version.  This can go away
10444          * once 8.3 is so old as to not be of interest to anyone.
10445          */
10446         if (fout->remoteVersion >= 90100)
10447         {
10448                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10449                                                   "amopopr::pg_catalog.regoperator, "
10450                                                   "opfname AS sortfamily, "
10451                                                   "nspname AS sortfamilynsp "
10452                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10453                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10454                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10455                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10456                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10457                                                   "AND refobjid = '%u'::pg_catalog.oid "
10458                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10459                                                   "ORDER BY amopstrategy",
10460                                                   opfinfo->dobj.catId.oid,
10461                                                   opfinfo->dobj.catId.oid);
10462         }
10463         else if (fout->remoteVersion >= 80400)
10464         {
10465                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10466                                                   "amopopr::pg_catalog.regoperator, "
10467                                                   "NULL AS sortfamily, "
10468                                                   "NULL AS sortfamilynsp "
10469                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10470                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10471                                                   "AND refobjid = '%u'::pg_catalog.oid "
10472                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10473                                                   "AND objid = ao.oid "
10474                                                   "ORDER BY amopstrategy",
10475                                                   opfinfo->dobj.catId.oid);
10476         }
10477         else
10478         {
10479                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10480                                                   "amopopr::pg_catalog.regoperator, "
10481                                                   "NULL AS sortfamily, "
10482                                                   "NULL AS sortfamilynsp "
10483                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10484                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10485                                                   "AND refobjid = '%u'::pg_catalog.oid "
10486                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10487                                                   "AND objid = ao.oid "
10488                                                   "ORDER BY amopstrategy",
10489                                                   opfinfo->dobj.catId.oid);
10490         }
10491
10492         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10493
10494         resetPQExpBuffer(query);
10495
10496         appendPQExpBuffer(query, "SELECT amprocnum, "
10497                                           "amproc::pg_catalog.regprocedure, "
10498                                           "amproclefttype::pg_catalog.regtype, "
10499                                           "amprocrighttype::pg_catalog.regtype "
10500                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10501                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10502                                           "AND refobjid = '%u'::pg_catalog.oid "
10503                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10504                                           "AND objid = ap.oid "
10505                                           "ORDER BY amprocnum",
10506                                           opfinfo->dobj.catId.oid);
10507
10508         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10509
10510         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10511         {
10512                 /* No loose members, so check contained opclasses */
10513                 resetPQExpBuffer(query);
10514
10515                 appendPQExpBuffer(query, "SELECT 1 "
10516                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10517                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10518                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10519                                                   "AND refobjid = f.oid "
10520                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10521                                                   "AND objid = c.oid "
10522                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10523                                                   "LIMIT 1",
10524                                                   opfinfo->dobj.catId.oid);
10525
10526                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10527
10528                 if (PQntuples(res) == 0)
10529                 {
10530                         /* no need to dump it, so bail out */
10531                         PQclear(res);
10532                         PQclear(res_ops);
10533                         PQclear(res_procs);
10534                         destroyPQExpBuffer(query);
10535                         destroyPQExpBuffer(q);
10536                         destroyPQExpBuffer(delq);
10537                         destroyPQExpBuffer(labelq);
10538                         return;
10539                 }
10540
10541                 PQclear(res);
10542         }
10543
10544         /* Get additional fields from the pg_opfamily row */
10545         resetPQExpBuffer(query);
10546
10547         appendPQExpBuffer(query, "SELECT "
10548          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
10549                                           "FROM pg_catalog.pg_opfamily "
10550                                           "WHERE oid = '%u'::pg_catalog.oid",
10551                                           opfinfo->dobj.catId.oid);
10552
10553         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10554
10555         /* Expecting a single result only */
10556         ntups = PQntuples(res);
10557         if (ntups != 1)
10558         {
10559                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10560                                                            "query returned %d rows instead of one: %s\n",
10561                                                                  ntups),
10562                                   ntups, query->data);
10563                 exit_nicely();
10564         }
10565
10566         i_amname = PQfnumber(res, "amname");
10567
10568         /* amname will still be needed after we PQclear res */
10569         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10570
10571         /*
10572          * DROP must be fully qualified in case same name appears in pg_catalog
10573          */
10574         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
10575                                           fmtId(opfinfo->dobj.namespace->dobj.name));
10576         appendPQExpBuffer(delq, ".%s",
10577                                           fmtId(opfinfo->dobj.name));
10578         appendPQExpBuffer(delq, " USING %s;\n",
10579                                           fmtId(amname));
10580
10581         /* Build the fixed portion of the CREATE command */
10582         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
10583                                           fmtId(opfinfo->dobj.name));
10584         appendPQExpBuffer(q, " USING %s;\n",
10585                                           fmtId(amname));
10586
10587         PQclear(res);
10588
10589         /* Do we need an ALTER to add loose members? */
10590         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
10591         {
10592                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
10593                                                   fmtId(opfinfo->dobj.name));
10594                 appendPQExpBuffer(q, " USING %s ADD\n    ",
10595                                                   fmtId(amname));
10596
10597                 needComma = false;
10598
10599                 /*
10600                  * Now fetch and print the OPERATOR entries (pg_amop rows).
10601                  */
10602                 ntups = PQntuples(res_ops);
10603
10604                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
10605                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
10606                 i_amopopr = PQfnumber(res_ops, "amopopr");
10607                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
10608                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
10609
10610                 for (i = 0; i < ntups; i++)
10611                 {
10612                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
10613                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
10614                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
10615                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
10616                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
10617
10618                         if (needComma)
10619                                 appendPQExpBuffer(q, " ,\n    ");
10620
10621                         appendPQExpBuffer(q, "OPERATOR %s %s",
10622                                                           amopstrategy, amopopr);
10623
10624                         if (strlen(sortfamily) > 0)
10625                         {
10626                                 appendPQExpBuffer(q, " FOR ORDER BY ");
10627                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
10628                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10629                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10630                         }
10631
10632                         if (strcmp(amopreqcheck, "t") == 0)
10633                                 appendPQExpBuffer(q, " RECHECK");
10634
10635                         needComma = true;
10636                 }
10637
10638                 /*
10639                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
10640                  */
10641                 ntups = PQntuples(res_procs);
10642
10643                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
10644                 i_amproc = PQfnumber(res_procs, "amproc");
10645                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
10646                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
10647
10648                 for (i = 0; i < ntups; i++)
10649                 {
10650                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
10651                         amproc = PQgetvalue(res_procs, i, i_amproc);
10652                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
10653                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
10654
10655                         if (needComma)
10656                                 appendPQExpBuffer(q, " ,\n    ");
10657
10658                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
10659                                                           amprocnum, amproclefttype, amprocrighttype,
10660                                                           amproc);
10661
10662                         needComma = true;
10663                 }
10664
10665                 appendPQExpBuffer(q, ";\n");
10666         }
10667
10668         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
10669                                           fmtId(opfinfo->dobj.name));
10670         appendPQExpBuffer(labelq, " USING %s",
10671                                           fmtId(amname));
10672
10673         if (binary_upgrade)
10674                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
10675
10676         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
10677                                  opfinfo->dobj.name,
10678                                  opfinfo->dobj.namespace->dobj.name,
10679                                  NULL,
10680                                  opfinfo->rolname,
10681                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
10682                                  q->data, delq->data, NULL,
10683                                  opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
10684                                  NULL, NULL);
10685
10686         /* Dump Operator Family Comments */
10687         dumpComment(fout, labelq->data,
10688                                 NULL, opfinfo->rolname,
10689                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
10690
10691         free(amname);
10692         PQclear(res_ops);
10693         PQclear(res_procs);
10694         destroyPQExpBuffer(query);
10695         destroyPQExpBuffer(q);
10696         destroyPQExpBuffer(delq);
10697         destroyPQExpBuffer(labelq);
10698 }
10699
10700 /*
10701  * dumpCollation
10702  *        write out a single collation definition
10703  */
10704 static void
10705 dumpCollation(Archive *fout, CollInfo *collinfo)
10706 {
10707         PQExpBuffer query;
10708         PQExpBuffer q;
10709         PQExpBuffer delq;
10710         PQExpBuffer labelq;
10711         PGresult   *res;
10712         int                     ntups;
10713         int                     i_collcollate;
10714         int                     i_collctype;
10715         const char *collcollate;
10716         const char *collctype;
10717
10718         /* Skip if not to be dumped */
10719         if (!collinfo->dobj.dump || dataOnly)
10720                 return;
10721
10722         query = createPQExpBuffer();
10723         q = createPQExpBuffer();
10724         delq = createPQExpBuffer();
10725         labelq = createPQExpBuffer();
10726
10727         /* Make sure we are in proper schema */
10728         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
10729
10730         /* Get conversion-specific details */
10731         appendPQExpBuffer(query, "SELECT "
10732                                           "collcollate, "
10733                                           "collctype "
10734                                           "FROM pg_catalog.pg_collation c "
10735                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10736                                           collinfo->dobj.catId.oid);
10737
10738         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10739
10740         /* Expecting a single result only */
10741         ntups = PQntuples(res);
10742         if (ntups != 1)
10743         {
10744                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10745                                                            "query returned %d rows instead of one: %s\n",
10746                                                                  ntups),
10747                                   ntups, query->data);
10748                 exit_nicely();
10749         }
10750
10751         i_collcollate = PQfnumber(res, "collcollate");
10752         i_collctype = PQfnumber(res, "collctype");
10753
10754         collcollate = PQgetvalue(res, 0, i_collcollate);
10755         collctype = PQgetvalue(res, 0, i_collctype);
10756
10757         /*
10758          * DROP must be fully qualified in case same name appears in pg_catalog
10759          */
10760         appendPQExpBuffer(delq, "DROP COLLATION %s",
10761                                           fmtId(collinfo->dobj.namespace->dobj.name));
10762         appendPQExpBuffer(delq, ".%s;\n",
10763                                           fmtId(collinfo->dobj.name));
10764
10765         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
10766                                           fmtId(collinfo->dobj.name));
10767         appendStringLiteralAH(q, collcollate, fout);
10768         appendPQExpBuffer(q, ", lc_ctype = ");
10769         appendStringLiteralAH(q, collctype, fout);
10770         appendPQExpBuffer(q, ");\n");
10771
10772         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
10773
10774         if (binary_upgrade)
10775                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
10776
10777         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
10778                                  collinfo->dobj.name,
10779                                  collinfo->dobj.namespace->dobj.name,
10780                                  NULL,
10781                                  collinfo->rolname,
10782                                  false, "COLLATION", SECTION_PRE_DATA,
10783                                  q->data, delq->data, NULL,
10784                                  collinfo->dobj.dependencies, collinfo->dobj.nDeps,
10785                                  NULL, NULL);
10786
10787         /* Dump Collation Comments */
10788         dumpComment(fout, labelq->data,
10789                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
10790                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
10791
10792         PQclear(res);
10793
10794         destroyPQExpBuffer(query);
10795         destroyPQExpBuffer(q);
10796         destroyPQExpBuffer(delq);
10797         destroyPQExpBuffer(labelq);
10798 }
10799
10800 /*
10801  * dumpConversion
10802  *        write out a single conversion definition
10803  */
10804 static void
10805 dumpConversion(Archive *fout, ConvInfo *convinfo)
10806 {
10807         PQExpBuffer query;
10808         PQExpBuffer q;
10809         PQExpBuffer delq;
10810         PQExpBuffer labelq;
10811         PGresult   *res;
10812         int                     ntups;
10813         int                     i_conforencoding;
10814         int                     i_contoencoding;
10815         int                     i_conproc;
10816         int                     i_condefault;
10817         const char *conforencoding;
10818         const char *contoencoding;
10819         const char *conproc;
10820         bool            condefault;
10821
10822         /* Skip if not to be dumped */
10823         if (!convinfo->dobj.dump || dataOnly)
10824                 return;
10825
10826         query = createPQExpBuffer();
10827         q = createPQExpBuffer();
10828         delq = createPQExpBuffer();
10829         labelq = createPQExpBuffer();
10830
10831         /* Make sure we are in proper schema */
10832         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
10833
10834         /* Get conversion-specific details */
10835         appendPQExpBuffer(query, "SELECT "
10836                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
10837                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
10838                                           "conproc, condefault "
10839                                           "FROM pg_catalog.pg_conversion c "
10840                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10841                                           convinfo->dobj.catId.oid);
10842
10843         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10844
10845         /* Expecting a single result only */
10846         ntups = PQntuples(res);
10847         if (ntups != 1)
10848         {
10849                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10850                                                            "query returned %d rows instead of one: %s\n",
10851                                                                  ntups),
10852                                   ntups, query->data);
10853                 exit_nicely();
10854         }
10855
10856         i_conforencoding = PQfnumber(res, "conforencoding");
10857         i_contoencoding = PQfnumber(res, "contoencoding");
10858         i_conproc = PQfnumber(res, "conproc");
10859         i_condefault = PQfnumber(res, "condefault");
10860
10861         conforencoding = PQgetvalue(res, 0, i_conforencoding);
10862         contoencoding = PQgetvalue(res, 0, i_contoencoding);
10863         conproc = PQgetvalue(res, 0, i_conproc);
10864         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
10865
10866         /*
10867          * DROP must be fully qualified in case same name appears in pg_catalog
10868          */
10869         appendPQExpBuffer(delq, "DROP CONVERSION %s",
10870                                           fmtId(convinfo->dobj.namespace->dobj.name));
10871         appendPQExpBuffer(delq, ".%s;\n",
10872                                           fmtId(convinfo->dobj.name));
10873
10874         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
10875                                           (condefault) ? "DEFAULT " : "",
10876                                           fmtId(convinfo->dobj.name));
10877         appendStringLiteralAH(q, conforencoding, fout);
10878         appendPQExpBuffer(q, " TO ");
10879         appendStringLiteralAH(q, contoencoding, fout);
10880         /* regproc is automatically quoted in 7.3 and above */
10881         appendPQExpBuffer(q, " FROM %s;\n", conproc);
10882
10883         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
10884
10885         if (binary_upgrade)
10886                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
10887
10888         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
10889                                  convinfo->dobj.name,
10890                                  convinfo->dobj.namespace->dobj.name,
10891                                  NULL,
10892                                  convinfo->rolname,
10893                                  false, "CONVERSION", SECTION_PRE_DATA,
10894                                  q->data, delq->data, NULL,
10895                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
10896                                  NULL, NULL);
10897
10898         /* Dump Conversion Comments */
10899         dumpComment(fout, labelq->data,
10900                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
10901                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
10902
10903         PQclear(res);
10904
10905         destroyPQExpBuffer(query);
10906         destroyPQExpBuffer(q);
10907         destroyPQExpBuffer(delq);
10908         destroyPQExpBuffer(labelq);
10909 }
10910
10911 /*
10912  * format_aggregate_signature: generate aggregate name and argument list
10913  *
10914  * The argument type names are qualified if needed.  The aggregate name
10915  * is never qualified.
10916  */
10917 static char *
10918 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
10919 {
10920         PQExpBufferData buf;
10921         int                     j;
10922
10923         initPQExpBuffer(&buf);
10924         if (honor_quotes)
10925                 appendPQExpBuffer(&buf, "%s",
10926                                                   fmtId(agginfo->aggfn.dobj.name));
10927         else
10928                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
10929
10930         if (agginfo->aggfn.nargs == 0)
10931                 appendPQExpBuffer(&buf, "(*)");
10932         else
10933         {
10934                 appendPQExpBuffer(&buf, "(");
10935                 for (j = 0; j < agginfo->aggfn.nargs; j++)
10936                 {
10937                         char       *typname;
10938
10939                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
10940                                                                                    zeroAsOpaque);
10941
10942                         appendPQExpBuffer(&buf, "%s%s",
10943                                                           (j > 0) ? ", " : "",
10944                                                           typname);
10945                         free(typname);
10946                 }
10947                 appendPQExpBuffer(&buf, ")");
10948         }
10949         return buf.data;
10950 }
10951
10952 /*
10953  * dumpAgg
10954  *        write out a single aggregate definition
10955  */
10956 static void
10957 dumpAgg(Archive *fout, AggInfo *agginfo)
10958 {
10959         PQExpBuffer query;
10960         PQExpBuffer q;
10961         PQExpBuffer delq;
10962         PQExpBuffer labelq;
10963         PQExpBuffer details;
10964         char       *aggsig;
10965         char       *aggsig_tag;
10966         PGresult   *res;
10967         int                     ntups;
10968         int                     i_aggtransfn;
10969         int                     i_aggfinalfn;
10970         int                     i_aggsortop;
10971         int                     i_aggtranstype;
10972         int                     i_agginitval;
10973         int                     i_convertok;
10974         const char *aggtransfn;
10975         const char *aggfinalfn;
10976         const char *aggsortop;
10977         const char *aggtranstype;
10978         const char *agginitval;
10979         bool            convertok;
10980
10981         /* Skip if not to be dumped */
10982         if (!agginfo->aggfn.dobj.dump || dataOnly)
10983                 return;
10984
10985         query = createPQExpBuffer();
10986         q = createPQExpBuffer();
10987         delq = createPQExpBuffer();
10988         labelq = createPQExpBuffer();
10989         details = createPQExpBuffer();
10990
10991         /* Make sure we are in proper schema */
10992         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
10993
10994         /* Get aggregate-specific details */
10995         if (fout->remoteVersion >= 80100)
10996         {
10997                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10998                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10999                                                   "aggsortop::pg_catalog.regoperator, "
11000                                                   "agginitval, "
11001                                                   "'t'::boolean AS convertok "
11002                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11003                                                   "WHERE a.aggfnoid = p.oid "
11004                                                   "AND p.oid = '%u'::pg_catalog.oid",
11005                                                   agginfo->aggfn.dobj.catId.oid);
11006         }
11007         else if (fout->remoteVersion >= 70300)
11008         {
11009                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11010                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11011                                                   "0 AS aggsortop, "
11012                                                   "agginitval, "
11013                                                   "'t'::boolean AS convertok "
11014                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11015                                                   "WHERE a.aggfnoid = p.oid "
11016                                                   "AND p.oid = '%u'::pg_catalog.oid",
11017                                                   agginfo->aggfn.dobj.catId.oid);
11018         }
11019         else if (fout->remoteVersion >= 70100)
11020         {
11021                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11022                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11023                                                   "0 AS aggsortop, "
11024                                                   "agginitval, "
11025                                                   "'t'::boolean AS convertok "
11026                                                   "FROM pg_aggregate "
11027                                                   "WHERE oid = '%u'::oid",
11028                                                   agginfo->aggfn.dobj.catId.oid);
11029         }
11030         else
11031         {
11032                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11033                                                   "aggfinalfn, "
11034                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11035                                                   "0 AS aggsortop, "
11036                                                   "agginitval1 AS agginitval, "
11037                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11038                                                   "FROM pg_aggregate "
11039                                                   "WHERE oid = '%u'::oid",
11040                                                   agginfo->aggfn.dobj.catId.oid);
11041         }
11042
11043         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11044
11045         /* Expecting a single result only */
11046         ntups = PQntuples(res);
11047         if (ntups != 1)
11048         {
11049                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11050                                                            "query returned %d rows instead of one: %s\n",
11051                                                                  ntups),
11052                                   ntups, query->data);
11053                 exit_nicely();
11054         }
11055
11056         i_aggtransfn = PQfnumber(res, "aggtransfn");
11057         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11058         i_aggsortop = PQfnumber(res, "aggsortop");
11059         i_aggtranstype = PQfnumber(res, "aggtranstype");
11060         i_agginitval = PQfnumber(res, "agginitval");
11061         i_convertok = PQfnumber(res, "convertok");
11062
11063         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11064         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11065         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11066         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11067         agginitval = PQgetvalue(res, 0, i_agginitval);
11068         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11069
11070         aggsig = format_aggregate_signature(agginfo, fout, true);
11071         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11072
11073         if (!convertok)
11074         {
11075                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11076                                   aggsig);
11077                 return;
11078         }
11079
11080         if (fout->remoteVersion >= 70300)
11081         {
11082                 /* If using 7.3's regproc or regtype, data is already quoted */
11083                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11084                                                   aggtransfn,
11085                                                   aggtranstype);
11086         }
11087         else if (fout->remoteVersion >= 70100)
11088         {
11089                 /* format_type quotes, regproc does not */
11090                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11091                                                   fmtId(aggtransfn),
11092                                                   aggtranstype);
11093         }
11094         else
11095         {
11096                 /* need quotes all around */
11097                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11098                                                   fmtId(aggtransfn));
11099                 appendPQExpBuffer(details, "    STYPE = %s",
11100                                                   fmtId(aggtranstype));
11101         }
11102
11103         if (!PQgetisnull(res, 0, i_agginitval))
11104         {
11105                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11106                 appendStringLiteralAH(details, agginitval, fout);
11107         }
11108
11109         if (strcmp(aggfinalfn, "-") != 0)
11110         {
11111                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11112                                                   aggfinalfn);
11113         }
11114
11115         aggsortop = convertOperatorReference(fout, aggsortop);
11116         if (aggsortop)
11117         {
11118                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11119                                                   aggsortop);
11120         }
11121
11122         /*
11123          * DROP must be fully qualified in case same name appears in pg_catalog
11124          */
11125         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11126                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11127                                           aggsig);
11128
11129         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11130                                           aggsig, details->data);
11131
11132         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11133
11134         if (binary_upgrade)
11135                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11136
11137         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11138                                  aggsig_tag,
11139                                  agginfo->aggfn.dobj.namespace->dobj.name,
11140                                  NULL,
11141                                  agginfo->aggfn.rolname,
11142                                  false, "AGGREGATE", SECTION_PRE_DATA,
11143                                  q->data, delq->data, NULL,
11144                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
11145                                  NULL, NULL);
11146
11147         /* Dump Aggregate Comments */
11148         dumpComment(fout, labelq->data,
11149                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11150                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11151         dumpSecLabel(fout, labelq->data,
11152                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11153                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11154
11155         /*
11156          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11157          * command look like a function's GRANT; in particular this affects the
11158          * syntax for zero-argument aggregates.
11159          */
11160         free(aggsig);
11161         free(aggsig_tag);
11162
11163         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11164         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11165
11166         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11167                         "FUNCTION",
11168                         aggsig, NULL, aggsig_tag,
11169                         agginfo->aggfn.dobj.namespace->dobj.name,
11170                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11171
11172         free(aggsig);
11173         free(aggsig_tag);
11174
11175         PQclear(res);
11176
11177         destroyPQExpBuffer(query);
11178         destroyPQExpBuffer(q);
11179         destroyPQExpBuffer(delq);
11180         destroyPQExpBuffer(labelq);
11181         destroyPQExpBuffer(details);
11182 }
11183
11184 /*
11185  * dumpTSParser
11186  *        write out a single text search parser
11187  */
11188 static void
11189 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11190 {
11191         PQExpBuffer q;
11192         PQExpBuffer delq;
11193         PQExpBuffer labelq;
11194
11195         /* Skip if not to be dumped */
11196         if (!prsinfo->dobj.dump || dataOnly)
11197                 return;
11198
11199         q = createPQExpBuffer();
11200         delq = createPQExpBuffer();
11201         labelq = createPQExpBuffer();
11202
11203         /* Make sure we are in proper schema */
11204         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11205
11206         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11207                                           fmtId(prsinfo->dobj.name));
11208
11209         appendPQExpBuffer(q, "    START = %s,\n",
11210                                           convertTSFunction(fout, prsinfo->prsstart));
11211         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11212                                           convertTSFunction(fout, prsinfo->prstoken));
11213         appendPQExpBuffer(q, "    END = %s,\n",
11214                                           convertTSFunction(fout, prsinfo->prsend));
11215         if (prsinfo->prsheadline != InvalidOid)
11216                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11217                                                   convertTSFunction(fout, prsinfo->prsheadline));
11218         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11219                                           convertTSFunction(fout, prsinfo->prslextype));
11220
11221         /*
11222          * DROP must be fully qualified in case same name appears in pg_catalog
11223          */
11224         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11225                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11226         appendPQExpBuffer(delq, ".%s;\n",
11227                                           fmtId(prsinfo->dobj.name));
11228
11229         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11230                                           fmtId(prsinfo->dobj.name));
11231
11232         if (binary_upgrade)
11233                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11234
11235         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11236                                  prsinfo->dobj.name,
11237                                  prsinfo->dobj.namespace->dobj.name,
11238                                  NULL,
11239                                  "",
11240                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11241                                  q->data, delq->data, NULL,
11242                                  prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
11243                                  NULL, NULL);
11244
11245         /* Dump Parser Comments */
11246         dumpComment(fout, labelq->data,
11247                                 NULL, "",
11248                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11249
11250         destroyPQExpBuffer(q);
11251         destroyPQExpBuffer(delq);
11252         destroyPQExpBuffer(labelq);
11253 }
11254
11255 /*
11256  * dumpTSDictionary
11257  *        write out a single text search dictionary
11258  */
11259 static void
11260 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11261 {
11262         PQExpBuffer q;
11263         PQExpBuffer delq;
11264         PQExpBuffer labelq;
11265         PQExpBuffer query;
11266         PGresult   *res;
11267         int                     ntups;
11268         char       *nspname;
11269         char       *tmplname;
11270
11271         /* Skip if not to be dumped */
11272         if (!dictinfo->dobj.dump || dataOnly)
11273                 return;
11274
11275         q = createPQExpBuffer();
11276         delq = createPQExpBuffer();
11277         labelq = createPQExpBuffer();
11278         query = createPQExpBuffer();
11279
11280         /* Fetch name and namespace of the dictionary's template */
11281         selectSourceSchema(fout, "pg_catalog");
11282         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11283                                           "FROM pg_ts_template p, pg_namespace n "
11284                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11285                                           dictinfo->dicttemplate);
11286         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11287         ntups = PQntuples(res);
11288         if (ntups != 1)
11289         {
11290                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11291                                                            "query returned %d rows instead of one: %s\n",
11292                                                                  ntups),
11293                                   ntups, query->data);
11294                 exit_nicely();
11295         }
11296         nspname = PQgetvalue(res, 0, 0);
11297         tmplname = PQgetvalue(res, 0, 1);
11298
11299         /* Make sure we are in proper schema */
11300         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11301
11302         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11303                                           fmtId(dictinfo->dobj.name));
11304
11305         appendPQExpBuffer(q, "    TEMPLATE = ");
11306         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11307                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11308         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11309
11310         PQclear(res);
11311
11312         /* the dictinitoption can be dumped straight into the command */
11313         if (dictinfo->dictinitoption)
11314                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11315
11316         appendPQExpBuffer(q, " );\n");
11317
11318         /*
11319          * DROP must be fully qualified in case same name appears in pg_catalog
11320          */
11321         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11322                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11323         appendPQExpBuffer(delq, ".%s;\n",
11324                                           fmtId(dictinfo->dobj.name));
11325
11326         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11327                                           fmtId(dictinfo->dobj.name));
11328
11329         if (binary_upgrade)
11330                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11331
11332         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11333                                  dictinfo->dobj.name,
11334                                  dictinfo->dobj.namespace->dobj.name,
11335                                  NULL,
11336                                  dictinfo->rolname,
11337                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11338                                  q->data, delq->data, NULL,
11339                                  dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
11340                                  NULL, NULL);
11341
11342         /* Dump Dictionary Comments */
11343         dumpComment(fout, labelq->data,
11344                                 NULL, dictinfo->rolname,
11345                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11346
11347         destroyPQExpBuffer(q);
11348         destroyPQExpBuffer(delq);
11349         destroyPQExpBuffer(labelq);
11350         destroyPQExpBuffer(query);
11351 }
11352
11353 /*
11354  * dumpTSTemplate
11355  *        write out a single text search template
11356  */
11357 static void
11358 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11359 {
11360         PQExpBuffer q;
11361         PQExpBuffer delq;
11362         PQExpBuffer labelq;
11363
11364         /* Skip if not to be dumped */
11365         if (!tmplinfo->dobj.dump || dataOnly)
11366                 return;
11367
11368         q = createPQExpBuffer();
11369         delq = createPQExpBuffer();
11370         labelq = createPQExpBuffer();
11371
11372         /* Make sure we are in proper schema */
11373         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11374
11375         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11376                                           fmtId(tmplinfo->dobj.name));
11377
11378         if (tmplinfo->tmplinit != InvalidOid)
11379                 appendPQExpBuffer(q, "    INIT = %s,\n",
11380                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11381         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11382                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11383
11384         /*
11385          * DROP must be fully qualified in case same name appears in pg_catalog
11386          */
11387         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11388                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11389         appendPQExpBuffer(delq, ".%s;\n",
11390                                           fmtId(tmplinfo->dobj.name));
11391
11392         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11393                                           fmtId(tmplinfo->dobj.name));
11394
11395         if (binary_upgrade)
11396                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11397
11398         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11399                                  tmplinfo->dobj.name,
11400                                  tmplinfo->dobj.namespace->dobj.name,
11401                                  NULL,
11402                                  "",
11403                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11404                                  q->data, delq->data, NULL,
11405                                  tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
11406                                  NULL, NULL);
11407
11408         /* Dump Template Comments */
11409         dumpComment(fout, labelq->data,
11410                                 NULL, "",
11411                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11412
11413         destroyPQExpBuffer(q);
11414         destroyPQExpBuffer(delq);
11415         destroyPQExpBuffer(labelq);
11416 }
11417
11418 /*
11419  * dumpTSConfig
11420  *        write out a single text search configuration
11421  */
11422 static void
11423 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11424 {
11425         PQExpBuffer q;
11426         PQExpBuffer delq;
11427         PQExpBuffer labelq;
11428         PQExpBuffer query;
11429         PGresult   *res;
11430         char       *nspname;
11431         char       *prsname;
11432         int                     ntups,
11433                                 i;
11434         int                     i_tokenname;
11435         int                     i_dictname;
11436
11437         /* Skip if not to be dumped */
11438         if (!cfginfo->dobj.dump || dataOnly)
11439                 return;
11440
11441         q = createPQExpBuffer();
11442         delq = createPQExpBuffer();
11443         labelq = createPQExpBuffer();
11444         query = createPQExpBuffer();
11445
11446         /* Fetch name and namespace of the config's parser */
11447         selectSourceSchema(fout, "pg_catalog");
11448         appendPQExpBuffer(query, "SELECT nspname, prsname "
11449                                           "FROM pg_ts_parser p, pg_namespace n "
11450                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11451                                           cfginfo->cfgparser);
11452         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11453         ntups = PQntuples(res);
11454         if (ntups != 1)
11455         {
11456                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11457                                                            "query returned %d rows instead of one: %s\n",
11458                                                                  ntups),
11459                                   ntups, query->data);
11460                 exit_nicely();
11461         }
11462         nspname = PQgetvalue(res, 0, 0);
11463         prsname = PQgetvalue(res, 0, 1);
11464
11465         /* Make sure we are in proper schema */
11466         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11467
11468         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11469                                           fmtId(cfginfo->dobj.name));
11470
11471         appendPQExpBuffer(q, "    PARSER = ");
11472         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11473                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11474         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11475
11476         PQclear(res);
11477
11478         resetPQExpBuffer(query);
11479         appendPQExpBuffer(query,
11480                                           "SELECT \n"
11481                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11482                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11483                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11484                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11485                                           "WHERE m.mapcfg = '%u' \n"
11486                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11487                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11488
11489         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11490         ntups = PQntuples(res);
11491
11492         i_tokenname = PQfnumber(res, "tokenname");
11493         i_dictname = PQfnumber(res, "dictname");
11494
11495         for (i = 0; i < ntups; i++)
11496         {
11497                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11498                 char       *dictname = PQgetvalue(res, i, i_dictname);
11499
11500                 if (i == 0 ||
11501                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11502                 {
11503                         /* starting a new token type, so start a new command */
11504                         if (i > 0)
11505                                 appendPQExpBuffer(q, ";\n");
11506                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11507                                                           fmtId(cfginfo->dobj.name));
11508                         /* tokenname needs quoting, dictname does NOT */
11509                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11510                                                           fmtId(tokenname), dictname);
11511                 }
11512                 else
11513                         appendPQExpBuffer(q, ", %s", dictname);
11514         }
11515
11516         if (ntups > 0)
11517                 appendPQExpBuffer(q, ";\n");
11518
11519         PQclear(res);
11520
11521         /*
11522          * DROP must be fully qualified in case same name appears in pg_catalog
11523          */
11524         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11525                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11526         appendPQExpBuffer(delq, ".%s;\n",
11527                                           fmtId(cfginfo->dobj.name));
11528
11529         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11530                                           fmtId(cfginfo->dobj.name));
11531
11532         if (binary_upgrade)
11533                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11534
11535         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11536                                  cfginfo->dobj.name,
11537                                  cfginfo->dobj.namespace->dobj.name,
11538                                  NULL,
11539                                  cfginfo->rolname,
11540                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11541                                  q->data, delq->data, NULL,
11542                                  cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
11543                                  NULL, NULL);
11544
11545         /* Dump Configuration Comments */
11546         dumpComment(fout, labelq->data,
11547                                 NULL, cfginfo->rolname,
11548                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11549
11550         destroyPQExpBuffer(q);
11551         destroyPQExpBuffer(delq);
11552         destroyPQExpBuffer(labelq);
11553         destroyPQExpBuffer(query);
11554 }
11555
11556 /*
11557  * dumpForeignDataWrapper
11558  *        write out a single foreign-data wrapper definition
11559  */
11560 static void
11561 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11562 {
11563         PQExpBuffer q;
11564         PQExpBuffer delq;
11565         PQExpBuffer labelq;
11566         char       *qfdwname;
11567
11568         /* Skip if not to be dumped */
11569         if (!fdwinfo->dobj.dump || dataOnly)
11570                 return;
11571
11572         /*
11573          * FDWs that belong to an extension are dumped based on their "dump"
11574          * field. Otherwise omit them if we are only dumping some specific object.
11575          */
11576         if (!fdwinfo->dobj.ext_member)
11577                 if (!include_everything)
11578                         return;
11579
11580         q = createPQExpBuffer();
11581         delq = createPQExpBuffer();
11582         labelq = createPQExpBuffer();
11583
11584         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11585
11586         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11587                                           qfdwname);
11588
11589         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11590                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11591
11592         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11593                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11594
11595         if (strlen(fdwinfo->fdwoptions) > 0)
11596                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
11597
11598         appendPQExpBuffer(q, ";\n");
11599
11600         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
11601                                           qfdwname);
11602
11603         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
11604                                           qfdwname);
11605
11606         if (binary_upgrade)
11607                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
11608
11609         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11610                                  fdwinfo->dobj.name,
11611                                  NULL,
11612                                  NULL,
11613                                  fdwinfo->rolname,
11614                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
11615                                  q->data, delq->data, NULL,
11616                                  fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
11617                                  NULL, NULL);
11618
11619         /* Handle the ACL */
11620         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11621                         "FOREIGN DATA WRAPPER",
11622                         qfdwname, NULL, fdwinfo->dobj.name,
11623                         NULL, fdwinfo->rolname,
11624                         fdwinfo->fdwacl);
11625
11626         /* Dump Foreign Data Wrapper Comments */
11627         dumpComment(fout, labelq->data,
11628                                 NULL, fdwinfo->rolname,
11629                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
11630
11631         free(qfdwname);
11632
11633         destroyPQExpBuffer(q);
11634         destroyPQExpBuffer(delq);
11635         destroyPQExpBuffer(labelq);
11636 }
11637
11638 /*
11639  * dumpForeignServer
11640  *        write out a foreign server definition
11641  */
11642 static void
11643 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
11644 {
11645         PQExpBuffer q;
11646         PQExpBuffer delq;
11647         PQExpBuffer labelq;
11648         PQExpBuffer query;
11649         PGresult   *res;
11650         int                     ntups;
11651         char       *qsrvname;
11652         char       *fdwname;
11653
11654         /* Skip if not to be dumped */
11655         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
11656                 return;
11657
11658         q = createPQExpBuffer();
11659         delq = createPQExpBuffer();
11660         labelq = createPQExpBuffer();
11661         query = createPQExpBuffer();
11662
11663         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
11664
11665         /* look up the foreign-data wrapper */
11666         selectSourceSchema(fout, "pg_catalog");
11667         appendPQExpBuffer(query, "SELECT fdwname "
11668                                           "FROM pg_foreign_data_wrapper w "
11669                                           "WHERE w.oid = '%u'",
11670                                           srvinfo->srvfdw);
11671         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11672         ntups = PQntuples(res);
11673         if (ntups != 1)
11674         {
11675                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11676                                                            "query returned %d rows instead of one: %s\n",
11677                                                                  ntups),
11678                                   ntups, query->data);
11679                 exit_nicely();
11680         }
11681         fdwname = PQgetvalue(res, 0, 0);
11682
11683         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
11684         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
11685         {
11686                 appendPQExpBuffer(q, " TYPE ");
11687                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
11688         }
11689         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
11690         {
11691                 appendPQExpBuffer(q, " VERSION ");
11692                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
11693         }
11694
11695         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
11696         appendPQExpBuffer(q, "%s", fmtId(fdwname));
11697
11698         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
11699                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
11700
11701         appendPQExpBuffer(q, ";\n");
11702
11703         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
11704                                           qsrvname);
11705
11706         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
11707
11708         if (binary_upgrade)
11709                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
11710
11711         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11712                                  srvinfo->dobj.name,
11713                                  NULL,
11714                                  NULL,
11715                                  srvinfo->rolname,
11716                                  false, "SERVER", SECTION_PRE_DATA,
11717                                  q->data, delq->data, NULL,
11718                                  srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
11719                                  NULL, NULL);
11720
11721         /* Handle the ACL */
11722         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11723                         "FOREIGN SERVER",
11724                         qsrvname, NULL, srvinfo->dobj.name,
11725                         NULL, srvinfo->rolname,
11726                         srvinfo->srvacl);
11727
11728         /* Dump user mappings */
11729         dumpUserMappings(fout,
11730                                          srvinfo->dobj.name, NULL,
11731                                          srvinfo->rolname,
11732                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
11733
11734         /* Dump Foreign Server Comments */
11735         dumpComment(fout, labelq->data,
11736                                 NULL, srvinfo->rolname,
11737                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
11738
11739         free(qsrvname);
11740
11741         destroyPQExpBuffer(q);
11742         destroyPQExpBuffer(delq);
11743         destroyPQExpBuffer(labelq);
11744 }
11745
11746 /*
11747  * dumpUserMappings
11748  *
11749  * This routine is used to dump any user mappings associated with the
11750  * server handed to this routine. Should be called after ArchiveEntry()
11751  * for the server.
11752  */
11753 static void
11754 dumpUserMappings(Archive *fout,
11755                                  const char *servername, const char *namespace,
11756                                  const char *owner,
11757                                  CatalogId catalogId, DumpId dumpId)
11758 {
11759         PQExpBuffer q;
11760         PQExpBuffer delq;
11761         PQExpBuffer query;
11762         PQExpBuffer tag;
11763         PGresult   *res;
11764         int                     ntups;
11765         int                     i_usename;
11766         int                     i_umoptions;
11767         int                     i;
11768
11769         q = createPQExpBuffer();
11770         tag = createPQExpBuffer();
11771         delq = createPQExpBuffer();
11772         query = createPQExpBuffer();
11773
11774         /*
11775          * We read from the publicly accessible view pg_user_mappings, so as not
11776          * to fail if run by a non-superuser.  Note that the view will show
11777          * umoptions as null if the user hasn't got privileges for the associated
11778          * server; this means that pg_dump will dump such a mapping, but with no
11779          * OPTIONS clause.      A possible alternative is to skip such mappings
11780          * altogether, but it's not clear that that's an improvement.
11781          */
11782         selectSourceSchema(fout, "pg_catalog");
11783
11784         appendPQExpBuffer(query,
11785                                           "SELECT usename, "
11786                                           "array_to_string(ARRAY("
11787                                           "SELECT quote_ident(option_name) || ' ' || "
11788                                           "quote_literal(option_value) "
11789                                           "FROM pg_options_to_table(umoptions) "
11790                                           "ORDER BY option_name"
11791                                           "), E',\n    ') AS umoptions "
11792                                           "FROM pg_user_mappings "
11793                                           "WHERE srvid = '%u' "
11794                                           "ORDER BY usename",
11795                                           catalogId.oid);
11796
11797         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11798
11799         ntups = PQntuples(res);
11800         i_usename = PQfnumber(res, "usename");
11801         i_umoptions = PQfnumber(res, "umoptions");
11802
11803         for (i = 0; i < ntups; i++)
11804         {
11805                 char       *usename;
11806                 char       *umoptions;
11807
11808                 usename = PQgetvalue(res, i, i_usename);
11809                 umoptions = PQgetvalue(res, i, i_umoptions);
11810
11811                 resetPQExpBuffer(q);
11812                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
11813                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
11814
11815                 if (umoptions && strlen(umoptions) > 0)
11816                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
11817
11818                 appendPQExpBuffer(q, ";\n");
11819
11820                 resetPQExpBuffer(delq);
11821                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
11822                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
11823
11824                 resetPQExpBuffer(tag);
11825                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
11826                                                   usename, servername);
11827
11828                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11829                                          tag->data,
11830                                          namespace,
11831                                          NULL,
11832                                          owner, false,
11833                                          "USER MAPPING", SECTION_PRE_DATA,
11834                                          q->data, delq->data, NULL,
11835                                          &dumpId, 1,
11836                                          NULL, NULL);
11837         }
11838
11839         PQclear(res);
11840
11841         destroyPQExpBuffer(query);
11842         destroyPQExpBuffer(delq);
11843         destroyPQExpBuffer(q);
11844 }
11845
11846 /*
11847  * Write out default privileges information
11848  */
11849 static void
11850 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
11851 {
11852         PQExpBuffer q;
11853         PQExpBuffer tag;
11854         const char *type;
11855
11856         /* Skip if not to be dumped */
11857         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
11858                 return;
11859
11860         q = createPQExpBuffer();
11861         tag = createPQExpBuffer();
11862
11863         switch (daclinfo->defaclobjtype)
11864         {
11865                 case DEFACLOBJ_RELATION:
11866                         type = "TABLES";
11867                         break;
11868                 case DEFACLOBJ_SEQUENCE:
11869                         type = "SEQUENCES";
11870                         break;
11871                 case DEFACLOBJ_FUNCTION:
11872                         type = "FUNCTIONS";
11873                         break;
11874                 default:
11875                         /* shouldn't get here */
11876                         write_msg(NULL, "unknown object type (%d) in default privileges\n",
11877                                           (int) daclinfo->defaclobjtype);
11878                         exit_nicely();
11879                         type = "";                      /* keep compiler quiet */
11880         }
11881
11882         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
11883
11884         /* build the actual command(s) for this tuple */
11885         if (!buildDefaultACLCommands(type,
11886                                                                  daclinfo->dobj.namespace != NULL ?
11887                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
11888                                                                  daclinfo->defaclacl,
11889                                                                  daclinfo->defaclrole,
11890                                                                  fout->remoteVersion,
11891                                                                  q))
11892         {
11893                 write_msg(NULL, "could not parse default ACL list (%s)\n",
11894                                   daclinfo->defaclacl);
11895                 exit_nicely();
11896         }
11897
11898         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
11899                                  tag->data,
11900            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
11901                                  NULL,
11902                                  daclinfo->defaclrole,
11903                                  false, "DEFAULT ACL", SECTION_NONE,
11904                                  q->data, "", NULL,
11905                                  daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
11906                                  NULL, NULL);
11907
11908         destroyPQExpBuffer(tag);
11909         destroyPQExpBuffer(q);
11910 }
11911
11912 /*----------
11913  * Write out grant/revoke information
11914  *
11915  * 'objCatId' is the catalog ID of the underlying object.
11916  * 'objDumpId' is the dump ID of the underlying object.
11917  * 'type' must be one of
11918  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
11919  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
11920  * 'name' is the formatted name of the object.  Must be quoted etc. already.
11921  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
11922  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
11923  * 'nspname' is the namespace the object is in (NULL if none).
11924  * 'owner' is the owner, NULL if there is no owner (for languages).
11925  * 'acls' is the string read out of the fooacl system catalog field;
11926  *              it will be parsed here.
11927  *----------
11928  */
11929 static void
11930 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
11931                 const char *type, const char *name, const char *subname,
11932                 const char *tag, const char *nspname, const char *owner,
11933                 const char *acls)
11934 {
11935         PQExpBuffer sql;
11936
11937         /* Do nothing if ACL dump is not enabled */
11938         if (aclsSkip)
11939                 return;
11940
11941         /* --data-only skips ACLs *except* BLOB ACLs */
11942         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
11943                 return;
11944
11945         sql = createPQExpBuffer();
11946
11947         if (!buildACLCommands(name, subname, type, acls, owner,
11948                                                   "", fout->remoteVersion, sql))
11949         {
11950                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
11951                                   acls, name, type);
11952                 exit_nicely();
11953         }
11954
11955         if (sql->len > 0)
11956                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11957                                          tag, nspname,
11958                                          NULL,
11959                                          owner ? owner : "",
11960                                          false, "ACL", SECTION_NONE,
11961                                          sql->data, "", NULL,
11962                                          &(objDumpId), 1,
11963                                          NULL, NULL);
11964
11965         destroyPQExpBuffer(sql);
11966 }
11967
11968 /*
11969  * dumpSecLabel
11970  *
11971  * This routine is used to dump any security labels associated with the
11972  * object handed to this routine. The routine takes a constant character
11973  * string for the target part of the security-label command, plus
11974  * the namespace and owner of the object (for labeling the ArchiveEntry),
11975  * plus catalog ID and subid which are the lookup key for pg_seclabel,
11976  * plus the dump ID for the object (for setting a dependency).
11977  * If a matching pg_seclabel entry is found, it is dumped.
11978  *
11979  * Note: although this routine takes a dumpId for dependency purposes,
11980  * that purpose is just to mark the dependency in the emitted dump file
11981  * for possible future use by pg_restore.  We do NOT use it for determining
11982  * ordering of the label in the dump file, because this routine is called
11983  * after dependency sorting occurs.  This routine should be called just after
11984  * calling ArchiveEntry() for the specified object.
11985  */
11986 static void
11987 dumpSecLabel(Archive *fout, const char *target,
11988                          const char *namespace, const char *owner,
11989                          CatalogId catalogId, int subid, DumpId dumpId)
11990 {
11991         SecLabelItem *labels;
11992         int                     nlabels;
11993         int                     i;
11994         PQExpBuffer query;
11995
11996         /* do nothing, if --no-security-labels is supplied */
11997         if (no_security_labels)
11998                 return;
11999
12000         /* Comments are schema not data ... except blob comments are data */
12001         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12002         {
12003                 if (dataOnly)
12004                         return;
12005         }
12006         else
12007         {
12008                 if (schemaOnly)
12009                         return;
12010         }
12011
12012         /* Search for security labels associated with catalogId, using table */
12013         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12014
12015         query = createPQExpBuffer();
12016
12017         for (i = 0; i < nlabels; i++)
12018         {
12019                 /*
12020                  * Ignore label entries for which the subid doesn't match.
12021                  */
12022                 if (labels[i].objsubid != subid)
12023                         continue;
12024
12025                 appendPQExpBuffer(query,
12026                                                   "SECURITY LABEL FOR %s ON %s IS ",
12027                                                   fmtId(labels[i].provider), target);
12028                 appendStringLiteralAH(query, labels[i].label, fout);
12029                 appendPQExpBuffer(query, ";\n");
12030         }
12031
12032         if (query->len > 0)
12033         {
12034                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12035                                          target, namespace, NULL, owner,
12036                                          false, "SECURITY LABEL", SECTION_NONE,
12037                                          query->data, "", NULL,
12038                                          &(dumpId), 1,
12039                                          NULL, NULL);
12040         }
12041         destroyPQExpBuffer(query);
12042 }
12043
12044 /*
12045  * dumpTableSecLabel
12046  *
12047  * As above, but dump security label for both the specified table (or view)
12048  * and its columns.
12049  */
12050 static void
12051 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12052 {
12053         SecLabelItem *labels;
12054         int                     nlabels;
12055         int                     i;
12056         PQExpBuffer query;
12057         PQExpBuffer target;
12058
12059         /* do nothing, if --no-security-labels is supplied */
12060         if (no_security_labels)
12061                 return;
12062
12063         /* SecLabel are SCHEMA not data */
12064         if (dataOnly)
12065                 return;
12066
12067         /* Search for comments associated with relation, using table */
12068         nlabels = findSecLabels(fout,
12069                                                         tbinfo->dobj.catId.tableoid,
12070                                                         tbinfo->dobj.catId.oid,
12071                                                         &labels);
12072
12073         /* If security labels exist, build SECURITY LABEL statements */
12074         if (nlabels <= 0)
12075                 return;
12076
12077         query = createPQExpBuffer();
12078         target = createPQExpBuffer();
12079
12080         for (i = 0; i < nlabels; i++)
12081         {
12082                 const char *colname;
12083                 const char *provider = labels[i].provider;
12084                 const char *label = labels[i].label;
12085                 int                     objsubid = labels[i].objsubid;
12086
12087                 resetPQExpBuffer(target);
12088                 if (objsubid == 0)
12089                 {
12090                         appendPQExpBuffer(target, "%s %s", reltypename,
12091                                                           fmtId(tbinfo->dobj.name));
12092                 }
12093                 else
12094                 {
12095                         colname = getAttrName(objsubid, tbinfo);
12096                         /* first fmtId result must be consumed before calling it again */
12097                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12098                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12099                 }
12100                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12101                                                   fmtId(provider), target->data);
12102                 appendStringLiteralAH(query, label, fout);
12103                 appendPQExpBuffer(query, ";\n");
12104         }
12105         if (query->len > 0)
12106         {
12107                 resetPQExpBuffer(target);
12108                 appendPQExpBuffer(target, "%s %s", reltypename,
12109                                                   fmtId(tbinfo->dobj.name));
12110                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12111                                          target->data,
12112                                          tbinfo->dobj.namespace->dobj.name,
12113                                          NULL, tbinfo->rolname,
12114                                          false, "SECURITY LABEL", SECTION_NONE,
12115                                          query->data, "", NULL,
12116                                          &(tbinfo->dobj.dumpId), 1,
12117                                          NULL, NULL);
12118         }
12119         destroyPQExpBuffer(query);
12120         destroyPQExpBuffer(target);
12121 }
12122
12123 /*
12124  * findSecLabels
12125  *
12126  * Find the security label(s), if any, associated with the given object.
12127  * All the objsubid values associated with the given classoid/objoid are
12128  * found with one search.
12129  */
12130 static int
12131 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12132 {
12133         /* static storage for table of security labels */
12134         static SecLabelItem *labels = NULL;
12135         static int      nlabels = -1;
12136
12137         SecLabelItem *middle = NULL;
12138         SecLabelItem *low;
12139         SecLabelItem *high;
12140         int                     nmatch;
12141
12142         /* Get security labels if we didn't already */
12143         if (nlabels < 0)
12144                 nlabels = collectSecLabels(fout, &labels);
12145
12146         if (nlabels <= 0)                       /* no labels, so no match is possible */
12147         {
12148                 *items = NULL;
12149                 return 0;
12150         }
12151
12152         /*
12153          * Do binary search to find some item matching the object.
12154          */
12155         low = &labels[0];
12156         high = &labels[nlabels - 1];
12157         while (low <= high)
12158         {
12159                 middle = low + (high - low) / 2;
12160
12161                 if (classoid < middle->classoid)
12162                         high = middle - 1;
12163                 else if (classoid > middle->classoid)
12164                         low = middle + 1;
12165                 else if (objoid < middle->objoid)
12166                         high = middle - 1;
12167                 else if (objoid > middle->objoid)
12168                         low = middle + 1;
12169                 else
12170                         break;                          /* found a match */
12171         }
12172
12173         if (low > high)                         /* no matches */
12174         {
12175                 *items = NULL;
12176                 return 0;
12177         }
12178
12179         /*
12180          * Now determine how many items match the object.  The search loop
12181          * invariant still holds: only items between low and high inclusive could
12182          * match.
12183          */
12184         nmatch = 1;
12185         while (middle > low)
12186         {
12187                 if (classoid != middle[-1].classoid ||
12188                         objoid != middle[-1].objoid)
12189                         break;
12190                 middle--;
12191                 nmatch++;
12192         }
12193
12194         *items = middle;
12195
12196         middle += nmatch;
12197         while (middle <= high)
12198         {
12199                 if (classoid != middle->classoid ||
12200                         objoid != middle->objoid)
12201                         break;
12202                 middle++;
12203                 nmatch++;
12204         }
12205
12206         return nmatch;
12207 }
12208
12209 /*
12210  * collectSecLabels
12211  *
12212  * Construct a table of all security labels available for database objects.
12213  * It's much faster to pull them all at once.
12214  *
12215  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12216  */
12217 static int
12218 collectSecLabels(Archive *fout, SecLabelItem **items)
12219 {
12220         PGresult   *res;
12221         PQExpBuffer query;
12222         int                     i_label;
12223         int                     i_provider;
12224         int                     i_classoid;
12225         int                     i_objoid;
12226         int                     i_objsubid;
12227         int                     ntups;
12228         int                     i;
12229         SecLabelItem *labels;
12230
12231         query = createPQExpBuffer();
12232
12233         appendPQExpBuffer(query,
12234                                           "SELECT label, provider, classoid, objoid, objsubid "
12235                                           "FROM pg_catalog.pg_seclabel "
12236                                           "ORDER BY classoid, objoid, objsubid");
12237
12238         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12239
12240         /* Construct lookup table containing OIDs in numeric form */
12241         i_label = PQfnumber(res, "label");
12242         i_provider = PQfnumber(res, "provider");
12243         i_classoid = PQfnumber(res, "classoid");
12244         i_objoid = PQfnumber(res, "objoid");
12245         i_objsubid = PQfnumber(res, "objsubid");
12246
12247         ntups = PQntuples(res);
12248
12249         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12250
12251         for (i = 0; i < ntups; i++)
12252         {
12253                 labels[i].label = PQgetvalue(res, i, i_label);
12254                 labels[i].provider = PQgetvalue(res, i, i_provider);
12255                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12256                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12257                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12258         }
12259
12260         /* Do NOT free the PGresult since we are keeping pointers into it */
12261         destroyPQExpBuffer(query);
12262
12263         *items = labels;
12264         return ntups;
12265 }
12266
12267 /*
12268  * dumpTable
12269  *        write out to fout the declarations (not data) of a user-defined table
12270  */
12271 static void
12272 dumpTable(Archive *fout, TableInfo *tbinfo)
12273 {
12274         if (tbinfo->dobj.dump)
12275         {
12276                 char       *namecopy;
12277
12278                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12279                         dumpSequence(fout, tbinfo);
12280                 else if (!dataOnly)
12281                         dumpTableSchema(fout, tbinfo);
12282
12283                 /* Handle the ACL here */
12284                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12285                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12286                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12287                                 "TABLE",
12288                                 namecopy, NULL, tbinfo->dobj.name,
12289                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12290                                 tbinfo->relacl);
12291
12292                 /*
12293                  * Handle column ACLs, if any.  Note: we pull these with a separate
12294                  * query rather than trying to fetch them during getTableAttrs, so
12295                  * that we won't miss ACLs on system columns.
12296                  */
12297                 if (fout->remoteVersion >= 80400)
12298                 {
12299                         PQExpBuffer query = createPQExpBuffer();
12300                         PGresult   *res;
12301                         int                     i;
12302
12303                         appendPQExpBuffer(query,
12304                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12305                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12306                                                           "ORDER BY attnum",
12307                                                           tbinfo->dobj.catId.oid);
12308                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12309
12310                         for (i = 0; i < PQntuples(res); i++)
12311                         {
12312                                 char       *attname = PQgetvalue(res, i, 0);
12313                                 char       *attacl = PQgetvalue(res, i, 1);
12314                                 char       *attnamecopy;
12315                                 char       *acltag;
12316
12317                                 attnamecopy = pg_strdup(fmtId(attname));
12318                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12319                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12320                                 /* Column's GRANT type is always TABLE */
12321                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12322                                                 namecopy, attnamecopy, acltag,
12323                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12324                                                 attacl);
12325                                 free(attnamecopy);
12326                                 free(acltag);
12327                         }
12328                         PQclear(res);
12329                         destroyPQExpBuffer(query);
12330                 }
12331
12332                 free(namecopy);
12333         }
12334 }
12335
12336 /*
12337  * dumpTableSchema
12338  *        write the declaration (not data) of one user-defined table or view
12339  */
12340 static void
12341 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12342 {
12343         PQExpBuffer query = createPQExpBuffer();
12344         PQExpBuffer q = createPQExpBuffer();
12345         PQExpBuffer delq = createPQExpBuffer();
12346         PQExpBuffer labelq = createPQExpBuffer();
12347         PGresult   *res;
12348         int                     numParents;
12349         TableInfo **parents;
12350         int                     actual_atts;    /* number of attrs in this CREATE statment */
12351         const char *reltypename;
12352         char       *storage;
12353         char       *srvname;
12354         char       *ftoptions;
12355         int                     j,
12356                                 k;
12357
12358         /* Make sure we are in proper schema */
12359         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12360
12361         if (binary_upgrade)
12362                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12363                                                                                                 tbinfo->dobj.catId.oid);
12364
12365         /* Is it a table or a view? */
12366         if (tbinfo->relkind == RELKIND_VIEW)
12367         {
12368                 char       *viewdef;
12369
12370                 reltypename = "VIEW";
12371
12372                 /* Fetch the view definition */
12373                 if (fout->remoteVersion >= 70300)
12374                 {
12375                         /* Beginning in 7.3, viewname is not unique; rely on OID */
12376                         appendPQExpBuffer(query,
12377                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12378                                                           tbinfo->dobj.catId.oid);
12379                 }
12380                 else
12381                 {
12382                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
12383                                                           "FROM pg_views WHERE viewname = ");
12384                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12385                         appendPQExpBuffer(query, ";");
12386                 }
12387
12388                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12389
12390                 if (PQntuples(res) != 1)
12391                 {
12392                         if (PQntuples(res) < 1)
12393                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12394                                                   tbinfo->dobj.name);
12395                         else
12396                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12397                                                   tbinfo->dobj.name);
12398                         exit_nicely();
12399                 }
12400
12401                 viewdef = PQgetvalue(res, 0, 0);
12402
12403                 if (strlen(viewdef) == 0)
12404                 {
12405                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12406                                           tbinfo->dobj.name);
12407                         exit_nicely();
12408                 }
12409
12410                 /*
12411                  * DROP must be fully qualified in case same name appears in
12412                  * pg_catalog
12413                  */
12414                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12415                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12416                 appendPQExpBuffer(delq, "%s;\n",
12417                                                   fmtId(tbinfo->dobj.name));
12418
12419                 if (binary_upgrade)
12420                         binary_upgrade_set_pg_class_oids(fout, q,
12421                                                                                          tbinfo->dobj.catId.oid, false);
12422
12423                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12424                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12425                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12426                 appendPQExpBuffer(q, " AS\n    %s\n", viewdef);
12427
12428                 appendPQExpBuffer(labelq, "VIEW %s",
12429                                                   fmtId(tbinfo->dobj.name));
12430
12431                 PQclear(res);
12432         }
12433         else
12434         {
12435                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12436                 {
12437                         int                     i_srvname;
12438                         int                     i_ftoptions;
12439
12440                         reltypename = "FOREIGN TABLE";
12441
12442                         /* retrieve name of foreign server and generic options */
12443                         appendPQExpBuffer(query,
12444                                                           "SELECT fs.srvname, "
12445                                                           "pg_catalog.array_to_string(ARRAY("
12446                                                           "SELECT pg_catalog.quote_ident(option_name) || "
12447                                                           "' ' || pg_catalog.quote_literal(option_value) "
12448                                                           "FROM pg_catalog.pg_options_to_table(ftoptions) "
12449                                                           "ORDER BY option_name"
12450                                                           "), E',\n    ') AS ftoptions "
12451                                                           "FROM pg_catalog.pg_foreign_table ft "
12452                                                           "JOIN pg_catalog.pg_foreign_server fs "
12453                                                           "ON (fs.oid = ft.ftserver) "
12454                                                           "WHERE ft.ftrelid = '%u'",
12455                                                           tbinfo->dobj.catId.oid);
12456                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12457                         if (PQntuples(res) != 1)
12458                         {
12459                                 write_msg(NULL, ngettext("query returned %d foreign server entry for foreign table \"%s\"\n",
12460                                                                                  "query returned %d foreign server entries for foreign table \"%s\"\n",
12461                                                                                  PQntuples(res)),
12462                                                   PQntuples(res), tbinfo->dobj.name);
12463                                 exit_nicely();
12464                         }
12465                         i_srvname = PQfnumber(res, "srvname");
12466                         i_ftoptions = PQfnumber(res, "ftoptions");
12467                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12468                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12469                         PQclear(res);
12470                 }
12471                 else
12472                 {
12473                         reltypename = "TABLE";
12474                         srvname = NULL;
12475                         ftoptions = NULL;
12476                 }
12477                 numParents = tbinfo->numParents;
12478                 parents = tbinfo->parents;
12479
12480                 /*
12481                  * DROP must be fully qualified in case same name appears in
12482                  * pg_catalog
12483                  */
12484                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12485                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12486                 appendPQExpBuffer(delq, "%s;\n",
12487                                                   fmtId(tbinfo->dobj.name));
12488
12489                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12490                                                   fmtId(tbinfo->dobj.name));
12491
12492                 if (binary_upgrade)
12493                         binary_upgrade_set_pg_class_oids(fout, q,
12494                                                                                          tbinfo->dobj.catId.oid, false);
12495
12496                 appendPQExpBuffer(q, "CREATE %s%s %s",
12497                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12498                                                   "UNLOGGED " : "",
12499                                                   reltypename,
12500                                                   fmtId(tbinfo->dobj.name));
12501
12502                 /*
12503                  * In case of a binary upgrade, we dump the table normally and attach
12504                  * it to the type afterward.
12505                  */
12506                 if (tbinfo->reloftype && !binary_upgrade)
12507                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12508                 actual_atts = 0;
12509                 for (j = 0; j < tbinfo->numatts; j++)
12510                 {
12511                         /*
12512                          * Normally, dump if it's one of the table's own attrs, and not
12513                          * dropped.  But for binary upgrade, dump all the columns.
12514                          */
12515                         if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
12516                                 binary_upgrade)
12517                         {
12518                                 /*
12519                                  * Default value --- suppress if inherited (except in
12520                                  * binary-upgrade case, where we're not doing normal
12521                                  * inheritance) or if it's to be printed separately.
12522                                  */
12523                                 bool            has_default = (tbinfo->attrdefs[j] != NULL
12524                                                                 && (!tbinfo->inhAttrDef[j] || binary_upgrade)
12525                                                                                    && !tbinfo->attrdefs[j]->separate);
12526
12527                                 /*
12528                                  * Not Null constraint --- suppress if inherited, except in
12529                                  * binary-upgrade case.
12530                                  */
12531                                 bool            has_notnull = (tbinfo->notnull[j]
12532                                                           && (!tbinfo->inhNotNull[j] || binary_upgrade));
12533
12534                                 if (tbinfo->reloftype && !has_default && !has_notnull && !binary_upgrade)
12535                                         continue;
12536
12537                                 /* Format properly if not first attr */
12538                                 if (actual_atts == 0)
12539                                         appendPQExpBuffer(q, " (");
12540                                 else
12541                                         appendPQExpBuffer(q, ",");
12542                                 appendPQExpBuffer(q, "\n    ");
12543                                 actual_atts++;
12544
12545                                 /* Attribute name */
12546                                 appendPQExpBuffer(q, "%s ",
12547                                                                   fmtId(tbinfo->attnames[j]));
12548
12549                                 if (tbinfo->attisdropped[j])
12550                                 {
12551                                         /*
12552                                          * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
12553                                          * so we will not have gotten a valid type name; insert
12554                                          * INTEGER as a stopgap.  We'll clean things up later.
12555                                          */
12556                                         appendPQExpBuffer(q, "INTEGER /* dummy */");
12557                                         /* Skip all the rest, too */
12558                                         continue;
12559                                 }
12560
12561                                 /* Attribute type */
12562                                 if (tbinfo->reloftype && !binary_upgrade)
12563                                 {
12564                                         appendPQExpBuffer(q, "WITH OPTIONS");
12565                                 }
12566                                 else if (fout->remoteVersion >= 70100)
12567                                 {
12568                                         appendPQExpBuffer(q, "%s",
12569                                                                           tbinfo->atttypnames[j]);
12570                                 }
12571                                 else
12572                                 {
12573                                         /* If no format_type, fake it */
12574                                         appendPQExpBuffer(q, "%s",
12575                                                                           myFormatType(tbinfo->atttypnames[j],
12576                                                                                                    tbinfo->atttypmod[j]));
12577                                 }
12578
12579                                 /* Add collation if not default for the type */
12580                                 if (OidIsValid(tbinfo->attcollation[j]))
12581                                 {
12582                                         CollInfo   *coll;
12583
12584                                         coll = findCollationByOid(tbinfo->attcollation[j]);
12585                                         if (coll)
12586                                         {
12587                                                 /* always schema-qualify, don't try to be smart */
12588                                                 appendPQExpBuffer(q, " COLLATE %s.",
12589                                                                          fmtId(coll->dobj.namespace->dobj.name));
12590                                                 appendPQExpBuffer(q, "%s",
12591                                                                                   fmtId(coll->dobj.name));
12592                                         }
12593                                 }
12594
12595                                 if (has_default)
12596                                         appendPQExpBuffer(q, " DEFAULT %s",
12597                                                                           tbinfo->attrdefs[j]->adef_expr);
12598
12599                                 if (has_notnull)
12600                                         appendPQExpBuffer(q, " NOT NULL");
12601                         }
12602                 }
12603
12604                 /*
12605                  * Add non-inherited CHECK constraints, if any.
12606                  */
12607                 for (j = 0; j < tbinfo->ncheck; j++)
12608                 {
12609                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12610
12611                         if (constr->separate || !constr->conislocal)
12612                                 continue;
12613
12614                         if (actual_atts == 0)
12615                                 appendPQExpBuffer(q, " (\n    ");
12616                         else
12617                                 appendPQExpBuffer(q, ",\n    ");
12618
12619                         appendPQExpBuffer(q, "CONSTRAINT %s ",
12620                                                           fmtId(constr->dobj.name));
12621                         appendPQExpBuffer(q, "%s", constr->condef);
12622
12623                         actual_atts++;
12624                 }
12625
12626                 if (actual_atts)
12627                         appendPQExpBuffer(q, "\n)");
12628                 else if (!(tbinfo->reloftype && !binary_upgrade))
12629                 {
12630                         /*
12631                          * We must have a parenthesized attribute list, even though empty,
12632                          * when not using the OF TYPE syntax.
12633                          */
12634                         appendPQExpBuffer(q, " (\n)");
12635                 }
12636
12637                 if (numParents > 0 && !binary_upgrade)
12638                 {
12639                         appendPQExpBuffer(q, "\nINHERITS (");
12640                         for (k = 0; k < numParents; k++)
12641                         {
12642                                 TableInfo  *parentRel = parents[k];
12643
12644                                 if (k > 0)
12645                                         appendPQExpBuffer(q, ", ");
12646                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12647                                         appendPQExpBuffer(q, "%s.",
12648                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12649                                 appendPQExpBuffer(q, "%s",
12650                                                                   fmtId(parentRel->dobj.name));
12651                         }
12652                         appendPQExpBuffer(q, ")");
12653                 }
12654
12655                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12656                         appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
12657
12658                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
12659                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
12660                 {
12661                         bool            addcomma = false;
12662
12663                         appendPQExpBuffer(q, "\nWITH (");
12664                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12665                         {
12666                                 addcomma = true;
12667                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
12668                         }
12669                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
12670                         {
12671                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
12672                                                                   tbinfo->toast_reloptions);
12673                         }
12674                         appendPQExpBuffer(q, ")");
12675                 }
12676
12677                 /* Dump generic options if any */
12678                 if (ftoptions && ftoptions[0])
12679                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
12680
12681                 appendPQExpBuffer(q, ";\n");
12682
12683                 /*
12684                  * To create binary-compatible heap files, we have to ensure the same
12685                  * physical column order, including dropped columns, as in the
12686                  * original.  Therefore, we create dropped columns above and drop them
12687                  * here, also updating their attlen/attalign values so that the
12688                  * dropped column can be skipped properly.      (We do not bother with
12689                  * restoring the original attbyval setting.)  Also, inheritance
12690                  * relationships are set up by doing ALTER INHERIT rather than using
12691                  * an INHERITS clause --- the latter would possibly mess up the column
12692                  * order.  That also means we have to take care about setting
12693                  * attislocal correctly, plus fix up any inherited CHECK constraints.
12694                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
12695                  */
12696                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
12697                 {
12698                         for (j = 0; j < tbinfo->numatts; j++)
12699                         {
12700                                 if (tbinfo->attisdropped[j])
12701                                 {
12702                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
12703                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12704                                                                           "SET attlen = %d, "
12705                                                                           "attalign = '%c', attbyval = false\n"
12706                                                                           "WHERE attname = ",
12707                                                                           tbinfo->attlen[j],
12708                                                                           tbinfo->attalign[j]);
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                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12715                                                                           fmtId(tbinfo->dobj.name));
12716                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
12717                                                                           fmtId(tbinfo->attnames[j]));
12718                                 }
12719                                 else if (!tbinfo->attislocal[j])
12720                                 {
12721                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
12722                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12723                                                                           "SET attislocal = false\n"
12724                                                                           "WHERE attname = ");
12725                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12726                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12727                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12728                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12729                                 }
12730                         }
12731
12732                         for (k = 0; k < tbinfo->ncheck; k++)
12733                         {
12734                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
12735
12736                                 if (constr->separate || constr->conislocal)
12737                                         continue;
12738
12739                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
12740                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12741                                                                   fmtId(tbinfo->dobj.name));
12742                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
12743                                                                   fmtId(constr->dobj.name));
12744                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
12745                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
12746                                                                   "SET conislocal = false\n"
12747                                                                   "WHERE contype = 'c' AND conname = ");
12748                                 appendStringLiteralAH(q, constr->dobj.name, fout);
12749                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
12750                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12751                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12752                         }
12753
12754                         if (numParents > 0)
12755                         {
12756                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
12757                                 for (k = 0; k < numParents; k++)
12758                                 {
12759                                         TableInfo  *parentRel = parents[k];
12760
12761                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
12762                                                                           fmtId(tbinfo->dobj.name));
12763                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12764                                                 appendPQExpBuffer(q, "%s.",
12765                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12766                                         appendPQExpBuffer(q, "%s;\n",
12767                                                                           fmtId(parentRel->dobj.name));
12768                                 }
12769                         }
12770
12771                         if (tbinfo->reloftype)
12772                         {
12773                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
12774                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
12775                                                                   fmtId(tbinfo->dobj.name),
12776                                                                   tbinfo->reloftype);
12777                         }
12778
12779                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
12780                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12781                                                           "SET relfrozenxid = '%u'\n"
12782                                                           "WHERE oid = ",
12783                                                           tbinfo->frozenxid);
12784                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12785                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12786
12787                         if (tbinfo->toast_oid)
12788                         {
12789                                 /* We preserve the toast oids, so we can use it during restore */
12790                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
12791                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12792                                                                   "SET relfrozenxid = '%u'\n"
12793                                                                   "WHERE oid = '%u';\n",
12794                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
12795                         }
12796                 }
12797
12798                 /* Loop dumping statistics and storage statements */
12799                 for (j = 0; j < tbinfo->numatts; j++)
12800                 {
12801                         /*
12802                          * Dump per-column statistics information. We only issue an ALTER
12803                          * TABLE statement if the attstattarget entry for this column is
12804                          * non-negative (i.e. it's not the default value)
12805                          */
12806                         if (tbinfo->attstattarget[j] >= 0 &&
12807                                 !tbinfo->attisdropped[j])
12808                         {
12809                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12810                                                                   fmtId(tbinfo->dobj.name));
12811                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12812                                                                   fmtId(tbinfo->attnames[j]));
12813                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
12814                                                                   tbinfo->attstattarget[j]);
12815                         }
12816
12817                         /*
12818                          * Dump per-column storage information.  The statement is only
12819                          * dumped if the storage has been changed from the type's default.
12820                          */
12821                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
12822                         {
12823                                 switch (tbinfo->attstorage[j])
12824                                 {
12825                                         case 'p':
12826                                                 storage = "PLAIN";
12827                                                 break;
12828                                         case 'e':
12829                                                 storage = "EXTERNAL";
12830                                                 break;
12831                                         case 'm':
12832                                                 storage = "MAIN";
12833                                                 break;
12834                                         case 'x':
12835                                                 storage = "EXTENDED";
12836                                                 break;
12837                                         default:
12838                                                 storage = NULL;
12839                                 }
12840
12841                                 /*
12842                                  * Only dump the statement if it's a storage type we recognize
12843                                  */
12844                                 if (storage != NULL)
12845                                 {
12846                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12847                                                                           fmtId(tbinfo->dobj.name));
12848                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
12849                                                                           fmtId(tbinfo->attnames[j]));
12850                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
12851                                                                           storage);
12852                                 }
12853                         }
12854
12855                         /*
12856                          * Dump per-column attributes.
12857                          */
12858                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
12859                         {
12860                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12861                                                                   fmtId(tbinfo->dobj.name));
12862                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12863                                                                   fmtId(tbinfo->attnames[j]));
12864                                 appendPQExpBuffer(q, "SET (%s);\n",
12865                                                                   tbinfo->attoptions[j]);
12866                         }
12867
12868                         /*
12869                          * Dump per-column fdw options.
12870                          */
12871                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
12872                                 tbinfo->attfdwoptions[j] &&
12873                                 tbinfo->attfdwoptions[j][0] != '\0')
12874                         {
12875                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
12876                                                                   fmtId(tbinfo->dobj.name));
12877                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12878                                                                   fmtId(tbinfo->attnames[j]));
12879                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
12880                                                                   tbinfo->attfdwoptions[j]);
12881                         }
12882                 }
12883         }
12884
12885         if (binary_upgrade)
12886                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
12887
12888         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12889                                  tbinfo->dobj.name,
12890                                  tbinfo->dobj.namespace->dobj.name,
12891                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
12892                                  tbinfo->rolname,
12893                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
12894                                  reltypename, SECTION_PRE_DATA,
12895                                  q->data, delq->data, NULL,
12896                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
12897                                  NULL, NULL);
12898
12899
12900         /* Dump Table Comments */
12901         dumpTableComment(fout, tbinfo, reltypename);
12902
12903         /* Dump Table Security Labels */
12904         dumpTableSecLabel(fout, tbinfo, reltypename);
12905
12906         /* Dump comments on inlined table constraints */
12907         for (j = 0; j < tbinfo->ncheck; j++)
12908         {
12909                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12910
12911                 if (constr->separate || !constr->conislocal)
12912                         continue;
12913
12914                 dumpTableConstraintComment(fout, constr);
12915         }
12916
12917         destroyPQExpBuffer(query);
12918         destroyPQExpBuffer(q);
12919         destroyPQExpBuffer(delq);
12920         destroyPQExpBuffer(labelq);
12921 }
12922
12923 /*
12924  * dumpAttrDef --- dump an attribute's default-value declaration
12925  */
12926 static void
12927 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
12928 {
12929         TableInfo  *tbinfo = adinfo->adtable;
12930         int                     adnum = adinfo->adnum;
12931         PQExpBuffer q;
12932         PQExpBuffer delq;
12933
12934         /* Only print it if "separate" mode is selected */
12935         if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
12936                 return;
12937
12938         /* Don't print inherited defaults, either, except for binary upgrade */
12939         if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
12940                 return;
12941
12942         q = createPQExpBuffer();
12943         delq = createPQExpBuffer();
12944
12945         appendPQExpBuffer(q, "ALTER TABLE %s ",
12946                                           fmtId(tbinfo->dobj.name));
12947         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
12948                                           fmtId(tbinfo->attnames[adnum - 1]),
12949                                           adinfo->adef_expr);
12950
12951         /*
12952          * DROP must be fully qualified in case same name appears in pg_catalog
12953          */
12954         appendPQExpBuffer(delq, "ALTER TABLE %s.",
12955                                           fmtId(tbinfo->dobj.namespace->dobj.name));
12956         appendPQExpBuffer(delq, "%s ",
12957                                           fmtId(tbinfo->dobj.name));
12958         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
12959                                           fmtId(tbinfo->attnames[adnum - 1]));
12960
12961         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
12962                                  tbinfo->attnames[adnum - 1],
12963                                  tbinfo->dobj.namespace->dobj.name,
12964                                  NULL,
12965                                  tbinfo->rolname,
12966                                  false, "DEFAULT", SECTION_PRE_DATA,
12967                                  q->data, delq->data, NULL,
12968                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
12969                                  NULL, NULL);
12970
12971         destroyPQExpBuffer(q);
12972         destroyPQExpBuffer(delq);
12973 }
12974
12975 /*
12976  * getAttrName: extract the correct name for an attribute
12977  *
12978  * The array tblInfo->attnames[] only provides names of user attributes;
12979  * if a system attribute number is supplied, we have to fake it.
12980  * We also do a little bit of bounds checking for safety's sake.
12981  */
12982 static const char *
12983 getAttrName(int attrnum, TableInfo *tblInfo)
12984 {
12985         if (attrnum > 0 && attrnum <= tblInfo->numatts)
12986                 return tblInfo->attnames[attrnum - 1];
12987         switch (attrnum)
12988         {
12989                 case SelfItemPointerAttributeNumber:
12990                         return "ctid";
12991                 case ObjectIdAttributeNumber:
12992                         return "oid";
12993                 case MinTransactionIdAttributeNumber:
12994                         return "xmin";
12995                 case MinCommandIdAttributeNumber:
12996                         return "cmin";
12997                 case MaxTransactionIdAttributeNumber:
12998                         return "xmax";
12999                 case MaxCommandIdAttributeNumber:
13000                         return "cmax";
13001                 case TableOidAttributeNumber:
13002                         return "tableoid";
13003         }
13004         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
13005                           attrnum, tblInfo->dobj.name);
13006         exit_nicely();
13007         return NULL;                            /* keep compiler quiet */
13008 }
13009
13010 /*
13011  * dumpIndex
13012  *        write out to fout a user-defined index
13013  */
13014 static void
13015 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13016 {
13017         TableInfo  *tbinfo = indxinfo->indextable;
13018         PQExpBuffer q;
13019         PQExpBuffer delq;
13020         PQExpBuffer labelq;
13021
13022         if (dataOnly)
13023                 return;
13024
13025         q = createPQExpBuffer();
13026         delq = createPQExpBuffer();
13027         labelq = createPQExpBuffer();
13028
13029         appendPQExpBuffer(labelq, "INDEX %s",
13030                                           fmtId(indxinfo->dobj.name));
13031
13032         /*
13033          * If there's an associated constraint, don't dump the index per se, but
13034          * do dump any comment for it.  (This is safe because dependency ordering
13035          * will have ensured the constraint is emitted first.)
13036          */
13037         if (indxinfo->indexconstraint == 0)
13038         {
13039                 if (binary_upgrade)
13040                         binary_upgrade_set_pg_class_oids(fout, q,
13041                                                                                          indxinfo->dobj.catId.oid, true);
13042
13043                 /* Plain secondary index */
13044                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13045
13046                 /* If the index is clustered, we need to record that. */
13047                 if (indxinfo->indisclustered)
13048                 {
13049                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13050                                                           fmtId(tbinfo->dobj.name));
13051                         appendPQExpBuffer(q, " ON %s;\n",
13052                                                           fmtId(indxinfo->dobj.name));
13053                 }
13054
13055                 /*
13056                  * DROP must be fully qualified in case same name appears in
13057                  * pg_catalog
13058                  */
13059                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13060                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13061                 appendPQExpBuffer(delq, "%s;\n",
13062                                                   fmtId(indxinfo->dobj.name));
13063
13064                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13065                                          indxinfo->dobj.name,
13066                                          tbinfo->dobj.namespace->dobj.name,
13067                                          indxinfo->tablespace,
13068                                          tbinfo->rolname, false,
13069                                          "INDEX", SECTION_POST_DATA,
13070                                          q->data, delq->data, NULL,
13071                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
13072                                          NULL, NULL);
13073         }
13074
13075         /* Dump Index Comments */
13076         dumpComment(fout, labelq->data,
13077                                 tbinfo->dobj.namespace->dobj.name,
13078                                 tbinfo->rolname,
13079                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13080
13081         destroyPQExpBuffer(q);
13082         destroyPQExpBuffer(delq);
13083         destroyPQExpBuffer(labelq);
13084 }
13085
13086 /*
13087  * dumpConstraint
13088  *        write out to fout a user-defined constraint
13089  */
13090 static void
13091 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13092 {
13093         TableInfo  *tbinfo = coninfo->contable;
13094         PQExpBuffer q;
13095         PQExpBuffer delq;
13096
13097         /* Skip if not to be dumped */
13098         if (!coninfo->dobj.dump || dataOnly)
13099                 return;
13100
13101         q = createPQExpBuffer();
13102         delq = createPQExpBuffer();
13103
13104         if (coninfo->contype == 'p' ||
13105                 coninfo->contype == 'u' ||
13106                 coninfo->contype == 'x')
13107         {
13108                 /* Index-related constraint */
13109                 IndxInfo   *indxinfo;
13110                 int                     k;
13111
13112                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13113
13114                 if (indxinfo == NULL)
13115                 {
13116                         write_msg(NULL, "missing index for constraint \"%s\"\n",
13117                                           coninfo->dobj.name);
13118                         exit_nicely();
13119                 }
13120
13121                 if (binary_upgrade)
13122                         binary_upgrade_set_pg_class_oids(fout, q,
13123                                                                                          indxinfo->dobj.catId.oid, true);
13124
13125                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13126                                                   fmtId(tbinfo->dobj.name));
13127                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13128                                                   fmtId(coninfo->dobj.name));
13129
13130                 if (coninfo->condef)
13131                 {
13132                         /* pg_get_constraintdef should have provided everything */
13133                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13134                 }
13135                 else
13136                 {
13137                         appendPQExpBuffer(q, "%s (",
13138                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13139                         for (k = 0; k < indxinfo->indnkeys; k++)
13140                         {
13141                                 int                     indkey = (int) indxinfo->indkeys[k];
13142                                 const char *attname;
13143
13144                                 if (indkey == InvalidAttrNumber)
13145                                         break;
13146                                 attname = getAttrName(indkey, tbinfo);
13147
13148                                 appendPQExpBuffer(q, "%s%s",
13149                                                                   (k == 0) ? "" : ", ",
13150                                                                   fmtId(attname));
13151                         }
13152
13153                         appendPQExpBuffer(q, ")");
13154
13155                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13156                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13157
13158                         if (coninfo->condeferrable)
13159                         {
13160                                 appendPQExpBuffer(q, " DEFERRABLE");
13161                                 if (coninfo->condeferred)
13162                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13163                         }
13164
13165                         appendPQExpBuffer(q, ";\n");
13166                 }
13167
13168                 /* If the index is clustered, we need to record that. */
13169                 if (indxinfo->indisclustered)
13170                 {
13171                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13172                                                           fmtId(tbinfo->dobj.name));
13173                         appendPQExpBuffer(q, " ON %s;\n",
13174                                                           fmtId(indxinfo->dobj.name));
13175                 }
13176
13177                 /*
13178                  * DROP must be fully qualified in case same name appears in
13179                  * pg_catalog
13180                  */
13181                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13182                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13183                 appendPQExpBuffer(delq, "%s ",
13184                                                   fmtId(tbinfo->dobj.name));
13185                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13186                                                   fmtId(coninfo->dobj.name));
13187
13188                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13189                                          coninfo->dobj.name,
13190                                          tbinfo->dobj.namespace->dobj.name,
13191                                          indxinfo->tablespace,
13192                                          tbinfo->rolname, false,
13193                                          "CONSTRAINT", SECTION_POST_DATA,
13194                                          q->data, delq->data, NULL,
13195                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13196                                          NULL, NULL);
13197         }
13198         else if (coninfo->contype == 'f')
13199         {
13200                 /*
13201                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13202                  * current table data is not processed
13203                  */
13204                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13205                                                   fmtId(tbinfo->dobj.name));
13206                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13207                                                   fmtId(coninfo->dobj.name),
13208                                                   coninfo->condef);
13209
13210                 /*
13211                  * DROP must be fully qualified in case same name appears in
13212                  * pg_catalog
13213                  */
13214                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13215                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13216                 appendPQExpBuffer(delq, "%s ",
13217                                                   fmtId(tbinfo->dobj.name));
13218                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13219                                                   fmtId(coninfo->dobj.name));
13220
13221                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13222                                          coninfo->dobj.name,
13223                                          tbinfo->dobj.namespace->dobj.name,
13224                                          NULL,
13225                                          tbinfo->rolname, false,
13226                                          "FK CONSTRAINT", SECTION_POST_DATA,
13227                                          q->data, delq->data, NULL,
13228                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13229                                          NULL, NULL);
13230         }
13231         else if (coninfo->contype == 'c' && tbinfo)
13232         {
13233                 /* CHECK constraint on a table */
13234
13235                 /* Ignore if not to be dumped separately */
13236                 if (coninfo->separate)
13237                 {
13238                         /* add ONLY if we do not want it to propagate to children */
13239                         appendPQExpBuffer(q, "ALTER TABLE %s %s\n",
13240                                                          coninfo->conisonly ? "ONLY" : "", fmtId(tbinfo->dobj.name));
13241                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13242                                                           fmtId(coninfo->dobj.name),
13243                                                           coninfo->condef);
13244
13245                         /*
13246                          * DROP must be fully qualified in case same name appears in
13247                          * pg_catalog
13248                          */
13249                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13250                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13251                         appendPQExpBuffer(delq, "%s ",
13252                                                           fmtId(tbinfo->dobj.name));
13253                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13254                                                           fmtId(coninfo->dobj.name));
13255
13256                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13257                                                  coninfo->dobj.name,
13258                                                  tbinfo->dobj.namespace->dobj.name,
13259                                                  NULL,
13260                                                  tbinfo->rolname, false,
13261                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13262                                                  q->data, delq->data, NULL,
13263                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13264                                                  NULL, NULL);
13265                 }
13266         }
13267         else if (coninfo->contype == 'c' && tbinfo == NULL)
13268         {
13269                 /* CHECK constraint on a domain */
13270                 TypeInfo   *tyinfo = coninfo->condomain;
13271
13272                 /* Ignore if not to be dumped separately */
13273                 if (coninfo->separate)
13274                 {
13275                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13276                                                           fmtId(tyinfo->dobj.name));
13277                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13278                                                           fmtId(coninfo->dobj.name),
13279                                                           coninfo->condef);
13280
13281                         /*
13282                          * DROP must be fully qualified in case same name appears in
13283                          * pg_catalog
13284                          */
13285                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13286                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13287                         appendPQExpBuffer(delq, "%s ",
13288                                                           fmtId(tyinfo->dobj.name));
13289                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13290                                                           fmtId(coninfo->dobj.name));
13291
13292                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13293                                                  coninfo->dobj.name,
13294                                                  tyinfo->dobj.namespace->dobj.name,
13295                                                  NULL,
13296                                                  tyinfo->rolname, false,
13297                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13298                                                  q->data, delq->data, NULL,
13299                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13300                                                  NULL, NULL);
13301                 }
13302         }
13303         else
13304         {
13305                 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
13306                 exit_nicely();
13307         }
13308
13309         /* Dump Constraint Comments --- only works for table constraints */
13310         if (tbinfo && coninfo->separate)
13311                 dumpTableConstraintComment(fout, coninfo);
13312
13313         destroyPQExpBuffer(q);
13314         destroyPQExpBuffer(delq);
13315 }
13316
13317 /*
13318  * dumpTableConstraintComment --- dump a constraint's comment if any
13319  *
13320  * This is split out because we need the function in two different places
13321  * depending on whether the constraint is dumped as part of CREATE TABLE
13322  * or as a separate ALTER command.
13323  */
13324 static void
13325 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13326 {
13327         TableInfo  *tbinfo = coninfo->contable;
13328         PQExpBuffer labelq = createPQExpBuffer();
13329
13330         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13331                                           fmtId(coninfo->dobj.name));
13332         appendPQExpBuffer(labelq, "ON %s",
13333                                           fmtId(tbinfo->dobj.name));
13334         dumpComment(fout, labelq->data,
13335                                 tbinfo->dobj.namespace->dobj.name,
13336                                 tbinfo->rolname,
13337                                 coninfo->dobj.catId, 0,
13338                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13339
13340         destroyPQExpBuffer(labelq);
13341 }
13342
13343 /*
13344  * findLastBuiltInOid -
13345  * find the last built in oid
13346  *
13347  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13348  * pg_database entry for the current database
13349  */
13350 static Oid
13351 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13352 {
13353         PGresult   *res;
13354         int                     ntups;
13355         Oid                     last_oid;
13356         PQExpBuffer query = createPQExpBuffer();
13357
13358         resetPQExpBuffer(query);
13359         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13360         appendStringLiteralAH(query, dbname, fout);
13361
13362         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13363
13364         ntups = PQntuples(res);
13365         if (ntups < 1)
13366         {
13367                 write_msg(NULL, "missing pg_database entry for this database\n");
13368                 exit_nicely();
13369         }
13370         if (ntups > 1)
13371         {
13372                 write_msg(NULL, "found more than one pg_database entry for this database\n");
13373                 exit_nicely();
13374         }
13375         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13376         PQclear(res);
13377         destroyPQExpBuffer(query);
13378         return last_oid;
13379 }
13380
13381 /*
13382  * findLastBuiltInOid -
13383  * find the last built in oid
13384  *
13385  * For 7.0, we do this by assuming that the last thing that initdb does is to
13386  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13387  * initdb won't be changing anymore, it'll do.
13388  */
13389 static Oid
13390 findLastBuiltinOid_V70(Archive *fout)
13391 {
13392         PGresult   *res;
13393         int                     ntups;
13394         int                     last_oid;
13395
13396         res = ExecuteSqlQuery(fout,
13397                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
13398                                         PGRES_TUPLES_OK);
13399         ntups = PQntuples(res);
13400         if (ntups < 1)
13401         {
13402                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
13403                 exit_nicely();
13404         }
13405         if (ntups > 1)
13406         {
13407                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
13408                 exit_nicely();
13409         }
13410         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13411         PQclear(res);
13412         return last_oid;
13413 }
13414
13415 static void
13416 dumpSequence(Archive *fout, TableInfo *tbinfo)
13417 {
13418         PGresult   *res;
13419         char       *startv,
13420                            *last,
13421                            *incby,
13422                            *maxv = NULL,
13423                            *minv = NULL,
13424                            *cache;
13425         char            bufm[100],
13426                                 bufx[100];
13427         bool            cycled,
13428                                 called;
13429         PQExpBuffer query = createPQExpBuffer();
13430         PQExpBuffer delqry = createPQExpBuffer();
13431         PQExpBuffer labelq = createPQExpBuffer();
13432
13433         /* Make sure we are in proper schema */
13434         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13435
13436         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13437         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13438
13439         if (fout->remoteVersion >= 80400)
13440         {
13441                 appendPQExpBuffer(query,
13442                                                   "SELECT sequence_name, "
13443                                                   "start_value, last_value, increment_by, "
13444                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13445                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13446                                                   "     ELSE max_value "
13447                                                   "END AS max_value, "
13448                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13449                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13450                                                   "     ELSE min_value "
13451                                                   "END AS min_value, "
13452                                                   "cache_value, is_cycled, is_called from %s",
13453                                                   bufx, bufm,
13454                                                   fmtId(tbinfo->dobj.name));
13455         }
13456         else
13457         {
13458                 appendPQExpBuffer(query,
13459                                                   "SELECT sequence_name, "
13460                                                   "0 AS start_value, last_value, increment_by, "
13461                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13462                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13463                                                   "     ELSE max_value "
13464                                                   "END AS max_value, "
13465                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13466                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13467                                                   "     ELSE min_value "
13468                                                   "END AS min_value, "
13469                                                   "cache_value, is_cycled, is_called from %s",
13470                                                   bufx, bufm,
13471                                                   fmtId(tbinfo->dobj.name));
13472         }
13473
13474         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13475
13476         if (PQntuples(res) != 1)
13477         {
13478                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13479                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13480                                                                  PQntuples(res)),
13481                                   tbinfo->dobj.name, PQntuples(res));
13482                 exit_nicely();
13483         }
13484
13485         /* Disable this check: it fails if sequence has been renamed */
13486 #ifdef NOT_USED
13487         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13488         {
13489                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13490                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13491                 exit_nicely();
13492         }
13493 #endif
13494
13495         startv = PQgetvalue(res, 0, 1);
13496         last = PQgetvalue(res, 0, 2);
13497         incby = PQgetvalue(res, 0, 3);
13498         if (!PQgetisnull(res, 0, 4))
13499                 maxv = PQgetvalue(res, 0, 4);
13500         if (!PQgetisnull(res, 0, 5))
13501                 minv = PQgetvalue(res, 0, 5);
13502         cache = PQgetvalue(res, 0, 6);
13503         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
13504         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
13505
13506         /*
13507          * The logic we use for restoring sequences is as follows:
13508          *
13509          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
13510          * last_val for start if called is false, else use min_val for start_val).
13511          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
13512          * BY command for it.
13513          *
13514          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
13515          */
13516         if (!dataOnly)
13517         {
13518                 /*
13519                  * DROP must be fully qualified in case same name appears in
13520                  * pg_catalog
13521                  */
13522                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13523                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13524                 appendPQExpBuffer(delqry, "%s;\n",
13525                                                   fmtId(tbinfo->dobj.name));
13526
13527                 resetPQExpBuffer(query);
13528
13529                 if (binary_upgrade)
13530                 {
13531                         binary_upgrade_set_pg_class_oids(fout, query,
13532                                                                                          tbinfo->dobj.catId.oid, false);
13533                         binary_upgrade_set_type_oids_by_rel_oid(fout, query,
13534                                                                                                         tbinfo->dobj.catId.oid);
13535                 }
13536
13537                 appendPQExpBuffer(query,
13538                                                   "CREATE SEQUENCE %s\n",
13539                                                   fmtId(tbinfo->dobj.name));
13540
13541                 if (fout->remoteVersion >= 80400)
13542                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
13543                 else
13544                 {
13545                         /*
13546                          * Versions before 8.4 did not remember the true start value.  If
13547                          * is_called is false then the sequence has never been incremented
13548                          * so we can use last_val.      Otherwise punt and let it default.
13549                          */
13550                         if (!called)
13551                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
13552                 }
13553
13554                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13555
13556                 if (minv)
13557                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13558                 else
13559                         appendPQExpBuffer(query, "    NO MINVALUE\n");
13560
13561                 if (maxv)
13562                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13563                 else
13564                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
13565
13566                 appendPQExpBuffer(query,
13567                                                   "    CACHE %s%s",
13568                                                   cache, (cycled ? "\n    CYCLE" : ""));
13569
13570                 appendPQExpBuffer(query, ";\n");
13571
13572                 appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13573
13574                 /* binary_upgrade:      no need to clear TOAST table oid */
13575
13576                 if (binary_upgrade)
13577                         binary_upgrade_extension_member(query, &tbinfo->dobj,
13578                                                                                         labelq->data);
13579
13580                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13581                                          tbinfo->dobj.name,
13582                                          tbinfo->dobj.namespace->dobj.name,
13583                                          NULL,
13584                                          tbinfo->rolname,
13585                                          false, "SEQUENCE", SECTION_PRE_DATA,
13586                                          query->data, delqry->data, NULL,
13587                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
13588                                          NULL, NULL);
13589
13590                 /*
13591                  * If the sequence is owned by a table column, emit the ALTER for it
13592                  * as a separate TOC entry immediately following the sequence's own
13593                  * entry.  It's OK to do this rather than using full sorting logic,
13594                  * because the dependency that tells us it's owned will have forced
13595                  * the table to be created first.  We can't just include the ALTER in
13596                  * the TOC entry because it will fail if we haven't reassigned the
13597                  * sequence owner to match the table's owner.
13598                  *
13599                  * We need not schema-qualify the table reference because both
13600                  * sequence and table must be in the same schema.
13601                  */
13602                 if (OidIsValid(tbinfo->owning_tab))
13603                 {
13604                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
13605
13606                         if (owning_tab && owning_tab->dobj.dump)
13607                         {
13608                                 resetPQExpBuffer(query);
13609                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
13610                                                                   fmtId(tbinfo->dobj.name));
13611                                 appendPQExpBuffer(query, " OWNED BY %s",
13612                                                                   fmtId(owning_tab->dobj.name));
13613                                 appendPQExpBuffer(query, ".%s;\n",
13614                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
13615
13616                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13617                                                          tbinfo->dobj.name,
13618                                                          tbinfo->dobj.namespace->dobj.name,
13619                                                          NULL,
13620                                                          tbinfo->rolname,
13621                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
13622                                                          query->data, "", NULL,
13623                                                          &(tbinfo->dobj.dumpId), 1,
13624                                                          NULL, NULL);
13625                         }
13626                 }
13627
13628                 /* Dump Sequence Comments and Security Labels */
13629                 dumpComment(fout, labelq->data,
13630                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13631                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13632                 dumpSecLabel(fout, labelq->data,
13633                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13634                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13635         }
13636
13637         if (!schemaOnly)
13638         {
13639                 resetPQExpBuffer(query);
13640                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
13641                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
13642                 appendPQExpBuffer(query, ", %s, %s);\n",
13643                                                   last, (called ? "true" : "false"));
13644
13645                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13646                                          tbinfo->dobj.name,
13647                                          tbinfo->dobj.namespace->dobj.name,
13648                                          NULL,
13649                                          tbinfo->rolname,
13650                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
13651                                          query->data, "", NULL,
13652                                          &(tbinfo->dobj.dumpId), 1,
13653                                          NULL, NULL);
13654         }
13655
13656         PQclear(res);
13657
13658         destroyPQExpBuffer(query);
13659         destroyPQExpBuffer(delqry);
13660         destroyPQExpBuffer(labelq);
13661 }
13662
13663 static void
13664 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
13665 {
13666         TableInfo  *tbinfo = tginfo->tgtable;
13667         PQExpBuffer query;
13668         PQExpBuffer delqry;
13669         PQExpBuffer labelq;
13670         char       *tgargs;
13671         size_t          lentgargs;
13672         const char *p;
13673         int                     findx;
13674
13675         if (dataOnly)
13676                 return;
13677
13678         query = createPQExpBuffer();
13679         delqry = createPQExpBuffer();
13680         labelq = createPQExpBuffer();
13681
13682         /*
13683          * DROP must be fully qualified in case same name appears in pg_catalog
13684          */
13685         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
13686                                           fmtId(tginfo->dobj.name));
13687         appendPQExpBuffer(delqry, "ON %s.",
13688                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13689         appendPQExpBuffer(delqry, "%s;\n",
13690                                           fmtId(tbinfo->dobj.name));
13691
13692         if (tginfo->tgdef)
13693         {
13694                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
13695         }
13696         else
13697         {
13698                 if (tginfo->tgisconstraint)
13699                 {
13700                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
13701                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
13702                 }
13703                 else
13704                 {
13705                         appendPQExpBuffer(query, "CREATE TRIGGER ");
13706                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
13707                 }
13708                 appendPQExpBuffer(query, "\n    ");
13709
13710                 /* Trigger type */
13711                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
13712                         appendPQExpBuffer(query, "BEFORE");
13713                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
13714                         appendPQExpBuffer(query, "AFTER");
13715                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
13716                         appendPQExpBuffer(query, "INSTEAD OF");
13717                 else
13718                 {
13719                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
13720                         exit_nicely();
13721                 }
13722
13723                 findx = 0;
13724                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
13725                 {
13726                         appendPQExpBuffer(query, " INSERT");
13727                         findx++;
13728                 }
13729                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
13730                 {
13731                         if (findx > 0)
13732                                 appendPQExpBuffer(query, " OR DELETE");
13733                         else
13734                                 appendPQExpBuffer(query, " DELETE");
13735                         findx++;
13736                 }
13737                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
13738                 {
13739                         if (findx > 0)
13740                                 appendPQExpBuffer(query, " OR UPDATE");
13741                         else
13742                                 appendPQExpBuffer(query, " UPDATE");
13743                         findx++;
13744                 }
13745                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
13746                 {
13747                         if (findx > 0)
13748                                 appendPQExpBuffer(query, " OR TRUNCATE");
13749                         else
13750                                 appendPQExpBuffer(query, " TRUNCATE");
13751                         findx++;
13752                 }
13753                 appendPQExpBuffer(query, " ON %s\n",
13754                                                   fmtId(tbinfo->dobj.name));
13755
13756                 if (tginfo->tgisconstraint)
13757                 {
13758                         if (OidIsValid(tginfo->tgconstrrelid))
13759                         {
13760                                 /* If we are using regclass, name is already quoted */
13761                                 if (fout->remoteVersion >= 70300)
13762                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13763                                                                           tginfo->tgconstrrelname);
13764                                 else
13765                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13766                                                                           fmtId(tginfo->tgconstrrelname));
13767                         }
13768                         if (!tginfo->tgdeferrable)
13769                                 appendPQExpBuffer(query, "NOT ");
13770                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
13771                         if (tginfo->tginitdeferred)
13772                                 appendPQExpBuffer(query, "DEFERRED\n");
13773                         else
13774                                 appendPQExpBuffer(query, "IMMEDIATE\n");
13775                 }
13776
13777                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
13778                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
13779                 else
13780                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
13781
13782                 /* In 7.3, result of regproc is already quoted */
13783                 if (fout->remoteVersion >= 70300)
13784                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13785                                                           tginfo->tgfname);
13786                 else
13787                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13788                                                           fmtId(tginfo->tgfname));
13789
13790                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
13791                                                                                   &lentgargs);
13792                 p = tgargs;
13793                 for (findx = 0; findx < tginfo->tgnargs; findx++)
13794                 {
13795                         /* find the embedded null that terminates this trigger argument */
13796                         size_t          tlen = strlen(p);
13797
13798                         if (p + tlen >= tgargs + lentgargs)
13799                         {
13800                                 /* hm, not found before end of bytea value... */
13801                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
13802                                                   tginfo->tgargs,
13803                                                   tginfo->dobj.name,
13804                                                   tbinfo->dobj.name);
13805                                 exit_nicely();
13806                         }
13807
13808                         if (findx > 0)
13809                                 appendPQExpBuffer(query, ", ");
13810                         appendStringLiteralAH(query, p, fout);
13811                         p += tlen + 1;
13812                 }
13813                 free(tgargs);
13814                 appendPQExpBuffer(query, ");\n");
13815         }
13816
13817         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
13818         {
13819                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
13820                                                   fmtId(tbinfo->dobj.name));
13821                 switch (tginfo->tgenabled)
13822                 {
13823                         case 'D':
13824                         case 'f':
13825                                 appendPQExpBuffer(query, "DISABLE");
13826                                 break;
13827                         case 'A':
13828                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
13829                                 break;
13830                         case 'R':
13831                                 appendPQExpBuffer(query, "ENABLE REPLICA");
13832                                 break;
13833                         default:
13834                                 appendPQExpBuffer(query, "ENABLE");
13835                                 break;
13836                 }
13837                 appendPQExpBuffer(query, " TRIGGER %s;\n",
13838                                                   fmtId(tginfo->dobj.name));
13839         }
13840
13841         appendPQExpBuffer(labelq, "TRIGGER %s ",
13842                                           fmtId(tginfo->dobj.name));
13843         appendPQExpBuffer(labelq, "ON %s",
13844                                           fmtId(tbinfo->dobj.name));
13845
13846         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
13847                                  tginfo->dobj.name,
13848                                  tbinfo->dobj.namespace->dobj.name,
13849                                  NULL,
13850                                  tbinfo->rolname, false,
13851                                  "TRIGGER", SECTION_POST_DATA,
13852                                  query->data, delqry->data, NULL,
13853                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
13854                                  NULL, NULL);
13855
13856         dumpComment(fout, labelq->data,
13857                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13858                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
13859
13860         destroyPQExpBuffer(query);
13861         destroyPQExpBuffer(delqry);
13862         destroyPQExpBuffer(labelq);
13863 }
13864
13865 /*
13866  * dumpRule
13867  *              Dump a rule
13868  */
13869 static void
13870 dumpRule(Archive *fout, RuleInfo *rinfo)
13871 {
13872         TableInfo  *tbinfo = rinfo->ruletable;
13873         PQExpBuffer query;
13874         PQExpBuffer cmd;
13875         PQExpBuffer delcmd;
13876         PQExpBuffer labelq;
13877         PGresult   *res;
13878
13879         /* Skip if not to be dumped */
13880         if (!rinfo->dobj.dump || dataOnly)
13881                 return;
13882
13883         /*
13884          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
13885          * we do not want to dump it as a separate object.
13886          */
13887         if (!rinfo->separate)
13888                 return;
13889
13890         /*
13891          * Make sure we are in proper schema.
13892          */
13893         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13894
13895         query = createPQExpBuffer();
13896         cmd = createPQExpBuffer();
13897         delcmd = createPQExpBuffer();
13898         labelq = createPQExpBuffer();
13899
13900         if (fout->remoteVersion >= 70300)
13901         {
13902                 appendPQExpBuffer(query,
13903                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
13904                                                   rinfo->dobj.catId.oid);
13905         }
13906         else
13907         {
13908                 /* Rule name was unique before 7.3 ... */
13909                 appendPQExpBuffer(query,
13910                                                   "SELECT pg_get_ruledef('%s') AS definition",
13911                                                   rinfo->dobj.name);
13912         }
13913
13914         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13915
13916         if (PQntuples(res) != 1)
13917         {
13918                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
13919                                   rinfo->dobj.name, tbinfo->dobj.name);
13920                 exit_nicely();
13921         }
13922
13923         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
13924
13925         /*
13926          * Add the command to alter the rules replication firing semantics if it
13927          * differs from the default.
13928          */
13929         if (rinfo->ev_enabled != 'O')
13930         {
13931                 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
13932                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13933                 appendPQExpBuffer(cmd, "%s ",
13934                                                   fmtId(tbinfo->dobj.name));
13935                 switch (rinfo->ev_enabled)
13936                 {
13937                         case 'A':
13938                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
13939                                                                   fmtId(rinfo->dobj.name));
13940                                 break;
13941                         case 'R':
13942                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
13943                                                                   fmtId(rinfo->dobj.name));
13944                                 break;
13945                         case 'D':
13946                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
13947                                                                   fmtId(rinfo->dobj.name));
13948                                 break;
13949                 }
13950         }
13951
13952         /*
13953          * DROP must be fully qualified in case same name appears in pg_catalog
13954          */
13955         appendPQExpBuffer(delcmd, "DROP RULE %s ",
13956                                           fmtId(rinfo->dobj.name));
13957         appendPQExpBuffer(delcmd, "ON %s.",
13958                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13959         appendPQExpBuffer(delcmd, "%s;\n",
13960                                           fmtId(tbinfo->dobj.name));
13961
13962         appendPQExpBuffer(labelq, "RULE %s",
13963                                           fmtId(rinfo->dobj.name));
13964         appendPQExpBuffer(labelq, " ON %s",
13965                                           fmtId(tbinfo->dobj.name));
13966
13967         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
13968                                  rinfo->dobj.name,
13969                                  tbinfo->dobj.namespace->dobj.name,
13970                                  NULL,
13971                                  tbinfo->rolname, false,
13972                                  "RULE", SECTION_POST_DATA,
13973                                  cmd->data, delcmd->data, NULL,
13974                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
13975                                  NULL, NULL);
13976
13977         /* Dump rule comments */
13978         dumpComment(fout, labelq->data,
13979                                 tbinfo->dobj.namespace->dobj.name,
13980                                 tbinfo->rolname,
13981                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
13982
13983         PQclear(res);
13984
13985         destroyPQExpBuffer(query);
13986         destroyPQExpBuffer(cmd);
13987         destroyPQExpBuffer(delcmd);
13988         destroyPQExpBuffer(labelq);
13989 }
13990
13991 /*
13992  * getExtensionMembership --- obtain extension membership data
13993  */
13994 void
13995 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
13996                                            int numExtensions)
13997 {
13998         PQExpBuffer query;
13999         PGresult   *res;
14000         int                     ntups,
14001                                 i;
14002         int                     i_classid,
14003                                 i_objid,
14004                                 i_refclassid,
14005                                 i_refobjid;
14006         DumpableObject *dobj,
14007                            *refdobj;
14008
14009         /* Nothing to do if no extensions */
14010         if (numExtensions == 0)
14011                 return;
14012
14013         /* Make sure we are in proper schema */
14014         selectSourceSchema(fout, "pg_catalog");
14015
14016         query = createPQExpBuffer();
14017
14018         /* refclassid constraint is redundant but may speed the search */
14019         appendPQExpBuffer(query, "SELECT "
14020                                           "classid, objid, refclassid, refobjid "
14021                                           "FROM pg_depend "
14022                                           "WHERE refclassid = 'pg_extension'::regclass "
14023                                           "AND deptype = 'e' "
14024                                           "ORDER BY 3,4");
14025
14026         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14027
14028         ntups = PQntuples(res);
14029
14030         i_classid = PQfnumber(res, "classid");
14031         i_objid = PQfnumber(res, "objid");
14032         i_refclassid = PQfnumber(res, "refclassid");
14033         i_refobjid = PQfnumber(res, "refobjid");
14034
14035         /*
14036          * Since we ordered the SELECT by referenced ID, we can expect that
14037          * multiple entries for the same extension will appear together; this
14038          * saves on searches.
14039          */
14040         refdobj = NULL;
14041
14042         for (i = 0; i < ntups; i++)
14043         {
14044                 CatalogId       objId;
14045                 CatalogId       refobjId;
14046
14047                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14048                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14049                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14050                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14051
14052                 if (refdobj == NULL ||
14053                         refdobj->catId.tableoid != refobjId.tableoid ||
14054                         refdobj->catId.oid != refobjId.oid)
14055                         refdobj = findObjectByCatalogId(refobjId);
14056
14057                 /*
14058                  * Failure to find objects mentioned in pg_depend is not unexpected,
14059                  * since for example we don't collect info about TOAST tables.
14060                  */
14061                 if (refdobj == NULL)
14062                 {
14063 #ifdef NOT_USED
14064                         fprintf(stderr, "no referenced object %u %u\n",
14065                                         refobjId.tableoid, refobjId.oid);
14066 #endif
14067                         continue;
14068                 }
14069
14070                 dobj = findObjectByCatalogId(objId);
14071
14072                 if (dobj == NULL)
14073                 {
14074 #ifdef NOT_USED
14075                         fprintf(stderr, "no referencing object %u %u\n",
14076                                         objId.tableoid, objId.oid);
14077 #endif
14078                         continue;
14079                 }
14080
14081                 /* Record dependency so that getDependencies needn't repeat this */
14082                 addObjectDependency(dobj, refdobj->dumpId);
14083
14084                 dobj->ext_member = true;
14085
14086                 /*
14087                  * Normally, mark the member object as not to be dumped.  But in
14088                  * binary upgrades, we still dump the members individually, since the
14089                  * idea is to exactly reproduce the database contents rather than
14090                  * replace the extension contents with something different.
14091                  */
14092                 if (!binary_upgrade)
14093                         dobj->dump = false;
14094                 else
14095                         dobj->dump = refdobj->dump;
14096         }
14097
14098         PQclear(res);
14099
14100         /*
14101          * Now identify extension configuration tables and create TableDataInfo
14102          * objects for them, ensuring their data will be dumped even though the
14103          * tables themselves won't be.
14104          *
14105          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14106          * user data in a configuration table is treated like schema data. This
14107          * seems appropriate since system data in a config table would get
14108          * reloaded by CREATE EXTENSION.
14109          */
14110         for (i = 0; i < numExtensions; i++)
14111         {
14112                 char       *extconfig = extinfo[i].extconfig;
14113                 char       *extcondition = extinfo[i].extcondition;
14114                 char      **extconfigarray = NULL;
14115                 char      **extconditionarray = NULL;
14116                 int                     nconfigitems;
14117                 int                     nconditionitems;
14118
14119                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14120                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14121                         nconfigitems == nconditionitems)
14122                 {
14123                         int                     j;
14124
14125                         for (j = 0; j < nconfigitems; j++)
14126                         {
14127                                 TableInfo  *configtbl;
14128
14129                                 configtbl = findTableByOid(atooid(extconfigarray[j]));
14130                                 if (configtbl && configtbl->dataObj == NULL)
14131                                 {
14132                                         /*
14133                                          * Note: config tables are dumped without OIDs regardless
14134                                          * of the --oids setting.  This is because row filtering
14135                                          * conditions aren't compatible with dumping OIDs.
14136                                          */
14137                                         makeTableDataInfo(configtbl, false);
14138                                         if (strlen(extconditionarray[j]) > 0)
14139                                                 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14140                                 }
14141                         }
14142                 }
14143                 if (extconfigarray)
14144                         free(extconfigarray);
14145                 if (extconditionarray)
14146                         free(extconditionarray);
14147         }
14148
14149         destroyPQExpBuffer(query);
14150 }
14151
14152 /*
14153  * getDependencies --- obtain available dependency data
14154  */
14155 static void
14156 getDependencies(Archive *fout)
14157 {
14158         PQExpBuffer query;
14159         PGresult   *res;
14160         int                     ntups,
14161                                 i;
14162         int                     i_classid,
14163                                 i_objid,
14164                                 i_refclassid,
14165                                 i_refobjid,
14166                                 i_deptype;
14167         DumpableObject *dobj,
14168                            *refdobj;
14169
14170         /* No dependency info available before 7.3 */
14171         if (fout->remoteVersion < 70300)
14172                 return;
14173
14174         if (g_verbose)
14175                 write_msg(NULL, "reading dependency data\n");
14176
14177         /* Make sure we are in proper schema */
14178         selectSourceSchema(fout, "pg_catalog");
14179
14180         query = createPQExpBuffer();
14181
14182         /*
14183          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14184          * already processed by getExtensionMembership.
14185          */
14186         appendPQExpBuffer(query, "SELECT "
14187                                           "classid, objid, refclassid, refobjid, deptype "
14188                                           "FROM pg_depend "
14189                                           "WHERE deptype != 'p' AND deptype != 'e' "
14190                                           "ORDER BY 1,2");
14191
14192         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14193
14194         ntups = PQntuples(res);
14195
14196         i_classid = PQfnumber(res, "classid");
14197         i_objid = PQfnumber(res, "objid");
14198         i_refclassid = PQfnumber(res, "refclassid");
14199         i_refobjid = PQfnumber(res, "refobjid");
14200         i_deptype = PQfnumber(res, "deptype");
14201
14202         /*
14203          * Since we ordered the SELECT by referencing ID, we can expect that
14204          * multiple entries for the same object will appear together; this saves
14205          * on searches.
14206          */
14207         dobj = NULL;
14208
14209         for (i = 0; i < ntups; i++)
14210         {
14211                 CatalogId       objId;
14212                 CatalogId       refobjId;
14213                 char            deptype;
14214
14215                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14216                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14217                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14218                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14219                 deptype = *(PQgetvalue(res, i, i_deptype));
14220
14221                 if (dobj == NULL ||
14222                         dobj->catId.tableoid != objId.tableoid ||
14223                         dobj->catId.oid != objId.oid)
14224                         dobj = findObjectByCatalogId(objId);
14225
14226                 /*
14227                  * Failure to find objects mentioned in pg_depend is not unexpected,
14228                  * since for example we don't collect info about TOAST tables.
14229                  */
14230                 if (dobj == NULL)
14231                 {
14232 #ifdef NOT_USED
14233                         fprintf(stderr, "no referencing object %u %u\n",
14234                                         objId.tableoid, objId.oid);
14235 #endif
14236                         continue;
14237                 }
14238
14239                 refdobj = findObjectByCatalogId(refobjId);
14240
14241                 if (refdobj == NULL)
14242                 {
14243 #ifdef NOT_USED
14244                         fprintf(stderr, "no referenced object %u %u\n",
14245                                         refobjId.tableoid, refobjId.oid);
14246 #endif
14247                         continue;
14248                 }
14249
14250                 /*
14251                  * Ordinarily, table rowtypes have implicit dependencies on their
14252                  * tables.      However, for a composite type the implicit dependency goes
14253                  * the other way in pg_depend; which is the right thing for DROP but
14254                  * it doesn't produce the dependency ordering we need. So in that one
14255                  * case, we reverse the direction of the dependency.
14256                  */
14257                 if (deptype == 'i' &&
14258                         dobj->objType == DO_TABLE &&
14259                         refdobj->objType == DO_TYPE)
14260                         addObjectDependency(refdobj, dobj->dumpId);
14261                 else
14262                         /* normal case */
14263                         addObjectDependency(dobj, refdobj->dumpId);
14264         }
14265
14266         PQclear(res);
14267
14268         destroyPQExpBuffer(query);
14269 }
14270
14271
14272 /*
14273  * selectSourceSchema - make the specified schema the active search path
14274  * in the source database.
14275  *
14276  * NB: pg_catalog is explicitly searched after the specified schema;
14277  * so user names are only qualified if they are cross-schema references,
14278  * and system names are only qualified if they conflict with a user name
14279  * in the current schema.
14280  *
14281  * Whenever the selected schema is not pg_catalog, be careful to qualify
14282  * references to system catalogs and types in our emitted commands!
14283  */
14284 static void
14285 selectSourceSchema(Archive *fout, const char *schemaName)
14286 {
14287         static char *curSchemaName = NULL;
14288         PQExpBuffer query;
14289
14290         /* Not relevant if fetching from pre-7.3 DB */
14291         if (fout->remoteVersion < 70300)
14292                 return;
14293         /* Ignore null schema names */
14294         if (schemaName == NULL || *schemaName == '\0')
14295                 return;
14296         /* Optimize away repeated selection of same schema */
14297         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
14298                 return;
14299
14300         query = createPQExpBuffer();
14301         appendPQExpBuffer(query, "SET search_path = %s",
14302                                           fmtId(schemaName));
14303         if (strcmp(schemaName, "pg_catalog") != 0)
14304                 appendPQExpBuffer(query, ", pg_catalog");
14305
14306         ExecuteSqlStatement(fout, query->data);
14307
14308         destroyPQExpBuffer(query);
14309         if (curSchemaName)
14310                 free(curSchemaName);
14311         curSchemaName = pg_strdup(schemaName);
14312 }
14313
14314 /*
14315  * getFormattedTypeName - retrieve a nicely-formatted type name for the
14316  * given type name.
14317  *
14318  * NB: in 7.3 and up the result may depend on the currently-selected
14319  * schema; this is why we don't try to cache the names.
14320  */
14321 static char *
14322 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
14323 {
14324         char       *result;
14325         PQExpBuffer query;
14326         PGresult   *res;
14327         int                     ntups;
14328
14329         if (oid == 0)
14330         {
14331                 if ((opts & zeroAsOpaque) != 0)
14332                         return pg_strdup(g_opaque_type);
14333                 else if ((opts & zeroAsAny) != 0)
14334                         return pg_strdup("'any'");
14335                 else if ((opts & zeroAsStar) != 0)
14336                         return pg_strdup("*");
14337                 else if ((opts & zeroAsNone) != 0)
14338                         return pg_strdup("NONE");
14339         }
14340
14341         query = createPQExpBuffer();
14342         if (fout->remoteVersion >= 70300)
14343         {
14344                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
14345                                                   oid);
14346         }
14347         else if (fout->remoteVersion >= 70100)
14348         {
14349                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
14350                                                   oid);
14351         }
14352         else
14353         {
14354                 appendPQExpBuffer(query, "SELECT typname "
14355                                                   "FROM pg_type "
14356                                                   "WHERE oid = '%u'::oid",
14357                                                   oid);
14358         }
14359
14360         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14361
14362         /* Expecting a single result only */
14363         ntups = PQntuples(res);
14364         if (ntups != 1)
14365         {
14366                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
14367                                                            "query returned %d rows instead of one: %s\n",
14368                                                                  ntups),
14369                                   ntups, query->data);
14370                 exit_nicely();
14371         }
14372
14373         if (fout->remoteVersion >= 70100)
14374         {
14375                 /* already quoted */
14376                 result = pg_strdup(PQgetvalue(res, 0, 0));
14377         }
14378         else
14379         {
14380                 /* may need to quote it */
14381                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
14382         }
14383
14384         PQclear(res);
14385         destroyPQExpBuffer(query);
14386
14387         return result;
14388 }
14389
14390 /*
14391  * myFormatType --- local implementation of format_type for use with 7.0.
14392  */
14393 static char *
14394 myFormatType(const char *typname, int32 typmod)
14395 {
14396         char       *result;
14397         bool            isarray = false;
14398         PQExpBuffer buf = createPQExpBuffer();
14399
14400         /* Handle array types */
14401         if (typname[0] == '_')
14402         {
14403                 isarray = true;
14404                 typname++;
14405         }
14406
14407         /* Show lengths on bpchar and varchar */
14408         if (strcmp(typname, "bpchar") == 0)
14409         {
14410                 int                     len = (typmod - VARHDRSZ);
14411
14412                 appendPQExpBuffer(buf, "character");
14413                 if (len > 1)
14414                         appendPQExpBuffer(buf, "(%d)",
14415                                                           typmod - VARHDRSZ);
14416         }
14417         else if (strcmp(typname, "varchar") == 0)
14418         {
14419                 appendPQExpBuffer(buf, "character varying");
14420                 if (typmod != -1)
14421                         appendPQExpBuffer(buf, "(%d)",
14422                                                           typmod - VARHDRSZ);
14423         }
14424         else if (strcmp(typname, "numeric") == 0)
14425         {
14426                 appendPQExpBuffer(buf, "numeric");
14427                 if (typmod != -1)
14428                 {
14429                         int32           tmp_typmod;
14430                         int                     precision;
14431                         int                     scale;
14432
14433                         tmp_typmod = typmod - VARHDRSZ;
14434                         precision = (tmp_typmod >> 16) & 0xffff;
14435                         scale = tmp_typmod & 0xffff;
14436                         appendPQExpBuffer(buf, "(%d,%d)",
14437                                                           precision, scale);
14438                 }
14439         }
14440
14441         /*
14442          * char is an internal single-byte data type; Let's make sure we force it
14443          * through with quotes. - thomas 1998-12-13
14444          */
14445         else if (strcmp(typname, "char") == 0)
14446                 appendPQExpBuffer(buf, "\"char\"");
14447         else
14448                 appendPQExpBuffer(buf, "%s", fmtId(typname));
14449
14450         /* Append array qualifier for array types */
14451         if (isarray)
14452                 appendPQExpBuffer(buf, "[]");
14453
14454         result = pg_strdup(buf->data);
14455         destroyPQExpBuffer(buf);
14456
14457         return result;
14458 }
14459
14460 /*
14461  * fmtQualifiedId - convert a qualified name to the proper format for
14462  * the source database.
14463  *
14464  * Like fmtId, use the result before calling again.
14465  */
14466 static const char *
14467 fmtQualifiedId(Archive *fout, const char *schema, const char *id)
14468 {
14469         static PQExpBuffer id_return = NULL;
14470
14471         if (id_return)                          /* first time through? */
14472                 resetPQExpBuffer(id_return);
14473         else
14474                 id_return = createPQExpBuffer();
14475
14476         /* Suppress schema name if fetching from pre-7.3 DB */
14477         if (fout->remoteVersion >= 70300 && schema && *schema)
14478         {
14479                 appendPQExpBuffer(id_return, "%s.",
14480                                                   fmtId(schema));
14481         }
14482         appendPQExpBuffer(id_return, "%s",
14483                                           fmtId(id));
14484
14485         return id_return->data;
14486 }
14487
14488 /*
14489  * Return a column list clause for the given relation.
14490  *
14491  * Special case: if there are no undropped columns in the relation, return
14492  * "", not an invalid "()" column list.
14493  */
14494 static const char *
14495 fmtCopyColumnList(const TableInfo *ti)
14496 {
14497         static PQExpBuffer q = NULL;
14498         int                     numatts = ti->numatts;
14499         char      **attnames = ti->attnames;
14500         bool       *attisdropped = ti->attisdropped;
14501         bool            needComma;
14502         int                     i;
14503
14504         if (q)                                          /* first time through? */
14505                 resetPQExpBuffer(q);
14506         else
14507                 q = createPQExpBuffer();
14508
14509         appendPQExpBuffer(q, "(");
14510         needComma = false;
14511         for (i = 0; i < numatts; i++)
14512         {
14513                 if (attisdropped[i])
14514                         continue;
14515                 if (needComma)
14516                         appendPQExpBuffer(q, ", ");
14517                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
14518                 needComma = true;
14519         }
14520
14521         if (!needComma)
14522                 return "";                              /* no undropped columns */
14523
14524         appendPQExpBuffer(q, ")");
14525         return q->data;
14526 }