]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Create a "sort support" interface API for faster sorting.
[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-2011, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to run on
18  *      SnapshotNow time, ie they look at the currently committed state.  So
19  *      it is possible to get 'cache lookup failed' error if someone
20  *      performs DDL changes while a dump is happening. The window for this
21  *      sort of thing is from the acquisition of the transaction snapshot to
22  *      getSchemaData() (when pg_dump acquires AccessShareLock on every
23  *      table it intends to dump). It isn't very large, but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32
33 #include "postgres_fe.h"
34
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef ENABLE_NLS
38 #include <locale.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h>
42 #endif
43
44 #include "getopt_long.h"
45
46 #include "access/attnum.h"
47 #include "access/sysattr.h"
48 #include "access/transam.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_largeobject.h"
53 #include "catalog/pg_largeobject_metadata.h"
54 #include "catalog/pg_proc.h"
55 #include "catalog/pg_trigger.h"
56 #include "catalog/pg_type.h"
57 #include "libpq/libpq-fs.h"
58
59 #include "pg_backup_archiver.h"
60 #include "dumpmem.h"
61 #include "dumputils.h"
62
63 extern char *optarg;
64 extern int      optind,
65                         opterr;
66
67
68 typedef struct
69 {
70         const char *descr;                      /* comment for an object */
71         Oid                     classoid;               /* object class (catalog OID) */
72         Oid                     objoid;                 /* object OID */
73         int                     objsubid;               /* subobject (table column #) */
74 } CommentItem;
75
76 typedef struct
77 {
78         const char *provider;           /* label provider of this security label */
79         const char *label;                      /* security label for an object */
80         Oid                     classoid;               /* object class (catalog OID) */
81         Oid                     objoid;                 /* object OID */
82         int                     objsubid;               /* subobject (table column #) */
83 } SecLabelItem;
84
85 /* global decls */
86 bool            g_verbose;                      /* User wants verbose narration of our
87                                                                  * activities. */
88 Archive    *g_fout;                             /* the script file */
89 PGconn     *g_conn;                             /* the database connection */
90
91 /* various user-settable parameters */
92 bool            schemaOnly;
93 bool            dataOnly;
94 bool            aclsSkip;
95 const char *lockWaitTimeout;
96
97 /* subquery used to convert user ID (eg, datdba) to user name */
98 static const char *username_subquery;
99
100 /* obsolete as of 7.3: */
101 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
102
103 /*
104  * Object inclusion/exclusion lists
105  *
106  * The string lists record the patterns given by command-line switches,
107  * which we then convert to lists of OIDs of matching objects.
108  */
109 static SimpleStringList schema_include_patterns = {NULL, NULL};
110 static SimpleOidList schema_include_oids = {NULL, NULL};
111 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
112 static SimpleOidList schema_exclude_oids = {NULL, NULL};
113
114 static SimpleStringList table_include_patterns = {NULL, NULL};
115 static SimpleOidList table_include_oids = {NULL, NULL};
116 static SimpleStringList table_exclude_patterns = {NULL, NULL};
117 static SimpleOidList table_exclude_oids = {NULL, NULL};
118
119 /* default, if no "inclusion" switches appear, is to dump everything */
120 static bool include_everything = true;
121
122 char            g_opaque_type[10];      /* name for the opaque type */
123
124 /* placeholders for the delimiters for comments */
125 char            g_comment_start[10];
126 char            g_comment_end[10];
127
128 static const CatalogId nilCatalogId = {0, 0};
129
130 /* these are to avoid passing around info for findNamespace() */
131 static NamespaceInfo *g_namespaces;
132 static int      g_numNamespaces;
133
134 /* flags for various command-line long options */
135 static int      binary_upgrade = 0;
136 static int      disable_dollar_quoting = 0;
137 static int      dump_inserts = 0;
138 static int      column_inserts = 0;
139 static int      no_security_labels = 0;
140 static int      no_unlogged_table_data = 0;
141 static int      serializable_deferrable = 0;
142
143
144 static void help(const char *progname);
145 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
146 static void expand_schema_name_patterns(SimpleStringList *patterns,
147                                                         SimpleOidList *oids);
148 static void expand_table_name_patterns(SimpleStringList *patterns,
149                                                    SimpleOidList *oids);
150 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
151 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
152 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
153 static void dumpComment(Archive *fout, const char *target,
154                         const char *namespace, const char *owner,
155                         CatalogId catalogId, int subid, DumpId dumpId);
156 static int findComments(Archive *fout, Oid classoid, Oid objoid,
157                          CommentItem **items);
158 static int      collectComments(Archive *fout, CommentItem **items);
159 static void dumpSecLabel(Archive *fout, const char *target,
160                          const char *namespace, const char *owner,
161                          CatalogId catalogId, int subid, DumpId dumpId);
162 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
163                           SecLabelItem **items);
164 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
165 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
166 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
167 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
168 static void dumpType(Archive *fout, TypeInfo *tyinfo);
169 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
170 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
171 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
172 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
173 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
174 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
175 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
176 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
177 static void dumpFunc(Archive *fout, FuncInfo *finfo);
178 static void dumpCast(Archive *fout, CastInfo *cast);
179 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
180 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
181 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
182 static void dumpCollation(Archive *fout, CollInfo *convinfo);
183 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
184 static void dumpRule(Archive *fout, RuleInfo *rinfo);
185 static void dumpAgg(Archive *fout, AggInfo *agginfo);
186 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
187 static void dumpTable(Archive *fout, TableInfo *tbinfo);
188 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
189 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
190 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
191 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
192 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
193 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
194 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
195 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
196 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
197 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
198 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
199 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
200 static void dumpUserMappings(Archive *fout,
201                                  const char *servername, const char *namespace,
202                                  const char *owner, CatalogId catalogId, DumpId dumpId);
203 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
204
205 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
206                 const char *type, const char *name, const char *subname,
207                 const char *tag, const char *nspname, const char *owner,
208                 const char *acls);
209
210 static void getDependencies(void);
211 static void getDomainConstraints(TypeInfo *tyinfo);
212 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
213 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
214 static void getTableDataFKConstraints(void);
215 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
216 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
217                                                           char **allargtypes,
218                                                           char **argmodes,
219                                                           char **argnames);
220 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
221 static const char *convertRegProcReference(const char *proc);
222 static const char *convertOperatorReference(const char *opr);
223 static const char *convertTSFunction(Oid funcOid);
224 static Oid      findLastBuiltinOid_V71(const char *);
225 static Oid      findLastBuiltinOid_V70(void);
226 static void selectSourceSchema(const char *schemaName);
227 static char *getFormattedTypeName(Oid oid, OidOptions opts);
228 static char *myFormatType(const char *typname, int32 typmod);
229 static const char *fmtQualifiedId(const char *schema, const char *id);
230 static void getBlobs(Archive *AH);
231 static void dumpBlob(Archive *AH, BlobInfo *binfo);
232 static int      dumpBlobs(Archive *AH, void *arg);
233 static void dumpDatabase(Archive *AH);
234 static void dumpEncoding(Archive *AH);
235 static void dumpStdStrings(Archive *AH);
236 static void binary_upgrade_set_type_oids_by_type_oid(
237                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
238 static bool binary_upgrade_set_type_oids_by_rel_oid(
239                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
240 static void binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer,
241                                                                  Oid pg_class_oid, bool is_index);
242 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
243                                                                 DumpableObject *dobj,
244                                                                 const char *objlabel);
245 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
246 static const char *fmtCopyColumnList(const TableInfo *ti);
247 static void do_sql_command(PGconn *conn, const char *query);
248 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
249                                  ExecStatusType expected);
250
251
252 int
253 main(int argc, char **argv)
254 {
255         int                     c;
256         const char *filename = NULL;
257         const char *format = "p";
258         const char *dbname = NULL;
259         const char *pghost = NULL;
260         const char *pgport = NULL;
261         const char *username = NULL;
262         const char *dumpencoding = NULL;
263         const char *std_strings;
264         bool            oids = false;
265         TableInfo  *tblinfo;
266         int                     numTables;
267         DumpableObject **dobjs;
268         int                     numObjs;
269         int                     i;
270         enum trivalue prompt_password = TRI_DEFAULT;
271         int                     compressLevel = -1;
272         int                     plainText = 0;
273         int                     outputClean = 0;
274         int                     outputCreateDB = 0;
275         bool            outputBlobs = false;
276         int                     outputNoOwner = 0;
277         char       *outputSuperuser = NULL;
278         char       *use_role = NULL;
279         int                     my_version;
280         int                     optindex;
281         RestoreOptions *ropt;
282         ArchiveFormat archiveFormat = archUnknown;
283         ArchiveMode archiveMode;
284
285         static int      disable_triggers = 0;
286         static int      outputNoTablespaces = 0;
287         static int      use_setsessauth = 0;
288
289         static struct option long_options[] = {
290                 {"data-only", no_argument, NULL, 'a'},
291                 {"blobs", no_argument, NULL, 'b'},
292                 {"clean", no_argument, NULL, 'c'},
293                 {"create", no_argument, NULL, 'C'},
294                 {"file", required_argument, NULL, 'f'},
295                 {"format", required_argument, NULL, 'F'},
296                 {"host", required_argument, NULL, 'h'},
297                 {"ignore-version", no_argument, NULL, 'i'},
298                 {"no-reconnect", no_argument, NULL, 'R'},
299                 {"oids", no_argument, NULL, 'o'},
300                 {"no-owner", no_argument, NULL, 'O'},
301                 {"port", required_argument, NULL, 'p'},
302                 {"schema", required_argument, NULL, 'n'},
303                 {"exclude-schema", required_argument, NULL, 'N'},
304                 {"schema-only", no_argument, NULL, 's'},
305                 {"superuser", required_argument, NULL, 'S'},
306                 {"table", required_argument, NULL, 't'},
307                 {"exclude-table", required_argument, NULL, 'T'},
308                 {"no-password", no_argument, NULL, 'w'},
309                 {"password", no_argument, NULL, 'W'},
310                 {"username", required_argument, NULL, 'U'},
311                 {"verbose", no_argument, NULL, 'v'},
312                 {"no-privileges", no_argument, NULL, 'x'},
313                 {"no-acl", no_argument, NULL, 'x'},
314                 {"compress", required_argument, NULL, 'Z'},
315                 {"encoding", required_argument, NULL, 'E'},
316                 {"help", no_argument, NULL, '?'},
317                 {"version", no_argument, NULL, 'V'},
318
319                 /*
320                  * the following options don't have an equivalent short option letter
321                  */
322                 {"attribute-inserts", no_argument, &column_inserts, 1},
323                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
324                 {"column-inserts", no_argument, &column_inserts, 1},
325                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
326                 {"disable-triggers", no_argument, &disable_triggers, 1},
327                 {"inserts", no_argument, &dump_inserts, 1},
328                 {"lock-wait-timeout", required_argument, NULL, 2},
329                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
330                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
331                 {"role", required_argument, NULL, 3},
332                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
333                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
334                 {"no-security-labels", no_argument, &no_security_labels, 1},
335                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
336
337                 {NULL, 0, NULL, 0}
338         };
339
340         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
341
342         g_verbose = false;
343
344         strcpy(g_comment_start, "-- ");
345         g_comment_end[0] = '\0';
346         strcpy(g_opaque_type, "opaque");
347
348         dataOnly = schemaOnly = false;
349         lockWaitTimeout = NULL;
350
351         progname = get_progname(argv[0]);
352
353         /* Set default options based on progname */
354         if (strcmp(progname, "pg_backup") == 0)
355                 format = "c";
356
357         if (argc > 1)
358         {
359                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
360                 {
361                         help(progname);
362                         exit(0);
363                 }
364                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
365                 {
366                         puts("pg_dump (PostgreSQL) " PG_VERSION);
367                         exit(0);
368                 }
369         }
370
371         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxZ:",
372                                                         long_options, &optindex)) != -1)
373         {
374                 switch (c)
375                 {
376                         case 'a':                       /* Dump data only */
377                                 dataOnly = true;
378                                 break;
379
380                         case 'b':                       /* Dump blobs */
381                                 outputBlobs = true;
382                                 break;
383
384                         case 'c':                       /* clean (i.e., drop) schema prior to create */
385                                 outputClean = 1;
386                                 break;
387
388                         case 'C':                       /* Create DB */
389                                 outputCreateDB = 1;
390                                 break;
391
392                         case 'E':                       /* Dump encoding */
393                                 dumpencoding = optarg;
394                                 break;
395
396                         case 'f':
397                                 filename = optarg;
398                                 break;
399
400                         case 'F':
401                                 format = optarg;
402                                 break;
403
404                         case 'h':                       /* server host */
405                                 pghost = optarg;
406                                 break;
407
408                         case 'i':
409                                 /* ignored, deprecated option */
410                                 break;
411
412                         case 'n':                       /* include schema(s) */
413                                 simple_string_list_append(&schema_include_patterns, optarg);
414                                 include_everything = false;
415                                 break;
416
417                         case 'N':                       /* exclude schema(s) */
418                                 simple_string_list_append(&schema_exclude_patterns, optarg);
419                                 break;
420
421                         case 'o':                       /* Dump oids */
422                                 oids = true;
423                                 break;
424
425                         case 'O':                       /* Don't reconnect to match owner */
426                                 outputNoOwner = 1;
427                                 break;
428
429                         case 'p':                       /* server port */
430                                 pgport = optarg;
431                                 break;
432
433                         case 'R':
434                                 /* no-op, still accepted for backwards compatibility */
435                                 break;
436
437                         case 's':                       /* dump schema only */
438                                 schemaOnly = true;
439                                 break;
440
441                         case 'S':                       /* Username for superuser in plain text output */
442                                 outputSuperuser = pg_strdup(optarg);
443                                 break;
444
445                         case 't':                       /* include table(s) */
446                                 simple_string_list_append(&table_include_patterns, optarg);
447                                 include_everything = false;
448                                 break;
449
450                         case 'T':                       /* exclude table(s) */
451                                 simple_string_list_append(&table_exclude_patterns, optarg);
452                                 break;
453
454                         case 'U':
455                                 username = optarg;
456                                 break;
457
458                         case 'v':                       /* verbose */
459                                 g_verbose = true;
460                                 break;
461
462                         case 'w':
463                                 prompt_password = TRI_NO;
464                                 break;
465
466                         case 'W':
467                                 prompt_password = TRI_YES;
468                                 break;
469
470                         case 'x':                       /* skip ACL dump */
471                                 aclsSkip = true;
472                                 break;
473
474                         case 'Z':                       /* Compression Level */
475                                 compressLevel = atoi(optarg);
476                                 break;
477
478                         case 0:
479                                 /* This covers the long options. */
480                                 break;
481
482                         case 2:                         /* lock-wait-timeout */
483                                 lockWaitTimeout = optarg;
484                                 break;
485
486                         case 3:                         /* SET ROLE */
487                                 use_role = optarg;
488                                 break;
489
490                         default:
491                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
492                                 exit(1);
493                 }
494         }
495
496         /* Get database name from command line */
497         if (optind < argc)
498                 dbname = argv[optind++];
499
500         /* Complain if any arguments remain */
501         if (optind < argc)
502         {
503                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
504                                 progname, argv[optind]);
505                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
506                                 progname);
507                 exit(1);
508         }
509
510         /* --column-inserts implies --inserts */
511         if (column_inserts)
512                 dump_inserts = 1;
513
514         if (dataOnly && schemaOnly)
515         {
516                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
517                 exit(1);
518         }
519
520         if (dataOnly && outputClean)
521         {
522                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
523                 exit(1);
524         }
525
526         if (dump_inserts && oids)
527         {
528                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
529                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
530                 exit(1);
531         }
532
533         /* Identify archive format to emit */
534         archiveFormat = parseArchiveFormat(format, &archiveMode);
535
536         /* archiveFormat specific setup */
537         if (archiveFormat == archNull)
538                 plainText = 1;
539
540         /* Custom and directory formats are compressed by default, others not */
541         if (compressLevel == -1)
542         {
543                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
544                         compressLevel = Z_DEFAULT_COMPRESSION;
545                 else
546                         compressLevel = 0;
547         }
548
549         /* Open the output file */
550         g_fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode);
551
552         if (g_fout == NULL)
553         {
554                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
555                 exit(1);
556         }
557
558         /* Let the archiver know how noisy to be */
559         g_fout->verbose = g_verbose;
560
561         my_version = parse_version(PG_VERSION);
562         if (my_version < 0)
563         {
564                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
565                 exit(1);
566         }
567
568         /*
569          * We allow the server to be back to 7.0, and up to any minor release of
570          * our own major version.  (See also version check in pg_dumpall.c.)
571          */
572         g_fout->minRemoteVersion = 70000;
573         g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
574
575         /*
576          * Open the database using the Archiver, so it knows about it. Errors mean
577          * death.
578          */
579         g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
580                                                          username, prompt_password);
581
582         /* Set the client encoding if requested */
583         if (dumpencoding)
584         {
585                 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
586                 {
587                         write_msg(NULL, "invalid client encoding \"%s\" specified\n",
588                                           dumpencoding);
589                         exit(1);
590                 }
591         }
592
593         /*
594          * Get the active encoding and the standard_conforming_strings setting, so
595          * we know how to escape strings.
596          */
597         g_fout->encoding = PQclientEncoding(g_conn);
598
599         std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
600         g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
601
602         /* Set the role if requested */
603         if (use_role && g_fout->remoteVersion >= 80100)
604         {
605                 PQExpBuffer query = createPQExpBuffer();
606
607                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
608                 do_sql_command(g_conn, query->data);
609                 destroyPQExpBuffer(query);
610         }
611
612         /* Set the datestyle to ISO to ensure the dump's portability */
613         do_sql_command(g_conn, "SET DATESTYLE = ISO");
614
615         /* Likewise, avoid using sql_standard intervalstyle */
616         if (g_fout->remoteVersion >= 80400)
617                 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
618
619         /*
620          * If supported, set extra_float_digits so that we can dump float data
621          * exactly (given correctly implemented float I/O code, anyway)
622          */
623         if (g_fout->remoteVersion >= 90000)
624                 do_sql_command(g_conn, "SET extra_float_digits TO 3");
625         else if (g_fout->remoteVersion >= 70400)
626                 do_sql_command(g_conn, "SET extra_float_digits TO 2");
627
628         /*
629          * If synchronized scanning is supported, disable it, to prevent
630          * unpredictable changes in row ordering across a dump and reload.
631          */
632         if (g_fout->remoteVersion >= 80300)
633                 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
634
635         /*
636          * Disable timeouts if supported.
637          */
638         if (g_fout->remoteVersion >= 70300)
639                 do_sql_command(g_conn, "SET statement_timeout = 0");
640
641         /*
642          * Quote all identifiers, if requested.
643          */
644         if (quote_all_identifiers && g_fout->remoteVersion >= 90100)
645                 do_sql_command(g_conn, "SET quote_all_identifiers = true");
646
647         /*
648          * Disable security label support if server version < v9.1.x (prevents
649          * access to nonexistent pg_seclabel catalog)
650          */
651         if (g_fout->remoteVersion < 90100)
652                 no_security_labels = 1;
653
654         /*
655          * Start transaction-snapshot mode transaction to dump consistent data.
656          */
657         do_sql_command(g_conn, "BEGIN");
658         if (g_fout->remoteVersion >= 90100)
659         {
660                 if (serializable_deferrable)
661                         do_sql_command(g_conn,
662                                                    "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, "
663                                                    "READ ONLY, DEFERRABLE");
664                 else
665                         do_sql_command(g_conn,
666                                                    "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ");
667         }
668         else
669                 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
670
671         /* Select the appropriate subquery to convert user IDs to names */
672         if (g_fout->remoteVersion >= 80100)
673                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
674         else if (g_fout->remoteVersion >= 70300)
675                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
676         else
677                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
678
679         /* Find the last built-in OID, if needed */
680         if (g_fout->remoteVersion < 70300)
681         {
682                 if (g_fout->remoteVersion >= 70100)
683                         g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
684                 else
685                         g_last_builtin_oid = findLastBuiltinOid_V70();
686                 if (g_verbose)
687                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
688         }
689
690         /* Expand schema selection patterns into OID lists */
691         if (schema_include_patterns.head != NULL)
692         {
693                 expand_schema_name_patterns(&schema_include_patterns,
694                                                                         &schema_include_oids);
695                 if (schema_include_oids.head == NULL)
696                 {
697                         write_msg(NULL, "No matching schemas were found\n");
698                         exit_nicely();
699                 }
700         }
701         expand_schema_name_patterns(&schema_exclude_patterns,
702                                                                 &schema_exclude_oids);
703         /* non-matching exclusion patterns aren't an error */
704
705         /* Expand table selection patterns into OID lists */
706         if (table_include_patterns.head != NULL)
707         {
708                 expand_table_name_patterns(&table_include_patterns,
709                                                                    &table_include_oids);
710                 if (table_include_oids.head == NULL)
711                 {
712                         write_msg(NULL, "No matching tables were found\n");
713                         exit_nicely();
714                 }
715         }
716         expand_table_name_patterns(&table_exclude_patterns,
717                                                            &table_exclude_oids);
718         /* non-matching exclusion patterns aren't an error */
719
720         /*
721          * Dumping blobs is now default unless we saw an inclusion switch or -s
722          * ... but even if we did see one of these, -b turns it back on.
723          */
724         if (include_everything && !schemaOnly)
725                 outputBlobs = true;
726
727         /*
728          * Now scan the database and create DumpableObject structs for all the
729          * objects we intend to dump.
730          */
731         tblinfo = getSchemaData(&numTables);
732
733         if (g_fout->remoteVersion < 80400)
734                 guessConstraintInheritance(tblinfo, numTables);
735
736         if (!schemaOnly)
737         {
738                 getTableData(tblinfo, numTables, oids);
739                 if (dataOnly)
740                         getTableDataFKConstraints();
741         }
742
743         if (outputBlobs)
744                 getBlobs(g_fout);
745
746         /*
747          * Collect dependency data to assist in ordering the objects.
748          */
749         getDependencies();
750
751         /*
752          * Sort the objects into a safe dump order (no forward references).
753          *
754          * In 7.3 or later, we can rely on dependency information to help us
755          * determine a safe order, so the initial sort is mostly for cosmetic
756          * purposes: we sort by name to ensure that logically identical schemas
757          * will dump identically.  Before 7.3 we don't have dependencies and we
758          * use OID ordering as an (unreliable) guide to creation order.
759          */
760         getDumpableObjects(&dobjs, &numObjs);
761
762         if (g_fout->remoteVersion >= 70300)
763                 sortDumpableObjectsByTypeName(dobjs, numObjs);
764         else
765                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
766
767         sortDumpableObjects(dobjs, numObjs);
768
769         /*
770          * Create archive TOC entries for all the objects to be dumped, in a safe
771          * order.
772          */
773
774         /* First the special ENCODING and STDSTRINGS entries. */
775         dumpEncoding(g_fout);
776         dumpStdStrings(g_fout);
777
778         /* The database item is always next, unless we don't want it at all */
779         if (include_everything && !dataOnly)
780                 dumpDatabase(g_fout);
781
782         /* Now the rearrangeable objects. */
783         for (i = 0; i < numObjs; i++)
784                 dumpDumpableObject(g_fout, dobjs[i]);
785
786         /*
787          * And finally we can do the actual output.
788          */
789         if (plainText)
790         {
791                 ropt = NewRestoreOptions();
792                 ropt->filename = (char *) filename;
793                 ropt->dropSchema = outputClean;
794                 ropt->aclsSkip = aclsSkip;
795                 ropt->superuser = outputSuperuser;
796                 ropt->createDB = outputCreateDB;
797                 ropt->noOwner = outputNoOwner;
798                 ropt->noTablespace = outputNoTablespaces;
799                 ropt->disable_triggers = disable_triggers;
800                 ropt->use_setsessauth = use_setsessauth;
801                 ropt->dataOnly = dataOnly;
802
803                 if (compressLevel == -1)
804                         ropt->compression = 0;
805                 else
806                         ropt->compression = compressLevel;
807
808                 ropt->suppressDumpWarnings = true;              /* We've already shown them */
809
810                 RestoreArchive(g_fout, ropt);
811         }
812
813         CloseArchive(g_fout);
814
815         PQfinish(g_conn);
816
817         exit(0);
818 }
819
820
821 static void
822 help(const char *progname)
823 {
824         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
825         printf(_("Usage:\n"));
826         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
827
828         printf(_("\nGeneral options:\n"));
829         printf(_("  -f, --file=FILENAME         output file or directory name\n"));
830         printf(_("  -F, --format=c|d|t|p        output file format (custom, directory, tar, plain text)\n"));
831         printf(_("  -v, --verbose               verbose mode\n"));
832         printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
833         printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
834         printf(_("  --help                      show this help, then exit\n"));
835         printf(_("  --version                   output version information, then exit\n"));
836
837         printf(_("\nOptions controlling the output content:\n"));
838         printf(_("  -a, --data-only             dump only the data, not the schema\n"));
839         printf(_("  -b, --blobs                 include large objects in dump\n"));
840         printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
841         printf(_("  -C, --create                include commands to create database in dump\n"));
842         printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
843         printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
844         printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
845         printf(_("  -o, --oids                  include OIDs in dump\n"));
846         printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
847                          "                              plain-text format\n"));
848         printf(_("  -s, --schema-only           dump only the schema, no data\n"));
849         printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
850         printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
851         printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
852         printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
853         printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
854         printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
855         printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
856         printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
857         printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
858         printf(_("  --no-security-labels        do not dump security label assignments\n"));
859         printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
860         printf(_("  --no-unlogged-table-data    do not dump unlogged table data\n"));
861         printf(_("  --quote-all-identifiers     quote all identifiers, even if not key words\n"));
862         printf(_("  --serializable-deferrable   wait until the dump can run without anomalies\n"));
863         printf(_("  --use-set-session-authorization\n"
864                          "                              use SET SESSION AUTHORIZATION commands instead of\n"
865         "                              ALTER OWNER commands to set ownership\n"));
866
867         printf(_("\nConnection options:\n"));
868         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
869         printf(_("  -p, --port=PORT          database server port number\n"));
870         printf(_("  -U, --username=NAME      connect as specified database user\n"));
871         printf(_("  -w, --no-password        never prompt for password\n"));
872         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
873         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
874
875         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
876                          "variable value is used.\n\n"));
877         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
878 }
879
880 void
881 exit_nicely(void)
882 {
883         PQfinish(g_conn);
884         if (g_verbose)
885                 write_msg(NULL, "*** aborted because of error\n");
886         exit(1);
887 }
888
889 static ArchiveFormat
890 parseArchiveFormat(const char *format, ArchiveMode *mode)
891 {
892         ArchiveFormat archiveFormat;
893
894         *mode = archModeWrite;
895
896         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
897         {
898                 /* This is used by pg_dumpall, and is not documented */
899                 archiveFormat = archNull;
900                 *mode = archModeAppend;
901         }
902         else if (pg_strcasecmp(format, "c") == 0)
903                 archiveFormat = archCustom;
904         else if (pg_strcasecmp(format, "custom") == 0)
905                 archiveFormat = archCustom;
906         else if (pg_strcasecmp(format, "d") == 0)
907                 archiveFormat = archDirectory;
908         else if (pg_strcasecmp(format, "directory") == 0)
909                 archiveFormat = archDirectory;
910         else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
911
912                 /*
913                  * Dump files into the current directory; for demonstration only, not
914                  * documented.
915                  */
916                 archiveFormat = archFiles;
917         else if (pg_strcasecmp(format, "p") == 0)
918                 archiveFormat = archNull;
919         else if (pg_strcasecmp(format, "plain") == 0)
920                 archiveFormat = archNull;
921         else if (pg_strcasecmp(format, "t") == 0)
922                 archiveFormat = archTar;
923         else if (pg_strcasecmp(format, "tar") == 0)
924                 archiveFormat = archTar;
925         else
926         {
927                 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
928                 exit(1);
929         }
930         return archiveFormat;
931 }
932
933 /*
934  * Find the OIDs of all schemas matching the given list of patterns,
935  * and append them to the given OID list.
936  */
937 static void
938 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
939 {
940         PQExpBuffer query;
941         PGresult   *res;
942         SimpleStringListCell *cell;
943         int                     i;
944
945         if (patterns->head == NULL)
946                 return;                                 /* nothing to do */
947
948         if (g_fout->remoteVersion < 70300)
949         {
950                 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
951                 exit_nicely();
952         }
953
954         query = createPQExpBuffer();
955
956         /*
957          * We use UNION ALL rather than UNION; this might sometimes result in
958          * duplicate entries in the OID list, but we don't care.
959          */
960
961         for (cell = patterns->head; cell; cell = cell->next)
962         {
963                 if (cell != patterns->head)
964                         appendPQExpBuffer(query, "UNION ALL\n");
965                 appendPQExpBuffer(query,
966                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
967                 processSQLNamePattern(g_conn, query, cell->val, false, false,
968                                                           NULL, "n.nspname", NULL,
969                                                           NULL);
970         }
971
972         res = PQexec(g_conn, query->data);
973         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
974
975         for (i = 0; i < PQntuples(res); i++)
976         {
977                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
978         }
979
980         PQclear(res);
981         destroyPQExpBuffer(query);
982 }
983
984 /*
985  * Find the OIDs of all tables matching the given list of patterns,
986  * and append them to the given OID list.
987  */
988 static void
989 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
990 {
991         PQExpBuffer query;
992         PGresult   *res;
993         SimpleStringListCell *cell;
994         int                     i;
995
996         if (patterns->head == NULL)
997                 return;                                 /* nothing to do */
998
999         query = createPQExpBuffer();
1000
1001         /*
1002          * We use UNION ALL rather than UNION; this might sometimes result in
1003          * duplicate entries in the OID list, but we don't care.
1004          */
1005
1006         for (cell = patterns->head; cell; cell = cell->next)
1007         {
1008                 if (cell != patterns->head)
1009                         appendPQExpBuffer(query, "UNION ALL\n");
1010                 appendPQExpBuffer(query,
1011                                                   "SELECT c.oid"
1012                                                   "\nFROM pg_catalog.pg_class c"
1013                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1014                                                   "\nWHERE c.relkind in ('%c', '%c', '%c', '%c')\n",
1015                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1016                                                   RELKIND_FOREIGN_TABLE);
1017                 processSQLNamePattern(g_conn, query, cell->val, true, false,
1018                                                           "n.nspname", "c.relname", NULL,
1019                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1020         }
1021
1022         res = PQexec(g_conn, query->data);
1023         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1024
1025         for (i = 0; i < PQntuples(res); i++)
1026         {
1027                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1028         }
1029
1030         PQclear(res);
1031         destroyPQExpBuffer(query);
1032 }
1033
1034 /*
1035  * selectDumpableNamespace: policy-setting subroutine
1036  *              Mark a namespace as to be dumped or not
1037  */
1038 static void
1039 selectDumpableNamespace(NamespaceInfo *nsinfo)
1040 {
1041         /*
1042          * If specific tables are being dumped, do not dump any complete
1043          * namespaces. If specific namespaces are being dumped, dump just those
1044          * namespaces. Otherwise, dump all non-system namespaces.
1045          */
1046         if (table_include_oids.head != NULL)
1047                 nsinfo->dobj.dump = false;
1048         else if (schema_include_oids.head != NULL)
1049                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1050                                                                                                    nsinfo->dobj.catId.oid);
1051         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1052                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1053                 nsinfo->dobj.dump = false;
1054         else
1055                 nsinfo->dobj.dump = true;
1056
1057         /*
1058          * In any case, a namespace can be excluded by an exclusion switch
1059          */
1060         if (nsinfo->dobj.dump &&
1061                 simple_oid_list_member(&schema_exclude_oids,
1062                                                            nsinfo->dobj.catId.oid))
1063                 nsinfo->dobj.dump = false;
1064 }
1065
1066 /*
1067  * selectDumpableTable: policy-setting subroutine
1068  *              Mark a table as to be dumped or not
1069  */
1070 static void
1071 selectDumpableTable(TableInfo *tbinfo)
1072 {
1073         /*
1074          * If specific tables are being dumped, dump just those tables; else, dump
1075          * according to the parent namespace's dump flag.
1076          */
1077         if (table_include_oids.head != NULL)
1078                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1079                                                                                                    tbinfo->dobj.catId.oid);
1080         else
1081                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1082
1083         /*
1084          * In any case, a table can be excluded by an exclusion switch
1085          */
1086         if (tbinfo->dobj.dump &&
1087                 simple_oid_list_member(&table_exclude_oids,
1088                                                            tbinfo->dobj.catId.oid))
1089                 tbinfo->dobj.dump = false;
1090 }
1091
1092 /*
1093  * selectDumpableType: policy-setting subroutine
1094  *              Mark a type as to be dumped or not
1095  *
1096  * If it's a table's rowtype or an autogenerated array type, we also apply a
1097  * special type code to facilitate sorting into the desired order.      (We don't
1098  * want to consider those to be ordinary types because that would bring tables
1099  * up into the datatype part of the dump order.)  We still set the object's
1100  * dump flag; that's not going to cause the dummy type to be dumped, but we
1101  * need it so that casts involving such types will be dumped correctly -- see
1102  * dumpCast.  This means the flag should be set the same as for the underlying
1103  * object (the table or base type).
1104  */
1105 static void
1106 selectDumpableType(TypeInfo *tyinfo)
1107 {
1108         /* skip complex types, except for standalone composite types */
1109         if (OidIsValid(tyinfo->typrelid) &&
1110                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1111         {
1112                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1113
1114                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1115                 if (tytable != NULL)
1116                         tyinfo->dobj.dump = tytable->dobj.dump;
1117                 else
1118                         tyinfo->dobj.dump = false;
1119                 return;
1120         }
1121
1122         /* skip auto-generated array types */
1123         if (tyinfo->isArray)
1124         {
1125                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1126                 /*
1127                  * Fall through to set the dump flag; we assume that the subsequent
1128                  * rules will do the same thing as they would for the array's base
1129                  * type.  (We cannot reliably look up the base type here, since
1130                  * getTypes may not have processed it yet.)
1131                  */
1132         }
1133
1134         /* dump only types in dumpable namespaces */
1135         if (!tyinfo->dobj.namespace->dobj.dump)
1136                 tyinfo->dobj.dump = false;
1137
1138         /* skip undefined placeholder types */
1139         else if (!tyinfo->isDefined)
1140                 tyinfo->dobj.dump = false;
1141
1142         else
1143                 tyinfo->dobj.dump = true;
1144 }
1145
1146 /*
1147  * selectDumpableDefaultACL: policy-setting subroutine
1148  *              Mark a default ACL as to be dumped or not
1149  *
1150  * For per-schema default ACLs, dump if the schema is to be dumped.
1151  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1152  * and aclsSkip are checked separately.
1153  */
1154 static void
1155 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1156 {
1157         if (dinfo->dobj.namespace)
1158                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1159         else
1160                 dinfo->dobj.dump = include_everything;
1161 }
1162
1163 /*
1164  * selectDumpableExtension: policy-setting subroutine
1165  *              Mark an extension as to be dumped or not
1166  *
1167  * Normally, we dump all extensions, or none of them if include_everything
1168  * is false (i.e., a --schema or --table switch was given).  However, in
1169  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1170  * assume those will already be installed in the target database.  We identify
1171  * such extensions by their having OIDs in the range reserved for initdb.
1172  */
1173 static void
1174 selectDumpableExtension(ExtensionInfo *extinfo)
1175 {
1176         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1177                 extinfo->dobj.dump = false;
1178         else
1179                 extinfo->dobj.dump = include_everything;
1180 }
1181
1182 /*
1183  * selectDumpableObject: policy-setting subroutine
1184  *              Mark a generic dumpable object as to be dumped or not
1185  *
1186  * Use this only for object types without a special-case routine above.
1187  */
1188 static void
1189 selectDumpableObject(DumpableObject *dobj)
1190 {
1191         /*
1192          * Default policy is to dump if parent namespace is dumpable, or always
1193          * for non-namespace-associated items.
1194          */
1195         if (dobj->namespace)
1196                 dobj->dump = dobj->namespace->dobj.dump;
1197         else
1198                 dobj->dump = true;
1199 }
1200
1201 /*
1202  *      Dump a table's contents for loading using the COPY command
1203  *      - this routine is called by the Archiver when it wants the table
1204  *        to be dumped.
1205  */
1206
1207 static int
1208 dumpTableData_copy(Archive *fout, void *dcontext)
1209 {
1210         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1211         TableInfo  *tbinfo = tdinfo->tdtable;
1212         const char *classname = tbinfo->dobj.name;
1213         const bool      hasoids = tbinfo->hasoids;
1214         const bool      oids = tdinfo->oids;
1215         PQExpBuffer q = createPQExpBuffer();
1216         PGresult   *res;
1217         int                     ret;
1218         char       *copybuf;
1219         const char *column_list;
1220
1221         if (g_verbose)
1222                 write_msg(NULL, "dumping contents of table %s\n", classname);
1223
1224         /*
1225          * Make sure we are in proper schema.  We will qualify the table name
1226          * below anyway (in case its name conflicts with a pg_catalog table); but
1227          * this ensures reproducible results in case the table contains regproc,
1228          * regclass, etc columns.
1229          */
1230         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1231
1232         /*
1233          * If possible, specify the column list explicitly so that we have no
1234          * possibility of retrieving data in the wrong column order.  (The default
1235          * column ordering of COPY will not be what we want in certain corner
1236          * cases involving ADD COLUMN and inheritance.)
1237          */
1238         if (g_fout->remoteVersion >= 70300)
1239                 column_list = fmtCopyColumnList(tbinfo);
1240         else
1241                 column_list = "";               /* can't select columns in COPY */
1242
1243         if (oids && hasoids)
1244         {
1245                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1246                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1247                                                                                  classname),
1248                                                   column_list);
1249         }
1250         else if (tdinfo->filtercond)
1251         {
1252                 /* Note: this syntax is only supported in 8.2 and up */
1253                 appendPQExpBufferStr(q, "COPY (SELECT ");
1254                 /* klugery to get rid of parens in column list */
1255                 if (strlen(column_list) > 2)
1256                 {
1257                         appendPQExpBufferStr(q, column_list + 1);
1258                         q->data[q->len - 1] = ' ';
1259                 }
1260                 else
1261                         appendPQExpBufferStr(q, "* ");
1262                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1263                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1264                                                                                  classname),
1265                                                   tdinfo->filtercond);
1266         }
1267         else
1268         {
1269                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1270                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1271                                                                                  classname),
1272                                                   column_list);
1273         }
1274         res = PQexec(g_conn, q->data);
1275         check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1276         PQclear(res);
1277
1278         for (;;)
1279         {
1280                 ret = PQgetCopyData(g_conn, &copybuf, 0);
1281
1282                 if (ret < 0)
1283                         break;                          /* done or error */
1284
1285                 if (copybuf)
1286                 {
1287                         WriteData(fout, copybuf, ret);
1288                         PQfreemem(copybuf);
1289                 }
1290
1291                 /* ----------
1292                  * THROTTLE:
1293                  *
1294                  * There was considerable discussion in late July, 2000 regarding
1295                  * slowing down pg_dump when backing up large tables. Users with both
1296                  * slow & fast (multi-processor) machines experienced performance
1297                  * degradation when doing a backup.
1298                  *
1299                  * Initial attempts based on sleeping for a number of ms for each ms
1300                  * of work were deemed too complex, then a simple 'sleep in each loop'
1301                  * implementation was suggested. The latter failed because the loop
1302                  * was too tight. Finally, the following was implemented:
1303                  *
1304                  * If throttle is non-zero, then
1305                  *              See how long since the last sleep.
1306                  *              Work out how long to sleep (based on ratio).
1307                  *              If sleep is more than 100ms, then
1308                  *                      sleep
1309                  *                      reset timer
1310                  *              EndIf
1311                  * EndIf
1312                  *
1313                  * where the throttle value was the number of ms to sleep per ms of
1314                  * work. The calculation was done in each loop.
1315                  *
1316                  * Most of the hard work is done in the backend, and this solution
1317                  * still did not work particularly well: on slow machines, the ratio
1318                  * was 50:1, and on medium paced machines, 1:1, and on fast
1319                  * multi-processor machines, it had little or no effect, for reasons
1320                  * that were unclear.
1321                  *
1322                  * Further discussion ensued, and the proposal was dropped.
1323                  *
1324                  * For those people who want this feature, it can be implemented using
1325                  * gettimeofday in each loop, calculating the time since last sleep,
1326                  * multiplying that by the sleep ratio, then if the result is more
1327                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1328                  * function to sleep for a subsecond period ie.
1329                  *
1330                  * select(0, NULL, NULL, NULL, &tvi);
1331                  *
1332                  * This will return after the interval specified in the structure tvi.
1333                  * Finally, call gettimeofday again to save the 'last sleep time'.
1334                  * ----------
1335                  */
1336         }
1337         archprintf(fout, "\\.\n\n\n");
1338
1339         if (ret == -2)
1340         {
1341                 /* copy data transfer failed */
1342                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1343                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1344                 write_msg(NULL, "The command was: %s\n", q->data);
1345                 exit_nicely();
1346         }
1347
1348         /* Check command status and return to normal libpq state */
1349         res = PQgetResult(g_conn);
1350         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1351         PQclear(res);
1352
1353         destroyPQExpBuffer(q);
1354         return 1;
1355 }
1356
1357 static int
1358 dumpTableData_insert(Archive *fout, void *dcontext)
1359 {
1360         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1361         TableInfo  *tbinfo = tdinfo->tdtable;
1362         const char *classname = tbinfo->dobj.name;
1363         PQExpBuffer q = createPQExpBuffer();
1364         PGresult   *res;
1365         int                     tuple;
1366         int                     nfields;
1367         int                     field;
1368
1369         /*
1370          * Make sure we are in proper schema.  We will qualify the table name
1371          * below anyway (in case its name conflicts with a pg_catalog table); but
1372          * this ensures reproducible results in case the table contains regproc,
1373          * regclass, etc columns.
1374          */
1375         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1376
1377         if (fout->remoteVersion >= 70100)
1378         {
1379                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1380                                                   "SELECT * FROM ONLY %s",
1381                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1382                                                                                  classname));
1383         }
1384         else
1385         {
1386                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1387                                                   "SELECT * FROM %s",
1388                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1389                                                                                  classname));
1390         }
1391         if (tdinfo->filtercond)
1392                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1393
1394         res = PQexec(g_conn, q->data);
1395         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1396
1397         do
1398         {
1399                 PQclear(res);
1400
1401                 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1402                 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1403                                                  PGRES_TUPLES_OK);
1404                 nfields = PQnfields(res);
1405                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1406                 {
1407                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1408                         if (nfields == 0)
1409                         {
1410                                 /* corner case for zero-column table */
1411                                 archprintf(fout, "DEFAULT VALUES;\n");
1412                                 continue;
1413                         }
1414                         if (column_inserts)
1415                         {
1416                                 resetPQExpBuffer(q);
1417                                 appendPQExpBuffer(q, "(");
1418                                 for (field = 0; field < nfields; field++)
1419                                 {
1420                                         if (field > 0)
1421                                                 appendPQExpBuffer(q, ", ");
1422                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1423                                 }
1424                                 appendPQExpBuffer(q, ") ");
1425                                 archputs(q->data, fout);
1426                         }
1427                         archprintf(fout, "VALUES (");
1428                         for (field = 0; field < nfields; field++)
1429                         {
1430                                 if (field > 0)
1431                                         archprintf(fout, ", ");
1432                                 if (PQgetisnull(res, tuple, field))
1433                                 {
1434                                         archprintf(fout, "NULL");
1435                                         continue;
1436                                 }
1437
1438                                 /* XXX This code is partially duplicated in ruleutils.c */
1439                                 switch (PQftype(res, field))
1440                                 {
1441                                         case INT2OID:
1442                                         case INT4OID:
1443                                         case INT8OID:
1444                                         case OIDOID:
1445                                         case FLOAT4OID:
1446                                         case FLOAT8OID:
1447                                         case NUMERICOID:
1448                                                 {
1449                                                         /*
1450                                                          * These types are printed without quotes unless
1451                                                          * they contain values that aren't accepted by the
1452                                                          * scanner unquoted (e.g., 'NaN').      Note that
1453                                                          * strtod() and friends might accept NaN, so we
1454                                                          * can't use that to test.
1455                                                          *
1456                                                          * In reality we only need to defend against
1457                                                          * infinity and NaN, so we need not get too crazy
1458                                                          * about pattern matching here.
1459                                                          */
1460                                                         const char *s = PQgetvalue(res, tuple, field);
1461
1462                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1463                                                                 archprintf(fout, "%s", s);
1464                                                         else
1465                                                                 archprintf(fout, "'%s'", s);
1466                                                 }
1467                                                 break;
1468
1469                                         case BITOID:
1470                                         case VARBITOID:
1471                                                 archprintf(fout, "B'%s'",
1472                                                                    PQgetvalue(res, tuple, field));
1473                                                 break;
1474
1475                                         case BOOLOID:
1476                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1477                                                         archprintf(fout, "true");
1478                                                 else
1479                                                         archprintf(fout, "false");
1480                                                 break;
1481
1482                                         default:
1483                                                 /* All other types are printed as string literals. */
1484                                                 resetPQExpBuffer(q);
1485                                                 appendStringLiteralAH(q,
1486                                                                                           PQgetvalue(res, tuple, field),
1487                                                                                           fout);
1488                                                 archputs(q->data, fout);
1489                                                 break;
1490                                 }
1491                         }
1492                         archprintf(fout, ");\n");
1493                 }
1494         } while (PQntuples(res) > 0);
1495
1496         PQclear(res);
1497
1498         archprintf(fout, "\n\n");
1499
1500         do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1501
1502         destroyPQExpBuffer(q);
1503         return 1;
1504 }
1505
1506
1507 /*
1508  * dumpTableData -
1509  *        dump the contents of a single table
1510  *
1511  * Actually, this just makes an ArchiveEntry for the table contents.
1512  */
1513 static void
1514 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1515 {
1516         TableInfo  *tbinfo = tdinfo->tdtable;
1517         PQExpBuffer copyBuf = createPQExpBuffer();
1518         DataDumperPtr dumpFn;
1519         char       *copyStmt;
1520
1521         if (!dump_inserts)
1522         {
1523                 /* Dump/restore using COPY */
1524                 dumpFn = dumpTableData_copy;
1525                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1526                 appendPQExpBuffer(copyBuf, "COPY %s ",
1527                                                   fmtId(tbinfo->dobj.name));
1528                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1529                                                   fmtCopyColumnList(tbinfo),
1530                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1531                 copyStmt = copyBuf->data;
1532         }
1533         else
1534         {
1535                 /* Restore using INSERT */
1536                 dumpFn = dumpTableData_insert;
1537                 copyStmt = NULL;
1538         }
1539
1540         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1541                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1542                                  NULL, tbinfo->rolname,
1543                                  false, "TABLE DATA", SECTION_DATA,
1544                                  "", "", copyStmt,
1545                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1546                                  dumpFn, tdinfo);
1547
1548         destroyPQExpBuffer(copyBuf);
1549 }
1550
1551 /*
1552  * getTableData -
1553  *        set up dumpable objects representing the contents of tables
1554  */
1555 static void
1556 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1557 {
1558         int                     i;
1559
1560         for (i = 0; i < numTables; i++)
1561         {
1562                 /* Skip VIEWs (no data to dump) */
1563                 if (tblinfo[i].relkind == RELKIND_VIEW)
1564                         continue;
1565                 /* Skip SEQUENCEs (handled elsewhere) */
1566                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1567                         continue;
1568                 /* Skip FOREIGN TABLEs (no data to dump) */
1569                 if (tblinfo[i].relkind == RELKIND_FOREIGN_TABLE)
1570                         continue;
1571                 /* Skip unlogged tables if so requested */
1572                 if (tblinfo[i].relpersistence == RELPERSISTENCE_UNLOGGED
1573                         && no_unlogged_table_data)
1574                         continue;
1575
1576                 if (tblinfo[i].dobj.dump && tblinfo[i].dataObj == NULL)
1577                         makeTableDataInfo(&(tblinfo[i]), oids);
1578         }
1579 }
1580
1581 /*
1582  * Make a dumpable object for the data of this specific table
1583  */
1584 static void
1585 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1586 {
1587         TableDataInfo *tdinfo;
1588
1589         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1590
1591         tdinfo->dobj.objType = DO_TABLE_DATA;
1592
1593         /*
1594          * Note: use tableoid 0 so that this object won't be mistaken for
1595          * something that pg_depend entries apply to.
1596          */
1597         tdinfo->dobj.catId.tableoid = 0;
1598         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1599         AssignDumpId(&tdinfo->dobj);
1600         tdinfo->dobj.name = tbinfo->dobj.name;
1601         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1602         tdinfo->tdtable = tbinfo;
1603         tdinfo->oids = oids;
1604         tdinfo->filtercond = NULL;      /* might get set later */
1605         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1606
1607         tbinfo->dataObj = tdinfo;
1608 }
1609
1610 /*
1611  * getTableDataFKConstraints -
1612  *        add dump-order dependencies reflecting foreign key constraints
1613  *
1614  * This code is executed only in a data-only dump --- in schema+data dumps
1615  * we handle foreign key issues by not creating the FK constraints until
1616  * after the data is loaded.  In a data-only dump, however, we want to
1617  * order the table data objects in such a way that a table's referenced
1618  * tables are restored first.  (In the presence of circular references or
1619  * self-references this may be impossible; we'll detect and complain about
1620  * that during the dependency sorting step.)
1621  */
1622 static void
1623 getTableDataFKConstraints(void)
1624 {
1625         DumpableObject **dobjs;
1626         int                     numObjs;
1627         int                     i;
1628
1629         /* Search through all the dumpable objects for FK constraints */
1630         getDumpableObjects(&dobjs, &numObjs);
1631         for (i = 0; i < numObjs; i++)
1632         {
1633                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1634                 {
1635                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1636                         TableInfo  *ftable;
1637
1638                         /* Not interesting unless both tables are to be dumped */
1639                         if (cinfo->contable == NULL ||
1640                                 cinfo->contable->dataObj == NULL)
1641                                 continue;
1642                         ftable = findTableByOid(cinfo->confrelid);
1643                         if (ftable == NULL ||
1644                                 ftable->dataObj == NULL)
1645                                 continue;
1646
1647                         /*
1648                          * Okay, make referencing table's TABLE_DATA object depend on the
1649                          * referenced table's TABLE_DATA object.
1650                          */
1651                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1652                                                                 ftable->dataObj->dobj.dumpId);
1653                 }
1654         }
1655         free(dobjs);
1656 }
1657
1658
1659 /*
1660  * guessConstraintInheritance:
1661  *      In pre-8.4 databases, we can't tell for certain which constraints
1662  *      are inherited.  We assume a CHECK constraint is inherited if its name
1663  *      matches the name of any constraint in the parent.  Originally this code
1664  *      tried to compare the expression texts, but that can fail for various
1665  *      reasons --- for example, if the parent and child tables are in different
1666  *      schemas, reverse-listing of function calls may produce different text
1667  *      (schema-qualified or not) depending on search path.
1668  *
1669  *      In 8.4 and up we can rely on the conislocal field to decide which
1670  *      constraints must be dumped; much safer.
1671  *
1672  *      This function assumes all conislocal flags were initialized to TRUE.
1673  *      It clears the flag on anything that seems to be inherited.
1674  */
1675 static void
1676 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1677 {
1678         int                     i,
1679                                 j,
1680                                 k;
1681
1682         for (i = 0; i < numTables; i++)
1683         {
1684                 TableInfo  *tbinfo = &(tblinfo[i]);
1685                 int                     numParents;
1686                 TableInfo **parents;
1687                 TableInfo  *parent;
1688
1689                 /* Sequences and views never have parents */
1690                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1691                         tbinfo->relkind == RELKIND_VIEW)
1692                         continue;
1693
1694                 /* Don't bother computing anything for non-target tables, either */
1695                 if (!tbinfo->dobj.dump)
1696                         continue;
1697
1698                 numParents = tbinfo->numParents;
1699                 parents = tbinfo->parents;
1700
1701                 if (numParents == 0)
1702                         continue;                       /* nothing to see here, move along */
1703
1704                 /* scan for inherited CHECK constraints */
1705                 for (j = 0; j < tbinfo->ncheck; j++)
1706                 {
1707                         ConstraintInfo *constr;
1708
1709                         constr = &(tbinfo->checkexprs[j]);
1710
1711                         for (k = 0; k < numParents; k++)
1712                         {
1713                                 int                     l;
1714
1715                                 parent = parents[k];
1716                                 for (l = 0; l < parent->ncheck; l++)
1717                                 {
1718                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1719
1720                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1721                                         {
1722                                                 constr->conislocal = false;
1723                                                 break;
1724                                         }
1725                                 }
1726                                 if (!constr->conislocal)
1727                                         break;
1728                         }
1729                 }
1730         }
1731 }
1732
1733
1734 /*
1735  * dumpDatabase:
1736  *      dump the database definition
1737  */
1738 static void
1739 dumpDatabase(Archive *AH)
1740 {
1741         PQExpBuffer dbQry = createPQExpBuffer();
1742         PQExpBuffer delQry = createPQExpBuffer();
1743         PQExpBuffer creaQry = createPQExpBuffer();
1744         PGresult   *res;
1745         int                     ntups;
1746         int                     i_tableoid,
1747                                 i_oid,
1748                                 i_dba,
1749                                 i_encoding,
1750                                 i_collate,
1751                                 i_ctype,
1752                                 i_frozenxid,
1753                                 i_tablespace;
1754         CatalogId       dbCatId;
1755         DumpId          dbDumpId;
1756         const char *datname,
1757                            *dba,
1758                            *encoding,
1759                            *collate,
1760                            *ctype,
1761                            *tablespace;
1762         uint32          frozenxid;
1763
1764         datname = PQdb(g_conn);
1765
1766         if (g_verbose)
1767                 write_msg(NULL, "saving database definition\n");
1768
1769         /* Make sure we are in proper schema */
1770         selectSourceSchema("pg_catalog");
1771
1772         /* Get the database owner and parameters from pg_database */
1773         if (g_fout->remoteVersion >= 80400)
1774         {
1775                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1776                                                   "(%s datdba) AS dba, "
1777                                                   "pg_encoding_to_char(encoding) AS encoding, "
1778                                                   "datcollate, datctype, datfrozenxid, "
1779                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1780                                           "shobj_description(oid, 'pg_database') AS description "
1781
1782                                                   "FROM pg_database "
1783                                                   "WHERE datname = ",
1784                                                   username_subquery);
1785                 appendStringLiteralAH(dbQry, datname, AH);
1786         }
1787         else if (g_fout->remoteVersion >= 80200)
1788         {
1789                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1790                                                   "(%s datdba) AS dba, "
1791                                                   "pg_encoding_to_char(encoding) AS encoding, "
1792                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1793                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1794                                           "shobj_description(oid, 'pg_database') AS description "
1795
1796                                                   "FROM pg_database "
1797                                                   "WHERE datname = ",
1798                                                   username_subquery);
1799                 appendStringLiteralAH(dbQry, datname, AH);
1800         }
1801         else if (g_fout->remoteVersion >= 80000)
1802         {
1803                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1804                                                   "(%s datdba) AS dba, "
1805                                                   "pg_encoding_to_char(encoding) AS encoding, "
1806                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1807                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1808                                                   "FROM pg_database "
1809                                                   "WHERE datname = ",
1810                                                   username_subquery);
1811                 appendStringLiteralAH(dbQry, datname, AH);
1812         }
1813         else if (g_fout->remoteVersion >= 70100)
1814         {
1815                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1816                                                   "(%s datdba) AS dba, "
1817                                                   "pg_encoding_to_char(encoding) AS encoding, "
1818                                                   "NULL AS datcollate, NULL AS datctype, "
1819                                                   "0 AS datfrozenxid, "
1820                                                   "NULL AS tablespace "
1821                                                   "FROM pg_database "
1822                                                   "WHERE datname = ",
1823                                                   username_subquery);
1824                 appendStringLiteralAH(dbQry, datname, AH);
1825         }
1826         else
1827         {
1828                 appendPQExpBuffer(dbQry, "SELECT "
1829                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1830                                                   "oid, "
1831                                                   "(%s datdba) AS dba, "
1832                                                   "pg_encoding_to_char(encoding) AS encoding, "
1833                                                   "NULL AS datcollate, NULL AS datctype, "
1834                                                   "0 AS datfrozenxid, "
1835                                                   "NULL AS tablespace "
1836                                                   "FROM pg_database "
1837                                                   "WHERE datname = ",
1838                                                   username_subquery);
1839                 appendStringLiteralAH(dbQry, datname, AH);
1840         }
1841
1842         res = PQexec(g_conn, dbQry->data);
1843         check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1844
1845         ntups = PQntuples(res);
1846
1847         if (ntups <= 0)
1848         {
1849                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1850                                   datname);
1851                 exit_nicely();
1852         }
1853
1854         if (ntups != 1)
1855         {
1856                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1857                                   ntups, datname);
1858                 exit_nicely();
1859         }
1860
1861         i_tableoid = PQfnumber(res, "tableoid");
1862         i_oid = PQfnumber(res, "oid");
1863         i_dba = PQfnumber(res, "dba");
1864         i_encoding = PQfnumber(res, "encoding");
1865         i_collate = PQfnumber(res, "datcollate");
1866         i_ctype = PQfnumber(res, "datctype");
1867         i_frozenxid = PQfnumber(res, "datfrozenxid");
1868         i_tablespace = PQfnumber(res, "tablespace");
1869
1870         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1871         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1872         dba = PQgetvalue(res, 0, i_dba);
1873         encoding = PQgetvalue(res, 0, i_encoding);
1874         collate = PQgetvalue(res, 0, i_collate);
1875         ctype = PQgetvalue(res, 0, i_ctype);
1876         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1877         tablespace = PQgetvalue(res, 0, i_tablespace);
1878
1879         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1880                                           fmtId(datname));
1881         if (strlen(encoding) > 0)
1882         {
1883                 appendPQExpBuffer(creaQry, " ENCODING = ");
1884                 appendStringLiteralAH(creaQry, encoding, AH);
1885         }
1886         if (strlen(collate) > 0)
1887         {
1888                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1889                 appendStringLiteralAH(creaQry, collate, AH);
1890         }
1891         if (strlen(ctype) > 0)
1892         {
1893                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1894                 appendStringLiteralAH(creaQry, ctype, AH);
1895         }
1896         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1897                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1898                                                   fmtId(tablespace));
1899         appendPQExpBuffer(creaQry, ";\n");
1900
1901         if (binary_upgrade)
1902         {
1903                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1904                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
1905                                                   "SET datfrozenxid = '%u'\n"
1906                                                   "WHERE        datname = ",
1907                                                   frozenxid);
1908                 appendStringLiteralAH(creaQry, datname, AH);
1909                 appendPQExpBuffer(creaQry, ";\n");
1910
1911         }
1912
1913         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1914                                           fmtId(datname));
1915
1916         dbDumpId = createDumpId();
1917
1918         ArchiveEntry(AH,
1919                                  dbCatId,               /* catalog ID */
1920                                  dbDumpId,              /* dump ID */
1921                                  datname,               /* Name */
1922                                  NULL,                  /* Namespace */
1923                                  NULL,                  /* Tablespace */
1924                                  dba,                   /* Owner */
1925                                  false,                 /* with oids */
1926                                  "DATABASE",    /* Desc */
1927                                  SECTION_PRE_DATA,              /* Section */
1928                                  creaQry->data, /* Create */
1929                                  delQry->data,  /* Del */
1930                                  NULL,                  /* Copy */
1931                                  NULL,                  /* Deps */
1932                                  0,                             /* # Deps */
1933                                  NULL,                  /* Dumper */
1934                                  NULL);                 /* Dumper Arg */
1935
1936         /*
1937          * pg_largeobject and pg_largeobject_metadata come from the old system
1938          * intact, so set their relfrozenxids.
1939          */
1940         if (binary_upgrade)
1941         {
1942                 PGresult   *lo_res;
1943                 PQExpBuffer loFrozenQry = createPQExpBuffer();
1944                 PQExpBuffer loOutQry = createPQExpBuffer();
1945                 int                     i_relfrozenxid;
1946
1947                 /*
1948                  * pg_largeobject
1949                  */
1950                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
1951                                                   "FROM pg_catalog.pg_class\n"
1952                                                   "WHERE oid = %u;\n",
1953                                                   LargeObjectRelationId);
1954
1955                 lo_res = PQexec(g_conn, loFrozenQry->data);
1956                 check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
1957
1958                 if (PQntuples(lo_res) != 1)
1959                 {
1960                         write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
1961                         exit_nicely();
1962                 }
1963
1964                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
1965
1966                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
1967                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
1968                                                   "SET relfrozenxid = '%u'\n"
1969                                                   "WHERE oid = %u;\n",
1970                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
1971                                                   LargeObjectRelationId);
1972                 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1973                                          "pg_largeobject", NULL, NULL, "",
1974                                          false, "pg_largeobject", SECTION_PRE_DATA,
1975                                          loOutQry->data, "", NULL,
1976                                          NULL, 0,
1977                                          NULL, NULL);
1978
1979                 PQclear(lo_res);
1980
1981                 /*
1982                  * pg_largeobject_metadata
1983                  */
1984                 if (g_fout->remoteVersion >= 90000)
1985                 {
1986                         resetPQExpBuffer(loFrozenQry);
1987                         resetPQExpBuffer(loOutQry);
1988
1989                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
1990                                                           "FROM pg_catalog.pg_class\n"
1991                                                           "WHERE oid = %u;\n",
1992                                                           LargeObjectMetadataRelationId);
1993
1994                         lo_res = PQexec(g_conn, loFrozenQry->data);
1995                         check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
1996
1997                         if (PQntuples(lo_res) != 1)
1998                         {
1999                                 write_msg(NULL, "dumpDatabase(): could not find pg_largeobject_metadata.relfrozenxid\n");
2000                                 exit_nicely();
2001                         }
2002
2003                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2004
2005                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2006                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2007                                                           "SET relfrozenxid = '%u'\n"
2008                                                           "WHERE oid = %u;\n",
2009                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2010                                                           LargeObjectMetadataRelationId);
2011                         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2012                                                  "pg_largeobject_metadata", NULL, NULL, "",
2013                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2014                                                  loOutQry->data, "", NULL,
2015                                                  NULL, 0,
2016                                                  NULL, NULL);
2017
2018                         PQclear(lo_res);
2019                 }
2020
2021                 destroyPQExpBuffer(loFrozenQry);
2022                 destroyPQExpBuffer(loOutQry);
2023         }
2024
2025         /* Dump DB comment if any */
2026         if (g_fout->remoteVersion >= 80200)
2027         {
2028                 /*
2029                  * 8.2 keeps comments on shared objects in a shared table, so we
2030                  * cannot use the dumpComment used for other database objects.
2031                  */
2032                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2033
2034                 if (comment && strlen(comment))
2035                 {
2036                         resetPQExpBuffer(dbQry);
2037
2038                         /*
2039                          * Generates warning when loaded into a differently-named
2040                          * database.
2041                          */
2042                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2043                         appendStringLiteralAH(dbQry, comment, AH);
2044                         appendPQExpBuffer(dbQry, ";\n");
2045
2046                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
2047                                                  dba, false, "COMMENT", SECTION_NONE,
2048                                                  dbQry->data, "", NULL,
2049                                                  &dbDumpId, 1, NULL, NULL);
2050                 }
2051         }
2052         else
2053         {
2054                 resetPQExpBuffer(dbQry);
2055                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2056                 dumpComment(AH, dbQry->data, NULL, "",
2057                                         dbCatId, 0, dbDumpId);
2058         }
2059
2060         PQclear(res);
2061
2062         /* Dump shared security label. */
2063         if (!no_security_labels && g_fout->remoteVersion >= 90200)
2064         {
2065                 PQExpBuffer seclabelQry = createPQExpBuffer();
2066
2067                 buildShSecLabelQuery(g_conn, "pg_database", dbCatId.oid, seclabelQry);
2068                 res = PQexec(g_conn, seclabelQry->data);
2069                 check_sql_result(res, g_conn, seclabelQry->data, PGRES_TUPLES_OK);
2070                 resetPQExpBuffer(seclabelQry);
2071                 emitShSecLabels(g_conn, res, seclabelQry, "DATABASE", datname);
2072                 if (strlen(seclabelQry->data))
2073                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
2074                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2075                                                  seclabelQry->data, "", NULL,
2076                                                  &dbDumpId, 1, NULL, NULL);
2077                 destroyPQExpBuffer(seclabelQry);
2078         }
2079
2080         destroyPQExpBuffer(dbQry);
2081         destroyPQExpBuffer(delQry);
2082         destroyPQExpBuffer(creaQry);
2083 }
2084
2085
2086 /*
2087  * dumpEncoding: put the correct encoding into the archive
2088  */
2089 static void
2090 dumpEncoding(Archive *AH)
2091 {
2092         const char *encname = pg_encoding_to_char(AH->encoding);
2093         PQExpBuffer qry = createPQExpBuffer();
2094
2095         if (g_verbose)
2096                 write_msg(NULL, "saving encoding = %s\n", encname);
2097
2098         appendPQExpBuffer(qry, "SET client_encoding = ");
2099         appendStringLiteralAH(qry, encname, AH);
2100         appendPQExpBuffer(qry, ";\n");
2101
2102         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2103                                  "ENCODING", NULL, NULL, "",
2104                                  false, "ENCODING", SECTION_PRE_DATA,
2105                                  qry->data, "", NULL,
2106                                  NULL, 0,
2107                                  NULL, NULL);
2108
2109         destroyPQExpBuffer(qry);
2110 }
2111
2112
2113 /*
2114  * dumpStdStrings: put the correct escape string behavior into the archive
2115  */
2116 static void
2117 dumpStdStrings(Archive *AH)
2118 {
2119         const char *stdstrings = AH->std_strings ? "on" : "off";
2120         PQExpBuffer qry = createPQExpBuffer();
2121
2122         if (g_verbose)
2123                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2124                                   stdstrings);
2125
2126         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2127                                           stdstrings);
2128
2129         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2130                                  "STDSTRINGS", NULL, NULL, "",
2131                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2132                                  qry->data, "", NULL,
2133                                  NULL, 0,
2134                                  NULL, NULL);
2135
2136         destroyPQExpBuffer(qry);
2137 }
2138
2139
2140 /*
2141  * getBlobs:
2142  *      Collect schema-level data about large objects
2143  */
2144 static void
2145 getBlobs(Archive *AH)
2146 {
2147         PQExpBuffer blobQry = createPQExpBuffer();
2148         BlobInfo   *binfo;
2149         DumpableObject *bdata;
2150         PGresult   *res;
2151         int                     ntups;
2152         int                     i;
2153
2154         /* Verbose message */
2155         if (g_verbose)
2156                 write_msg(NULL, "reading large objects\n");
2157
2158         /* Make sure we are in proper schema */
2159         selectSourceSchema("pg_catalog");
2160
2161         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2162         if (AH->remoteVersion >= 90000)
2163                 appendPQExpBuffer(blobQry,
2164                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2165                                                   " FROM pg_largeobject_metadata",
2166                                                   username_subquery);
2167         else if (AH->remoteVersion >= 70100)
2168                 appendPQExpBuffer(blobQry,
2169                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2170                                                   " FROM pg_largeobject");
2171         else
2172                 appendPQExpBuffer(blobQry,
2173                                                   "SELECT oid, NULL::oid, NULL::oid"
2174                                                   " FROM pg_class WHERE relkind = 'l'");
2175
2176         res = PQexec(g_conn, blobQry->data);
2177         check_sql_result(res, g_conn, blobQry->data, PGRES_TUPLES_OK);
2178
2179         ntups = PQntuples(res);
2180         if (ntups > 0)
2181         {
2182                 /*
2183                  * Each large object has its own BLOB archive entry.
2184                  */
2185                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2186
2187                 for (i = 0; i < ntups; i++)
2188                 {
2189                         binfo[i].dobj.objType = DO_BLOB;
2190                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2191                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2192                         AssignDumpId(&binfo[i].dobj);
2193
2194                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2195                         if (!PQgetisnull(res, i, 1))
2196                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2197                         else
2198                                 binfo[i].rolname = "";
2199                         if (!PQgetisnull(res, i, 2))
2200                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2201                         else
2202                                 binfo[i].blobacl = NULL;
2203                 }
2204
2205                 /*
2206                  * If we have any large objects, a "BLOBS" archive entry is needed.
2207                  * This is just a placeholder for sorting; it carries no data now.
2208                  */
2209                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2210                 bdata->objType = DO_BLOB_DATA;
2211                 bdata->catId = nilCatalogId;
2212                 AssignDumpId(bdata);
2213                 bdata->name = pg_strdup("BLOBS");
2214         }
2215
2216         PQclear(res);
2217         destroyPQExpBuffer(blobQry);
2218 }
2219
2220 /*
2221  * dumpBlob
2222  *
2223  * dump the definition (metadata) of the given large object
2224  */
2225 static void
2226 dumpBlob(Archive *AH, BlobInfo *binfo)
2227 {
2228         PQExpBuffer cquery = createPQExpBuffer();
2229         PQExpBuffer dquery = createPQExpBuffer();
2230
2231         appendPQExpBuffer(cquery,
2232                                           "SELECT pg_catalog.lo_create('%s');\n",
2233                                           binfo->dobj.name);
2234
2235         appendPQExpBuffer(dquery,
2236                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2237                                           binfo->dobj.name);
2238
2239         ArchiveEntry(AH, binfo->dobj.catId, binfo->dobj.dumpId,
2240                                  binfo->dobj.name,
2241                                  NULL, NULL,
2242                                  binfo->rolname, false,
2243                                  "BLOB", SECTION_PRE_DATA,
2244                                  cquery->data, dquery->data, NULL,
2245                                  binfo->dobj.dependencies, binfo->dobj.nDeps,
2246                                  NULL, NULL);
2247
2248         /* set up tag for comment and/or ACL */
2249         resetPQExpBuffer(cquery);
2250         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2251
2252         /* Dump comment if any */
2253         dumpComment(AH, cquery->data,
2254                                 NULL, binfo->rolname,
2255                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2256
2257         /* Dump security label if any */
2258         dumpSecLabel(AH, cquery->data,
2259                                  NULL, binfo->rolname,
2260                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2261
2262         /* Dump ACL if any */
2263         if (binfo->blobacl)
2264                 dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2265                                 binfo->dobj.name, NULL, cquery->data,
2266                                 NULL, binfo->rolname, binfo->blobacl);
2267
2268         destroyPQExpBuffer(cquery);
2269         destroyPQExpBuffer(dquery);
2270 }
2271
2272 /*
2273  * dumpBlobs:
2274  *      dump the data contents of all large objects
2275  */
2276 static int
2277 dumpBlobs(Archive *AH, void *arg)
2278 {
2279         const char *blobQry;
2280         const char *blobFetchQry;
2281         PGresult   *res;
2282         char            buf[LOBBUFSIZE];
2283         int                     ntups;
2284         int                     i;
2285         int                     cnt;
2286
2287         if (g_verbose)
2288                 write_msg(NULL, "saving large objects\n");
2289
2290         /* Make sure we are in proper schema */
2291         selectSourceSchema("pg_catalog");
2292
2293         /*
2294          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2295          * the already-in-memory dumpable objects instead...
2296          */
2297         if (AH->remoteVersion >= 90000)
2298                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2299         else if (AH->remoteVersion >= 70100)
2300                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2301         else
2302                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2303
2304         res = PQexec(g_conn, blobQry);
2305         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2306
2307         /* Command to fetch from cursor */
2308         blobFetchQry = "FETCH 1000 IN bloboid";
2309
2310         do
2311         {
2312                 PQclear(res);
2313
2314                 /* Do a fetch */
2315                 res = PQexec(g_conn, blobFetchQry);
2316                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2317
2318                 /* Process the tuples, if any */
2319                 ntups = PQntuples(res);
2320                 for (i = 0; i < ntups; i++)
2321                 {
2322                         Oid                     blobOid;
2323                         int                     loFd;
2324
2325                         blobOid = atooid(PQgetvalue(res, i, 0));
2326                         /* Open the BLOB */
2327                         loFd = lo_open(g_conn, blobOid, INV_READ);
2328                         if (loFd == -1)
2329                         {
2330                                 write_msg(NULL, "could not open large object %u: %s",
2331                                                   blobOid, PQerrorMessage(g_conn));
2332                                 exit_nicely();
2333                         }
2334
2335                         StartBlob(AH, blobOid);
2336
2337                         /* Now read it in chunks, sending data to archive */
2338                         do
2339                         {
2340                                 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
2341                                 if (cnt < 0)
2342                                 {
2343                                         write_msg(NULL, "error reading large object %u: %s",
2344                                                           blobOid, PQerrorMessage(g_conn));
2345                                         exit_nicely();
2346                                 }
2347
2348                                 WriteData(AH, buf, cnt);
2349                         } while (cnt > 0);
2350
2351                         lo_close(g_conn, loFd);
2352
2353                         EndBlob(AH, blobOid);
2354                 }
2355         } while (ntups > 0);
2356
2357         PQclear(res);
2358
2359         return 1;
2360 }
2361
2362 static void
2363 binary_upgrade_set_type_oids_by_type_oid(PQExpBuffer upgrade_buffer,
2364                                                                                  Oid pg_type_oid)
2365 {
2366         PQExpBuffer upgrade_query = createPQExpBuffer();
2367         int                     ntups;
2368         PGresult   *upgrade_res;
2369         Oid                     pg_type_array_oid;
2370
2371         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2372         appendPQExpBuffer(upgrade_buffer,
2373          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2374                                           pg_type_oid);
2375
2376         /* we only support old >= 8.3 for binary upgrades */
2377         appendPQExpBuffer(upgrade_query,
2378                                           "SELECT typarray "
2379                                           "FROM pg_catalog.pg_type "
2380                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2381                                           pg_type_oid);
2382
2383         upgrade_res = PQexec(g_conn, upgrade_query->data);
2384         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2385
2386         /* Expecting a single result only */
2387         ntups = PQntuples(upgrade_res);
2388         if (ntups != 1)
2389         {
2390                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2391                                                            "query returned %d rows instead of one: %s\n",
2392                                                                  ntups),
2393                                   ntups, upgrade_query->data);
2394                 exit_nicely();
2395         }
2396
2397         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2398
2399         if (OidIsValid(pg_type_array_oid))
2400         {
2401                 appendPQExpBuffer(upgrade_buffer,
2402                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2403                 appendPQExpBuffer(upgrade_buffer,
2404                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2405                                                   pg_type_array_oid);
2406         }
2407
2408         PQclear(upgrade_res);
2409         destroyPQExpBuffer(upgrade_query);
2410 }
2411
2412 static bool
2413 binary_upgrade_set_type_oids_by_rel_oid(PQExpBuffer upgrade_buffer,
2414                                                                                 Oid pg_rel_oid)
2415 {
2416         PQExpBuffer upgrade_query = createPQExpBuffer();
2417         int                     ntups;
2418         PGresult   *upgrade_res;
2419         Oid                     pg_type_oid;
2420         bool            toast_set = false;
2421
2422         /* we only support old >= 8.3 for binary upgrades */
2423         appendPQExpBuffer(upgrade_query,
2424                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2425                                           "FROM pg_catalog.pg_class c "
2426                                           "LEFT JOIN pg_catalog.pg_class t ON "
2427                                           "  (c.reltoastrelid = t.oid) "
2428                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2429                                           pg_rel_oid);
2430
2431         upgrade_res = PQexec(g_conn, upgrade_query->data);
2432         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2433
2434         /* Expecting a single result only */
2435         ntups = PQntuples(upgrade_res);
2436         if (ntups != 1)
2437         {
2438                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2439                                                            "query returned %d rows instead of one: %s\n",
2440                                                                  ntups),
2441                                   ntups, upgrade_query->data);
2442                 exit_nicely();
2443         }
2444
2445         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2446
2447         binary_upgrade_set_type_oids_by_type_oid(upgrade_buffer, pg_type_oid);
2448
2449         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2450         {
2451                 /* Toast tables do not have pg_type array rows */
2452                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2453                                                                                         PQfnumber(upgrade_res, "trel")));
2454
2455                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2456                 appendPQExpBuffer(upgrade_buffer,
2457                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2458                                                   pg_type_toast_oid);
2459
2460                 toast_set = true;
2461         }
2462
2463         PQclear(upgrade_res);
2464         destroyPQExpBuffer(upgrade_query);
2465
2466         return toast_set;
2467 }
2468
2469 static void
2470 binary_upgrade_set_pg_class_oids(PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2471                                                                  bool is_index)
2472 {
2473         PQExpBuffer upgrade_query = createPQExpBuffer();
2474         int                     ntups;
2475         PGresult   *upgrade_res;
2476         Oid                     pg_class_reltoastrelid;
2477         Oid                     pg_class_reltoastidxid;
2478
2479         appendPQExpBuffer(upgrade_query,
2480                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2481                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2482                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2483                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2484                                           pg_class_oid);
2485
2486         upgrade_res = PQexec(g_conn, upgrade_query->data);
2487         check_sql_result(upgrade_res, g_conn, upgrade_query->data, PGRES_TUPLES_OK);
2488
2489         /* Expecting a single result only */
2490         ntups = PQntuples(upgrade_res);
2491         if (ntups != 1)
2492         {
2493                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
2494                                                            "query returned %d rows instead of one: %s\n",
2495                                                                  ntups),
2496                                   ntups, upgrade_query->data);
2497                 exit_nicely();
2498         }
2499
2500         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2501         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2502
2503         appendPQExpBuffer(upgrade_buffer,
2504                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2505
2506         if (!is_index)
2507         {
2508                 appendPQExpBuffer(upgrade_buffer,
2509                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2510                                                   pg_class_oid);
2511                 /* only tables have toast tables, not indexes */
2512                 if (OidIsValid(pg_class_reltoastrelid))
2513                 {
2514                         /*
2515                          * One complexity is that the table definition might not require
2516                          * the creation of a TOAST table, and the TOAST table might have
2517                          * been created long after table creation, when the table was
2518                          * loaded with wide data.  By setting the TOAST oid we force
2519                          * creation of the TOAST heap and TOAST index by the backend so we
2520                          * can cleanly copy the files during binary upgrade.
2521                          */
2522
2523                         appendPQExpBuffer(upgrade_buffer,
2524                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2525                                                           pg_class_reltoastrelid);
2526
2527                         /* every toast table has an index */
2528                         appendPQExpBuffer(upgrade_buffer,
2529                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2530                                                           pg_class_reltoastidxid);
2531                 }
2532         }
2533         else
2534                 appendPQExpBuffer(upgrade_buffer,
2535                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2536                                                   pg_class_oid);
2537
2538         appendPQExpBuffer(upgrade_buffer, "\n");
2539
2540         PQclear(upgrade_res);
2541         destroyPQExpBuffer(upgrade_query);
2542 }
2543
2544 /*
2545  * If the DumpableObject is a member of an extension, add a suitable
2546  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2547  */
2548 static void
2549 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2550                                                                 DumpableObject *dobj,
2551                                                                 const char *objlabel)
2552 {
2553         DumpableObject *extobj = NULL;
2554         int                     i;
2555
2556         if (!dobj->ext_member)
2557                 return;
2558
2559         /*
2560          * Find the parent extension.  We could avoid this search if we wanted to
2561          * add a link field to DumpableObject, but the space costs of that would
2562          * be considerable.  We assume that member objects could only have a
2563          * direct dependency on their own extension, not any others.
2564          */
2565         for (i = 0; i < dobj->nDeps; i++)
2566         {
2567                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2568                 if (extobj && extobj->objType == DO_EXTENSION)
2569                         break;
2570                 extobj = NULL;
2571         }
2572         if (extobj == NULL)
2573         {
2574                 write_msg(NULL, "could not find parent extension for %s", objlabel);
2575                 exit_nicely();
2576         }
2577
2578         appendPQExpBuffer(upgrade_buffer,
2579           "\n-- For binary upgrade, handle extension membership the hard way\n");
2580         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2581                                           fmtId(extobj->name),
2582                                           objlabel);
2583 }
2584
2585 /*
2586  * getNamespaces:
2587  *        read all namespaces in the system catalogs and return them in the
2588  * NamespaceInfo* structure
2589  *
2590  *      numNamespaces is set to the number of namespaces read in
2591  */
2592 NamespaceInfo *
2593 getNamespaces(int *numNamespaces)
2594 {
2595         PGresult   *res;
2596         int                     ntups;
2597         int                     i;
2598         PQExpBuffer query;
2599         NamespaceInfo *nsinfo;
2600         int                     i_tableoid;
2601         int                     i_oid;
2602         int                     i_nspname;
2603         int                     i_rolname;
2604         int                     i_nspacl;
2605
2606         /*
2607          * Before 7.3, there are no real namespaces; create two dummy entries, one
2608          * for user stuff and one for system stuff.
2609          */
2610         if (g_fout->remoteVersion < 70300)
2611         {
2612                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2613
2614                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2615                 nsinfo[0].dobj.catId.tableoid = 0;
2616                 nsinfo[0].dobj.catId.oid = 0;
2617                 AssignDumpId(&nsinfo[0].dobj);
2618                 nsinfo[0].dobj.name = pg_strdup("public");
2619                 nsinfo[0].rolname = pg_strdup("");
2620                 nsinfo[0].nspacl = pg_strdup("");
2621
2622                 selectDumpableNamespace(&nsinfo[0]);
2623
2624                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2625                 nsinfo[1].dobj.catId.tableoid = 0;
2626                 nsinfo[1].dobj.catId.oid = 1;
2627                 AssignDumpId(&nsinfo[1].dobj);
2628                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2629                 nsinfo[1].rolname = pg_strdup("");
2630                 nsinfo[1].nspacl = pg_strdup("");
2631
2632                 selectDumpableNamespace(&nsinfo[1]);
2633
2634                 g_namespaces = nsinfo;
2635                 g_numNamespaces = *numNamespaces = 2;
2636
2637                 return nsinfo;
2638         }
2639
2640         query = createPQExpBuffer();
2641
2642         /* Make sure we are in proper schema */
2643         selectSourceSchema("pg_catalog");
2644
2645         /*
2646          * we fetch all namespaces including system ones, so that every object we
2647          * read in can be linked to a containing namespace.
2648          */
2649         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2650                                           "(%s nspowner) AS rolname, "
2651                                           "nspacl FROM pg_namespace",
2652                                           username_subquery);
2653
2654         res = PQexec(g_conn, query->data);
2655         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2656
2657         ntups = PQntuples(res);
2658
2659         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2660
2661         i_tableoid = PQfnumber(res, "tableoid");
2662         i_oid = PQfnumber(res, "oid");
2663         i_nspname = PQfnumber(res, "nspname");
2664         i_rolname = PQfnumber(res, "rolname");
2665         i_nspacl = PQfnumber(res, "nspacl");
2666
2667         for (i = 0; i < ntups; i++)
2668         {
2669                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2670                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2671                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2672                 AssignDumpId(&nsinfo[i].dobj);
2673                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2674                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2675                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2676
2677                 /* Decide whether to dump this namespace */
2678                 selectDumpableNamespace(&nsinfo[i]);
2679
2680                 if (strlen(nsinfo[i].rolname) == 0)
2681                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2682                                           nsinfo[i].dobj.name);
2683         }
2684
2685         PQclear(res);
2686         destroyPQExpBuffer(query);
2687
2688         g_namespaces = nsinfo;
2689         g_numNamespaces = *numNamespaces = ntups;
2690
2691         return nsinfo;
2692 }
2693
2694 /*
2695  * findNamespace:
2696  *              given a namespace OID and an object OID, look up the info read by
2697  *              getNamespaces
2698  *
2699  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2700  * a system object or not.      In 7.3 and later there is no guessing.
2701  */
2702 static NamespaceInfo *
2703 findNamespace(Oid nsoid, Oid objoid)
2704 {
2705         int                     i;
2706
2707         if (g_fout->remoteVersion >= 70300)
2708         {
2709                 for (i = 0; i < g_numNamespaces; i++)
2710                 {
2711                         NamespaceInfo *nsinfo = &g_namespaces[i];
2712
2713                         if (nsoid == nsinfo->dobj.catId.oid)
2714                                 return nsinfo;
2715                 }
2716                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2717                 exit_nicely();
2718         }
2719         else
2720         {
2721                 /* This code depends on the layout set up by getNamespaces. */
2722                 if (objoid > g_last_builtin_oid)
2723                         i = 0;                          /* user object */
2724                 else
2725                         i = 1;                          /* system object */
2726                 return &g_namespaces[i];
2727         }
2728
2729         return NULL;                            /* keep compiler quiet */
2730 }
2731
2732 /*
2733  * getExtensions:
2734  *        read all extensions in the system catalogs and return them in the
2735  * ExtensionInfo* structure
2736  *
2737  *      numExtensions is set to the number of extensions read in
2738  */
2739 ExtensionInfo *
2740 getExtensions(int *numExtensions)
2741 {
2742         PGresult   *res;
2743         int                     ntups;
2744         int                     i;
2745         PQExpBuffer query;
2746         ExtensionInfo *extinfo;
2747         int                     i_tableoid;
2748         int                     i_oid;
2749         int                     i_extname;
2750         int                     i_nspname;
2751         int                     i_extrelocatable;
2752         int                     i_extversion;
2753         int                     i_extconfig;
2754         int                     i_extcondition;
2755
2756         /*
2757          * Before 9.1, there are no extensions.
2758          */
2759         if (g_fout->remoteVersion < 90100)
2760         {
2761                 *numExtensions = 0;
2762                 return NULL;
2763         }
2764
2765         query = createPQExpBuffer();
2766
2767         /* Make sure we are in proper schema */
2768         selectSourceSchema("pg_catalog");
2769
2770         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
2771                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
2772                                           "FROM pg_extension x "
2773                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
2774
2775         res = PQexec(g_conn, query->data);
2776         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2777
2778         ntups = PQntuples(res);
2779
2780         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
2781
2782         i_tableoid = PQfnumber(res, "tableoid");
2783         i_oid = PQfnumber(res, "oid");
2784         i_extname = PQfnumber(res, "extname");
2785         i_nspname = PQfnumber(res, "nspname");
2786         i_extrelocatable = PQfnumber(res, "extrelocatable");
2787         i_extversion = PQfnumber(res, "extversion");
2788         i_extconfig = PQfnumber(res, "extconfig");
2789         i_extcondition = PQfnumber(res, "extcondition");
2790
2791         for (i = 0; i < ntups; i++)
2792         {
2793                 extinfo[i].dobj.objType = DO_EXTENSION;
2794                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2795                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2796                 AssignDumpId(&extinfo[i].dobj);
2797                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
2798                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
2799                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
2800                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
2801                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
2802                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
2803
2804                 /* Decide whether we want to dump it */
2805                 selectDumpableExtension(&(extinfo[i]));
2806         }
2807
2808         PQclear(res);
2809         destroyPQExpBuffer(query);
2810
2811         *numExtensions = ntups;
2812
2813         return extinfo;
2814 }
2815
2816 /*
2817  * getTypes:
2818  *        read all types in the system catalogs and return them in the
2819  * TypeInfo* structure
2820  *
2821  *      numTypes is set to the number of types read in
2822  *
2823  * NB: this must run after getFuncs() because we assume we can do
2824  * findFuncByOid().
2825  */
2826 TypeInfo *
2827 getTypes(int *numTypes)
2828 {
2829         PGresult   *res;
2830         int                     ntups;
2831         int                     i;
2832         PQExpBuffer query = createPQExpBuffer();
2833         TypeInfo   *tyinfo;
2834         ShellTypeInfo *stinfo;
2835         int                     i_tableoid;
2836         int                     i_oid;
2837         int                     i_typname;
2838         int                     i_typnamespace;
2839         int                     i_rolname;
2840         int                     i_typinput;
2841         int                     i_typoutput;
2842         int                     i_typelem;
2843         int                     i_typrelid;
2844         int                     i_typrelkind;
2845         int                     i_typtype;
2846         int                     i_typisdefined;
2847         int                     i_isarray;
2848
2849         /*
2850          * we include even the built-in types because those may be used as array
2851          * elements by user-defined types
2852          *
2853          * we filter out the built-in types when we dump out the types
2854          *
2855          * same approach for undefined (shell) types and array types
2856          *
2857          * Note: as of 8.3 we can reliably detect whether a type is an
2858          * auto-generated array type by checking the element type's typarray.
2859          * (Before that the test is capable of generating false positives.) We
2860          * still check for name beginning with '_', though, so as to avoid the
2861          * cost of the subselect probe for all standard types.  This would have to
2862          * be revisited if the backend ever allows renaming of array types.
2863          */
2864
2865         /* Make sure we are in proper schema */
2866         selectSourceSchema("pg_catalog");
2867
2868         if (g_fout->remoteVersion >= 80300)
2869         {
2870                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2871                                                   "typnamespace, "
2872                                                   "(%s typowner) AS rolname, "
2873                                                   "typinput::oid AS typinput, "
2874                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2875                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2876                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2877                                                   "typtype, typisdefined, "
2878                                                   "typname[0] = '_' AND typelem != 0 AND "
2879                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2880                                                   "FROM pg_type",
2881                                                   username_subquery);
2882         }
2883         else if (g_fout->remoteVersion >= 70300)
2884         {
2885                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2886                                                   "typnamespace, "
2887                                                   "(%s typowner) AS rolname, "
2888                                                   "typinput::oid AS typinput, "
2889                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2890                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2891                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2892                                                   "typtype, typisdefined, "
2893                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2894                                                   "FROM pg_type",
2895                                                   username_subquery);
2896         }
2897         else if (g_fout->remoteVersion >= 70100)
2898         {
2899                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2900                                                   "0::oid AS typnamespace, "
2901                                                   "(%s typowner) AS rolname, "
2902                                                   "typinput::oid AS typinput, "
2903                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2904                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2905                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2906                                                   "typtype, typisdefined, "
2907                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2908                                                   "FROM pg_type",
2909                                                   username_subquery);
2910         }
2911         else
2912         {
2913                 appendPQExpBuffer(query, "SELECT "
2914                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2915                                                   "oid, typname, "
2916                                                   "0::oid AS typnamespace, "
2917                                                   "(%s typowner) AS rolname, "
2918                                                   "typinput::oid AS typinput, "
2919                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2920                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2921                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2922                                                   "typtype, typisdefined, "
2923                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2924                                                   "FROM pg_type",
2925                                                   username_subquery);
2926         }
2927
2928         res = PQexec(g_conn, query->data);
2929         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2930
2931         ntups = PQntuples(res);
2932
2933         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
2934
2935         i_tableoid = PQfnumber(res, "tableoid");
2936         i_oid = PQfnumber(res, "oid");
2937         i_typname = PQfnumber(res, "typname");
2938         i_typnamespace = PQfnumber(res, "typnamespace");
2939         i_rolname = PQfnumber(res, "rolname");
2940         i_typinput = PQfnumber(res, "typinput");
2941         i_typoutput = PQfnumber(res, "typoutput");
2942         i_typelem = PQfnumber(res, "typelem");
2943         i_typrelid = PQfnumber(res, "typrelid");
2944         i_typrelkind = PQfnumber(res, "typrelkind");
2945         i_typtype = PQfnumber(res, "typtype");
2946         i_typisdefined = PQfnumber(res, "typisdefined");
2947         i_isarray = PQfnumber(res, "isarray");
2948
2949         for (i = 0; i < ntups; i++)
2950         {
2951                 tyinfo[i].dobj.objType = DO_TYPE;
2952                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2953                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2954                 AssignDumpId(&tyinfo[i].dobj);
2955                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
2956                 tyinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2957                                                                                                  tyinfo[i].dobj.catId.oid);
2958                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2959                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2960                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2961                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2962                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2963                 tyinfo[i].shellType = NULL;
2964
2965                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2966                         tyinfo[i].isDefined = true;
2967                 else
2968                         tyinfo[i].isDefined = false;
2969
2970                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2971                         tyinfo[i].isArray = true;
2972                 else
2973                         tyinfo[i].isArray = false;
2974
2975                 /* Decide whether we want to dump it */
2976                 selectDumpableType(&tyinfo[i]);
2977
2978                 /*
2979                  * If it's a domain, fetch info about its constraints, if any
2980                  */
2981                 tyinfo[i].nDomChecks = 0;
2982                 tyinfo[i].domChecks = NULL;
2983                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
2984                         getDomainConstraints(&(tyinfo[i]));
2985
2986                 /*
2987                  * If it's a base type, make a DumpableObject representing a shell
2988                  * definition of the type.      We will need to dump that ahead of the I/O
2989                  * functions for the type.  Similarly, range types need a shell
2990                  * definition in case they have a canonicalize function.
2991                  *
2992                  * Note: the shell type doesn't have a catId.  You might think it
2993                  * should copy the base type's catId, but then it might capture the
2994                  * pg_depend entries for the type, which we don't want.
2995                  */
2996                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
2997                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
2998                 {
2999                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3000                         stinfo->dobj.objType = DO_SHELL_TYPE;
3001                         stinfo->dobj.catId = nilCatalogId;
3002                         AssignDumpId(&stinfo->dobj);
3003                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3004                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3005                         stinfo->baseType = &(tyinfo[i]);
3006                         tyinfo[i].shellType = stinfo;
3007
3008                         /*
3009                          * Initially mark the shell type as not to be dumped.  We'll only
3010                          * dump it if the I/O or canonicalize functions need to be dumped;
3011                          * this is taken care of while sorting dependencies.
3012                          */
3013                         stinfo->dobj.dump = false;
3014
3015                         /*
3016                          * However, if dumping from pre-7.3, there will be no dependency
3017                          * info so we have to fake it here.  We only need to worry about
3018                          * typinput and typoutput since the other functions only exist
3019                          * post-7.3.
3020                          */
3021                         if (g_fout->remoteVersion < 70300)
3022                         {
3023                                 Oid                     typinput;
3024                                 Oid                     typoutput;
3025                                 FuncInfo   *funcInfo;
3026
3027                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3028                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3029
3030                                 funcInfo = findFuncByOid(typinput);
3031                                 if (funcInfo && funcInfo->dobj.dump)
3032                                 {
3033                                         /* base type depends on function */
3034                                         addObjectDependency(&tyinfo[i].dobj,
3035                                                                                 funcInfo->dobj.dumpId);
3036                                         /* function depends on shell type */
3037                                         addObjectDependency(&funcInfo->dobj,
3038                                                                                 stinfo->dobj.dumpId);
3039                                         /* mark shell type as to be dumped */
3040                                         stinfo->dobj.dump = true;
3041                                 }
3042
3043                                 funcInfo = findFuncByOid(typoutput);
3044                                 if (funcInfo && funcInfo->dobj.dump)
3045                                 {
3046                                         /* base type depends on function */
3047                                         addObjectDependency(&tyinfo[i].dobj,
3048                                                                                 funcInfo->dobj.dumpId);
3049                                         /* function depends on shell type */
3050                                         addObjectDependency(&funcInfo->dobj,
3051                                                                                 stinfo->dobj.dumpId);
3052                                         /* mark shell type as to be dumped */
3053                                         stinfo->dobj.dump = true;
3054                                 }
3055                         }
3056                 }
3057
3058                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3059                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3060                                           tyinfo[i].dobj.name);
3061         }
3062
3063         *numTypes = ntups;
3064
3065         PQclear(res);
3066
3067         destroyPQExpBuffer(query);
3068
3069         return tyinfo;
3070 }
3071
3072 /*
3073  * getOperators:
3074  *        read all operators in the system catalogs and return them in the
3075  * OprInfo* structure
3076  *
3077  *      numOprs is set to the number of operators read in
3078  */
3079 OprInfo *
3080 getOperators(int *numOprs)
3081 {
3082         PGresult   *res;
3083         int                     ntups;
3084         int                     i;
3085         PQExpBuffer query = createPQExpBuffer();
3086         OprInfo    *oprinfo;
3087         int                     i_tableoid;
3088         int                     i_oid;
3089         int                     i_oprname;
3090         int                     i_oprnamespace;
3091         int                     i_rolname;
3092         int                     i_oprcode;
3093
3094         /*
3095          * find all operators, including builtin operators; we filter out
3096          * system-defined operators at dump-out time.
3097          */
3098
3099         /* Make sure we are in proper schema */
3100         selectSourceSchema("pg_catalog");
3101
3102         if (g_fout->remoteVersion >= 70300)
3103         {
3104                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3105                                                   "oprnamespace, "
3106                                                   "(%s oprowner) AS rolname, "
3107                                                   "oprcode::oid AS oprcode "
3108                                                   "FROM pg_operator",
3109                                                   username_subquery);
3110         }
3111         else if (g_fout->remoteVersion >= 70100)
3112         {
3113                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3114                                                   "0::oid AS oprnamespace, "
3115                                                   "(%s oprowner) AS rolname, "
3116                                                   "oprcode::oid AS oprcode "
3117                                                   "FROM pg_operator",
3118                                                   username_subquery);
3119         }
3120         else
3121         {
3122                 appendPQExpBuffer(query, "SELECT "
3123                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3124                                                   "oid, oprname, "
3125                                                   "0::oid AS oprnamespace, "
3126                                                   "(%s oprowner) AS rolname, "
3127                                                   "oprcode::oid AS oprcode "
3128                                                   "FROM pg_operator",
3129                                                   username_subquery);
3130         }
3131
3132         res = PQexec(g_conn, query->data);
3133         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3134
3135         ntups = PQntuples(res);
3136         *numOprs = ntups;
3137
3138         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3139
3140         i_tableoid = PQfnumber(res, "tableoid");
3141         i_oid = PQfnumber(res, "oid");
3142         i_oprname = PQfnumber(res, "oprname");
3143         i_oprnamespace = PQfnumber(res, "oprnamespace");
3144         i_rolname = PQfnumber(res, "rolname");
3145         i_oprcode = PQfnumber(res, "oprcode");
3146
3147         for (i = 0; i < ntups; i++)
3148         {
3149                 oprinfo[i].dobj.objType = DO_OPERATOR;
3150                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3151                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3152                 AssignDumpId(&oprinfo[i].dobj);
3153                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3154                 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
3155                                                                                                   oprinfo[i].dobj.catId.oid);
3156                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3157                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3158
3159                 /* Decide whether we want to dump it */
3160                 selectDumpableObject(&(oprinfo[i].dobj));
3161
3162                 if (strlen(oprinfo[i].rolname) == 0)
3163                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3164                                           oprinfo[i].dobj.name);
3165         }
3166
3167         PQclear(res);
3168
3169         destroyPQExpBuffer(query);
3170
3171         return oprinfo;
3172 }
3173
3174 /*
3175  * getCollations:
3176  *        read all collations in the system catalogs and return them in the
3177  * CollInfo* structure
3178  *
3179  *      numCollations is set to the number of collations read in
3180  */
3181 CollInfo *
3182 getCollations(int *numCollations)
3183 {
3184         PGresult   *res;
3185         int                     ntups;
3186         int                     i;
3187         PQExpBuffer query = createPQExpBuffer();
3188         CollInfo   *collinfo;
3189         int                     i_tableoid;
3190         int                     i_oid;
3191         int                     i_collname;
3192         int                     i_collnamespace;
3193         int                     i_rolname;
3194
3195         /* Collations didn't exist pre-9.1 */
3196         if (g_fout->remoteVersion < 90100)
3197         {
3198                 *numCollations = 0;
3199                 return NULL;
3200         }
3201
3202         /*
3203          * find all collations, including builtin collations; we filter out
3204          * system-defined collations at dump-out time.
3205          */
3206
3207         /* Make sure we are in proper schema */
3208         selectSourceSchema("pg_catalog");
3209
3210         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3211                                           "collnamespace, "
3212                                           "(%s collowner) AS rolname "
3213                                           "FROM pg_collation",
3214                                           username_subquery);
3215
3216         res = PQexec(g_conn, query->data);
3217         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3218
3219         ntups = PQntuples(res);
3220         *numCollations = ntups;
3221
3222         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3223
3224         i_tableoid = PQfnumber(res, "tableoid");
3225         i_oid = PQfnumber(res, "oid");
3226         i_collname = PQfnumber(res, "collname");
3227         i_collnamespace = PQfnumber(res, "collnamespace");
3228         i_rolname = PQfnumber(res, "rolname");
3229
3230         for (i = 0; i < ntups; i++)
3231         {
3232                 collinfo[i].dobj.objType = DO_COLLATION;
3233                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3234                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3235                 AssignDumpId(&collinfo[i].dobj);
3236                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3237                 collinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_collnamespace)),
3238                                                                                                  collinfo[i].dobj.catId.oid);
3239                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3240
3241                 /* Decide whether we want to dump it */
3242                 selectDumpableObject(&(collinfo[i].dobj));
3243         }
3244
3245         PQclear(res);
3246
3247         destroyPQExpBuffer(query);
3248
3249         return collinfo;
3250 }
3251
3252 /*
3253  * getConversions:
3254  *        read all conversions in the system catalogs and return them in the
3255  * ConvInfo* structure
3256  *
3257  *      numConversions is set to the number of conversions read in
3258  */
3259 ConvInfo *
3260 getConversions(int *numConversions)
3261 {
3262         PGresult   *res;
3263         int                     ntups;
3264         int                     i;
3265         PQExpBuffer query = createPQExpBuffer();
3266         ConvInfo   *convinfo;
3267         int                     i_tableoid;
3268         int                     i_oid;
3269         int                     i_conname;
3270         int                     i_connamespace;
3271         int                     i_rolname;
3272
3273         /* Conversions didn't exist pre-7.3 */
3274         if (g_fout->remoteVersion < 70300)
3275         {
3276                 *numConversions = 0;
3277                 return NULL;
3278         }
3279
3280         /*
3281          * find all conversions, including builtin conversions; we filter out
3282          * system-defined conversions at dump-out time.
3283          */
3284
3285         /* Make sure we are in proper schema */
3286         selectSourceSchema("pg_catalog");
3287
3288         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3289                                           "connamespace, "
3290                                           "(%s conowner) AS rolname "
3291                                           "FROM pg_conversion",
3292                                           username_subquery);
3293
3294         res = PQexec(g_conn, query->data);
3295         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3296
3297         ntups = PQntuples(res);
3298         *numConversions = ntups;
3299
3300         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3301
3302         i_tableoid = PQfnumber(res, "tableoid");
3303         i_oid = PQfnumber(res, "oid");
3304         i_conname = PQfnumber(res, "conname");
3305         i_connamespace = PQfnumber(res, "connamespace");
3306         i_rolname = PQfnumber(res, "rolname");
3307
3308         for (i = 0; i < ntups; i++)
3309         {
3310                 convinfo[i].dobj.objType = DO_CONVERSION;
3311                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3312                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3313                 AssignDumpId(&convinfo[i].dobj);
3314                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3315                 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
3316                                                                                                  convinfo[i].dobj.catId.oid);
3317                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3318
3319                 /* Decide whether we want to dump it */
3320                 selectDumpableObject(&(convinfo[i].dobj));
3321         }
3322
3323         PQclear(res);
3324
3325         destroyPQExpBuffer(query);
3326
3327         return convinfo;
3328 }
3329
3330 /*
3331  * getOpclasses:
3332  *        read all opclasses in the system catalogs and return them in the
3333  * OpclassInfo* structure
3334  *
3335  *      numOpclasses is set to the number of opclasses read in
3336  */
3337 OpclassInfo *
3338 getOpclasses(int *numOpclasses)
3339 {
3340         PGresult   *res;
3341         int                     ntups;
3342         int                     i;
3343         PQExpBuffer query = createPQExpBuffer();
3344         OpclassInfo *opcinfo;
3345         int                     i_tableoid;
3346         int                     i_oid;
3347         int                     i_opcname;
3348         int                     i_opcnamespace;
3349         int                     i_rolname;
3350
3351         /*
3352          * find all opclasses, including builtin opclasses; we filter out
3353          * system-defined opclasses at dump-out time.
3354          */
3355
3356         /* Make sure we are in proper schema */
3357         selectSourceSchema("pg_catalog");
3358
3359         if (g_fout->remoteVersion >= 70300)
3360         {
3361                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3362                                                   "opcnamespace, "
3363                                                   "(%s opcowner) AS rolname "
3364                                                   "FROM pg_opclass",
3365                                                   username_subquery);
3366         }
3367         else if (g_fout->remoteVersion >= 70100)
3368         {
3369                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3370                                                   "0::oid AS opcnamespace, "
3371                                                   "''::name AS rolname "
3372                                                   "FROM pg_opclass");
3373         }
3374         else
3375         {
3376                 appendPQExpBuffer(query, "SELECT "
3377                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3378                                                   "oid, opcname, "
3379                                                   "0::oid AS opcnamespace, "
3380                                                   "''::name AS rolname "
3381                                                   "FROM pg_opclass");
3382         }
3383
3384         res = PQexec(g_conn, query->data);
3385         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3386
3387         ntups = PQntuples(res);
3388         *numOpclasses = ntups;
3389
3390         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3391
3392         i_tableoid = PQfnumber(res, "tableoid");
3393         i_oid = PQfnumber(res, "oid");
3394         i_opcname = PQfnumber(res, "opcname");
3395         i_opcnamespace = PQfnumber(res, "opcnamespace");
3396         i_rolname = PQfnumber(res, "rolname");
3397
3398         for (i = 0; i < ntups; i++)
3399         {
3400                 opcinfo[i].dobj.objType = DO_OPCLASS;
3401                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3402                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3403                 AssignDumpId(&opcinfo[i].dobj);
3404                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3405                 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
3406                                                                                                   opcinfo[i].dobj.catId.oid);
3407                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3408
3409                 /* Decide whether we want to dump it */
3410                 selectDumpableObject(&(opcinfo[i].dobj));
3411
3412                 if (g_fout->remoteVersion >= 70300)
3413                 {
3414                         if (strlen(opcinfo[i].rolname) == 0)
3415                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3416                                                   opcinfo[i].dobj.name);
3417                 }
3418         }
3419
3420         PQclear(res);
3421
3422         destroyPQExpBuffer(query);
3423
3424         return opcinfo;
3425 }
3426
3427 /*
3428  * getOpfamilies:
3429  *        read all opfamilies in the system catalogs and return them in the
3430  * OpfamilyInfo* structure
3431  *
3432  *      numOpfamilies is set to the number of opfamilies read in
3433  */
3434 OpfamilyInfo *
3435 getOpfamilies(int *numOpfamilies)
3436 {
3437         PGresult   *res;
3438         int                     ntups;
3439         int                     i;
3440         PQExpBuffer query;
3441         OpfamilyInfo *opfinfo;
3442         int                     i_tableoid;
3443         int                     i_oid;
3444         int                     i_opfname;
3445         int                     i_opfnamespace;
3446         int                     i_rolname;
3447
3448         /* Before 8.3, there is no separate concept of opfamilies */
3449         if (g_fout->remoteVersion < 80300)
3450         {
3451                 *numOpfamilies = 0;
3452                 return NULL;
3453         }
3454
3455         query = createPQExpBuffer();
3456
3457         /*
3458          * find all opfamilies, including builtin opfamilies; we filter out
3459          * system-defined opfamilies at dump-out time.
3460          */
3461
3462         /* Make sure we are in proper schema */
3463         selectSourceSchema("pg_catalog");
3464
3465         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3466                                           "opfnamespace, "
3467                                           "(%s opfowner) AS rolname "
3468                                           "FROM pg_opfamily",
3469                                           username_subquery);
3470
3471         res = PQexec(g_conn, query->data);
3472         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3473
3474         ntups = PQntuples(res);
3475         *numOpfamilies = ntups;
3476
3477         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3478
3479         i_tableoid = PQfnumber(res, "tableoid");
3480         i_oid = PQfnumber(res, "oid");
3481         i_opfname = PQfnumber(res, "opfname");
3482         i_opfnamespace = PQfnumber(res, "opfnamespace");
3483         i_rolname = PQfnumber(res, "rolname");
3484
3485         for (i = 0; i < ntups; i++)
3486         {
3487                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3488                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3489                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3490                 AssignDumpId(&opfinfo[i].dobj);
3491                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3492                 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
3493                                                                                                   opfinfo[i].dobj.catId.oid);
3494                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3495
3496                 /* Decide whether we want to dump it */
3497                 selectDumpableObject(&(opfinfo[i].dobj));
3498
3499                 if (g_fout->remoteVersion >= 70300)
3500                 {
3501                         if (strlen(opfinfo[i].rolname) == 0)
3502                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3503                                                   opfinfo[i].dobj.name);
3504                 }
3505         }
3506
3507         PQclear(res);
3508
3509         destroyPQExpBuffer(query);
3510
3511         return opfinfo;
3512 }
3513
3514 /*
3515  * getAggregates:
3516  *        read all the user-defined aggregates in the system catalogs and
3517  * return them in the AggInfo* structure
3518  *
3519  * numAggs is set to the number of aggregates read in
3520  */
3521 AggInfo *
3522 getAggregates(int *numAggs)
3523 {
3524         PGresult   *res;
3525         int                     ntups;
3526         int                     i;
3527         PQExpBuffer query = createPQExpBuffer();
3528         AggInfo    *agginfo;
3529         int                     i_tableoid;
3530         int                     i_oid;
3531         int                     i_aggname;
3532         int                     i_aggnamespace;
3533         int                     i_pronargs;
3534         int                     i_proargtypes;
3535         int                     i_rolname;
3536         int                     i_aggacl;
3537
3538         /* Make sure we are in proper schema */
3539         selectSourceSchema("pg_catalog");
3540
3541         /*
3542          * Find all user-defined aggregates.  See comment in getFuncs() for the
3543          * rationale behind the filtering logic.
3544          */
3545
3546         if (g_fout->remoteVersion >= 80200)
3547         {
3548                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3549                                                   "pronamespace AS aggnamespace, "
3550                                                   "pronargs, proargtypes, "
3551                                                   "(%s proowner) AS rolname, "
3552                                                   "proacl AS aggacl "
3553                                                   "FROM pg_proc p "
3554                                                   "WHERE proisagg AND ("
3555                                                   "pronamespace != "
3556                                                   "(SELECT oid FROM pg_namespace "
3557                                                   "WHERE nspname = 'pg_catalog')",
3558                                                   username_subquery);
3559                 if (binary_upgrade && g_fout->remoteVersion >= 90100)
3560                         appendPQExpBuffer(query,
3561                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3562                                                           "classid = 'pg_proc'::regclass AND "
3563                                                           "objid = p.oid AND "
3564                                                           "refclassid = 'pg_extension'::regclass AND "
3565                                                           "deptype = 'e')");
3566                 appendPQExpBuffer(query, ")");
3567         }
3568         else if (g_fout->remoteVersion >= 70300)
3569         {
3570                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3571                                                   "pronamespace AS aggnamespace, "
3572                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3573                                                   "proargtypes, "
3574                                                   "(%s proowner) AS rolname, "
3575                                                   "proacl AS aggacl "
3576                                                   "FROM pg_proc "
3577                                                   "WHERE proisagg "
3578                                                   "AND pronamespace != "
3579                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3580                                                   username_subquery);
3581         }
3582         else if (g_fout->remoteVersion >= 70100)
3583         {
3584                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3585                                                   "0::oid AS aggnamespace, "
3586                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3587                                                   "aggbasetype AS proargtypes, "
3588                                                   "(%s aggowner) AS rolname, "
3589                                                   "'{=X}' AS aggacl "
3590                                                   "FROM pg_aggregate "
3591                                                   "where oid > '%u'::oid",
3592                                                   username_subquery,
3593                                                   g_last_builtin_oid);
3594         }
3595         else
3596         {
3597                 appendPQExpBuffer(query, "SELECT "
3598                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3599                                                   "oid, aggname, "
3600                                                   "0::oid AS aggnamespace, "
3601                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3602                                                   "aggbasetype AS proargtypes, "
3603                                                   "(%s aggowner) AS rolname, "
3604                                                   "'{=X}' AS aggacl "
3605                                                   "FROM pg_aggregate "
3606                                                   "where oid > '%u'::oid",
3607                                                   username_subquery,
3608                                                   g_last_builtin_oid);
3609         }
3610
3611         res = PQexec(g_conn, query->data);
3612         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3613
3614         ntups = PQntuples(res);
3615         *numAggs = ntups;
3616
3617         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3618
3619         i_tableoid = PQfnumber(res, "tableoid");
3620         i_oid = PQfnumber(res, "oid");
3621         i_aggname = PQfnumber(res, "aggname");
3622         i_aggnamespace = PQfnumber(res, "aggnamespace");
3623         i_pronargs = PQfnumber(res, "pronargs");
3624         i_proargtypes = PQfnumber(res, "proargtypes");
3625         i_rolname = PQfnumber(res, "rolname");
3626         i_aggacl = PQfnumber(res, "aggacl");
3627
3628         for (i = 0; i < ntups; i++)
3629         {
3630                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3631                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3632                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3633                 AssignDumpId(&agginfo[i].aggfn.dobj);
3634                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3635                 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
3636                                                                                         agginfo[i].aggfn.dobj.catId.oid);
3637                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3638                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3639                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3640                                           agginfo[i].aggfn.dobj.name);
3641                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3642                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3643                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3644                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3645                 if (agginfo[i].aggfn.nargs == 0)
3646                         agginfo[i].aggfn.argtypes = NULL;
3647                 else
3648                 {
3649                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3650                         if (g_fout->remoteVersion >= 70300)
3651                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3652                                                           agginfo[i].aggfn.argtypes,
3653                                                           agginfo[i].aggfn.nargs);
3654                         else
3655                                 /* it's just aggbasetype */
3656                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3657                 }
3658
3659                 /* Decide whether we want to dump it */
3660                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3661         }
3662
3663         PQclear(res);
3664
3665         destroyPQExpBuffer(query);
3666
3667         return agginfo;
3668 }
3669
3670 /*
3671  * getFuncs:
3672  *        read all the user-defined functions in the system catalogs and
3673  * return them in the FuncInfo* structure
3674  *
3675  * numFuncs is set to the number of functions read in
3676  */
3677 FuncInfo *
3678 getFuncs(int *numFuncs)
3679 {
3680         PGresult   *res;
3681         int                     ntups;
3682         int                     i;
3683         PQExpBuffer query = createPQExpBuffer();
3684         FuncInfo   *finfo;
3685         int                     i_tableoid;
3686         int                     i_oid;
3687         int                     i_proname;
3688         int                     i_pronamespace;
3689         int                     i_rolname;
3690         int                     i_prolang;
3691         int                     i_pronargs;
3692         int                     i_proargtypes;
3693         int                     i_prorettype;
3694         int                     i_proacl;
3695
3696         /* Make sure we are in proper schema */
3697         selectSourceSchema("pg_catalog");
3698
3699         /*
3700          * Find all user-defined functions.  Normally we can exclude functions in
3701          * pg_catalog, which is worth doing since there are several thousand of
3702          * 'em.  However, there are some extensions that create functions in
3703          * pg_catalog.  In normal dumps we can still ignore those --- but in
3704          * binary-upgrade mode, we must dump the member objects of the extension,
3705          * so be sure to fetch any such functions.
3706          *
3707          * Also, in 9.2 and up, exclude functions that are internally dependent on
3708          * something else, since presumably those will be created as a result of
3709          * creating the something else.  This currently only acts to suppress
3710          * constructor functions for range types.  Note that this is OK only
3711          * because the constructors don't have any dependencies the range type
3712          * doesn't have; otherwise we might not get creation ordering correct.
3713          */
3714
3715         if (g_fout->remoteVersion >= 70300)
3716         {
3717                 appendPQExpBuffer(query,
3718                                                   "SELECT tableoid, oid, proname, prolang, "
3719                                                   "pronargs, proargtypes, prorettype, proacl, "
3720                                                   "pronamespace, "
3721                                                   "(%s proowner) AS rolname "
3722                                                   "FROM pg_proc p "
3723                                                   "WHERE NOT proisagg AND ("
3724                                                   "pronamespace != "
3725                                                   "(SELECT oid FROM pg_namespace "
3726                                                   "WHERE nspname = 'pg_catalog')",
3727                                                   username_subquery);
3728                 if (g_fout->remoteVersion >= 90200)
3729                         appendPQExpBuffer(query,
3730                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
3731                                                           "WHERE classid = 'pg_proc'::regclass AND "
3732                                                           "objid = p.oid AND deptype = 'i')");
3733                 if (binary_upgrade && g_fout->remoteVersion >= 90100)
3734                         appendPQExpBuffer(query,
3735                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3736                                                           "classid = 'pg_proc'::regclass AND "
3737                                                           "objid = p.oid AND "
3738                                                           "refclassid = 'pg_extension'::regclass AND "
3739                                                           "deptype = 'e')");
3740                 appendPQExpBuffer(query, ")");
3741         }
3742         else if (g_fout->remoteVersion >= 70100)
3743         {
3744                 appendPQExpBuffer(query,
3745                                                   "SELECT tableoid, oid, proname, prolang, "
3746                                                   "pronargs, proargtypes, prorettype, "
3747                                                   "'{=X}' AS proacl, "
3748                                                   "0::oid AS pronamespace, "
3749                                                   "(%s proowner) AS rolname "
3750                                                   "FROM pg_proc "
3751                                                   "WHERE pg_proc.oid > '%u'::oid",
3752                                                   username_subquery,
3753                                                   g_last_builtin_oid);
3754         }
3755         else
3756         {
3757                 appendPQExpBuffer(query,
3758                                                   "SELECT "
3759                                                   "(SELECT oid FROM pg_class "
3760                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3761                                                   "oid, proname, prolang, "
3762                                                   "pronargs, proargtypes, prorettype, "
3763                                                   "'{=X}' AS proacl, "
3764                                                   "0::oid AS pronamespace, "
3765                                                   "(%s proowner) AS rolname "
3766                                                   "FROM pg_proc "
3767                                                   "where pg_proc.oid > '%u'::oid",
3768                                                   username_subquery,
3769                                                   g_last_builtin_oid);
3770         }
3771
3772         res = PQexec(g_conn, query->data);
3773         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3774
3775         ntups = PQntuples(res);
3776
3777         *numFuncs = ntups;
3778
3779         finfo = (FuncInfo *) pg_calloc(ntups, sizeof(FuncInfo));
3780
3781         i_tableoid = PQfnumber(res, "tableoid");
3782         i_oid = PQfnumber(res, "oid");
3783         i_proname = PQfnumber(res, "proname");
3784         i_pronamespace = PQfnumber(res, "pronamespace");
3785         i_rolname = PQfnumber(res, "rolname");
3786         i_prolang = PQfnumber(res, "prolang");
3787         i_pronargs = PQfnumber(res, "pronargs");
3788         i_proargtypes = PQfnumber(res, "proargtypes");
3789         i_prorettype = PQfnumber(res, "prorettype");
3790         i_proacl = PQfnumber(res, "proacl");
3791
3792         for (i = 0; i < ntups; i++)
3793         {
3794                 finfo[i].dobj.objType = DO_FUNC;
3795                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3796                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3797                 AssignDumpId(&finfo[i].dobj);
3798                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
3799                 finfo[i].dobj.namespace =
3800                         findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3801                                                   finfo[i].dobj.catId.oid);
3802                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3803                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3804                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3805                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
3806                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3807                 if (finfo[i].nargs == 0)
3808                         finfo[i].argtypes = NULL;
3809                 else
3810                 {
3811                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
3812                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3813                                                   finfo[i].argtypes, finfo[i].nargs);
3814                 }
3815
3816                 /* Decide whether we want to dump it */
3817                 selectDumpableObject(&(finfo[i].dobj));
3818
3819                 if (strlen(finfo[i].rolname) == 0)
3820                         write_msg(NULL,
3821                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3822                                           finfo[i].dobj.name);
3823         }
3824
3825         PQclear(res);
3826
3827         destroyPQExpBuffer(query);
3828
3829         return finfo;
3830 }
3831
3832 /*
3833  * getTables
3834  *        read all the user-defined tables (no indexes, no catalogs)
3835  * in the system catalogs return them in the TableInfo* structure
3836  *
3837  * numTables is set to the number of tables read in
3838  */
3839 TableInfo *
3840 getTables(int *numTables)
3841 {
3842         PGresult   *res;
3843         int                     ntups;
3844         int                     i;
3845         PQExpBuffer query = createPQExpBuffer();
3846         TableInfo  *tblinfo;
3847         int                     i_reltableoid;
3848         int                     i_reloid;
3849         int                     i_relname;
3850         int                     i_relnamespace;
3851         int                     i_relkind;
3852         int                     i_relacl;
3853         int                     i_rolname;
3854         int                     i_relchecks;
3855         int                     i_relhastriggers;
3856         int                     i_relhasindex;
3857         int                     i_relhasrules;
3858         int                     i_relhasoids;
3859         int                     i_relfrozenxid;
3860         int                     i_toastoid;
3861         int                     i_toastfrozenxid;
3862         int                     i_relpersistence;
3863         int                     i_owning_tab;
3864         int                     i_owning_col;
3865         int                     i_reltablespace;
3866         int                     i_reloptions;
3867         int                     i_toastreloptions;
3868         int                     i_reloftype;
3869
3870         /* Make sure we are in proper schema */
3871         selectSourceSchema("pg_catalog");
3872
3873         /*
3874          * Find all the tables (including views and sequences).
3875          *
3876          * We include system catalogs, so that we can work if a user table is
3877          * defined to inherit from a system catalog (pretty weird, but...)
3878          *
3879          * We ignore tables that are not type 'r' (ordinary relation), 'S'
3880          * (sequence), 'v' (view), or 'c' (composite type).
3881          *
3882          * Composite-type table entries won't be dumped as such, but we have to
3883          * make a DumpableObject for them so that we can track dependencies of the
3884          * composite type (pg_depend entries for columns of the composite type
3885          * link to the pg_class entry not the pg_type entry).
3886          *
3887          * Note: in this phase we should collect only a minimal amount of
3888          * information about each table, basically just enough to decide if it is
3889          * interesting. We must fetch all tables in this phase because otherwise
3890          * we cannot correctly identify inherited columns, owned sequences, etc.
3891          */
3892
3893         if (g_fout->remoteVersion >= 90100)
3894         {
3895                 /*
3896                  * Left join to pick up dependency info linking sequences to their
3897                  * owning column, if any (note this dependency is AUTO as of 8.2)
3898                  */
3899                 appendPQExpBuffer(query,
3900                                                   "SELECT c.tableoid, c.oid, c.relname, "
3901                                                   "c.relacl, c.relkind, c.relnamespace, "
3902                                                   "(%s c.relowner) AS rolname, "
3903                                                   "c.relchecks, c.relhastriggers, "
3904                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3905                                                   "c.relfrozenxid, tc.oid AS toid, "
3906                                                   "tc.relfrozenxid AS tfrozenxid, "
3907                                                   "c.relpersistence, "
3908                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3909                                                   "d.refobjid AS owning_tab, "
3910                                                   "d.refobjsubid AS owning_col, "
3911                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3912                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3913                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3914                                                   "FROM pg_class c "
3915                                                   "LEFT JOIN pg_depend d ON "
3916                                                   "(c.relkind = '%c' AND "
3917                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3918                                                   "d.objsubid = 0 AND "
3919                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3920                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3921                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c') "
3922                                                   "ORDER BY c.oid",
3923                                                   username_subquery,
3924                                                   RELKIND_SEQUENCE,
3925                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3926                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
3927                                                   RELKIND_FOREIGN_TABLE);
3928         }
3929         else if (g_fout->remoteVersion >= 90000)
3930         {
3931                 /*
3932                  * Left join to pick up dependency info linking sequences to their
3933                  * owning column, if any (note this dependency is AUTO as of 8.2)
3934                  */
3935                 appendPQExpBuffer(query,
3936                                                   "SELECT c.tableoid, c.oid, c.relname, "
3937                                                   "c.relacl, c.relkind, c.relnamespace, "
3938                                                   "(%s c.relowner) AS rolname, "
3939                                                   "c.relchecks, c.relhastriggers, "
3940                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3941                                                   "c.relfrozenxid, tc.oid AS toid, "
3942                                                   "tc.relfrozenxid AS tfrozenxid, "
3943                                                   "'p' AS relpersistence, "
3944                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
3945                                                   "d.refobjid AS owning_tab, "
3946                                                   "d.refobjsubid AS owning_col, "
3947                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3948                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3949                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3950                                                   "FROM pg_class c "
3951                                                   "LEFT JOIN pg_depend d ON "
3952                                                   "(c.relkind = '%c' AND "
3953                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3954                                                   "d.objsubid = 0 AND "
3955                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3956                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3957                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3958                                                   "ORDER BY c.oid",
3959                                                   username_subquery,
3960                                                   RELKIND_SEQUENCE,
3961                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3962                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3963         }
3964         else if (g_fout->remoteVersion >= 80400)
3965         {
3966                 /*
3967                  * Left join to pick up dependency info linking sequences to their
3968                  * owning column, if any (note this dependency is AUTO as of 8.2)
3969                  */
3970                 appendPQExpBuffer(query,
3971                                                   "SELECT c.tableoid, c.oid, c.relname, "
3972                                                   "c.relacl, c.relkind, c.relnamespace, "
3973                                                   "(%s c.relowner) AS rolname, "
3974                                                   "c.relchecks, c.relhastriggers, "
3975                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3976                                                   "c.relfrozenxid, tc.oid AS toid, "
3977                                                   "tc.relfrozenxid AS tfrozenxid, "
3978                                                   "'p' AS relpersistence, "
3979                                                   "NULL AS reloftype, "
3980                                                   "d.refobjid AS owning_tab, "
3981                                                   "d.refobjsubid AS owning_col, "
3982                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3983                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3984                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3985                                                   "FROM pg_class c "
3986                                                   "LEFT JOIN pg_depend d ON "
3987                                                   "(c.relkind = '%c' AND "
3988                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3989                                                   "d.objsubid = 0 AND "
3990                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3991                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3992                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3993                                                   "ORDER BY c.oid",
3994                                                   username_subquery,
3995                                                   RELKIND_SEQUENCE,
3996                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3997                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3998         }
3999         else if (g_fout->remoteVersion >= 80200)
4000         {
4001                 /*
4002                  * Left join to pick up dependency info linking sequences to their
4003                  * owning column, if any (note this dependency is AUTO as of 8.2)
4004                  */
4005                 appendPQExpBuffer(query,
4006                                                   "SELECT c.tableoid, c.oid, c.relname, "
4007                                                   "c.relacl, c.relkind, c.relnamespace, "
4008                                                   "(%s c.relowner) AS rolname, "
4009                                                   "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4010                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4011                                                   "c.relfrozenxid, tc.oid AS toid, "
4012                                                   "tc.relfrozenxid AS tfrozenxid, "
4013                                                   "'p' AS relpersistence, "
4014                                                   "NULL AS reloftype, "
4015                                                   "d.refobjid AS owning_tab, "
4016                                                   "d.refobjsubid AS owning_col, "
4017                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4018                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4019                                                   "NULL AS toast_reloptions "
4020                                                   "FROM pg_class c "
4021                                                   "LEFT JOIN pg_depend d ON "
4022                                                   "(c.relkind = '%c' AND "
4023                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4024                                                   "d.objsubid = 0 AND "
4025                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4026                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4027                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4028                                                   "ORDER BY c.oid",
4029                                                   username_subquery,
4030                                                   RELKIND_SEQUENCE,
4031                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4032                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4033         }
4034         else if (g_fout->remoteVersion >= 80000)
4035         {
4036                 /*
4037                  * Left join to pick up dependency info linking sequences to their
4038                  * owning column, if any
4039                  */
4040                 appendPQExpBuffer(query,
4041                                                   "SELECT c.tableoid, c.oid, relname, "
4042                                                   "relacl, relkind, relnamespace, "
4043                                                   "(%s relowner) AS rolname, "
4044                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4045                                                   "relhasindex, relhasrules, relhasoids, "
4046                                                   "0 AS relfrozenxid, "
4047                                                   "0 AS toid, "
4048                                                   "0 AS tfrozenxid, "
4049                                                   "'p' AS relpersistence, "
4050                                                   "NULL AS reloftype, "
4051                                                   "d.refobjid AS owning_tab, "
4052                                                   "d.refobjsubid AS owning_col, "
4053                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4054                                                   "NULL AS reloptions, "
4055                                                   "NULL AS toast_reloptions "
4056                                                   "FROM pg_class c "
4057                                                   "LEFT JOIN pg_depend d ON "
4058                                                   "(c.relkind = '%c' AND "
4059                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4060                                                   "d.objsubid = 0 AND "
4061                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4062                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4063                                                   "ORDER BY c.oid",
4064                                                   username_subquery,
4065                                                   RELKIND_SEQUENCE,
4066                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4067                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4068         }
4069         else if (g_fout->remoteVersion >= 70300)
4070         {
4071                 /*
4072                  * Left join to pick up dependency info linking sequences to their
4073                  * owning column, if any
4074                  */
4075                 appendPQExpBuffer(query,
4076                                                   "SELECT c.tableoid, c.oid, relname, "
4077                                                   "relacl, relkind, relnamespace, "
4078                                                   "(%s relowner) AS rolname, "
4079                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4080                                                   "relhasindex, relhasrules, relhasoids, "
4081                                                   "0 AS relfrozenxid, "
4082                                                   "0 AS toid, "
4083                                                   "0 AS tfrozenxid, "
4084                                                   "'p' AS relpersistence, "
4085                                                   "NULL AS reloftype, "
4086                                                   "d.refobjid AS owning_tab, "
4087                                                   "d.refobjsubid AS owning_col, "
4088                                                   "NULL AS reltablespace, "
4089                                                   "NULL AS reloptions, "
4090                                                   "NULL AS toast_reloptions "
4091                                                   "FROM pg_class c "
4092                                                   "LEFT JOIN pg_depend d ON "
4093                                                   "(c.relkind = '%c' AND "
4094                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4095                                                   "d.objsubid = 0 AND "
4096                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4097                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4098                                                   "ORDER BY c.oid",
4099                                                   username_subquery,
4100                                                   RELKIND_SEQUENCE,
4101                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4102                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4103         }
4104         else if (g_fout->remoteVersion >= 70200)
4105         {
4106                 appendPQExpBuffer(query,
4107                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4108                                                   "0::oid AS relnamespace, "
4109                                                   "(%s relowner) AS rolname, "
4110                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4111                                                   "relhasindex, relhasrules, relhasoids, "
4112                                                   "0 AS relfrozenxid, "
4113                                                   "0 AS toid, "
4114                                                   "0 AS tfrozenxid, "
4115                                                   "'p' AS relpersistence, "
4116                                                   "NULL AS reloftype, "
4117                                                   "NULL::oid AS owning_tab, "
4118                                                   "NULL::int4 AS owning_col, "
4119                                                   "NULL AS reltablespace, "
4120                                                   "NULL AS reloptions, "
4121                                                   "NULL AS toast_reloptions "
4122                                                   "FROM pg_class "
4123                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4124                                                   "ORDER BY oid",
4125                                                   username_subquery,
4126                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4127         }
4128         else if (g_fout->remoteVersion >= 70100)
4129         {
4130                 /* all tables have oids in 7.1 */
4131                 appendPQExpBuffer(query,
4132                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4133                                                   "0::oid AS relnamespace, "
4134                                                   "(%s relowner) AS rolname, "
4135                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4136                                                   "relhasindex, relhasrules, "
4137                                                   "'t'::bool AS relhasoids, "
4138                                                   "0 AS relfrozenxid, "
4139                                                   "0 AS toid, "
4140                                                   "0 AS tfrozenxid, "
4141                                                   "'p' AS relpersistence, "
4142                                                   "NULL AS reloftype, "
4143                                                   "NULL::oid AS owning_tab, "
4144                                                   "NULL::int4 AS owning_col, "
4145                                                   "NULL AS reltablespace, "
4146                                                   "NULL AS reloptions, "
4147                                                   "NULL AS toast_reloptions "
4148                                                   "FROM pg_class "
4149                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4150                                                   "ORDER BY oid",
4151                                                   username_subquery,
4152                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4153         }
4154         else
4155         {
4156                 /*
4157                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4158                  * have a view by looking for a rule in pg_rewrite.
4159                  */
4160                 appendPQExpBuffer(query,
4161                                                   "SELECT "
4162                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4163                                                   "oid, relname, relacl, "
4164                                                   "CASE WHEN relhasrules and relkind = 'r' "
4165                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4166                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4167                                                   "THEN '%c'::\"char\" "
4168                                                   "ELSE relkind END AS relkind,"
4169                                                   "0::oid AS relnamespace, "
4170                                                   "(%s relowner) AS rolname, "
4171                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4172                                                   "relhasindex, relhasrules, "
4173                                                   "'t'::bool AS relhasoids, "
4174                                                   "0 as relfrozenxid, "
4175                                                   "0 AS toid, "
4176                                                   "0 AS tfrozenxid, "
4177                                                   "'p' AS relpersistence, "
4178                                                   "NULL AS reloftype, "
4179                                                   "NULL::oid AS owning_tab, "
4180                                                   "NULL::int4 AS owning_col, "
4181                                                   "NULL AS reltablespace, "
4182                                                   "NULL AS reloptions, "
4183                                                   "NULL AS toast_reloptions "
4184                                                   "FROM pg_class c "
4185                                                   "WHERE relkind IN ('%c', '%c') "
4186                                                   "ORDER BY oid",
4187                                                   RELKIND_VIEW,
4188                                                   username_subquery,
4189                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4190         }
4191
4192         res = PQexec(g_conn, query->data);
4193         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4194
4195         ntups = PQntuples(res);
4196
4197         *numTables = ntups;
4198
4199         /*
4200          * Extract data from result and lock dumpable tables.  We do the locking
4201          * before anything else, to minimize the window wherein a table could
4202          * disappear under us.
4203          *
4204          * Note that we have to save info about all tables here, even when dumping
4205          * only one, because we don't yet know which tables might be inheritance
4206          * ancestors of the target table.
4207          */
4208         tblinfo = (TableInfo *) pg_calloc(ntups, sizeof(TableInfo));
4209
4210         i_reltableoid = PQfnumber(res, "tableoid");
4211         i_reloid = PQfnumber(res, "oid");
4212         i_relname = PQfnumber(res, "relname");
4213         i_relnamespace = PQfnumber(res, "relnamespace");
4214         i_relacl = PQfnumber(res, "relacl");
4215         i_relkind = PQfnumber(res, "relkind");
4216         i_rolname = PQfnumber(res, "rolname");
4217         i_relchecks = PQfnumber(res, "relchecks");
4218         i_relhastriggers = PQfnumber(res, "relhastriggers");
4219         i_relhasindex = PQfnumber(res, "relhasindex");
4220         i_relhasrules = PQfnumber(res, "relhasrules");
4221         i_relhasoids = PQfnumber(res, "relhasoids");
4222         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4223         i_toastoid = PQfnumber(res, "toid");
4224         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4225         i_relpersistence = PQfnumber(res, "relpersistence");
4226         i_owning_tab = PQfnumber(res, "owning_tab");
4227         i_owning_col = PQfnumber(res, "owning_col");
4228         i_reltablespace = PQfnumber(res, "reltablespace");
4229         i_reloptions = PQfnumber(res, "reloptions");
4230         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4231         i_reloftype = PQfnumber(res, "reloftype");
4232
4233         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
4234         {
4235                 /*
4236                  * Arrange to fail instead of waiting forever for a table lock.
4237                  *
4238                  * NB: this coding assumes that the only queries issued within the
4239                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4240                  * applied to other things too.
4241                  */
4242                 resetPQExpBuffer(query);
4243                 appendPQExpBuffer(query, "SET statement_timeout = ");
4244                 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
4245                 do_sql_command(g_conn, query->data);
4246         }
4247
4248         for (i = 0; i < ntups; i++)
4249         {
4250                 tblinfo[i].dobj.objType = DO_TABLE;
4251                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4252                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4253                 AssignDumpId(&tblinfo[i].dobj);
4254                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4255                 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
4256                                                                                                   tblinfo[i].dobj.catId.oid);
4257                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4258                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4259                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4260                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4261                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4262                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4263                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4264                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4265                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4266                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4267                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4268                 if (PQgetisnull(res, i, i_reloftype))
4269                         tblinfo[i].reloftype = NULL;
4270                 else
4271                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4272                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4273                 if (PQgetisnull(res, i, i_owning_tab))
4274                 {
4275                         tblinfo[i].owning_tab = InvalidOid;
4276                         tblinfo[i].owning_col = 0;
4277                 }
4278                 else
4279                 {
4280                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4281                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4282                 }
4283                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4284                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4285                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4286
4287                 /* other fields were zeroed above */
4288
4289                 /*
4290                  * Decide whether we want to dump this table.
4291                  */
4292                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4293                         tblinfo[i].dobj.dump = false;
4294                 else
4295                         selectDumpableTable(&tblinfo[i]);
4296                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4297
4298                 /*
4299                  * Read-lock target tables to make sure they aren't DROPPED or altered
4300                  * in schema before we get around to dumping them.
4301                  *
4302                  * Note that we don't explicitly lock parents of the target tables; we
4303                  * assume our lock on the child is enough to prevent schema
4304                  * alterations to parent tables.
4305                  *
4306                  * NOTE: it'd be kinda nice to lock other relations too, not only
4307                  * plain tables, but the backend doesn't presently allow that.
4308                  */
4309                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4310                 {
4311                         resetPQExpBuffer(query);
4312                         appendPQExpBuffer(query,
4313                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4314                                                  fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
4315                                                                                 tblinfo[i].dobj.name));
4316                         do_sql_command(g_conn, query->data);
4317                 }
4318
4319                 /* Emit notice if join for owner failed */
4320                 if (strlen(tblinfo[i].rolname) == 0)
4321                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4322                                           tblinfo[i].dobj.name);
4323         }
4324
4325         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
4326         {
4327                 do_sql_command(g_conn, "SET statement_timeout = 0");
4328         }
4329
4330         PQclear(res);
4331
4332         /*
4333          * Force sequences that are "owned" by table columns to be dumped whenever
4334          * their owning table is being dumped.
4335          */
4336         for (i = 0; i < ntups; i++)
4337         {
4338                 TableInfo  *seqinfo = &tblinfo[i];
4339                 int                     j;
4340
4341                 if (!OidIsValid(seqinfo->owning_tab))
4342                         continue;                       /* not an owned sequence */
4343                 if (seqinfo->dobj.dump)
4344                         continue;                       /* no need to search */
4345
4346                 /* can't use findTableByOid yet, unfortunately */
4347                 for (j = 0; j < ntups; j++)
4348                 {
4349                         if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
4350                         {
4351                                 if (tblinfo[j].dobj.dump)
4352                                 {
4353                                         seqinfo->interesting = true;
4354                                         seqinfo->dobj.dump = true;
4355                                 }
4356                                 break;
4357                         }
4358                 }
4359         }
4360
4361         destroyPQExpBuffer(query);
4362
4363         return tblinfo;
4364 }
4365
4366 /*
4367  * getInherits
4368  *        read all the inheritance information
4369  * from the system catalogs return them in the InhInfo* structure
4370  *
4371  * numInherits is set to the number of pairs read in
4372  */
4373 InhInfo *
4374 getInherits(int *numInherits)
4375 {
4376         PGresult   *res;
4377         int                     ntups;
4378         int                     i;
4379         PQExpBuffer query = createPQExpBuffer();
4380         InhInfo    *inhinfo;
4381
4382         int                     i_inhrelid;
4383         int                     i_inhparent;
4384
4385         /* Make sure we are in proper schema */
4386         selectSourceSchema("pg_catalog");
4387
4388         /* find all the inheritance information */
4389
4390         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4391
4392         res = PQexec(g_conn, query->data);
4393         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4394
4395         ntups = PQntuples(res);
4396
4397         *numInherits = ntups;
4398
4399         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4400
4401         i_inhrelid = PQfnumber(res, "inhrelid");
4402         i_inhparent = PQfnumber(res, "inhparent");
4403
4404         for (i = 0; i < ntups; i++)
4405         {
4406                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4407                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4408         }
4409
4410         PQclear(res);
4411
4412         destroyPQExpBuffer(query);
4413
4414         return inhinfo;
4415 }
4416
4417 /*
4418  * getIndexes
4419  *        get information about every index on a dumpable table
4420  *
4421  * Note: index data is not returned directly to the caller, but it
4422  * does get entered into the DumpableObject tables.
4423  */
4424 void
4425 getIndexes(TableInfo tblinfo[], int numTables)
4426 {
4427         int                     i,
4428                                 j;
4429         PQExpBuffer query = createPQExpBuffer();
4430         PGresult   *res;
4431         IndxInfo   *indxinfo;
4432         ConstraintInfo *constrinfo;
4433         int                     i_tableoid,
4434                                 i_oid,
4435                                 i_indexname,
4436                                 i_indexdef,
4437                                 i_indnkeys,
4438                                 i_indkey,
4439                                 i_indisclustered,
4440                                 i_contype,
4441                                 i_conname,
4442                                 i_condeferrable,
4443                                 i_condeferred,
4444                                 i_contableoid,
4445                                 i_conoid,
4446                                 i_condef,
4447                                 i_tablespace,
4448                                 i_options;
4449         int                     ntups;
4450
4451         for (i = 0; i < numTables; i++)
4452         {
4453                 TableInfo  *tbinfo = &tblinfo[i];
4454
4455                 /* Only plain tables have indexes */
4456                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
4457                         continue;
4458
4459                 /* Ignore indexes of tables not to be dumped */
4460                 if (!tbinfo->dobj.dump)
4461                         continue;
4462
4463                 if (g_verbose)
4464                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4465                                           tbinfo->dobj.name);
4466
4467                 /* Make sure we are in proper schema so indexdef is right */
4468                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4469
4470                 /*
4471                  * The point of the messy-looking outer join is to find a constraint
4472                  * that is related by an internal dependency link to the index. If we
4473                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4474                  * assume an index won't have more than one internal dependency.
4475                  *
4476                  * As of 9.0 we don't need to look at pg_depend but can check for a
4477                  * match to pg_constraint.conindid.  The check on conrelid is
4478                  * redundant but useful because that column is indexed while conindid
4479                  * is not.
4480                  */
4481                 resetPQExpBuffer(query);
4482                 if (g_fout->remoteVersion >= 90000)
4483                 {
4484                         appendPQExpBuffer(query,
4485                                                           "SELECT t.tableoid, t.oid, "
4486                                                           "t.relname AS indexname, "
4487                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4488                                                           "t.relnatts AS indnkeys, "
4489                                                           "i.indkey, i.indisclustered, "
4490                                                           "c.contype, c.conname, "
4491                                                           "c.condeferrable, c.condeferred, "
4492                                                           "c.tableoid AS contableoid, "
4493                                                           "c.oid AS conoid, "
4494                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4495                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4496                                                         "array_to_string(t.reloptions, ', ') AS options "
4497                                                           "FROM pg_catalog.pg_index i "
4498                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4499                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4500                                                           "ON (i.indrelid = c.conrelid AND "
4501                                                           "i.indexrelid = c.conindid AND "
4502                                                           "c.contype IN ('p','u','x')) "
4503                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4504                                                           "ORDER BY indexname",
4505                                                           tbinfo->dobj.catId.oid);
4506                 }
4507                 else if (g_fout->remoteVersion >= 80200)
4508                 {
4509                         appendPQExpBuffer(query,
4510                                                           "SELECT t.tableoid, t.oid, "
4511                                                           "t.relname AS indexname, "
4512                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4513                                                           "t.relnatts AS indnkeys, "
4514                                                           "i.indkey, i.indisclustered, "
4515                                                           "c.contype, c.conname, "
4516                                                           "c.condeferrable, c.condeferred, "
4517                                                           "c.tableoid AS contableoid, "
4518                                                           "c.oid AS conoid, "
4519                                                           "null AS condef, "
4520                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4521                                                         "array_to_string(t.reloptions, ', ') AS options "
4522                                                           "FROM pg_catalog.pg_index i "
4523                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4524                                                           "LEFT JOIN pg_catalog.pg_depend d "
4525                                                           "ON (d.classid = t.tableoid "
4526                                                           "AND d.objid = t.oid "
4527                                                           "AND d.deptype = 'i') "
4528                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4529                                                           "ON (d.refclassid = c.tableoid "
4530                                                           "AND d.refobjid = c.oid) "
4531                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4532                                                           "ORDER BY indexname",
4533                                                           tbinfo->dobj.catId.oid);
4534                 }
4535                 else if (g_fout->remoteVersion >= 80000)
4536                 {
4537                         appendPQExpBuffer(query,
4538                                                           "SELECT t.tableoid, t.oid, "
4539                                                           "t.relname AS indexname, "
4540                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4541                                                           "t.relnatts AS indnkeys, "
4542                                                           "i.indkey, i.indisclustered, "
4543                                                           "c.contype, c.conname, "
4544                                                           "c.condeferrable, c.condeferred, "
4545                                                           "c.tableoid AS contableoid, "
4546                                                           "c.oid AS conoid, "
4547                                                           "null AS condef, "
4548                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4549                                                           "null AS options "
4550                                                           "FROM pg_catalog.pg_index i "
4551                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4552                                                           "LEFT JOIN pg_catalog.pg_depend d "
4553                                                           "ON (d.classid = t.tableoid "
4554                                                           "AND d.objid = t.oid "
4555                                                           "AND d.deptype = 'i') "
4556                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4557                                                           "ON (d.refclassid = c.tableoid "
4558                                                           "AND d.refobjid = c.oid) "
4559                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4560                                                           "ORDER BY indexname",
4561                                                           tbinfo->dobj.catId.oid);
4562                 }
4563                 else if (g_fout->remoteVersion >= 70300)
4564                 {
4565                         appendPQExpBuffer(query,
4566                                                           "SELECT t.tableoid, t.oid, "
4567                                                           "t.relname AS indexname, "
4568                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4569                                                           "t.relnatts AS indnkeys, "
4570                                                           "i.indkey, i.indisclustered, "
4571                                                           "c.contype, c.conname, "
4572                                                           "c.condeferrable, c.condeferred, "
4573                                                           "c.tableoid AS contableoid, "
4574                                                           "c.oid AS conoid, "
4575                                                           "null AS condef, "
4576                                                           "NULL AS tablespace, "
4577                                                           "null AS options "
4578                                                           "FROM pg_catalog.pg_index i "
4579                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4580                                                           "LEFT JOIN pg_catalog.pg_depend d "
4581                                                           "ON (d.classid = t.tableoid "
4582                                                           "AND d.objid = t.oid "
4583                                                           "AND d.deptype = 'i') "
4584                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4585                                                           "ON (d.refclassid = c.tableoid "
4586                                                           "AND d.refobjid = c.oid) "
4587                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4588                                                           "ORDER BY indexname",
4589                                                           tbinfo->dobj.catId.oid);
4590                 }
4591                 else if (g_fout->remoteVersion >= 70100)
4592                 {
4593                         appendPQExpBuffer(query,
4594                                                           "SELECT t.tableoid, t.oid, "
4595                                                           "t.relname AS indexname, "
4596                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4597                                                           "t.relnatts AS indnkeys, "
4598                                                           "i.indkey, false AS indisclustered, "
4599                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4600                                                           "ELSE '0'::char END AS contype, "
4601                                                           "t.relname AS conname, "
4602                                                           "false AS condeferrable, "
4603                                                           "false AS condeferred, "
4604                                                           "0::oid AS contableoid, "
4605                                                           "t.oid AS conoid, "
4606                                                           "null AS condef, "
4607                                                           "NULL AS tablespace, "
4608                                                           "null AS options "
4609                                                           "FROM pg_index i, pg_class t "
4610                                                           "WHERE t.oid = i.indexrelid "
4611                                                           "AND i.indrelid = '%u'::oid "
4612                                                           "ORDER BY indexname",
4613                                                           tbinfo->dobj.catId.oid);
4614                 }
4615                 else
4616                 {
4617                         appendPQExpBuffer(query,
4618                                                           "SELECT "
4619                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4620                                                           "t.oid, "
4621                                                           "t.relname AS indexname, "
4622                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
4623                                                           "t.relnatts AS indnkeys, "
4624                                                           "i.indkey, false AS indisclustered, "
4625                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
4626                                                           "ELSE '0'::char END AS contype, "
4627                                                           "t.relname AS conname, "
4628                                                           "false AS condeferrable, "
4629                                                           "false AS condeferred, "
4630                                                           "0::oid AS contableoid, "
4631                                                           "t.oid AS conoid, "
4632                                                           "null AS condef, "
4633                                                           "NULL AS tablespace, "
4634                                                           "null AS options "
4635                                                           "FROM pg_index i, pg_class t "
4636                                                           "WHERE t.oid = i.indexrelid "
4637                                                           "AND i.indrelid = '%u'::oid "
4638                                                           "ORDER BY indexname",
4639                                                           tbinfo->dobj.catId.oid);
4640                 }
4641
4642                 res = PQexec(g_conn, query->data);
4643                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4644
4645                 ntups = PQntuples(res);
4646
4647                 i_tableoid = PQfnumber(res, "tableoid");
4648                 i_oid = PQfnumber(res, "oid");
4649                 i_indexname = PQfnumber(res, "indexname");
4650                 i_indexdef = PQfnumber(res, "indexdef");
4651                 i_indnkeys = PQfnumber(res, "indnkeys");
4652                 i_indkey = PQfnumber(res, "indkey");
4653                 i_indisclustered = PQfnumber(res, "indisclustered");
4654                 i_contype = PQfnumber(res, "contype");
4655                 i_conname = PQfnumber(res, "conname");
4656                 i_condeferrable = PQfnumber(res, "condeferrable");
4657                 i_condeferred = PQfnumber(res, "condeferred");
4658                 i_contableoid = PQfnumber(res, "contableoid");
4659                 i_conoid = PQfnumber(res, "conoid");
4660                 i_condef = PQfnumber(res, "condef");
4661                 i_tablespace = PQfnumber(res, "tablespace");
4662                 i_options = PQfnumber(res, "options");
4663
4664                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
4665                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4666
4667                 for (j = 0; j < ntups; j++)
4668                 {
4669                         char            contype;
4670
4671                         indxinfo[j].dobj.objType = DO_INDEX;
4672                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4673                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4674                         AssignDumpId(&indxinfo[j].dobj);
4675                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
4676                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4677                         indxinfo[j].indextable = tbinfo;
4678                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
4679                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
4680                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
4681                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
4682
4683                         /*
4684                          * In pre-7.4 releases, indkeys may contain more entries than
4685                          * indnkeys says (since indnkeys will be 1 for a functional
4686                          * index).      We don't actually care about this case since we don't
4687                          * examine indkeys except for indexes associated with PRIMARY and
4688                          * UNIQUE constraints, which are never functional indexes. But we
4689                          * have to allocate enough space to keep parseOidArray from
4690                          * complaining.
4691                          */
4692                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
4693                         parseOidArray(PQgetvalue(res, j, i_indkey),
4694                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
4695                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
4696                         contype = *(PQgetvalue(res, j, i_contype));
4697
4698                         if (contype == 'p' || contype == 'u' || contype == 'x')
4699                         {
4700                                 /*
4701                                  * If we found a constraint matching the index, create an
4702                                  * entry for it.
4703                                  *
4704                                  * In a pre-7.3 database, we take this path iff the index was
4705                                  * marked indisprimary.
4706                                  */
4707                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
4708                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4709                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4710                                 AssignDumpId(&constrinfo[j].dobj);
4711                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4712                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4713                                 constrinfo[j].contable = tbinfo;
4714                                 constrinfo[j].condomain = NULL;
4715                                 constrinfo[j].contype = contype;
4716                                 if (contype == 'x')
4717                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4718                                 else
4719                                         constrinfo[j].condef = NULL;
4720                                 constrinfo[j].confrelid = InvalidOid;
4721                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
4722                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
4723                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
4724                                 constrinfo[j].conislocal = true;
4725                                 constrinfo[j].separate = true;
4726
4727                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
4728
4729                                 /* If pre-7.3 DB, better make sure table comes first */
4730                                 addObjectDependency(&constrinfo[j].dobj,
4731                                                                         tbinfo->dobj.dumpId);
4732                         }
4733                         else
4734                         {
4735                                 /* Plain secondary index */
4736                                 indxinfo[j].indexconstraint = 0;
4737                         }
4738                 }
4739
4740                 PQclear(res);
4741         }
4742
4743         destroyPQExpBuffer(query);
4744 }
4745
4746 /*
4747  * getConstraints
4748  *
4749  * Get info about constraints on dumpable tables.
4750  *
4751  * Currently handles foreign keys only.
4752  * Unique and primary key constraints are handled with indexes,
4753  * while check constraints are processed in getTableAttrs().
4754  */
4755 void
4756 getConstraints(TableInfo tblinfo[], int numTables)
4757 {
4758         int                     i,
4759                                 j;
4760         ConstraintInfo *constrinfo;
4761         PQExpBuffer query;
4762         PGresult   *res;
4763         int                     i_contableoid,
4764                                 i_conoid,
4765                                 i_conname,
4766                                 i_confrelid,
4767                                 i_condef;
4768         int                     ntups;
4769
4770         /* pg_constraint was created in 7.3, so nothing to do if older */
4771         if (g_fout->remoteVersion < 70300)
4772                 return;
4773
4774         query = createPQExpBuffer();
4775
4776         for (i = 0; i < numTables; i++)
4777         {
4778                 TableInfo  *tbinfo = &tblinfo[i];
4779
4780                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4781                         continue;
4782
4783                 if (g_verbose)
4784                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
4785                                           tbinfo->dobj.name);
4786
4787                 /*
4788                  * select table schema to ensure constraint expr is qualified if
4789                  * needed
4790                  */
4791                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4792
4793                 resetPQExpBuffer(query);
4794                 appendPQExpBuffer(query,
4795                                                   "SELECT tableoid, oid, conname, confrelid, "
4796                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
4797                                                   "FROM pg_catalog.pg_constraint "
4798                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4799                                                   "AND contype = 'f'",
4800                                                   tbinfo->dobj.catId.oid);
4801                 res = PQexec(g_conn, query->data);
4802                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4803
4804                 ntups = PQntuples(res);
4805
4806                 i_contableoid = PQfnumber(res, "tableoid");
4807                 i_conoid = PQfnumber(res, "oid");
4808                 i_conname = PQfnumber(res, "conname");
4809                 i_confrelid = PQfnumber(res, "confrelid");
4810                 i_condef = PQfnumber(res, "condef");
4811
4812                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4813
4814                 for (j = 0; j < ntups; j++)
4815                 {
4816                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
4817                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4818                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4819                         AssignDumpId(&constrinfo[j].dobj);
4820                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
4821                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4822                         constrinfo[j].contable = tbinfo;
4823                         constrinfo[j].condomain = NULL;
4824                         constrinfo[j].contype = 'f';
4825                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
4826                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
4827                         constrinfo[j].conindex = 0;
4828                         constrinfo[j].condeferrable = false;
4829                         constrinfo[j].condeferred = false;
4830                         constrinfo[j].conislocal = true;
4831                         constrinfo[j].separate = true;
4832                 }
4833
4834                 PQclear(res);
4835         }
4836
4837         destroyPQExpBuffer(query);
4838 }
4839
4840 /*
4841  * getDomainConstraints
4842  *
4843  * Get info about constraints on a domain.
4844  */
4845 static void
4846 getDomainConstraints(TypeInfo *tyinfo)
4847 {
4848         int                     i;
4849         ConstraintInfo *constrinfo;
4850         PQExpBuffer query;
4851         PGresult   *res;
4852         int                     i_tableoid,
4853                                 i_oid,
4854                                 i_conname,
4855                                 i_consrc;
4856         int                     ntups;
4857
4858         /* pg_constraint was created in 7.3, so nothing to do if older */
4859         if (g_fout->remoteVersion < 70300)
4860                 return;
4861
4862         /*
4863          * select appropriate schema to ensure names in constraint are properly
4864          * qualified
4865          */
4866         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
4867
4868         query = createPQExpBuffer();
4869
4870         if (g_fout->remoteVersion >= 90100)
4871                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4872                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4873                                                   "convalidated "
4874                                                   "FROM pg_catalog.pg_constraint "
4875                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4876                                                   "ORDER BY conname",
4877                                                   tyinfo->dobj.catId.oid);
4878
4879         else if (g_fout->remoteVersion >= 70400)
4880                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4881                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4882                                                   "true as convalidated "
4883                                                   "FROM pg_catalog.pg_constraint "
4884                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4885                                                   "ORDER BY conname",
4886                                                   tyinfo->dobj.catId.oid);
4887         else
4888                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4889                                                   "'CHECK (' || consrc || ')' AS consrc, "
4890                                                   "true as convalidated "
4891                                                   "FROM pg_catalog.pg_constraint "
4892                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4893                                                   "ORDER BY conname",
4894                                                   tyinfo->dobj.catId.oid);
4895
4896         res = PQexec(g_conn, query->data);
4897         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4898
4899         ntups = PQntuples(res);
4900
4901         i_tableoid = PQfnumber(res, "tableoid");
4902         i_oid = PQfnumber(res, "oid");
4903         i_conname = PQfnumber(res, "conname");
4904         i_consrc = PQfnumber(res, "consrc");
4905
4906         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
4907
4908         tyinfo->nDomChecks = ntups;
4909         tyinfo->domChecks = constrinfo;
4910
4911         for (i = 0; i < ntups; i++)
4912         {
4913                 bool    validated = PQgetvalue(res, i, 4)[0] == 't';
4914
4915                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4916                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4917                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4918                 AssignDumpId(&constrinfo[i].dobj);
4919                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
4920                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
4921                 constrinfo[i].contable = NULL;
4922                 constrinfo[i].condomain = tyinfo;
4923                 constrinfo[i].contype = 'c';
4924                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
4925                 constrinfo[i].confrelid = InvalidOid;
4926                 constrinfo[i].conindex = 0;
4927                 constrinfo[i].condeferrable = false;
4928                 constrinfo[i].condeferred = false;
4929                 constrinfo[i].conislocal = true;
4930
4931                 constrinfo[i].separate = !validated;
4932
4933                 /*
4934                  * Make the domain depend on the constraint, ensuring it won't be
4935                  * output till any constraint dependencies are OK.  If the constraint
4936                  * has not been validated, it's going to be dumped after the domain
4937                  * anyway, so this doesn't matter.
4938                  */
4939                 if (validated)
4940                         addObjectDependency(&tyinfo->dobj,
4941                                                                 constrinfo[i].dobj.dumpId);
4942         }
4943
4944         PQclear(res);
4945
4946         destroyPQExpBuffer(query);
4947 }
4948
4949 /*
4950  * getRules
4951  *        get basic information about every rule in the system
4952  *
4953  * numRules is set to the number of rules read in
4954  */
4955 RuleInfo *
4956 getRules(int *numRules)
4957 {
4958         PGresult   *res;
4959         int                     ntups;
4960         int                     i;
4961         PQExpBuffer query = createPQExpBuffer();
4962         RuleInfo   *ruleinfo;
4963         int                     i_tableoid;
4964         int                     i_oid;
4965         int                     i_rulename;
4966         int                     i_ruletable;
4967         int                     i_ev_type;
4968         int                     i_is_instead;
4969         int                     i_ev_enabled;
4970
4971         /* Make sure we are in proper schema */
4972         selectSourceSchema("pg_catalog");
4973
4974         if (g_fout->remoteVersion >= 80300)
4975         {
4976                 appendPQExpBuffer(query, "SELECT "
4977                                                   "tableoid, oid, rulename, "
4978                                                   "ev_class AS ruletable, ev_type, is_instead, "
4979                                                   "ev_enabled "
4980                                                   "FROM pg_rewrite "
4981                                                   "ORDER BY oid");
4982         }
4983         else if (g_fout->remoteVersion >= 70100)
4984         {
4985                 appendPQExpBuffer(query, "SELECT "
4986                                                   "tableoid, oid, rulename, "
4987                                                   "ev_class AS ruletable, ev_type, is_instead, "
4988                                                   "'O'::char AS ev_enabled "
4989                                                   "FROM pg_rewrite "
4990                                                   "ORDER BY oid");
4991         }
4992         else
4993         {
4994                 appendPQExpBuffer(query, "SELECT "
4995                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4996                                                   "oid, rulename, "
4997                                                   "ev_class AS ruletable, ev_type, is_instead, "
4998                                                   "'O'::char AS ev_enabled "
4999                                                   "FROM pg_rewrite "
5000                                                   "ORDER BY oid");
5001         }
5002
5003         res = PQexec(g_conn, query->data);
5004         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5005
5006         ntups = PQntuples(res);
5007
5008         *numRules = ntups;
5009
5010         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5011
5012         i_tableoid = PQfnumber(res, "tableoid");
5013         i_oid = PQfnumber(res, "oid");
5014         i_rulename = PQfnumber(res, "rulename");
5015         i_ruletable = PQfnumber(res, "ruletable");
5016         i_ev_type = PQfnumber(res, "ev_type");
5017         i_is_instead = PQfnumber(res, "is_instead");
5018         i_ev_enabled = PQfnumber(res, "ev_enabled");
5019
5020         for (i = 0; i < ntups; i++)
5021         {
5022                 Oid                     ruletableoid;
5023
5024                 ruleinfo[i].dobj.objType = DO_RULE;
5025                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5026                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5027                 AssignDumpId(&ruleinfo[i].dobj);
5028                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5029                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5030                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5031                 if (ruleinfo[i].ruletable == NULL)
5032                 {
5033                         write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5034                                           ruletableoid,
5035                                           ruleinfo[i].dobj.catId.oid);
5036                         exit_nicely();
5037                 }
5038                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5039                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5040                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5041                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5042                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5043                 if (ruleinfo[i].ruletable)
5044                 {
5045                         /*
5046                          * If the table is a view, force its ON SELECT rule to be sorted
5047                          * before the view itself --- this ensures that any dependencies
5048                          * for the rule affect the table's positioning. Other rules are
5049                          * forced to appear after their table.
5050                          */
5051                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
5052                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5053                         {
5054                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5055                                                                         ruleinfo[i].dobj.dumpId);
5056                                 /* We'll merge the rule into CREATE VIEW, if possible */
5057                                 ruleinfo[i].separate = false;
5058                         }
5059                         else
5060                         {
5061                                 addObjectDependency(&ruleinfo[i].dobj,
5062                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5063                                 ruleinfo[i].separate = true;
5064                         }
5065                 }
5066                 else
5067                         ruleinfo[i].separate = true;
5068         }
5069
5070         PQclear(res);
5071
5072         destroyPQExpBuffer(query);
5073
5074         return ruleinfo;
5075 }
5076
5077 /*
5078  * getTriggers
5079  *        get information about every trigger on a dumpable table
5080  *
5081  * Note: trigger data is not returned directly to the caller, but it
5082  * does get entered into the DumpableObject tables.
5083  */
5084 void
5085 getTriggers(TableInfo tblinfo[], int numTables)
5086 {
5087         int                     i,
5088                                 j;
5089         PQExpBuffer query = createPQExpBuffer();
5090         PGresult   *res;
5091         TriggerInfo *tginfo;
5092         int                     i_tableoid,
5093                                 i_oid,
5094                                 i_tgname,
5095                                 i_tgfname,
5096                                 i_tgtype,
5097                                 i_tgnargs,
5098                                 i_tgargs,
5099                                 i_tgisconstraint,
5100                                 i_tgconstrname,
5101                                 i_tgconstrrelid,
5102                                 i_tgconstrrelname,
5103                                 i_tgenabled,
5104                                 i_tgdeferrable,
5105                                 i_tginitdeferred,
5106                                 i_tgdef;
5107         int                     ntups;
5108
5109         for (i = 0; i < numTables; i++)
5110         {
5111                 TableInfo  *tbinfo = &tblinfo[i];
5112
5113                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5114                         continue;
5115
5116                 if (g_verbose)
5117                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5118                                           tbinfo->dobj.name);
5119
5120                 /*
5121                  * select table schema to ensure regproc name is qualified if needed
5122                  */
5123                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
5124
5125                 resetPQExpBuffer(query);
5126                 if (g_fout->remoteVersion >= 90000)
5127                 {
5128                         /*
5129                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5130                          * could result in non-forward-compatible dumps of WHEN clauses
5131                          * due to under-parenthesization.
5132                          */
5133                         appendPQExpBuffer(query,
5134                                                           "SELECT tgname, "
5135                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5136                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5137                                                           "tgenabled, tableoid, oid "
5138                                                           "FROM pg_catalog.pg_trigger t "
5139                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5140                                                           "AND NOT tgisinternal",
5141                                                           tbinfo->dobj.catId.oid);
5142                 }
5143                 else if (g_fout->remoteVersion >= 80300)
5144                 {
5145                         /*
5146                          * We ignore triggers that are tied to a foreign-key constraint
5147                          */
5148                         appendPQExpBuffer(query,
5149                                                           "SELECT tgname, "
5150                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5151                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5152                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5153                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5154                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5155                                                           "FROM pg_catalog.pg_trigger t "
5156                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5157                                                           "AND tgconstraint = 0",
5158                                                           tbinfo->dobj.catId.oid);
5159                 }
5160                 else if (g_fout->remoteVersion >= 70300)
5161                 {
5162                         /*
5163                          * We ignore triggers that are tied to a foreign-key constraint,
5164                          * but in these versions we have to grovel through pg_constraint
5165                          * to find out
5166                          */
5167                         appendPQExpBuffer(query,
5168                                                           "SELECT tgname, "
5169                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5170                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5171                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5172                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5173                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5174                                                           "FROM pg_catalog.pg_trigger t "
5175                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5176                                                           "AND (NOT tgisconstraint "
5177                                                           " OR NOT EXISTS"
5178                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5179                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5180                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5181                                                           tbinfo->dobj.catId.oid);
5182                 }
5183                 else if (g_fout->remoteVersion >= 70100)
5184                 {
5185                         appendPQExpBuffer(query,
5186                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5187                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5188                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5189                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5190                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5191                                                           "             AS tgconstrrelname "
5192                                                           "FROM pg_trigger "
5193                                                           "WHERE tgrelid = '%u'::oid",
5194                                                           tbinfo->dobj.catId.oid);
5195                 }
5196                 else
5197                 {
5198                         appendPQExpBuffer(query,
5199                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5200                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5201                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5202                                                           "tgconstrrelid, tginitdeferred, "
5203                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5204                                                           "oid, "
5205                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5206                                                           "             AS tgconstrrelname "
5207                                                           "FROM pg_trigger "
5208                                                           "WHERE tgrelid = '%u'::oid",
5209                                                           tbinfo->dobj.catId.oid);
5210                 }
5211                 res = PQexec(g_conn, query->data);
5212                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5213
5214                 ntups = PQntuples(res);
5215
5216                 i_tableoid = PQfnumber(res, "tableoid");
5217                 i_oid = PQfnumber(res, "oid");
5218                 i_tgname = PQfnumber(res, "tgname");
5219                 i_tgfname = PQfnumber(res, "tgfname");
5220                 i_tgtype = PQfnumber(res, "tgtype");
5221                 i_tgnargs = PQfnumber(res, "tgnargs");
5222                 i_tgargs = PQfnumber(res, "tgargs");
5223                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5224                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5225                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5226                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5227                 i_tgenabled = PQfnumber(res, "tgenabled");
5228                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5229                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5230                 i_tgdef = PQfnumber(res, "tgdef");
5231
5232                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5233
5234                 for (j = 0; j < ntups; j++)
5235                 {
5236                         tginfo[j].dobj.objType = DO_TRIGGER;
5237                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5238                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5239                         AssignDumpId(&tginfo[j].dobj);
5240                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5241                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5242                         tginfo[j].tgtable = tbinfo;
5243                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5244                         if (i_tgdef >= 0)
5245                         {
5246                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5247
5248                                 /* remaining fields are not valid if we have tgdef */
5249                                 tginfo[j].tgfname = NULL;
5250                                 tginfo[j].tgtype = 0;
5251                                 tginfo[j].tgnargs = 0;
5252                                 tginfo[j].tgargs = NULL;
5253                                 tginfo[j].tgisconstraint = false;
5254                                 tginfo[j].tgdeferrable = false;
5255                                 tginfo[j].tginitdeferred = false;
5256                                 tginfo[j].tgconstrname = NULL;
5257                                 tginfo[j].tgconstrrelid = InvalidOid;
5258                                 tginfo[j].tgconstrrelname = NULL;
5259                         }
5260                         else
5261                         {
5262                                 tginfo[j].tgdef = NULL;
5263
5264                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5265                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5266                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5267                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5268                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5269                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5270                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5271
5272                                 if (tginfo[j].tgisconstraint)
5273                                 {
5274                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5275                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5276                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5277                                         {
5278                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5279                                                 {
5280                                                         write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5281                                                                           tginfo[j].dobj.name, tbinfo->dobj.name,
5282                                                                           tginfo[j].tgconstrrelid);
5283                                                         exit_nicely();
5284                                                 }
5285                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5286                                         }
5287                                         else
5288                                                 tginfo[j].tgconstrrelname = NULL;
5289                                 }
5290                                 else
5291                                 {
5292                                         tginfo[j].tgconstrname = NULL;
5293                                         tginfo[j].tgconstrrelid = InvalidOid;
5294                                         tginfo[j].tgconstrrelname = NULL;
5295                                 }
5296                         }
5297                 }
5298
5299                 PQclear(res);
5300         }
5301
5302         destroyPQExpBuffer(query);
5303 }
5304
5305 /*
5306  * getProcLangs
5307  *        get basic information about every procedural language in the system
5308  *
5309  * numProcLangs is set to the number of langs read in
5310  *
5311  * NB: this must run after getFuncs() because we assume we can do
5312  * findFuncByOid().
5313  */
5314 ProcLangInfo *
5315 getProcLangs(int *numProcLangs)
5316 {
5317         PGresult   *res;
5318         int                     ntups;
5319         int                     i;
5320         PQExpBuffer query = createPQExpBuffer();
5321         ProcLangInfo *planginfo;
5322         int                     i_tableoid;
5323         int                     i_oid;
5324         int                     i_lanname;
5325         int                     i_lanpltrusted;
5326         int                     i_lanplcallfoid;
5327         int                     i_laninline;
5328         int                     i_lanvalidator;
5329         int                     i_lanacl;
5330         int                     i_lanowner;
5331
5332         /* Make sure we are in proper schema */
5333         selectSourceSchema("pg_catalog");
5334
5335         if (g_fout->remoteVersion >= 90000)
5336         {
5337                 /* pg_language has a laninline column */
5338                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5339                                                   "lanname, lanpltrusted, lanplcallfoid, "
5340                                                   "laninline, lanvalidator,  lanacl, "
5341                                                   "(%s lanowner) AS lanowner "
5342                                                   "FROM pg_language "
5343                                                   "WHERE lanispl "
5344                                                   "ORDER BY oid",
5345                                                   username_subquery);
5346         }
5347         else if (g_fout->remoteVersion >= 80300)
5348         {
5349                 /* pg_language has a lanowner column */
5350                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5351                                                   "lanname, lanpltrusted, lanplcallfoid, "
5352                                                   "lanvalidator,  lanacl, "
5353                                                   "(%s lanowner) AS lanowner "
5354                                                   "FROM pg_language "
5355                                                   "WHERE lanispl "
5356                                                   "ORDER BY oid",
5357                                                   username_subquery);
5358         }
5359         else if (g_fout->remoteVersion >= 80100)
5360         {
5361                 /* Languages are owned by the bootstrap superuser, OID 10 */
5362                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5363                                                   "(%s '10') AS lanowner "
5364                                                   "FROM pg_language "
5365                                                   "WHERE lanispl "
5366                                                   "ORDER BY oid",
5367                                                   username_subquery);
5368         }
5369         else if (g_fout->remoteVersion >= 70400)
5370         {
5371                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5372                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5373                                                   "(%s '1') AS lanowner "
5374                                                   "FROM pg_language "
5375                                                   "WHERE lanispl "
5376                                                   "ORDER BY oid",
5377                                                   username_subquery);
5378         }
5379         else if (g_fout->remoteVersion >= 70100)
5380         {
5381                 /* No clear notion of an owner at all before 7.4 ... */
5382                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5383                                                   "WHERE lanispl "
5384                                                   "ORDER BY oid");
5385         }
5386         else
5387         {
5388                 appendPQExpBuffer(query, "SELECT "
5389                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5390                                                   "oid, * FROM pg_language "
5391                                                   "WHERE lanispl "
5392                                                   "ORDER BY oid");
5393         }
5394
5395         res = PQexec(g_conn, query->data);
5396         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5397
5398         ntups = PQntuples(res);
5399
5400         *numProcLangs = ntups;
5401
5402         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5403
5404         i_tableoid = PQfnumber(res, "tableoid");
5405         i_oid = PQfnumber(res, "oid");
5406         i_lanname = PQfnumber(res, "lanname");
5407         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5408         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5409         /* these may fail and return -1: */
5410         i_laninline = PQfnumber(res, "laninline");
5411         i_lanvalidator = PQfnumber(res, "lanvalidator");
5412         i_lanacl = PQfnumber(res, "lanacl");
5413         i_lanowner = PQfnumber(res, "lanowner");
5414
5415         for (i = 0; i < ntups; i++)
5416         {
5417                 planginfo[i].dobj.objType = DO_PROCLANG;
5418                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5419                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5420                 AssignDumpId(&planginfo[i].dobj);
5421
5422                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5423                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5424                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5425                 if (i_laninline >= 0)
5426                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5427                 else
5428                         planginfo[i].laninline = InvalidOid;
5429                 if (i_lanvalidator >= 0)
5430                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5431                 else
5432                         planginfo[i].lanvalidator = InvalidOid;
5433                 if (i_lanacl >= 0)
5434                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5435                 else
5436                         planginfo[i].lanacl = pg_strdup("{=U}");
5437                 if (i_lanowner >= 0)
5438                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5439                 else
5440                         planginfo[i].lanowner = pg_strdup("");
5441
5442                 if (g_fout->remoteVersion < 70300)
5443                 {
5444                         /*
5445                          * We need to make a dependency to ensure the function will be
5446                          * dumped first.  (In 7.3 and later the regular dependency
5447                          * mechanism will handle this for us.)
5448                          */
5449                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5450
5451                         if (funcInfo)
5452                                 addObjectDependency(&planginfo[i].dobj,
5453                                                                         funcInfo->dobj.dumpId);
5454                 }
5455         }
5456
5457         PQclear(res);
5458
5459         destroyPQExpBuffer(query);
5460
5461         return planginfo;
5462 }
5463
5464 /*
5465  * getCasts
5466  *        get basic information about every cast in the system
5467  *
5468  * numCasts is set to the number of casts read in
5469  */
5470 CastInfo *
5471 getCasts(int *numCasts)
5472 {
5473         PGresult   *res;
5474         int                     ntups;
5475         int                     i;
5476         PQExpBuffer query = createPQExpBuffer();
5477         CastInfo   *castinfo;
5478         int                     i_tableoid;
5479         int                     i_oid;
5480         int                     i_castsource;
5481         int                     i_casttarget;
5482         int                     i_castfunc;
5483         int                     i_castcontext;
5484         int                     i_castmethod;
5485
5486         /* Make sure we are in proper schema */
5487         selectSourceSchema("pg_catalog");
5488
5489         if (g_fout->remoteVersion >= 80400)
5490         {
5491                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5492                                                   "castsource, casttarget, castfunc, castcontext, "
5493                                                   "castmethod "
5494                                                   "FROM pg_cast ORDER BY 3,4");
5495         }
5496         else if (g_fout->remoteVersion >= 70300)
5497         {
5498                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5499                                                   "castsource, casttarget, castfunc, castcontext, "
5500                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
5501                                                   "FROM pg_cast ORDER BY 3,4");
5502         }
5503         else
5504         {
5505                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
5506                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
5507                                                   "p.oid AS castfunc, 'e' AS castcontext, "
5508                                                   "'f' AS castmethod "
5509                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
5510                                                   "WHERE p.pronargs = 1 AND "
5511                                                   "p.proargtypes[0] = t1.oid AND "
5512                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
5513                                                   "ORDER BY 3,4");
5514         }
5515
5516         res = PQexec(g_conn, query->data);
5517         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5518
5519         ntups = PQntuples(res);
5520
5521         *numCasts = ntups;
5522
5523         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
5524
5525         i_tableoid = PQfnumber(res, "tableoid");
5526         i_oid = PQfnumber(res, "oid");
5527         i_castsource = PQfnumber(res, "castsource");
5528         i_casttarget = PQfnumber(res, "casttarget");
5529         i_castfunc = PQfnumber(res, "castfunc");
5530         i_castcontext = PQfnumber(res, "castcontext");
5531         i_castmethod = PQfnumber(res, "castmethod");
5532
5533         for (i = 0; i < ntups; i++)
5534         {
5535                 PQExpBufferData namebuf;
5536                 TypeInfo   *sTypeInfo;
5537                 TypeInfo   *tTypeInfo;
5538
5539                 castinfo[i].dobj.objType = DO_CAST;
5540                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5541                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5542                 AssignDumpId(&castinfo[i].dobj);
5543                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
5544                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
5545                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
5546                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
5547                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
5548
5549                 /*
5550                  * Try to name cast as concatenation of typnames.  This is only used
5551                  * for purposes of sorting.  If we fail to find either type, the name
5552                  * will be an empty string.
5553                  */
5554                 initPQExpBuffer(&namebuf);
5555                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
5556                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
5557                 if (sTypeInfo && tTypeInfo)
5558                         appendPQExpBuffer(&namebuf, "%s %s",
5559                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
5560                 castinfo[i].dobj.name = namebuf.data;
5561
5562                 if (OidIsValid(castinfo[i].castfunc))
5563                 {
5564                         /*
5565                          * We need to make a dependency to ensure the function will be
5566                          * dumped first.  (In 7.3 and later the regular dependency
5567                          * mechanism will handle this for us.)
5568                          */
5569                         FuncInfo   *funcInfo;
5570
5571                         funcInfo = findFuncByOid(castinfo[i].castfunc);
5572                         if (funcInfo)
5573                                 addObjectDependency(&castinfo[i].dobj,
5574                                                                         funcInfo->dobj.dumpId);
5575                 }
5576         }
5577
5578         PQclear(res);
5579
5580         destroyPQExpBuffer(query);
5581
5582         return castinfo;
5583 }
5584
5585 /*
5586  * getTableAttrs -
5587  *        for each interesting table, read info about its attributes
5588  *        (names, types, default values, CHECK constraints, etc)
5589  *
5590  * This is implemented in a very inefficient way right now, looping
5591  * through the tblinfo and doing a join per table to find the attrs and their
5592  * types.  However, because we want type names and so forth to be named
5593  * relative to the schema of each table, we couldn't do it in just one
5594  * query.  (Maybe one query per schema?)
5595  *
5596  *      modifies tblinfo
5597  */
5598 void
5599 getTableAttrs(TableInfo *tblinfo, int numTables)
5600 {
5601         int                     i,
5602                                 j;
5603         PQExpBuffer q = createPQExpBuffer();
5604         int                     i_attnum;
5605         int                     i_attname;
5606         int                     i_atttypname;
5607         int                     i_atttypmod;
5608         int                     i_attstattarget;
5609         int                     i_attstorage;
5610         int                     i_typstorage;
5611         int                     i_attnotnull;
5612         int                     i_atthasdef;
5613         int                     i_attisdropped;
5614         int                     i_attlen;
5615         int                     i_attalign;
5616         int                     i_attislocal;
5617         int                     i_attoptions;
5618         int                     i_attcollation;
5619         int                     i_attfdwoptions;
5620         PGresult   *res;
5621         int                     ntups;
5622         bool            hasdefaults;
5623
5624         for (i = 0; i < numTables; i++)
5625         {
5626                 TableInfo  *tbinfo = &tblinfo[i];
5627
5628                 /* Don't bother to collect info for sequences */
5629                 if (tbinfo->relkind == RELKIND_SEQUENCE)
5630                         continue;
5631
5632                 /* Don't bother with uninteresting tables, either */
5633                 if (!tbinfo->interesting)
5634                         continue;
5635
5636                 /*
5637                  * Make sure we are in proper schema for this table; this allows
5638                  * correct retrieval of formatted type names and default exprs
5639                  */
5640                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
5641
5642                 /* find all the user attributes and their types */
5643
5644                 /*
5645                  * we must read the attribute names in attribute number order! because
5646                  * we will use the attnum to index into the attnames array later.  We
5647                  * actually ask to order by "attrelid, attnum" because (at least up to
5648                  * 7.3) the planner is not smart enough to realize it needn't re-sort
5649                  * the output of an indexscan on pg_attribute_relid_attnum_index.
5650                  */
5651                 if (g_verbose)
5652                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
5653                                           tbinfo->dobj.name);
5654
5655                 resetPQExpBuffer(q);
5656
5657                 if (g_fout->remoteVersion >= 90200)
5658                 {
5659                         /*
5660                          * attfdwoptions is new in 9.2.
5661                          */
5662                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5663                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5664                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5665                                                           "a.attlen, a.attalign, a.attislocal, "
5666                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5667                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5668                                                           "CASE WHEN a.attcollation <> t.typcollation "
5669                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5670                                                           "pg_catalog.array_to_string(ARRAY("
5671                                                           "SELECT pg_catalog.quote_ident(option_name) || "
5672                                                           "' ' || pg_catalog.quote_literal(option_value) "
5673                                                           "FROM pg_catalog.pg_options_to_table(attfdwoptions)"
5674                                                           "), ', ') AS attfdwoptions "
5675                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5676                                                           "ON a.atttypid = t.oid "
5677                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5678                                                           "AND a.attnum > 0::pg_catalog.int2 "
5679                                                           "ORDER BY a.attrelid, a.attnum",
5680                                                           tbinfo->dobj.catId.oid);
5681                 }
5682                 else if (g_fout->remoteVersion >= 90100)
5683                 {
5684                         /*
5685                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
5686                          * clauses for attributes whose collation is different from their
5687                          * type's default, we use a CASE here to suppress uninteresting
5688                          * attcollations cheaply.
5689                          */
5690                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5691                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5692                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5693                                                           "a.attlen, a.attalign, a.attislocal, "
5694                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5695                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5696                                                           "CASE WHEN a.attcollation <> t.typcollation "
5697                                                         "THEN a.attcollation ELSE 0 END AS attcollation, "
5698                                                           "NULL AS attfdwoptions "
5699                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5700                                                           "ON a.atttypid = t.oid "
5701                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5702                                                           "AND a.attnum > 0::pg_catalog.int2 "
5703                                                           "ORDER BY a.attrelid, a.attnum",
5704                                                           tbinfo->dobj.catId.oid);
5705                 }
5706                 else if (g_fout->remoteVersion >= 90000)
5707                 {
5708                         /* attoptions is new in 9.0 */
5709                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5710                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5711                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5712                                                           "a.attlen, a.attalign, a.attislocal, "
5713                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5714                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
5715                                                           "0 AS attcollation, "
5716                                                           "NULL AS attfdwoptions "
5717                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5718                                                           "ON a.atttypid = t.oid "
5719                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5720                                                           "AND a.attnum > 0::pg_catalog.int2 "
5721                                                           "ORDER BY a.attrelid, a.attnum",
5722                                                           tbinfo->dobj.catId.oid);
5723                 }
5724                 else if (g_fout->remoteVersion >= 70300)
5725                 {
5726                         /* need left join here to not fail on dropped columns ... */
5727                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5728                                                           "a.attstattarget, a.attstorage, t.typstorage, "
5729                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
5730                                                           "a.attlen, a.attalign, a.attislocal, "
5731                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
5732                                                           "'' AS attoptions, 0 AS attcollation, "
5733                                                           "NULL AS attfdwoptions "
5734                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
5735                                                           "ON a.atttypid = t.oid "
5736                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
5737                                                           "AND a.attnum > 0::pg_catalog.int2 "
5738                                                           "ORDER BY a.attrelid, a.attnum",
5739                                                           tbinfo->dobj.catId.oid);
5740                 }
5741                 else if (g_fout->remoteVersion >= 70100)
5742                 {
5743                         /*
5744                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
5745                          * we don't dump it because we can't tell whether it's been
5746                          * explicitly set or was just a default.
5747                          */
5748                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
5749                                                           "-1 AS attstattarget, a.attstorage, "
5750                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
5751                                                           "false AS attisdropped, a.attlen, "
5752                                                           "a.attalign, false AS attislocal, "
5753                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
5754                                                           "'' AS attoptions, 0 AS attcollation, "
5755                                                           "NULL AS attfdwoptions "
5756                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
5757                                                           "ON a.atttypid = t.oid "
5758                                                           "WHERE a.attrelid = '%u'::oid "
5759                                                           "AND a.attnum > 0::int2 "
5760                                                           "ORDER BY a.attrelid, a.attnum",
5761                                                           tbinfo->dobj.catId.oid);
5762                 }
5763                 else
5764                 {
5765                         /* format_type not available before 7.1 */
5766                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
5767                                                           "-1 AS attstattarget, "
5768                                                           "attstorage, attstorage AS typstorage, "
5769                                                           "attnotnull, atthasdef, false AS attisdropped, "
5770                                                           "attlen, attalign, "
5771                                                           "false AS attislocal, "
5772                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
5773                                                           "'' AS attoptions, 0 AS attcollation, "
5774                                                           "NULL AS attfdwoptions "
5775                                                           "FROM pg_attribute a "
5776                                                           "WHERE attrelid = '%u'::oid "
5777                                                           "AND attnum > 0::int2 "
5778                                                           "ORDER BY attrelid, attnum",
5779                                                           tbinfo->dobj.catId.oid);
5780                 }
5781
5782                 res = PQexec(g_conn, q->data);
5783                 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5784
5785                 ntups = PQntuples(res);
5786
5787                 i_attnum = PQfnumber(res, "attnum");
5788                 i_attname = PQfnumber(res, "attname");
5789                 i_atttypname = PQfnumber(res, "atttypname");
5790                 i_atttypmod = PQfnumber(res, "atttypmod");
5791                 i_attstattarget = PQfnumber(res, "attstattarget");
5792                 i_attstorage = PQfnumber(res, "attstorage");
5793                 i_typstorage = PQfnumber(res, "typstorage");
5794                 i_attnotnull = PQfnumber(res, "attnotnull");
5795                 i_atthasdef = PQfnumber(res, "atthasdef");
5796                 i_attisdropped = PQfnumber(res, "attisdropped");
5797                 i_attlen = PQfnumber(res, "attlen");
5798                 i_attalign = PQfnumber(res, "attalign");
5799                 i_attislocal = PQfnumber(res, "attislocal");
5800                 i_attoptions = PQfnumber(res, "attoptions");
5801                 i_attcollation = PQfnumber(res, "attcollation");
5802                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
5803
5804                 tbinfo->numatts = ntups;
5805                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
5806                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
5807                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
5808                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
5809                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
5810                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
5811                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
5812                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
5813                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
5814                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
5815                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
5816                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
5817                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
5818                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
5819                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
5820                 tbinfo->inhAttrs = (bool *) pg_malloc(ntups * sizeof(bool));
5821                 tbinfo->inhAttrDef = (bool *) pg_malloc(ntups * sizeof(bool));
5822                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
5823                 hasdefaults = false;
5824
5825                 for (j = 0; j < ntups; j++)
5826                 {
5827                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
5828                         {
5829                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
5830                                                   tbinfo->dobj.name);
5831                                 exit_nicely();
5832                         }
5833                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
5834                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
5835                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
5836                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
5837                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
5838                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
5839                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
5840                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
5841                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
5842                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
5843                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
5844                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
5845                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
5846                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
5847                         tbinfo->attrdefs[j] = NULL; /* fix below */
5848                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
5849                                 hasdefaults = true;
5850                         /* these flags will be set in flagInhAttrs() */
5851                         tbinfo->inhAttrs[j] = false;
5852                         tbinfo->inhAttrDef[j] = false;
5853                         tbinfo->inhNotNull[j] = false;
5854                 }
5855
5856                 PQclear(res);
5857
5858                 /*
5859                  * Get info about column defaults
5860                  */
5861                 if (hasdefaults)
5862                 {
5863                         AttrDefInfo *attrdefs;
5864                         int                     numDefaults;
5865
5866                         if (g_verbose)
5867                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
5868                                                   tbinfo->dobj.name);
5869
5870                         resetPQExpBuffer(q);
5871                         if (g_fout->remoteVersion >= 70300)
5872                         {
5873                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
5874                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
5875                                                                   "FROM pg_catalog.pg_attrdef "
5876                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
5877                                                                   tbinfo->dobj.catId.oid);
5878                         }
5879                         else if (g_fout->remoteVersion >= 70200)
5880                         {
5881                                 /* 7.2 did not have OIDs in pg_attrdef */
5882                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
5883                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
5884                                                                   "FROM pg_attrdef "
5885                                                                   "WHERE adrelid = '%u'::oid",
5886                                                                   tbinfo->dobj.catId.oid);
5887                         }
5888                         else if (g_fout->remoteVersion >= 70100)
5889                         {
5890                                 /* no pg_get_expr, so must rely on adsrc */
5891                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
5892                                                                   "FROM pg_attrdef "
5893                                                                   "WHERE adrelid = '%u'::oid",
5894                                                                   tbinfo->dobj.catId.oid);
5895                         }
5896                         else
5897                         {
5898                                 /* no pg_get_expr, no tableoid either */
5899                                 appendPQExpBuffer(q, "SELECT "
5900                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
5901                                                                   "oid, adnum, adsrc "
5902                                                                   "FROM pg_attrdef "
5903                                                                   "WHERE adrelid = '%u'::oid",
5904                                                                   tbinfo->dobj.catId.oid);
5905                         }
5906                         res = PQexec(g_conn, q->data);
5907                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5908
5909                         numDefaults = PQntuples(res);
5910                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
5911
5912                         for (j = 0; j < numDefaults; j++)
5913                         {
5914                                 int                     adnum;
5915
5916                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
5917                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5918                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5919                                 AssignDumpId(&attrdefs[j].dobj);
5920                                 attrdefs[j].adtable = tbinfo;
5921                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
5922                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
5923
5924                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
5925                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
5926
5927                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
5928
5929                                 /*
5930                                  * Defaults on a VIEW must always be dumped as separate ALTER
5931                                  * TABLE commands.      Defaults on regular tables are dumped as
5932                                  * part of the CREATE TABLE if possible.  To check if it's
5933                                  * safe, we mark the default as needing to appear before the
5934                                  * CREATE.
5935                                  */
5936                                 if (tbinfo->relkind == RELKIND_VIEW)
5937                                 {
5938                                         attrdefs[j].separate = true;
5939                                         /* needed in case pre-7.3 DB: */
5940                                         addObjectDependency(&attrdefs[j].dobj,
5941                                                                                 tbinfo->dobj.dumpId);
5942                                 }
5943                                 else
5944                                 {
5945                                         attrdefs[j].separate = false;
5946                                         addObjectDependency(&tbinfo->dobj,
5947                                                                                 attrdefs[j].dobj.dumpId);
5948                                 }
5949
5950                                 if (adnum <= 0 || adnum > ntups)
5951                                 {
5952                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
5953                                                           adnum, tbinfo->dobj.name);
5954                                         exit_nicely();
5955                                 }
5956                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
5957                         }
5958                         PQclear(res);
5959                 }
5960
5961                 /*
5962                  * Get info about table CHECK constraints
5963                  */
5964                 if (tbinfo->ncheck > 0)
5965                 {
5966                         ConstraintInfo *constrs;
5967                         int                     numConstrs;
5968
5969                         if (g_verbose)
5970                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
5971                                                   tbinfo->dobj.name);
5972
5973                         resetPQExpBuffer(q);
5974                         if (g_fout->remoteVersion >= 90100)
5975                         {
5976                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5977                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5978                                                                   "conislocal, convalidated "
5979                                                                   "FROM pg_catalog.pg_constraint "
5980                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5981                                                                   "   AND contype = 'c' "
5982                                                                   "ORDER BY conname",
5983                                                                   tbinfo->dobj.catId.oid);
5984                         }
5985                         else if (g_fout->remoteVersion >= 80400)
5986                         {
5987                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5988                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5989                                                                   "conislocal, true AS convalidated "
5990                                                                   "FROM pg_catalog.pg_constraint "
5991                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5992                                                                   "   AND contype = 'c' "
5993                                                                   "ORDER BY conname",
5994                                                                   tbinfo->dobj.catId.oid);
5995                         }
5996                         else if (g_fout->remoteVersion >= 70400)
5997                         {
5998                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5999                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6000                                                                   "true AS conislocal, true AS convalidated "
6001                                                                   "FROM pg_catalog.pg_constraint "
6002                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6003                                                                   "   AND contype = 'c' "
6004                                                                   "ORDER BY conname",
6005                                                                   tbinfo->dobj.catId.oid);
6006                         }
6007                         else if (g_fout->remoteVersion >= 70300)
6008                         {
6009                                 /* no pg_get_constraintdef, must use consrc */
6010                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6011                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6012                                                                   "true AS conislocal, true AS convalidated "
6013                                                                   "FROM pg_catalog.pg_constraint "
6014                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6015                                                                   "   AND contype = 'c' "
6016                                                                   "ORDER BY conname",
6017                                                                   tbinfo->dobj.catId.oid);
6018                         }
6019                         else if (g_fout->remoteVersion >= 70200)
6020                         {
6021                                 /* 7.2 did not have OIDs in pg_relcheck */
6022                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6023                                                                   "rcname AS conname, "
6024                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6025                                                                   "true AS conislocal, true AS convalidated "
6026                                                                   "FROM pg_relcheck "
6027                                                                   "WHERE rcrelid = '%u'::oid "
6028                                                                   "ORDER BY rcname",
6029                                                                   tbinfo->dobj.catId.oid);
6030                         }
6031                         else if (g_fout->remoteVersion >= 70100)
6032                         {
6033                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6034                                                                   "rcname AS conname, "
6035                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6036                                                                   "true AS conislocal, true AS convalidated "
6037                                                                   "FROM pg_relcheck "
6038                                                                   "WHERE rcrelid = '%u'::oid "
6039                                                                   "ORDER BY rcname",
6040                                                                   tbinfo->dobj.catId.oid);
6041                         }
6042                         else
6043                         {
6044                                 /* no tableoid in 7.0 */
6045                                 appendPQExpBuffer(q, "SELECT "
6046                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6047                                                                   "oid, rcname AS conname, "
6048                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6049                                                                   "true AS conislocal, true AS convalidated "
6050                                                                   "FROM pg_relcheck "
6051                                                                   "WHERE rcrelid = '%u'::oid "
6052                                                                   "ORDER BY rcname",
6053                                                                   tbinfo->dobj.catId.oid);
6054                         }
6055                         res = PQexec(g_conn, q->data);
6056                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
6057
6058                         numConstrs = PQntuples(res);
6059                         if (numConstrs != tbinfo->ncheck)
6060                         {
6061                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6062                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6063                                                                                  tbinfo->ncheck),
6064                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6065                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6066                                 exit_nicely();
6067                         }
6068
6069                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6070                         tbinfo->checkexprs = constrs;
6071
6072                         for (j = 0; j < numConstrs; j++)
6073                         {
6074                                 bool    validated = PQgetvalue(res, j, 5)[0] == 't';
6075
6076                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6077                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6078                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6079                                 AssignDumpId(&constrs[j].dobj);
6080                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6081                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6082                                 constrs[j].contable = tbinfo;
6083                                 constrs[j].condomain = NULL;
6084                                 constrs[j].contype = 'c';
6085                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6086                                 constrs[j].confrelid = InvalidOid;
6087                                 constrs[j].conindex = 0;
6088                                 constrs[j].condeferrable = false;
6089                                 constrs[j].condeferred = false;
6090                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6091                                 /*
6092                                  * An unvalidated constraint needs to be dumped separately, so
6093                                  * that potentially-violating existing data is loaded before
6094                                  * the constraint.
6095                                  */
6096                                 constrs[j].separate = !validated;
6097
6098                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6099
6100                                 /*
6101                                  * Mark the constraint as needing to appear before the table
6102                                  * --- this is so that any other dependencies of the
6103                                  * constraint will be emitted before we try to create the
6104                                  * table.  If the constraint is not validated, it will be
6105                                  * dumped after data is loaded anyway, so don't do it.  (There's
6106                                  * an automatic dependency in the opposite direction anyway, so
6107                                  * don't need to add one manually here.)
6108                                  */
6109                                 if (validated)
6110                                         addObjectDependency(&tbinfo->dobj,
6111                                                                                 constrs[j].dobj.dumpId);
6112
6113                                 /*
6114                                  * If the constraint is inherited, this will be detected later
6115                                  * (in pre-8.4 databases).      We also detect later if the
6116                                  * constraint must be split out from the table definition.
6117                                  */
6118                         }
6119                         PQclear(res);
6120                 }
6121         }
6122
6123         destroyPQExpBuffer(q);
6124 }
6125
6126
6127 /*
6128  * getTSParsers:
6129  *        read all text search parsers in the system catalogs and return them
6130  *        in the TSParserInfo* structure
6131  *
6132  *      numTSParsers is set to the number of parsers read in
6133  */
6134 TSParserInfo *
6135 getTSParsers(int *numTSParsers)
6136 {
6137         PGresult   *res;
6138         int                     ntups;
6139         int                     i;
6140         PQExpBuffer query = createPQExpBuffer();
6141         TSParserInfo *prsinfo;
6142         int                     i_tableoid;
6143         int                     i_oid;
6144         int                     i_prsname;
6145         int                     i_prsnamespace;
6146         int                     i_prsstart;
6147         int                     i_prstoken;
6148         int                     i_prsend;
6149         int                     i_prsheadline;
6150         int                     i_prslextype;
6151
6152         /* Before 8.3, there is no built-in text search support */
6153         if (g_fout->remoteVersion < 80300)
6154         {
6155                 *numTSParsers = 0;
6156                 return NULL;
6157         }
6158
6159         /*
6160          * find all text search objects, including builtin ones; we filter out
6161          * system-defined objects at dump-out time.
6162          */
6163
6164         /* Make sure we are in proper schema */
6165         selectSourceSchema("pg_catalog");
6166
6167         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6168                                           "prsstart::oid, prstoken::oid, "
6169                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6170                                           "FROM pg_ts_parser");
6171
6172         res = PQexec(g_conn, query->data);
6173         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6174
6175         ntups = PQntuples(res);
6176         *numTSParsers = ntups;
6177
6178         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6179
6180         i_tableoid = PQfnumber(res, "tableoid");
6181         i_oid = PQfnumber(res, "oid");
6182         i_prsname = PQfnumber(res, "prsname");
6183         i_prsnamespace = PQfnumber(res, "prsnamespace");
6184         i_prsstart = PQfnumber(res, "prsstart");
6185         i_prstoken = PQfnumber(res, "prstoken");
6186         i_prsend = PQfnumber(res, "prsend");
6187         i_prsheadline = PQfnumber(res, "prsheadline");
6188         i_prslextype = PQfnumber(res, "prslextype");
6189
6190         for (i = 0; i < ntups; i++)
6191         {
6192                 prsinfo[i].dobj.objType = DO_TSPARSER;
6193                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6194                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6195                 AssignDumpId(&prsinfo[i].dobj);
6196                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6197                 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
6198                                                                                                   prsinfo[i].dobj.catId.oid);
6199                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6200                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6201                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6202                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6203                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6204
6205                 /* Decide whether we want to dump it */
6206                 selectDumpableObject(&(prsinfo[i].dobj));
6207         }
6208
6209         PQclear(res);
6210
6211         destroyPQExpBuffer(query);
6212
6213         return prsinfo;
6214 }
6215
6216 /*
6217  * getTSDictionaries:
6218  *        read all text search dictionaries in the system catalogs and return them
6219  *        in the TSDictInfo* structure
6220  *
6221  *      numTSDicts is set to the number of dictionaries read in
6222  */
6223 TSDictInfo *
6224 getTSDictionaries(int *numTSDicts)
6225 {
6226         PGresult   *res;
6227         int                     ntups;
6228         int                     i;
6229         PQExpBuffer query = createPQExpBuffer();
6230         TSDictInfo *dictinfo;
6231         int                     i_tableoid;
6232         int                     i_oid;
6233         int                     i_dictname;
6234         int                     i_dictnamespace;
6235         int                     i_rolname;
6236         int                     i_dicttemplate;
6237         int                     i_dictinitoption;
6238
6239         /* Before 8.3, there is no built-in text search support */
6240         if (g_fout->remoteVersion < 80300)
6241         {
6242                 *numTSDicts = 0;
6243                 return NULL;
6244         }
6245
6246         /* Make sure we are in proper schema */
6247         selectSourceSchema("pg_catalog");
6248
6249         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6250                                           "dictnamespace, (%s dictowner) AS rolname, "
6251                                           "dicttemplate, dictinitoption "
6252                                           "FROM pg_ts_dict",
6253                                           username_subquery);
6254
6255         res = PQexec(g_conn, query->data);
6256         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6257
6258         ntups = PQntuples(res);
6259         *numTSDicts = ntups;
6260
6261         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6262
6263         i_tableoid = PQfnumber(res, "tableoid");
6264         i_oid = PQfnumber(res, "oid");
6265         i_dictname = PQfnumber(res, "dictname");
6266         i_dictnamespace = PQfnumber(res, "dictnamespace");
6267         i_rolname = PQfnumber(res, "rolname");
6268         i_dictinitoption = PQfnumber(res, "dictinitoption");
6269         i_dicttemplate = PQfnumber(res, "dicttemplate");
6270
6271         for (i = 0; i < ntups; i++)
6272         {
6273                 dictinfo[i].dobj.objType = DO_TSDICT;
6274                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6275                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6276                 AssignDumpId(&dictinfo[i].dobj);
6277                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6278                 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
6279                                                                                                  dictinfo[i].dobj.catId.oid);
6280                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6281                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6282                 if (PQgetisnull(res, i, i_dictinitoption))
6283                         dictinfo[i].dictinitoption = NULL;
6284                 else
6285                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6286
6287                 /* Decide whether we want to dump it */
6288                 selectDumpableObject(&(dictinfo[i].dobj));
6289         }
6290
6291         PQclear(res);
6292
6293         destroyPQExpBuffer(query);
6294
6295         return dictinfo;
6296 }
6297
6298 /*
6299  * getTSTemplates:
6300  *        read all text search templates in the system catalogs and return them
6301  *        in the TSTemplateInfo* structure
6302  *
6303  *      numTSTemplates is set to the number of templates read in
6304  */
6305 TSTemplateInfo *
6306 getTSTemplates(int *numTSTemplates)
6307 {
6308         PGresult   *res;
6309         int                     ntups;
6310         int                     i;
6311         PQExpBuffer query = createPQExpBuffer();
6312         TSTemplateInfo *tmplinfo;
6313         int                     i_tableoid;
6314         int                     i_oid;
6315         int                     i_tmplname;
6316         int                     i_tmplnamespace;
6317         int                     i_tmplinit;
6318         int                     i_tmpllexize;
6319
6320         /* Before 8.3, there is no built-in text search support */
6321         if (g_fout->remoteVersion < 80300)
6322         {
6323                 *numTSTemplates = 0;
6324                 return NULL;
6325         }
6326
6327         /* Make sure we are in proper schema */
6328         selectSourceSchema("pg_catalog");
6329
6330         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6331                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6332                                           "FROM pg_ts_template");
6333
6334         res = PQexec(g_conn, query->data);
6335         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6336
6337         ntups = PQntuples(res);
6338         *numTSTemplates = ntups;
6339
6340         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6341
6342         i_tableoid = PQfnumber(res, "tableoid");
6343         i_oid = PQfnumber(res, "oid");
6344         i_tmplname = PQfnumber(res, "tmplname");
6345         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6346         i_tmplinit = PQfnumber(res, "tmplinit");
6347         i_tmpllexize = PQfnumber(res, "tmpllexize");
6348
6349         for (i = 0; i < ntups; i++)
6350         {
6351                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6352                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6353                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6354                 AssignDumpId(&tmplinfo[i].dobj);
6355                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6356                 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
6357                                                                                                  tmplinfo[i].dobj.catId.oid);
6358                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6359                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6360
6361                 /* Decide whether we want to dump it */
6362                 selectDumpableObject(&(tmplinfo[i].dobj));
6363         }
6364
6365         PQclear(res);
6366
6367         destroyPQExpBuffer(query);
6368
6369         return tmplinfo;
6370 }
6371
6372 /*
6373  * getTSConfigurations:
6374  *        read all text search configurations in the system catalogs and return
6375  *        them in the TSConfigInfo* structure
6376  *
6377  *      numTSConfigs is set to the number of configurations read in
6378  */
6379 TSConfigInfo *
6380 getTSConfigurations(int *numTSConfigs)
6381 {
6382         PGresult   *res;
6383         int                     ntups;
6384         int                     i;
6385         PQExpBuffer query = createPQExpBuffer();
6386         TSConfigInfo *cfginfo;
6387         int                     i_tableoid;
6388         int                     i_oid;
6389         int                     i_cfgname;
6390         int                     i_cfgnamespace;
6391         int                     i_rolname;
6392         int                     i_cfgparser;
6393
6394         /* Before 8.3, there is no built-in text search support */
6395         if (g_fout->remoteVersion < 80300)
6396         {
6397                 *numTSConfigs = 0;
6398                 return NULL;
6399         }
6400
6401         /* Make sure we are in proper schema */
6402         selectSourceSchema("pg_catalog");
6403
6404         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6405                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6406                                           "FROM pg_ts_config",
6407                                           username_subquery);
6408
6409         res = PQexec(g_conn, query->data);
6410         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6411
6412         ntups = PQntuples(res);
6413         *numTSConfigs = ntups;
6414
6415         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6416
6417         i_tableoid = PQfnumber(res, "tableoid");
6418         i_oid = PQfnumber(res, "oid");
6419         i_cfgname = PQfnumber(res, "cfgname");
6420         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6421         i_rolname = PQfnumber(res, "rolname");
6422         i_cfgparser = PQfnumber(res, "cfgparser");
6423
6424         for (i = 0; i < ntups; i++)
6425         {
6426                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6427                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6428                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6429                 AssignDumpId(&cfginfo[i].dobj);
6430                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
6431                 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
6432                                                                                                   cfginfo[i].dobj.catId.oid);
6433                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6434                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
6435
6436                 /* Decide whether we want to dump it */
6437                 selectDumpableObject(&(cfginfo[i].dobj));
6438         }
6439
6440         PQclear(res);
6441
6442         destroyPQExpBuffer(query);
6443
6444         return cfginfo;
6445 }
6446
6447 /*
6448  * getForeignDataWrappers:
6449  *        read all foreign-data wrappers in the system catalogs and return
6450  *        them in the FdwInfo* structure
6451  *
6452  *      numForeignDataWrappers is set to the number of fdws read in
6453  */
6454 FdwInfo *
6455 getForeignDataWrappers(int *numForeignDataWrappers)
6456 {
6457         PGresult   *res;
6458         int                     ntups;
6459         int                     i;
6460         PQExpBuffer query = createPQExpBuffer();
6461         FdwInfo    *fdwinfo;
6462         int                     i_tableoid;
6463         int                     i_oid;
6464         int                     i_fdwname;
6465         int                     i_rolname;
6466         int                     i_fdwhandler;
6467         int                     i_fdwvalidator;
6468         int                     i_fdwacl;
6469         int                     i_fdwoptions;
6470
6471         /* Before 8.4, there are no foreign-data wrappers */
6472         if (g_fout->remoteVersion < 80400)
6473         {
6474                 *numForeignDataWrappers = 0;
6475                 return NULL;
6476         }
6477
6478         /* Make sure we are in proper schema */
6479         selectSourceSchema("pg_catalog");
6480
6481         if (g_fout->remoteVersion >= 90100)
6482         {
6483                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6484                                                   "(%s fdwowner) AS rolname, "
6485                                                   "fdwhandler::pg_catalog.regproc, "
6486                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6487                                                   "array_to_string(ARRAY("
6488                                                   "SELECT quote_ident(option_name) || ' ' || "
6489                                                   "quote_literal(option_value) "
6490                                                   "FROM pg_options_to_table(fdwoptions)"
6491                                                   "), ', ') AS fdwoptions "
6492                                                   "FROM pg_foreign_data_wrapper",
6493                                                   username_subquery);
6494         }
6495         else
6496         {
6497                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
6498                                                   "(%s fdwowner) AS rolname, "
6499                                                   "'-' AS fdwhandler, "
6500                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
6501                                                   "array_to_string(ARRAY("
6502                                                   "SELECT quote_ident(option_name) || ' ' || "
6503                                                   "quote_literal(option_value) "
6504                                                   "FROM pg_options_to_table(fdwoptions)"
6505                                                   "), ', ') AS fdwoptions "
6506                                                   "FROM pg_foreign_data_wrapper",
6507                                                   username_subquery);
6508         }
6509
6510         res = PQexec(g_conn, query->data);
6511         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6512
6513         ntups = PQntuples(res);
6514         *numForeignDataWrappers = ntups;
6515
6516         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
6517
6518         i_tableoid = PQfnumber(res, "tableoid");
6519         i_oid = PQfnumber(res, "oid");
6520         i_fdwname = PQfnumber(res, "fdwname");
6521         i_rolname = PQfnumber(res, "rolname");
6522         i_fdwhandler = PQfnumber(res, "fdwhandler");
6523         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
6524         i_fdwacl = PQfnumber(res, "fdwacl");
6525         i_fdwoptions = PQfnumber(res, "fdwoptions");
6526
6527         for (i = 0; i < ntups; i++)
6528         {
6529                 fdwinfo[i].dobj.objType = DO_FDW;
6530                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6531                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6532                 AssignDumpId(&fdwinfo[i].dobj);
6533                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
6534                 fdwinfo[i].dobj.namespace = NULL;
6535                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6536                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
6537                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
6538                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
6539                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
6540
6541                 /* Decide whether we want to dump it */
6542                 selectDumpableObject(&(fdwinfo[i].dobj));
6543         }
6544
6545         PQclear(res);
6546
6547         destroyPQExpBuffer(query);
6548
6549         return fdwinfo;
6550 }
6551
6552 /*
6553  * getForeignServers:
6554  *        read all foreign servers in the system catalogs and return
6555  *        them in the ForeignServerInfo * structure
6556  *
6557  *      numForeignServers is set to the number of servers read in
6558  */
6559 ForeignServerInfo *
6560 getForeignServers(int *numForeignServers)
6561 {
6562         PGresult   *res;
6563         int                     ntups;
6564         int                     i;
6565         PQExpBuffer query = createPQExpBuffer();
6566         ForeignServerInfo *srvinfo;
6567         int                     i_tableoid;
6568         int                     i_oid;
6569         int                     i_srvname;
6570         int                     i_rolname;
6571         int                     i_srvfdw;
6572         int                     i_srvtype;
6573         int                     i_srvversion;
6574         int                     i_srvacl;
6575         int                     i_srvoptions;
6576
6577         /* Before 8.4, there are no foreign servers */
6578         if (g_fout->remoteVersion < 80400)
6579         {
6580                 *numForeignServers = 0;
6581                 return NULL;
6582         }
6583
6584         /* Make sure we are in proper schema */
6585         selectSourceSchema("pg_catalog");
6586
6587         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
6588                                           "(%s srvowner) AS rolname, "
6589                                           "srvfdw, srvtype, srvversion, srvacl,"
6590                                           "array_to_string(ARRAY("
6591                                           "SELECT quote_ident(option_name) || ' ' || "
6592                                           "quote_literal(option_value) "
6593                                           "FROM pg_options_to_table(srvoptions)"
6594                                           "), ', ') AS srvoptions "
6595                                           "FROM pg_foreign_server",
6596                                           username_subquery);
6597
6598         res = PQexec(g_conn, query->data);
6599         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6600
6601         ntups = PQntuples(res);
6602         *numForeignServers = ntups;
6603
6604         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
6605
6606         i_tableoid = PQfnumber(res, "tableoid");
6607         i_oid = PQfnumber(res, "oid");
6608         i_srvname = PQfnumber(res, "srvname");
6609         i_rolname = PQfnumber(res, "rolname");
6610         i_srvfdw = PQfnumber(res, "srvfdw");
6611         i_srvtype = PQfnumber(res, "srvtype");
6612         i_srvversion = PQfnumber(res, "srvversion");
6613         i_srvacl = PQfnumber(res, "srvacl");
6614         i_srvoptions = PQfnumber(res, "srvoptions");
6615
6616         for (i = 0; i < ntups; i++)
6617         {
6618                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
6619                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6620                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6621                 AssignDumpId(&srvinfo[i].dobj);
6622                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
6623                 srvinfo[i].dobj.namespace = NULL;
6624                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6625                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
6626                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
6627                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
6628                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
6629                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
6630
6631                 /* Decide whether we want to dump it */
6632                 selectDumpableObject(&(srvinfo[i].dobj));
6633         }
6634
6635         PQclear(res);
6636
6637         destroyPQExpBuffer(query);
6638
6639         return srvinfo;
6640 }
6641
6642 /*
6643  * getDefaultACLs:
6644  *        read all default ACL information in the system catalogs and return
6645  *        them in the DefaultACLInfo structure
6646  *
6647  *      numDefaultACLs is set to the number of ACLs read in
6648  */
6649 DefaultACLInfo *
6650 getDefaultACLs(int *numDefaultACLs)
6651 {
6652         DefaultACLInfo *daclinfo;
6653         PQExpBuffer query;
6654         PGresult   *res;
6655         int                     i_oid;
6656         int                     i_tableoid;
6657         int                     i_defaclrole;
6658         int                     i_defaclnamespace;
6659         int                     i_defaclobjtype;
6660         int                     i_defaclacl;
6661         int                     i,
6662                                 ntups;
6663
6664         if (g_fout->remoteVersion < 90000)
6665         {
6666                 *numDefaultACLs = 0;
6667                 return NULL;
6668         }
6669
6670         query = createPQExpBuffer();
6671
6672         /* Make sure we are in proper schema */
6673         selectSourceSchema("pg_catalog");
6674
6675         appendPQExpBuffer(query, "SELECT oid, tableoid, "
6676                                           "(%s defaclrole) AS defaclrole, "
6677                                           "defaclnamespace, "
6678                                           "defaclobjtype, "
6679                                           "defaclacl "
6680                                           "FROM pg_default_acl",
6681                                           username_subquery);
6682
6683         res = PQexec(g_conn, query->data);
6684         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6685
6686         ntups = PQntuples(res);
6687         *numDefaultACLs = ntups;
6688
6689         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
6690
6691         i_oid = PQfnumber(res, "oid");
6692         i_tableoid = PQfnumber(res, "tableoid");
6693         i_defaclrole = PQfnumber(res, "defaclrole");
6694         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
6695         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
6696         i_defaclacl = PQfnumber(res, "defaclacl");
6697
6698         for (i = 0; i < ntups; i++)
6699         {
6700                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
6701
6702                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
6703                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6704                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6705                 AssignDumpId(&daclinfo[i].dobj);
6706                 /* cheesy ... is it worth coming up with a better object name? */
6707                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
6708
6709                 if (nspid != InvalidOid)
6710                         daclinfo[i].dobj.namespace = findNamespace(nspid,
6711                                                                                                  daclinfo[i].dobj.catId.oid);
6712                 else
6713                         daclinfo[i].dobj.namespace = NULL;
6714
6715                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
6716                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
6717                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
6718
6719                 /* Decide whether we want to dump it */
6720                 selectDumpableDefaultACL(&(daclinfo[i]));
6721         }
6722
6723         PQclear(res);
6724
6725         destroyPQExpBuffer(query);
6726
6727         return daclinfo;
6728 }
6729
6730 /*
6731  * dumpComment --
6732  *
6733  * This routine is used to dump any comments associated with the
6734  * object handed to this routine. The routine takes a constant character
6735  * string for the target part of the comment-creation command, plus
6736  * the namespace and owner of the object (for labeling the ArchiveEntry),
6737  * plus catalog ID and subid which are the lookup key for pg_description,
6738  * plus the dump ID for the object (for setting a dependency).
6739  * If a matching pg_description entry is found, it is dumped.
6740  *
6741  * Note: although this routine takes a dumpId for dependency purposes,
6742  * that purpose is just to mark the dependency in the emitted dump file
6743  * for possible future use by pg_restore.  We do NOT use it for determining
6744  * ordering of the comment in the dump file, because this routine is called
6745  * after dependency sorting occurs.  This routine should be called just after
6746  * calling ArchiveEntry() for the specified object.
6747  */
6748 static void
6749 dumpComment(Archive *fout, const char *target,
6750                         const char *namespace, const char *owner,
6751                         CatalogId catalogId, int subid, DumpId dumpId)
6752 {
6753         CommentItem *comments;
6754         int                     ncomments;
6755
6756         /* Comments are schema not data ... except blob comments are data */
6757         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
6758         {
6759                 if (dataOnly)
6760                         return;
6761         }
6762         else
6763         {
6764                 if (schemaOnly)
6765                         return;
6766         }
6767
6768         /* Search for comments associated with catalogId, using table */
6769         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
6770                                                          &comments);
6771
6772         /* Is there one matching the subid? */
6773         while (ncomments > 0)
6774         {
6775                 if (comments->objsubid == subid)
6776                         break;
6777                 comments++;
6778                 ncomments--;
6779         }
6780
6781         /* If a comment exists, build COMMENT ON statement */
6782         if (ncomments > 0)
6783         {
6784                 PQExpBuffer query = createPQExpBuffer();
6785
6786                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
6787                 appendStringLiteralAH(query, comments->descr, fout);
6788                 appendPQExpBuffer(query, ";\n");
6789
6790                 /*
6791                  * We mark comments as SECTION_NONE because they really belong in the
6792                  * same section as their parent, whether that is pre-data or
6793                  * post-data.
6794                  */
6795                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
6796                                          target, namespace, NULL, owner,
6797                                          false, "COMMENT", SECTION_NONE,
6798                                          query->data, "", NULL,
6799                                          &(dumpId), 1,
6800                                          NULL, NULL);
6801
6802                 destroyPQExpBuffer(query);
6803         }
6804 }
6805
6806 /*
6807  * dumpTableComment --
6808  *
6809  * As above, but dump comments for both the specified table (or view)
6810  * and its columns.
6811  */
6812 static void
6813 dumpTableComment(Archive *fout, TableInfo *tbinfo,
6814                                  const char *reltypename)
6815 {
6816         CommentItem *comments;
6817         int                     ncomments;
6818         PQExpBuffer query;
6819         PQExpBuffer target;
6820
6821         /* Comments are SCHEMA not data */
6822         if (dataOnly)
6823                 return;
6824
6825         /* Search for comments associated with relation, using table */
6826         ncomments = findComments(fout,
6827                                                          tbinfo->dobj.catId.tableoid,
6828                                                          tbinfo->dobj.catId.oid,
6829                                                          &comments);
6830
6831         /* If comments exist, build COMMENT ON statements */
6832         if (ncomments <= 0)
6833                 return;
6834
6835         query = createPQExpBuffer();
6836         target = createPQExpBuffer();
6837
6838         while (ncomments > 0)
6839         {
6840                 const char *descr = comments->descr;
6841                 int                     objsubid = comments->objsubid;
6842
6843                 if (objsubid == 0)
6844                 {
6845                         resetPQExpBuffer(target);
6846                         appendPQExpBuffer(target, "%s %s", reltypename,
6847                                                           fmtId(tbinfo->dobj.name));
6848
6849                         resetPQExpBuffer(query);
6850                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6851                         appendStringLiteralAH(query, descr, fout);
6852                         appendPQExpBuffer(query, ";\n");
6853
6854                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6855                                                  target->data,
6856                                                  tbinfo->dobj.namespace->dobj.name,
6857                                                  NULL, tbinfo->rolname,
6858                                                  false, "COMMENT", SECTION_NONE,
6859                                                  query->data, "", NULL,
6860                                                  &(tbinfo->dobj.dumpId), 1,
6861                                                  NULL, NULL);
6862                 }
6863                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
6864                 {
6865                         resetPQExpBuffer(target);
6866                         appendPQExpBuffer(target, "COLUMN %s.",
6867                                                           fmtId(tbinfo->dobj.name));
6868                         appendPQExpBuffer(target, "%s",
6869                                                           fmtId(tbinfo->attnames[objsubid - 1]));
6870
6871                         resetPQExpBuffer(query);
6872                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6873                         appendStringLiteralAH(query, descr, fout);
6874                         appendPQExpBuffer(query, ";\n");
6875
6876                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6877                                                  target->data,
6878                                                  tbinfo->dobj.namespace->dobj.name,
6879                                                  NULL, tbinfo->rolname,
6880                                                  false, "COMMENT", SECTION_NONE,
6881                                                  query->data, "", NULL,
6882                                                  &(tbinfo->dobj.dumpId), 1,
6883                                                  NULL, NULL);
6884                 }
6885
6886                 comments++;
6887                 ncomments--;
6888         }
6889
6890         destroyPQExpBuffer(query);
6891         destroyPQExpBuffer(target);
6892 }
6893
6894 /*
6895  * findComments --
6896  *
6897  * Find the comment(s), if any, associated with the given object.  All the
6898  * objsubid values associated with the given classoid/objoid are found with
6899  * one search.
6900  */
6901 static int
6902 findComments(Archive *fout, Oid classoid, Oid objoid,
6903                          CommentItem **items)
6904 {
6905         /* static storage for table of comments */
6906         static CommentItem *comments = NULL;
6907         static int      ncomments = -1;
6908
6909         CommentItem *middle = NULL;
6910         CommentItem *low;
6911         CommentItem *high;
6912         int                     nmatch;
6913
6914         /* Get comments if we didn't already */
6915         if (ncomments < 0)
6916                 ncomments = collectComments(fout, &comments);
6917
6918         /*
6919          * Pre-7.2, pg_description does not contain classoid, so collectComments
6920          * just stores a zero.  If there's a collision on object OID, well, you
6921          * get duplicate comments.
6922          */
6923         if (fout->remoteVersion < 70200)
6924                 classoid = 0;
6925
6926         /*
6927          * Do binary search to find some item matching the object.
6928          */
6929         low = &comments[0];
6930         high = &comments[ncomments - 1];
6931         while (low <= high)
6932         {
6933                 middle = low + (high - low) / 2;
6934
6935                 if (classoid < middle->classoid)
6936                         high = middle - 1;
6937                 else if (classoid > middle->classoid)
6938                         low = middle + 1;
6939                 else if (objoid < middle->objoid)
6940                         high = middle - 1;
6941                 else if (objoid > middle->objoid)
6942                         low = middle + 1;
6943                 else
6944                         break;                          /* found a match */
6945         }
6946
6947         if (low > high)                         /* no matches */
6948         {
6949                 *items = NULL;
6950                 return 0;
6951         }
6952
6953         /*
6954          * Now determine how many items match the object.  The search loop
6955          * invariant still holds: only items between low and high inclusive could
6956          * match.
6957          */
6958         nmatch = 1;
6959         while (middle > low)
6960         {
6961                 if (classoid != middle[-1].classoid ||
6962                         objoid != middle[-1].objoid)
6963                         break;
6964                 middle--;
6965                 nmatch++;
6966         }
6967
6968         *items = middle;
6969
6970         middle += nmatch;
6971         while (middle <= high)
6972         {
6973                 if (classoid != middle->classoid ||
6974                         objoid != middle->objoid)
6975                         break;
6976                 middle++;
6977                 nmatch++;
6978         }
6979
6980         return nmatch;
6981 }
6982
6983 /*
6984  * collectComments --
6985  *
6986  * Construct a table of all comments available for database objects.
6987  * We used to do per-object queries for the comments, but it's much faster
6988  * to pull them all over at once, and on most databases the memory cost
6989  * isn't high.
6990  *
6991  * The table is sorted by classoid/objid/objsubid for speed in lookup.
6992  */
6993 static int
6994 collectComments(Archive *fout, CommentItem **items)
6995 {
6996         PGresult   *res;
6997         PQExpBuffer query;
6998         int                     i_description;
6999         int                     i_classoid;
7000         int                     i_objoid;
7001         int                     i_objsubid;
7002         int                     ntups;
7003         int                     i;
7004         CommentItem *comments;
7005
7006         /*
7007          * Note we do NOT change source schema here; preserve the caller's
7008          * setting, instead.
7009          */
7010
7011         query = createPQExpBuffer();
7012
7013         if (fout->remoteVersion >= 70300)
7014         {
7015                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7016                                                   "FROM pg_catalog.pg_description "
7017                                                   "ORDER BY classoid, objoid, objsubid");
7018         }
7019         else if (fout->remoteVersion >= 70200)
7020         {
7021                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7022                                                   "FROM pg_description "
7023                                                   "ORDER BY classoid, objoid, objsubid");
7024         }
7025         else
7026         {
7027                 /* Note: this will fail to find attribute comments in pre-7.2... */
7028                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7029                                                   "FROM pg_description "
7030                                                   "ORDER BY objoid");
7031         }
7032
7033         res = PQexec(g_conn, query->data);
7034         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7035
7036         /* Construct lookup table containing OIDs in numeric form */
7037
7038         i_description = PQfnumber(res, "description");
7039         i_classoid = PQfnumber(res, "classoid");
7040         i_objoid = PQfnumber(res, "objoid");
7041         i_objsubid = PQfnumber(res, "objsubid");
7042
7043         ntups = PQntuples(res);
7044
7045         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7046
7047         for (i = 0; i < ntups; i++)
7048         {
7049                 comments[i].descr = PQgetvalue(res, i, i_description);
7050                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7051                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7052                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7053         }
7054
7055         /* Do NOT free the PGresult since we are keeping pointers into it */
7056         destroyPQExpBuffer(query);
7057
7058         *items = comments;
7059         return ntups;
7060 }
7061
7062 /*
7063  * dumpDumpableObject
7064  *
7065  * This routine and its subsidiaries are responsible for creating
7066  * ArchiveEntries (TOC objects) for each object to be dumped.
7067  */
7068 static void
7069 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7070 {
7071         switch (dobj->objType)
7072         {
7073                 case DO_NAMESPACE:
7074                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7075                         break;
7076                 case DO_EXTENSION:
7077                         dumpExtension(fout, (ExtensionInfo *) dobj);
7078                         break;
7079                 case DO_TYPE:
7080                         dumpType(fout, (TypeInfo *) dobj);
7081                         break;
7082                 case DO_SHELL_TYPE:
7083                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7084                         break;
7085                 case DO_FUNC:
7086                         dumpFunc(fout, (FuncInfo *) dobj);
7087                         break;
7088                 case DO_AGG:
7089                         dumpAgg(fout, (AggInfo *) dobj);
7090                         break;
7091                 case DO_OPERATOR:
7092                         dumpOpr(fout, (OprInfo *) dobj);
7093                         break;
7094                 case DO_OPCLASS:
7095                         dumpOpclass(fout, (OpclassInfo *) dobj);
7096                         break;
7097                 case DO_OPFAMILY:
7098                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7099                         break;
7100                 case DO_COLLATION:
7101                         dumpCollation(fout, (CollInfo *) dobj);
7102                         break;
7103                 case DO_CONVERSION:
7104                         dumpConversion(fout, (ConvInfo *) dobj);
7105                         break;
7106                 case DO_TABLE:
7107                         dumpTable(fout, (TableInfo *) dobj);
7108                         break;
7109                 case DO_ATTRDEF:
7110                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7111                         break;
7112                 case DO_INDEX:
7113                         dumpIndex(fout, (IndxInfo *) dobj);
7114                         break;
7115                 case DO_RULE:
7116                         dumpRule(fout, (RuleInfo *) dobj);
7117                         break;
7118                 case DO_TRIGGER:
7119                         dumpTrigger(fout, (TriggerInfo *) dobj);
7120                         break;
7121                 case DO_CONSTRAINT:
7122                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7123                         break;
7124                 case DO_FK_CONSTRAINT:
7125                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7126                         break;
7127                 case DO_PROCLANG:
7128                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7129                         break;
7130                 case DO_CAST:
7131                         dumpCast(fout, (CastInfo *) dobj);
7132                         break;
7133                 case DO_TABLE_DATA:
7134                         dumpTableData(fout, (TableDataInfo *) dobj);
7135                         break;
7136                 case DO_DUMMY_TYPE:
7137                         /* table rowtypes and array types are never dumped separately */
7138                         break;
7139                 case DO_TSPARSER:
7140                         dumpTSParser(fout, (TSParserInfo *) dobj);
7141                         break;
7142                 case DO_TSDICT:
7143                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7144                         break;
7145                 case DO_TSTEMPLATE:
7146                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7147                         break;
7148                 case DO_TSCONFIG:
7149                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7150                         break;
7151                 case DO_FDW:
7152                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7153                         break;
7154                 case DO_FOREIGN_SERVER:
7155                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7156                         break;
7157                 case DO_DEFAULT_ACL:
7158                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7159                         break;
7160                 case DO_BLOB:
7161                         dumpBlob(fout, (BlobInfo *) dobj);
7162                         break;
7163                 case DO_BLOB_DATA:
7164                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7165                                                  dobj->name, NULL, NULL, "",
7166                                                  false, "BLOBS", SECTION_DATA,
7167                                                  "", "", NULL,
7168                                                  dobj->dependencies, dobj->nDeps,
7169                                                  dumpBlobs, NULL);
7170                         break;
7171         }
7172 }
7173
7174 /*
7175  * dumpNamespace
7176  *        writes out to fout the queries to recreate a user-defined namespace
7177  */
7178 static void
7179 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7180 {
7181         PQExpBuffer q;
7182         PQExpBuffer delq;
7183         PQExpBuffer labelq;
7184         char       *qnspname;
7185
7186         /* Skip if not to be dumped */
7187         if (!nspinfo->dobj.dump || dataOnly)
7188                 return;
7189
7190         /* don't dump dummy namespace from pre-7.3 source */
7191         if (strlen(nspinfo->dobj.name) == 0)
7192                 return;
7193
7194         q = createPQExpBuffer();
7195         delq = createPQExpBuffer();
7196         labelq = createPQExpBuffer();
7197
7198         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7199
7200         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7201
7202         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7203
7204         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7205
7206         if (binary_upgrade)
7207                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7208
7209         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7210                                  nspinfo->dobj.name,
7211                                  NULL, NULL,
7212                                  nspinfo->rolname,
7213                                  false, "SCHEMA", SECTION_PRE_DATA,
7214                                  q->data, delq->data, NULL,
7215                                  nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
7216                                  NULL, NULL);
7217
7218         /* Dump Schema Comments and Security Labels */
7219         dumpComment(fout, labelq->data,
7220                                 NULL, nspinfo->rolname,
7221                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7222         dumpSecLabel(fout, labelq->data,
7223                                  NULL, nspinfo->rolname,
7224                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7225
7226         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7227                         qnspname, NULL, nspinfo->dobj.name, NULL,
7228                         nspinfo->rolname, nspinfo->nspacl);
7229
7230         free(qnspname);
7231
7232         destroyPQExpBuffer(q);
7233         destroyPQExpBuffer(delq);
7234         destroyPQExpBuffer(labelq);
7235 }
7236
7237 /*
7238  * dumpExtension
7239  *        writes out to fout the queries to recreate an extension
7240  */
7241 static void
7242 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7243 {
7244         PQExpBuffer q;
7245         PQExpBuffer delq;
7246         PQExpBuffer labelq;
7247         char       *qextname;
7248
7249         /* Skip if not to be dumped */
7250         if (!extinfo->dobj.dump || dataOnly)
7251                 return;
7252
7253         q = createPQExpBuffer();
7254         delq = createPQExpBuffer();
7255         labelq = createPQExpBuffer();
7256
7257         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7258
7259         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7260
7261         if (!binary_upgrade)
7262         {
7263                 /*
7264                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7265                  * problem if the extension already exists in the target database;
7266                  * this is essential for installed-by-default extensions such as
7267                  * plpgsql.
7268                  *
7269                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7270                  * built-in extensions based on their OIDs; see
7271                  * selectDumpableExtension.
7272                  */
7273                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7274                                                   qextname, fmtId(extinfo->namespace));
7275         }
7276         else
7277         {
7278                 int                     i;
7279                 int                     n;
7280
7281                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7282                 appendPQExpBuffer(q,
7283                                                   "SELECT binary_upgrade.create_empty_extension(");
7284                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7285                 appendPQExpBuffer(q, ", ");
7286                 appendStringLiteralAH(q, extinfo->namespace, fout);
7287                 appendPQExpBuffer(q, ", ");
7288                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7289                 appendStringLiteralAH(q, extinfo->extversion, fout);
7290                 appendPQExpBuffer(q, ", ");
7291
7292                 /*
7293                  * Note that we're pushing extconfig (an OID array) back into
7294                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7295                  * preserved in binary upgrade.
7296                  */
7297                 if (strlen(extinfo->extconfig) > 2)
7298                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7299                 else
7300                         appendPQExpBuffer(q, "NULL");
7301                 appendPQExpBuffer(q, ", ");
7302                 if (strlen(extinfo->extcondition) > 2)
7303                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7304                 else
7305                         appendPQExpBuffer(q, "NULL");
7306                 appendPQExpBuffer(q, ", ");
7307                 appendPQExpBuffer(q, "ARRAY[");
7308                 n = 0;
7309                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7310                 {
7311                         DumpableObject *extobj;
7312
7313                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7314                         if (extobj && extobj->objType == DO_EXTENSION)
7315                         {
7316                                 if (n++ > 0)
7317                                         appendPQExpBuffer(q, ",");
7318                                 appendStringLiteralAH(q, extobj->name, fout);
7319                         }
7320                 }
7321                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7322                 appendPQExpBuffer(q, ");\n");
7323         }
7324
7325         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7326
7327         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7328                                  extinfo->dobj.name,
7329                                  NULL, NULL,
7330                                  "",
7331                                  false, "EXTENSION", SECTION_PRE_DATA,
7332                                  q->data, delq->data, NULL,
7333                                  extinfo->dobj.dependencies, extinfo->dobj.nDeps,
7334                                  NULL, NULL);
7335
7336         /* Dump Extension Comments and Security Labels */
7337         dumpComment(fout, labelq->data,
7338                                 NULL, "",
7339                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7340         dumpSecLabel(fout, labelq->data,
7341                                  NULL, "",
7342                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7343
7344         free(qextname);
7345
7346         destroyPQExpBuffer(q);
7347         destroyPQExpBuffer(delq);
7348         destroyPQExpBuffer(labelq);
7349 }
7350
7351 /*
7352  * dumpType
7353  *        writes out to fout the queries to recreate a user-defined type
7354  */
7355 static void
7356 dumpType(Archive *fout, TypeInfo *tyinfo)
7357 {
7358         /* Skip if not to be dumped */
7359         if (!tyinfo->dobj.dump || dataOnly)
7360                 return;
7361
7362         /* Dump out in proper style */
7363         if (tyinfo->typtype == TYPTYPE_BASE)
7364                 dumpBaseType(fout, tyinfo);
7365         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7366                 dumpDomain(fout, tyinfo);
7367         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7368                 dumpCompositeType(fout, tyinfo);
7369         else if (tyinfo->typtype == TYPTYPE_ENUM)
7370                 dumpEnumType(fout, tyinfo);
7371         else if (tyinfo->typtype == TYPTYPE_RANGE)
7372                 dumpRangeType(fout, tyinfo);
7373         else
7374                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7375                                   tyinfo->dobj.name);
7376 }
7377
7378 /*
7379  * dumpEnumType
7380  *        writes out to fout the queries to recreate a user-defined enum type
7381  */
7382 static void
7383 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7384 {
7385         PQExpBuffer q = createPQExpBuffer();
7386         PQExpBuffer delq = createPQExpBuffer();
7387         PQExpBuffer labelq = createPQExpBuffer();
7388         PQExpBuffer query = createPQExpBuffer();
7389         PGresult   *res;
7390         int                     num,
7391                                 i;
7392         Oid                     enum_oid;
7393         char       *label;
7394
7395         /* Set proper schema search path */
7396         selectSourceSchema("pg_catalog");
7397
7398         if (fout->remoteVersion >= 90100)
7399                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7400                                                   "FROM pg_catalog.pg_enum "
7401                                                   "WHERE enumtypid = '%u'"
7402                                                   "ORDER BY enumsortorder",
7403                                                   tyinfo->dobj.catId.oid);
7404         else
7405                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7406                                                   "FROM pg_catalog.pg_enum "
7407                                                   "WHERE enumtypid = '%u'"
7408                                                   "ORDER BY oid",
7409                                                   tyinfo->dobj.catId.oid);
7410
7411         res = PQexec(g_conn, query->data);
7412         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7413
7414         num = PQntuples(res);
7415
7416         /*
7417          * DROP must be fully qualified in case same name appears in pg_catalog.
7418          * CASCADE shouldn't be required here as for normal types since the I/O
7419          * functions are generic and do not get dropped.
7420          */
7421         appendPQExpBuffer(delq, "DROP TYPE %s.",
7422                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7423         appendPQExpBuffer(delq, "%s;\n",
7424                                           fmtId(tyinfo->dobj.name));
7425
7426         if (binary_upgrade)
7427                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7428
7429         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
7430                                           fmtId(tyinfo->dobj.name));
7431
7432         if (!binary_upgrade)
7433         {
7434                 /* Labels with server-assigned oids */
7435                 for (i = 0; i < num; i++)
7436                 {
7437                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7438                         if (i > 0)
7439                                 appendPQExpBuffer(q, ",");
7440                         appendPQExpBuffer(q, "\n    ");
7441                         appendStringLiteralAH(q, label, fout);
7442                 }
7443         }
7444
7445         appendPQExpBuffer(q, "\n);\n");
7446
7447         if (binary_upgrade)
7448         {
7449                 /* Labels with dump-assigned (preserved) oids */
7450                 for (i = 0; i < num; i++)
7451                 {
7452                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
7453                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
7454
7455                         if (i == 0)
7456                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
7457                         appendPQExpBuffer(q,
7458                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
7459                                                           enum_oid);
7460                         appendPQExpBuffer(q, "ALTER TYPE %s.",
7461                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7462                         appendPQExpBuffer(q, "%s ADD VALUE ",
7463                                                           fmtId(tyinfo->dobj.name));
7464                         appendStringLiteralAH(q, label, fout);
7465                         appendPQExpBuffer(q, ";\n\n");
7466                 }
7467         }
7468
7469         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7470
7471         if (binary_upgrade)
7472                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7473
7474         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7475                                  tyinfo->dobj.name,
7476                                  tyinfo->dobj.namespace->dobj.name,
7477                                  NULL,
7478                                  tyinfo->rolname, false,
7479                                  "TYPE", SECTION_PRE_DATA,
7480                                  q->data, delq->data, NULL,
7481                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7482                                  NULL, NULL);
7483
7484         /* Dump Type Comments and Security Labels */
7485         dumpComment(fout, labelq->data,
7486                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7487                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7488         dumpSecLabel(fout, labelq->data,
7489                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7490                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7491
7492         PQclear(res);
7493         destroyPQExpBuffer(q);
7494         destroyPQExpBuffer(delq);
7495         destroyPQExpBuffer(labelq);
7496         destroyPQExpBuffer(query);
7497 }
7498
7499 /*
7500  * dumpRangeType
7501  *        writes out to fout the queries to recreate a user-defined range type
7502  */
7503 static void
7504 dumpRangeType(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         Oid                     collationOid;
7512         char       *procname;
7513
7514         /*
7515          * select appropriate schema to ensure names in CREATE are properly
7516          * qualified
7517          */
7518         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
7519
7520         appendPQExpBuffer(query,
7521                                           "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
7522                                           "opc.opcname AS opcname, "
7523                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
7524                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
7525                                           "opc.opcdefault, "
7526                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
7527                                           "     ELSE rngcollation END AS collation, "
7528                                           "rngcanonical, rngsubdiff "
7529                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
7530                                           "     pg_catalog.pg_opclass opc "
7531                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
7532                                           "rngtypid = '%u'",
7533                                           tyinfo->dobj.catId.oid);
7534
7535         res = PQexec(g_conn, query->data);
7536         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7537         if (PQntuples(res) != 1)
7538         {
7539                 write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
7540                                   PQntuples(res), tyinfo->dobj.name);
7541                 exit_nicely();
7542         }
7543
7544         /*
7545          * DROP must be fully qualified in case same name appears in pg_catalog.
7546          * CASCADE shouldn't be required here as for normal types since the I/O
7547          * functions are generic and do not get dropped.
7548          */
7549         appendPQExpBuffer(delq, "DROP TYPE %s.",
7550                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7551         appendPQExpBuffer(delq, "%s;\n",
7552                                           fmtId(tyinfo->dobj.name));
7553
7554         if (binary_upgrade)
7555                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7556
7557         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
7558                                           fmtId(tyinfo->dobj.name));
7559
7560         appendPQExpBuffer(q, "\n    subtype = %s",
7561                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
7562
7563         /* print subtype_opclass only if not default for subtype */
7564         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
7565         {
7566                 char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
7567                 char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
7568
7569                 /* always schema-qualify, don't try to be smart */
7570                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
7571                                                   fmtId(nspname));
7572                 appendPQExpBuffer(q, "%s", fmtId(opcname));
7573         }
7574
7575         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
7576         if (OidIsValid(collationOid))
7577         {
7578                 CollInfo   *coll = findCollationByOid(collationOid);
7579
7580                 if (coll)
7581                 {
7582                         /* always schema-qualify, don't try to be smart */
7583                         appendPQExpBuffer(q, ",\n    collation = %s.",
7584                                                           fmtId(coll->dobj.namespace->dobj.name));
7585                         appendPQExpBuffer(q, "%s",
7586                                                           fmtId(coll->dobj.name));
7587                 }
7588         }
7589
7590         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
7591         if (strcmp(procname, "-") != 0)
7592                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
7593
7594         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
7595         if (strcmp(procname, "-") != 0)
7596                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
7597
7598         appendPQExpBuffer(q, "\n);\n");
7599
7600         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7601
7602         if (binary_upgrade)
7603                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7604
7605         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
7606                                  tyinfo->dobj.name,
7607                                  tyinfo->dobj.namespace->dobj.name,
7608                                  NULL,
7609                                  tyinfo->rolname, false,
7610                                  "TYPE", SECTION_PRE_DATA,
7611                                  q->data, delq->data, NULL,
7612                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
7613                                  NULL, NULL);
7614
7615         /* Dump Type Comments and Security Labels */
7616         dumpComment(fout, labelq->data,
7617                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7618                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7619         dumpSecLabel(fout, labelq->data,
7620                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
7621                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
7622
7623         PQclear(res);
7624         destroyPQExpBuffer(q);
7625         destroyPQExpBuffer(delq);
7626         destroyPQExpBuffer(labelq);
7627         destroyPQExpBuffer(query);
7628 }
7629
7630 /*
7631  * dumpBaseType
7632  *        writes out to fout the queries to recreate a user-defined base type
7633  */
7634 static void
7635 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
7636 {
7637         PQExpBuffer q = createPQExpBuffer();
7638         PQExpBuffer delq = createPQExpBuffer();
7639         PQExpBuffer labelq = createPQExpBuffer();
7640         PQExpBuffer query = createPQExpBuffer();
7641         PGresult   *res;
7642         int                     ntups;
7643         char       *typlen;
7644         char       *typinput;
7645         char       *typoutput;
7646         char       *typreceive;
7647         char       *typsend;
7648         char       *typmodin;
7649         char       *typmodout;
7650         char       *typanalyze;
7651         Oid                     typreceiveoid;
7652         Oid                     typsendoid;
7653         Oid                     typmodinoid;
7654         Oid                     typmodoutoid;
7655         Oid                     typanalyzeoid;
7656         char       *typcategory;
7657         char       *typispreferred;
7658         char       *typdelim;
7659         char       *typbyval;
7660         char       *typalign;
7661         char       *typstorage;
7662         char       *typcollatable;
7663         char       *typdefault;
7664         bool            typdefault_is_literal = false;
7665
7666         /* Set proper schema search path so regproc references list correctly */
7667         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
7668
7669         /* Fetch type-specific details */
7670         if (fout->remoteVersion >= 90100)
7671         {
7672                 appendPQExpBuffer(query, "SELECT typlen, "
7673                                                   "typinput, typoutput, typreceive, typsend, "
7674                                                   "typmodin, typmodout, typanalyze, "
7675                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7676                                                   "typsend::pg_catalog.oid AS typsendoid, "
7677                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7678                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7679                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7680                                                   "typcategory, typispreferred, "
7681                                                   "typdelim, typbyval, typalign, typstorage, "
7682                                                   "(typcollation <> 0) AS typcollatable, "
7683                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7684                                                   "FROM pg_catalog.pg_type "
7685                                                   "WHERE oid = '%u'::pg_catalog.oid",
7686                                                   tyinfo->dobj.catId.oid);
7687         }
7688         else if (fout->remoteVersion >= 80400)
7689         {
7690                 appendPQExpBuffer(query, "SELECT typlen, "
7691                                                   "typinput, typoutput, typreceive, typsend, "
7692                                                   "typmodin, typmodout, typanalyze, "
7693                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7694                                                   "typsend::pg_catalog.oid AS typsendoid, "
7695                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7696                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7697                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7698                                                   "typcategory, typispreferred, "
7699                                                   "typdelim, typbyval, typalign, typstorage, "
7700                                                   "false AS typcollatable, "
7701                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
7702                                                   "FROM pg_catalog.pg_type "
7703                                                   "WHERE oid = '%u'::pg_catalog.oid",
7704                                                   tyinfo->dobj.catId.oid);
7705         }
7706         else if (fout->remoteVersion >= 80300)
7707         {
7708                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
7709                 appendPQExpBuffer(query, "SELECT typlen, "
7710                                                   "typinput, typoutput, typreceive, typsend, "
7711                                                   "typmodin, typmodout, typanalyze, "
7712                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7713                                                   "typsend::pg_catalog.oid AS typsendoid, "
7714                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
7715                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
7716                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7717                                                   "'U' AS typcategory, false AS typispreferred, "
7718                                                   "typdelim, typbyval, typalign, typstorage, "
7719                                                   "false AS typcollatable, "
7720                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7721                                                   "FROM pg_catalog.pg_type "
7722                                                   "WHERE oid = '%u'::pg_catalog.oid",
7723                                                   tyinfo->dobj.catId.oid);
7724         }
7725         else if (fout->remoteVersion >= 80000)
7726         {
7727                 appendPQExpBuffer(query, "SELECT typlen, "
7728                                                   "typinput, typoutput, typreceive, typsend, "
7729                                                   "'-' AS typmodin, '-' AS typmodout, "
7730                                                   "typanalyze, "
7731                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7732                                                   "typsend::pg_catalog.oid AS typsendoid, "
7733                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7734                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
7735                                                   "'U' AS typcategory, false AS typispreferred, "
7736                                                   "typdelim, typbyval, typalign, typstorage, "
7737                                                   "false AS typcollatable, "
7738                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7739                                                   "FROM pg_catalog.pg_type "
7740                                                   "WHERE oid = '%u'::pg_catalog.oid",
7741                                                   tyinfo->dobj.catId.oid);
7742         }
7743         else if (fout->remoteVersion >= 70400)
7744         {
7745                 appendPQExpBuffer(query, "SELECT typlen, "
7746                                                   "typinput, typoutput, typreceive, typsend, "
7747                                                   "'-' AS typmodin, '-' AS typmodout, "
7748                                                   "'-' AS typanalyze, "
7749                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
7750                                                   "typsend::pg_catalog.oid AS typsendoid, "
7751                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7752                                                   "0 AS typanalyzeoid, "
7753                                                   "'U' AS typcategory, false AS typispreferred, "
7754                                                   "typdelim, typbyval, typalign, typstorage, "
7755                                                   "false AS typcollatable, "
7756                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7757                                                   "FROM pg_catalog.pg_type "
7758                                                   "WHERE oid = '%u'::pg_catalog.oid",
7759                                                   tyinfo->dobj.catId.oid);
7760         }
7761         else if (fout->remoteVersion >= 70300)
7762         {
7763                 appendPQExpBuffer(query, "SELECT typlen, "
7764                                                   "typinput, typoutput, "
7765                                                   "'-' AS typreceive, '-' AS typsend, "
7766                                                   "'-' AS typmodin, '-' AS typmodout, "
7767                                                   "'-' AS typanalyze, "
7768                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7769                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7770                                                   "0 AS typanalyzeoid, "
7771                                                   "'U' AS typcategory, false AS typispreferred, "
7772                                                   "typdelim, typbyval, typalign, typstorage, "
7773                                                   "false AS typcollatable, "
7774                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
7775                                                   "FROM pg_catalog.pg_type "
7776                                                   "WHERE oid = '%u'::pg_catalog.oid",
7777                                                   tyinfo->dobj.catId.oid);
7778         }
7779         else if (fout->remoteVersion >= 70200)
7780         {
7781                 /*
7782                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
7783                  * ignore them because they are not right.
7784                  */
7785                 appendPQExpBuffer(query, "SELECT typlen, "
7786                                                   "typinput, typoutput, "
7787                                                   "'-' AS typreceive, '-' AS typsend, "
7788                                                   "'-' AS typmodin, '-' AS typmodout, "
7789                                                   "'-' AS typanalyze, "
7790                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7791                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7792                                                   "0 AS typanalyzeoid, "
7793                                                   "'U' AS typcategory, false AS typispreferred, "
7794                                                   "typdelim, typbyval, typalign, typstorage, "
7795                                                   "false AS typcollatable, "
7796                                                   "NULL AS typdefaultbin, typdefault "
7797                                                   "FROM pg_type "
7798                                                   "WHERE oid = '%u'::oid",
7799                                                   tyinfo->dobj.catId.oid);
7800         }
7801         else if (fout->remoteVersion >= 70100)
7802         {
7803                 /*
7804                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
7805                  * representation.
7806                  */
7807                 appendPQExpBuffer(query, "SELECT typlen, "
7808                                                   "typinput, typoutput, "
7809                                                   "'-' AS typreceive, '-' AS typsend, "
7810                                                   "'-' AS typmodin, '-' AS typmodout, "
7811                                                   "'-' AS typanalyze, "
7812                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7813                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7814                                                   "0 AS typanalyzeoid, "
7815                                                   "'U' AS typcategory, false AS typispreferred, "
7816                                                   "typdelim, typbyval, typalign, typstorage, "
7817                                                   "false AS typcollatable, "
7818                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7819                                                   "FROM pg_type "
7820                                                   "WHERE oid = '%u'::oid",
7821                                                   tyinfo->dobj.catId.oid);
7822         }
7823         else
7824         {
7825                 appendPQExpBuffer(query, "SELECT typlen, "
7826                                                   "typinput, typoutput, "
7827                                                   "'-' AS typreceive, '-' AS typsend, "
7828                                                   "'-' AS typmodin, '-' AS typmodout, "
7829                                                   "'-' AS typanalyze, "
7830                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
7831                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
7832                                                   "0 AS typanalyzeoid, "
7833                                                   "'U' AS typcategory, false AS typispreferred, "
7834                                                   "typdelim, typbyval, typalign, "
7835                                                   "'p'::char AS typstorage, "
7836                                                   "false AS typcollatable, "
7837                                                   "NULL AS typdefaultbin, NULL AS typdefault "
7838                                                   "FROM pg_type "
7839                                                   "WHERE oid = '%u'::oid",
7840                                                   tyinfo->dobj.catId.oid);
7841         }
7842
7843         res = PQexec(g_conn, query->data);
7844         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7845
7846         /* Expecting a single result only */
7847         ntups = PQntuples(res);
7848         if (ntups != 1)
7849         {
7850                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7851                                                            "query returned %d rows instead of one: %s\n",
7852                                                                  ntups),
7853                                   ntups, query->data);
7854                 exit_nicely();
7855         }
7856
7857         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
7858         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
7859         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
7860         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
7861         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
7862         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
7863         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
7864         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
7865         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
7866         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
7867         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
7868         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
7869         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
7870         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
7871         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
7872         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
7873         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
7874         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
7875         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
7876         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
7877         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
7878                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
7879         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
7880         {
7881                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
7882                 typdefault_is_literal = true;   /* it needs quotes */
7883         }
7884         else
7885                 typdefault = NULL;
7886
7887         /*
7888          * DROP must be fully qualified in case same name appears in pg_catalog.
7889          * The reason we include CASCADE is that the circular dependency between
7890          * the type and its I/O functions makes it impossible to drop the type any
7891          * other way.
7892          */
7893         appendPQExpBuffer(delq, "DROP TYPE %s.",
7894                                           fmtId(tyinfo->dobj.namespace->dobj.name));
7895         appendPQExpBuffer(delq, "%s CASCADE;\n",
7896                                           fmtId(tyinfo->dobj.name));
7897
7898         /* We might already have a shell type, but setting pg_type_oid is harmless */
7899         if (binary_upgrade)
7900                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
7901
7902         appendPQExpBuffer(q,
7903                                           "CREATE TYPE %s (\n"
7904                                           "    INTERNALLENGTH = %s",
7905                                           fmtId(tyinfo->dobj.name),
7906                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
7907
7908         if (fout->remoteVersion >= 70300)
7909         {
7910                 /* regproc result is correctly quoted as of 7.3 */
7911                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
7912                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
7913                 if (OidIsValid(typreceiveoid))
7914                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
7915                 if (OidIsValid(typsendoid))
7916                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
7917                 if (OidIsValid(typmodinoid))
7918                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
7919                 if (OidIsValid(typmodoutoid))
7920                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
7921                 if (OidIsValid(typanalyzeoid))
7922                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
7923         }
7924         else
7925         {
7926                 /* regproc delivers an unquoted name before 7.3 */
7927                 /* cannot combine these because fmtId uses static result area */
7928                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
7929                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
7930                 /* receive/send/typmodin/typmodout/analyze need not be printed */
7931         }
7932
7933         if (strcmp(typcollatable, "t") == 0)
7934                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
7935
7936         if (typdefault != NULL)
7937         {
7938                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
7939                 if (typdefault_is_literal)
7940                         appendStringLiteralAH(q, typdefault, fout);
7941                 else
7942                         appendPQExpBufferStr(q, typdefault);
7943         }
7944
7945         if (OidIsValid(tyinfo->typelem))
7946         {
7947                 char       *elemType;
7948
7949                 /* reselect schema in case changed by function dump */
7950                 selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
7951                 elemType = getFormattedTypeName(tyinfo->typelem, zeroAsOpaque);
7952                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
7953                 free(elemType);
7954         }
7955
7956         if (strcmp(typcategory, "U") != 0)
7957         {
7958                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
7959                 appendStringLiteralAH(q, typcategory, fout);
7960         }
7961
7962         if (strcmp(typispreferred, "t") == 0)
7963                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
7964
7965         if (typdelim && strcmp(typdelim, ",") != 0)
7966         {
7967                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
7968                 appendStringLiteralAH(q, typdelim, fout);
7969         }
7970
7971         if (strcmp(typalign, "c") == 0)
7972                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
7973         else if (strcmp(typalign, "s") == 0)
7974                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
7975         else if (strcmp(typalign, "i") == 0)
7976                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
7977         else if (strcmp(typalign, "d") == 0)
7978                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
7979
7980         if (strcmp(typstorage, "p") == 0)
7981                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
7982         else if (strcmp(typstorage, "e") == 0)
7983                 appendPQExpBuffer(q, ",\n    STORAGE = external");
7984         else if (strcmp(typstorage, "x") == 0)
7985                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
7986         else if (strcmp(typstorage, "m") == 0)
7987                 appendPQExpBuffer(q, ",\n    STORAGE = main");
7988
7989         if (strcmp(typbyval, "t") == 0)
7990                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
7991
7992         appendPQExpBuffer(q, "\n);\n");
7993
7994         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
7995
7996         if (binary_upgrade)
7997                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
7998
7999         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8000                                  tyinfo->dobj.name,
8001                                  tyinfo->dobj.namespace->dobj.name,
8002                                  NULL,
8003                                  tyinfo->rolname, false,
8004                                  "TYPE", SECTION_PRE_DATA,
8005                                  q->data, delq->data, NULL,
8006                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8007                                  NULL, NULL);
8008
8009         /* Dump Type Comments and Security Labels */
8010         dumpComment(fout, labelq->data,
8011                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8012                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8013         dumpSecLabel(fout, labelq->data,
8014                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8015                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8016
8017         PQclear(res);
8018         destroyPQExpBuffer(q);
8019         destroyPQExpBuffer(delq);
8020         destroyPQExpBuffer(labelq);
8021         destroyPQExpBuffer(query);
8022 }
8023
8024 /*
8025  * dumpDomain
8026  *        writes out to fout the queries to recreate a user-defined domain
8027  */
8028 static void
8029 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8030 {
8031         PQExpBuffer q = createPQExpBuffer();
8032         PQExpBuffer delq = createPQExpBuffer();
8033         PQExpBuffer labelq = createPQExpBuffer();
8034         PQExpBuffer query = createPQExpBuffer();
8035         PGresult   *res;
8036         int                     ntups;
8037         int                     i;
8038         char       *typnotnull;
8039         char       *typdefn;
8040         char       *typdefault;
8041         Oid                     typcollation;
8042         bool            typdefault_is_literal = false;
8043
8044         /* Set proper schema search path so type references list correctly */
8045         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
8046
8047         /* Fetch domain specific details */
8048         if (g_fout->remoteVersion >= 90100)
8049         {
8050                 /* typcollation is new in 9.1 */
8051                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8052                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8053                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8054                                                   "t.typdefault, "
8055                                                   "CASE WHEN t.typcollation <> u.typcollation "
8056                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8057                                                   "FROM pg_catalog.pg_type t "
8058                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8059                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8060                                                   tyinfo->dobj.catId.oid);
8061         }
8062         else
8063         {
8064                 /* We assume here that remoteVersion must be at least 70300 */
8065                 appendPQExpBuffer(query, "SELECT typnotnull, "
8066                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8067                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8068                                                   "typdefault, 0 AS typcollation "
8069                                                   "FROM pg_catalog.pg_type "
8070                                                   "WHERE oid = '%u'::pg_catalog.oid",
8071                                                   tyinfo->dobj.catId.oid);
8072         }
8073
8074         res = PQexec(g_conn, query->data);
8075         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8076
8077         /* Expecting a single result only */
8078         ntups = PQntuples(res);
8079         if (ntups != 1)
8080         {
8081                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8082                                                            "query returned %d rows instead of one: %s\n",
8083                                                                  ntups),
8084                                   ntups, query->data);
8085                 exit_nicely();
8086         }
8087
8088         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8089         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8090         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8091                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8092         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8093         {
8094                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8095                 typdefault_is_literal = true;   /* it needs quotes */
8096         }
8097         else
8098                 typdefault = NULL;
8099         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8100
8101         if (binary_upgrade)
8102                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
8103
8104         appendPQExpBuffer(q,
8105                                           "CREATE DOMAIN %s AS %s",
8106                                           fmtId(tyinfo->dobj.name),
8107                                           typdefn);
8108
8109         /* Print collation only if different from base type's collation */
8110         if (OidIsValid(typcollation))
8111         {
8112                 CollInfo   *coll;
8113
8114                 coll = findCollationByOid(typcollation);
8115                 if (coll)
8116                 {
8117                         /* always schema-qualify, don't try to be smart */
8118                         appendPQExpBuffer(q, " COLLATE %s.",
8119                                                           fmtId(coll->dobj.namespace->dobj.name));
8120                         appendPQExpBuffer(q, "%s",
8121                                                           fmtId(coll->dobj.name));
8122                 }
8123         }
8124
8125         if (typnotnull[0] == 't')
8126                 appendPQExpBuffer(q, " NOT NULL");
8127
8128         if (typdefault != NULL)
8129         {
8130                 appendPQExpBuffer(q, " DEFAULT ");
8131                 if (typdefault_is_literal)
8132                         appendStringLiteralAH(q, typdefault, fout);
8133                 else
8134                         appendPQExpBufferStr(q, typdefault);
8135         }
8136
8137         PQclear(res);
8138
8139         /*
8140          * Add any CHECK constraints for the domain
8141          */
8142         for (i = 0; i < tyinfo->nDomChecks; i++)
8143         {
8144                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8145
8146                 if (!domcheck->separate)
8147                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8148                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8149         }
8150
8151         appendPQExpBuffer(q, ";\n");
8152
8153         /*
8154          * DROP must be fully qualified in case same name appears in pg_catalog
8155          */
8156         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8157                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8158         appendPQExpBuffer(delq, "%s;\n",
8159                                           fmtId(tyinfo->dobj.name));
8160
8161         appendPQExpBuffer(labelq, "DOMAIN %s", fmtId(tyinfo->dobj.name));
8162
8163         if (binary_upgrade)
8164                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8165
8166         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8167                                  tyinfo->dobj.name,
8168                                  tyinfo->dobj.namespace->dobj.name,
8169                                  NULL,
8170                                  tyinfo->rolname, false,
8171                                  "DOMAIN", SECTION_PRE_DATA,
8172                                  q->data, delq->data, NULL,
8173                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8174                                  NULL, NULL);
8175
8176         /* Dump Domain Comments and Security Labels */
8177         dumpComment(fout, labelq->data,
8178                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8179                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8180         dumpSecLabel(fout, labelq->data,
8181                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8182                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8183
8184         destroyPQExpBuffer(q);
8185         destroyPQExpBuffer(delq);
8186         destroyPQExpBuffer(labelq);
8187         destroyPQExpBuffer(query);
8188 }
8189
8190 /*
8191  * dumpCompositeType
8192  *        writes out to fout the queries to recreate a user-defined stand-alone
8193  *        composite type
8194  */
8195 static void
8196 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8197 {
8198         PQExpBuffer q = createPQExpBuffer();
8199         PQExpBuffer dropped = createPQExpBuffer();
8200         PQExpBuffer delq = createPQExpBuffer();
8201         PQExpBuffer labelq = createPQExpBuffer();
8202         PQExpBuffer query = createPQExpBuffer();
8203         PGresult   *res;
8204         int                     ntups;
8205         int                     i_attname;
8206         int                     i_atttypdefn;
8207         int                     i_attlen;
8208         int                     i_attalign;
8209         int                     i_attisdropped;
8210         int                     i_attcollation;
8211         int                     i_typrelid;
8212         int                     i;
8213         int                     actual_atts;
8214
8215         /* Set proper schema search path so type references list correctly */
8216         selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
8217
8218         /* Fetch type specific details */
8219         if (fout->remoteVersion >= 90100)
8220         {
8221                 /*
8222                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8223                  * clauses for attributes whose collation is different from their
8224                  * type's default, we use a CASE here to suppress uninteresting
8225                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8226                  * collation does not matter for those.
8227                  */
8228                 appendPQExpBuffer(query, "SELECT a.attname, "
8229                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8230                                                   "a.attlen, a.attalign, a.attisdropped, "
8231                                                   "CASE WHEN a.attcollation <> at.typcollation "
8232                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8233                                                   "ct.typrelid "
8234                                                   "FROM pg_catalog.pg_type ct "
8235                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8236                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8237                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8238                                                   "ORDER BY a.attnum ",
8239                                                   tyinfo->dobj.catId.oid);
8240         }
8241         else
8242         {
8243                 /*
8244                  * We assume here that remoteVersion must be at least 70300.  Since
8245                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8246                  * always be false.
8247                  */
8248                 appendPQExpBuffer(query, "SELECT a.attname, "
8249                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8250                                                   "a.attlen, a.attalign, a.attisdropped, "
8251                                                   "0 AS attcollation, "
8252                                                   "ct.typrelid "
8253                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8254                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8255                                                   "AND a.attrelid = ct.typrelid "
8256                                                   "ORDER BY a.attnum ",
8257                                                   tyinfo->dobj.catId.oid);
8258         }
8259
8260         res = PQexec(g_conn, query->data);
8261         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8262
8263         ntups = PQntuples(res);
8264
8265         i_attname = PQfnumber(res, "attname");
8266         i_atttypdefn = PQfnumber(res, "atttypdefn");
8267         i_attlen = PQfnumber(res, "attlen");
8268         i_attalign = PQfnumber(res, "attalign");
8269         i_attisdropped = PQfnumber(res, "attisdropped");
8270         i_attcollation = PQfnumber(res, "attcollation");
8271         i_typrelid = PQfnumber(res, "typrelid");
8272
8273         if (binary_upgrade)
8274         {
8275                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8276
8277                 binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
8278                 binary_upgrade_set_pg_class_oids(q, typrelid, false);
8279         }
8280
8281         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8282                                           fmtId(tyinfo->dobj.name));
8283
8284         actual_atts = 0;
8285         for (i = 0; i < ntups; i++)
8286         {
8287                 char       *attname;
8288                 char       *atttypdefn;
8289                 char       *attlen;
8290                 char       *attalign;
8291                 bool            attisdropped;
8292                 Oid                     attcollation;
8293
8294                 attname = PQgetvalue(res, i, i_attname);
8295                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8296                 attlen = PQgetvalue(res, i, i_attlen);
8297                 attalign = PQgetvalue(res, i, i_attalign);
8298                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8299                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8300
8301                 if (attisdropped && !binary_upgrade)
8302                         continue;
8303
8304                 /* Format properly if not first attr */
8305                 if (actual_atts++ > 0)
8306                         appendPQExpBuffer(q, ",");
8307                 appendPQExpBuffer(q, "\n\t");
8308
8309                 if (!attisdropped)
8310                 {
8311                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8312
8313                         /* Add collation if not default for the column type */
8314                         if (OidIsValid(attcollation))
8315                         {
8316                                 CollInfo   *coll;
8317
8318                                 coll = findCollationByOid(attcollation);
8319                                 if (coll)
8320                                 {
8321                                         /* always schema-qualify, don't try to be smart */
8322                                         appendPQExpBuffer(q, " COLLATE %s.",
8323                                                                           fmtId(coll->dobj.namespace->dobj.name));
8324                                         appendPQExpBuffer(q, "%s",
8325                                                                           fmtId(coll->dobj.name));
8326                                 }
8327                         }
8328                 }
8329                 else
8330                 {
8331                         /*
8332                          * This is a dropped attribute and we're in binary_upgrade mode.
8333                          * Insert a placeholder for it in the CREATE TYPE command, and set
8334                          * length and alignment with direct UPDATE to the catalogs
8335                          * afterwards. See similar code in dumpTableSchema().
8336                          */
8337                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8338
8339                         /* stash separately for insertion after the CREATE TYPE */
8340                         appendPQExpBuffer(dropped,
8341                                           "\n-- For binary upgrade, recreate dropped column.\n");
8342                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8343                                                           "SET attlen = %s, "
8344                                                           "attalign = '%s', attbyval = false\n"
8345                                                           "WHERE attname = ", attlen, attalign);
8346                         appendStringLiteralAH(dropped, attname, fout);
8347                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8348                         appendStringLiteralAH(dropped, fmtId(tyinfo->dobj.name), fout);
8349                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8350
8351                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8352                                                           fmtId(tyinfo->dobj.name));
8353                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8354                                                           fmtId(attname));
8355                 }
8356         }
8357         appendPQExpBuffer(q, "\n);\n");
8358         appendPQExpBufferStr(q, dropped->data);
8359
8360         /*
8361          * DROP must be fully qualified in case same name appears in pg_catalog
8362          */
8363         appendPQExpBuffer(delq, "DROP TYPE %s.",
8364                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8365         appendPQExpBuffer(delq, "%s;\n",
8366                                           fmtId(tyinfo->dobj.name));
8367
8368         appendPQExpBuffer(labelq, "TYPE %s", fmtId(tyinfo->dobj.name));
8369
8370         if (binary_upgrade)
8371                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8372
8373         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8374                                  tyinfo->dobj.name,
8375                                  tyinfo->dobj.namespace->dobj.name,
8376                                  NULL,
8377                                  tyinfo->rolname, false,
8378                                  "TYPE", SECTION_PRE_DATA,
8379                                  q->data, delq->data, NULL,
8380                                  tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
8381                                  NULL, NULL);
8382
8383
8384         /* Dump Type Comments and Security Labels */
8385         dumpComment(fout, labelq->data,
8386                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8387                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8388         dumpSecLabel(fout, labelq->data,
8389                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8390                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8391
8392         PQclear(res);
8393         destroyPQExpBuffer(q);
8394         destroyPQExpBuffer(dropped);
8395         destroyPQExpBuffer(delq);
8396         destroyPQExpBuffer(labelq);
8397         destroyPQExpBuffer(query);
8398
8399         /* Dump any per-column comments */
8400         dumpCompositeTypeColComments(fout, tyinfo);
8401 }
8402
8403 /*
8404  * dumpCompositeTypeColComments
8405  *        writes out to fout the queries to recreate comments on the columns of
8406  *        a user-defined stand-alone composite type
8407  */
8408 static void
8409 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
8410 {
8411         CommentItem *comments;
8412         int                     ncomments;
8413         PGresult   *res;
8414         PQExpBuffer query;
8415         PQExpBuffer target;
8416         Oid                     pgClassOid;
8417         int                     i;
8418         int                     ntups;
8419         int                     i_attname;
8420         int                     i_attnum;
8421
8422         query = createPQExpBuffer();
8423
8424         /* We assume here that remoteVersion must be at least 70300 */
8425         appendPQExpBuffer(query,
8426                                           "SELECT c.tableoid, a.attname, a.attnum "
8427                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
8428                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
8429                                           "  AND NOT a.attisdropped "
8430                                           "ORDER BY a.attnum ",
8431                                           tyinfo->typrelid);
8432
8433         /* Fetch column attnames */
8434         res = PQexec(g_conn, query->data);
8435         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8436
8437         ntups = PQntuples(res);
8438         if (ntups < 1)
8439         {
8440                 PQclear(res);
8441                 destroyPQExpBuffer(query);
8442                 return;
8443         }
8444
8445         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
8446
8447         /* Search for comments associated with type's pg_class OID */
8448         ncomments = findComments(fout,
8449                                                          pgClassOid,
8450                                                          tyinfo->typrelid,
8451                                                          &comments);
8452
8453         /* If no comments exist, we're done */
8454         if (ncomments <= 0)
8455         {
8456                 PQclear(res);
8457                 destroyPQExpBuffer(query);
8458                 return;
8459         }
8460
8461         /* Build COMMENT ON statements */
8462         target = createPQExpBuffer();
8463
8464         i_attnum = PQfnumber(res, "attnum");
8465         i_attname = PQfnumber(res, "attname");
8466         while (ncomments > 0)
8467         {
8468                 const char *attname;
8469
8470                 attname = NULL;
8471                 for (i = 0; i < ntups; i++)
8472                 {
8473                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
8474                         {
8475                                 attname = PQgetvalue(res, i, i_attname);
8476                                 break;
8477                         }
8478                 }
8479                 if (attname)                    /* just in case we don't find it */
8480                 {
8481                         const char *descr = comments->descr;
8482
8483                         resetPQExpBuffer(target);
8484                         appendPQExpBuffer(target, "COLUMN %s.",
8485                                                           fmtId(tyinfo->dobj.name));
8486                         appendPQExpBuffer(target, "%s",
8487                                                           fmtId(attname));
8488
8489                         resetPQExpBuffer(query);
8490                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
8491                         appendStringLiteralAH(query, descr, fout);
8492                         appendPQExpBuffer(query, ";\n");
8493
8494                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
8495                                                  target->data,
8496                                                  tyinfo->dobj.namespace->dobj.name,
8497                                                  NULL, tyinfo->rolname,
8498                                                  false, "COMMENT", SECTION_NONE,
8499                                                  query->data, "", NULL,
8500                                                  &(tyinfo->dobj.dumpId), 1,
8501                                                  NULL, NULL);
8502                 }
8503
8504                 comments++;
8505                 ncomments--;
8506         }
8507
8508         PQclear(res);
8509         destroyPQExpBuffer(query);
8510         destroyPQExpBuffer(target);
8511 }
8512
8513 /*
8514  * dumpShellType
8515  *        writes out to fout the queries to create a shell type
8516  *
8517  * We dump a shell definition in advance of the I/O functions for the type.
8518  */
8519 static void
8520 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
8521 {
8522         PQExpBuffer q;
8523
8524         /* Skip if not to be dumped */
8525         if (!stinfo->dobj.dump || dataOnly)
8526                 return;
8527
8528         q = createPQExpBuffer();
8529
8530         /*
8531          * Note the lack of a DROP command for the shell type; any required DROP
8532          * is driven off the base type entry, instead.  This interacts with
8533          * _printTocEntry()'s use of the presence of a DROP command to decide
8534          * whether an entry needs an ALTER OWNER command.  We don't want to alter
8535          * the shell type's owner immediately on creation; that should happen only
8536          * after it's filled in, otherwise the backend complains.
8537          */
8538
8539         if (binary_upgrade)
8540                 binary_upgrade_set_type_oids_by_type_oid(q,
8541                                                                                    stinfo->baseType->dobj.catId.oid);
8542
8543         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
8544                                           fmtId(stinfo->dobj.name));
8545
8546         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
8547                                  stinfo->dobj.name,
8548                                  stinfo->dobj.namespace->dobj.name,
8549                                  NULL,
8550                                  stinfo->baseType->rolname, false,
8551                                  "SHELL TYPE", SECTION_PRE_DATA,
8552                                  q->data, "", NULL,
8553                                  stinfo->dobj.dependencies, stinfo->dobj.nDeps,
8554                                  NULL, NULL);
8555
8556         destroyPQExpBuffer(q);
8557 }
8558
8559 /*
8560  * Determine whether we want to dump definitions for procedural languages.
8561  * Since the languages themselves don't have schemas, we can't rely on
8562  * the normal schema-based selection mechanism.  We choose to dump them
8563  * whenever neither --schema nor --table was given.  (Before 8.1, we used
8564  * the dump flag of the PL's call handler function, but in 8.1 this will
8565  * probably always be false since call handlers are created in pg_catalog.)
8566  *
8567  * For some backwards compatibility with the older behavior, we forcibly
8568  * dump a PL if its handler function (and validator if any) are in a
8569  * dumpable namespace.  That case is not checked here.
8570  *
8571  * Also, if the PL belongs to an extension, we do not use this heuristic.
8572  * That case isn't checked here either.
8573  */
8574 static bool
8575 shouldDumpProcLangs(void)
8576 {
8577         if (!include_everything)
8578                 return false;
8579         /* And they're schema not data */
8580         if (dataOnly)
8581                 return false;
8582         return true;
8583 }
8584
8585 /*
8586  * dumpProcLang
8587  *                writes out to fout the queries to recreate a user-defined
8588  *                procedural language
8589  */
8590 static void
8591 dumpProcLang(Archive *fout, ProcLangInfo *plang)
8592 {
8593         PQExpBuffer defqry;
8594         PQExpBuffer delqry;
8595         PQExpBuffer labelq;
8596         bool            useParams;
8597         char       *qlanname;
8598         char       *lanschema;
8599         FuncInfo   *funcInfo;
8600         FuncInfo   *inlineInfo = NULL;
8601         FuncInfo   *validatorInfo = NULL;
8602
8603         /* Skip if not to be dumped */
8604         if (!plang->dobj.dump || dataOnly)
8605                 return;
8606
8607         /*
8608          * Try to find the support function(s).  It is not an error if we don't
8609          * find them --- if the functions are in the pg_catalog schema, as is
8610          * standard in 8.1 and up, then we won't have loaded them. (In this case
8611          * we will emit a parameterless CREATE LANGUAGE command, which will
8612          * require PL template knowledge in the backend to reload.)
8613          */
8614
8615         funcInfo = findFuncByOid(plang->lanplcallfoid);
8616         if (funcInfo != NULL && !funcInfo->dobj.dump)
8617                 funcInfo = NULL;                /* treat not-dumped same as not-found */
8618
8619         if (OidIsValid(plang->laninline))
8620         {
8621                 inlineInfo = findFuncByOid(plang->laninline);
8622                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
8623                         inlineInfo = NULL;
8624         }
8625
8626         if (OidIsValid(plang->lanvalidator))
8627         {
8628                 validatorInfo = findFuncByOid(plang->lanvalidator);
8629                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
8630                         validatorInfo = NULL;
8631         }
8632
8633         /*
8634          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
8635          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
8636          * dump it.
8637          *
8638          * However, for a language that belongs to an extension, we must not use
8639          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
8640          * told to (via dobj.dump).  Generally the support functions will belong
8641          * to the same extension and so have the same dump flags ... if they
8642          * don't, this might not work terribly nicely.
8643          */
8644         useParams = (funcInfo != NULL &&
8645                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
8646                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
8647
8648         if (!plang->dobj.ext_member)
8649         {
8650                 if (!useParams && !shouldDumpProcLangs())
8651                         return;
8652         }
8653
8654         defqry = createPQExpBuffer();
8655         delqry = createPQExpBuffer();
8656         labelq = createPQExpBuffer();
8657
8658         qlanname = pg_strdup(fmtId(plang->dobj.name));
8659
8660         /*
8661          * If dumping a HANDLER clause, treat the language as being in the handler
8662          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
8663          * it doesn't really have a schema.
8664          */
8665         if (useParams)
8666                 lanschema = funcInfo->dobj.namespace->dobj.name;
8667         else
8668                 lanschema = NULL;
8669
8670         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
8671                                           qlanname);
8672
8673         if (useParams)
8674         {
8675                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
8676                                                   plang->lanpltrusted ? "TRUSTED " : "",
8677                                                   qlanname);
8678                 appendPQExpBuffer(defqry, " HANDLER %s",
8679                                                   fmtId(funcInfo->dobj.name));
8680                 if (OidIsValid(plang->laninline))
8681                 {
8682                         appendPQExpBuffer(defqry, " INLINE ");
8683                         /* Cope with possibility that inline is in different schema */
8684                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
8685                                 appendPQExpBuffer(defqry, "%s.",
8686                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
8687                         appendPQExpBuffer(defqry, "%s",
8688                                                           fmtId(inlineInfo->dobj.name));
8689                 }
8690                 if (OidIsValid(plang->lanvalidator))
8691                 {
8692                         appendPQExpBuffer(defqry, " VALIDATOR ");
8693                         /* Cope with possibility that validator is in different schema */
8694                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
8695                                 appendPQExpBuffer(defqry, "%s.",
8696                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
8697                         appendPQExpBuffer(defqry, "%s",
8698                                                           fmtId(validatorInfo->dobj.name));
8699                 }
8700         }
8701         else
8702         {
8703                 /*
8704                  * If not dumping parameters, then use CREATE OR REPLACE so that the
8705                  * command will not fail if the language is preinstalled in the target
8706                  * database.  We restrict the use of REPLACE to this case so as to
8707                  * eliminate the risk of replacing a language with incompatible
8708                  * parameter settings: this command will only succeed at all if there
8709                  * is a pg_pltemplate entry, and if there is one, the existing entry
8710                  * must match it too.
8711                  */
8712                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
8713                                                   qlanname);
8714         }
8715         appendPQExpBuffer(defqry, ";\n");
8716
8717         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
8718
8719         if (binary_upgrade)
8720                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
8721
8722         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
8723                                  plang->dobj.name,
8724                                  lanschema, NULL, plang->lanowner,
8725                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
8726                                  defqry->data, delqry->data, NULL,
8727                                  plang->dobj.dependencies, plang->dobj.nDeps,
8728                                  NULL, NULL);
8729
8730         /* Dump Proc Lang Comments and Security Labels */
8731         dumpComment(fout, labelq->data,
8732                                 NULL, "",
8733                                 plang->dobj.catId, 0, plang->dobj.dumpId);
8734         dumpSecLabel(fout, labelq->data,
8735                                  NULL, "",
8736                                  plang->dobj.catId, 0, plang->dobj.dumpId);
8737
8738         if (plang->lanpltrusted)
8739                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
8740                                 qlanname, NULL, plang->dobj.name,
8741                                 lanschema,
8742                                 plang->lanowner, plang->lanacl);
8743
8744         free(qlanname);
8745
8746         destroyPQExpBuffer(defqry);
8747         destroyPQExpBuffer(delqry);
8748         destroyPQExpBuffer(labelq);
8749 }
8750
8751 /*
8752  * format_function_arguments: generate function name and argument list
8753  *
8754  * This is used when we can rely on pg_get_function_arguments to format
8755  * the argument list.
8756  */
8757 static char *
8758 format_function_arguments(FuncInfo *finfo, char *funcargs)
8759 {
8760         PQExpBufferData fn;
8761
8762         initPQExpBuffer(&fn);
8763         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
8764         return fn.data;
8765 }
8766
8767 /*
8768  * format_function_arguments_old: generate function name and argument list
8769  *
8770  * The argument type names are qualified if needed.  The function name
8771  * is never qualified.
8772  *
8773  * This is used only with pre-8.4 servers, so we aren't expecting to see
8774  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
8775  *
8776  * Any or all of allargtypes, argmodes, argnames may be NULL.
8777  */
8778 static char *
8779 format_function_arguments_old(FuncInfo *finfo, int nallargs,
8780                                                           char **allargtypes,
8781                                                           char **argmodes,
8782                                                           char **argnames)
8783 {
8784         PQExpBufferData fn;
8785         int                     j;
8786
8787         initPQExpBuffer(&fn);
8788         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8789         for (j = 0; j < nallargs; j++)
8790         {
8791                 Oid                     typid;
8792                 char       *typname;
8793                 const char *argmode;
8794                 const char *argname;
8795
8796                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
8797                 typname = getFormattedTypeName(typid, zeroAsOpaque);
8798
8799                 if (argmodes)
8800                 {
8801                         switch (argmodes[j][0])
8802                         {
8803                                 case PROARGMODE_IN:
8804                                         argmode = "";
8805                                         break;
8806                                 case PROARGMODE_OUT:
8807                                         argmode = "OUT ";
8808                                         break;
8809                                 case PROARGMODE_INOUT:
8810                                         argmode = "INOUT ";
8811                                         break;
8812                                 default:
8813                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
8814                                         argmode = "";
8815                                         break;
8816                         }
8817                 }
8818                 else
8819                         argmode = "";
8820
8821                 argname = argnames ? argnames[j] : (char *) NULL;
8822                 if (argname && argname[0] == '\0')
8823                         argname = NULL;
8824
8825                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
8826                                                   (j > 0) ? ", " : "",
8827                                                   argmode,
8828                                                   argname ? fmtId(argname) : "",
8829                                                   argname ? " " : "",
8830                                                   typname);
8831                 free(typname);
8832         }
8833         appendPQExpBuffer(&fn, ")");
8834         return fn.data;
8835 }
8836
8837 /*
8838  * format_function_signature: generate function name and argument list
8839  *
8840  * This is like format_function_arguments_old except that only a minimal
8841  * list of input argument types is generated; this is sufficient to
8842  * reference the function, but not to define it.
8843  *
8844  * If honor_quotes is false then the function name is never quoted.
8845  * This is appropriate for use in TOC tags, but not in SQL commands.
8846  */
8847 static char *
8848 format_function_signature(FuncInfo *finfo, bool honor_quotes)
8849 {
8850         PQExpBufferData fn;
8851         int                     j;
8852
8853         initPQExpBuffer(&fn);
8854         if (honor_quotes)
8855                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
8856         else
8857                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
8858         for (j = 0; j < finfo->nargs; j++)
8859         {
8860                 char       *typname;
8861
8862                 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
8863
8864                 appendPQExpBuffer(&fn, "%s%s",
8865                                                   (j > 0) ? ", " : "",
8866                                                   typname);
8867                 free(typname);
8868         }
8869         appendPQExpBuffer(&fn, ")");
8870         return fn.data;
8871 }
8872
8873
8874 /*
8875  * dumpFunc:
8876  *        dump out one function
8877  */
8878 static void
8879 dumpFunc(Archive *fout, FuncInfo *finfo)
8880 {
8881         PQExpBuffer query;
8882         PQExpBuffer q;
8883         PQExpBuffer delqry;
8884         PQExpBuffer labelq;
8885         PQExpBuffer asPart;
8886         PGresult   *res;
8887         char       *funcsig;            /* identity signature */
8888         char       *funcfullsig;        /* full signature */
8889         char       *funcsig_tag;
8890         int                     ntups;
8891         char       *proretset;
8892         char       *prosrc;
8893         char       *probin;
8894         char       *funcargs;
8895         char       *funciargs;
8896         char       *funcresult;
8897         char       *proallargtypes;
8898         char       *proargmodes;
8899         char       *proargnames;
8900         char       *proiswindow;
8901         char       *provolatile;
8902         char       *proisstrict;
8903         char       *prosecdef;
8904         char       *proconfig;
8905         char       *procost;
8906         char       *prorows;
8907         char       *lanname;
8908         char       *rettypename;
8909         int                     nallargs;
8910         char      **allargtypes = NULL;
8911         char      **argmodes = NULL;
8912         char      **argnames = NULL;
8913         char      **configitems = NULL;
8914         int                     nconfigitems = 0;
8915         int                     i;
8916
8917         /* Skip if not to be dumped */
8918         if (!finfo->dobj.dump || dataOnly)
8919                 return;
8920
8921         query = createPQExpBuffer();
8922         q = createPQExpBuffer();
8923         delqry = createPQExpBuffer();
8924         labelq = createPQExpBuffer();
8925         asPart = createPQExpBuffer();
8926
8927         /* Set proper schema search path so type references list correctly */
8928         selectSourceSchema(finfo->dobj.namespace->dobj.name);
8929
8930         /* Fetch function-specific details */
8931         if (g_fout->remoteVersion >= 80400)
8932         {
8933                 /*
8934                  * In 8.4 and up we rely on pg_get_function_arguments and
8935                  * pg_get_function_result instead of examining proallargtypes etc.
8936                  */
8937                 appendPQExpBuffer(query,
8938                                                   "SELECT proretset, prosrc, probin, "
8939                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
8940                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
8941                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
8942                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
8943                                                   "proconfig, procost, prorows, "
8944                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
8945                                                   "FROM pg_catalog.pg_proc "
8946                                                   "WHERE oid = '%u'::pg_catalog.oid",
8947                                                   finfo->dobj.catId.oid);
8948         }
8949         else if (g_fout->remoteVersion >= 80300)
8950         {
8951                 appendPQExpBuffer(query,
8952                                                   "SELECT proretset, prosrc, probin, "
8953                                                   "proallargtypes, proargmodes, proargnames, "
8954                                                   "false AS proiswindow, "
8955                                                   "provolatile, proisstrict, prosecdef, "
8956                                                   "proconfig, procost, prorows, "
8957                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
8958                                                   "FROM pg_catalog.pg_proc "
8959                                                   "WHERE oid = '%u'::pg_catalog.oid",
8960                                                   finfo->dobj.catId.oid);
8961         }
8962         else if (g_fout->remoteVersion >= 80100)
8963         {
8964                 appendPQExpBuffer(query,
8965                                                   "SELECT proretset, prosrc, probin, "
8966                                                   "proallargtypes, proargmodes, proargnames, "
8967                                                   "false AS proiswindow, "
8968                                                   "provolatile, proisstrict, prosecdef, "
8969                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
8970                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
8971                                                   "FROM pg_catalog.pg_proc "
8972                                                   "WHERE oid = '%u'::pg_catalog.oid",
8973                                                   finfo->dobj.catId.oid);
8974         }
8975         else if (g_fout->remoteVersion >= 80000)
8976         {
8977                 appendPQExpBuffer(query,
8978                                                   "SELECT proretset, prosrc, probin, "
8979                                                   "null AS proallargtypes, "
8980                                                   "null AS proargmodes, "
8981                                                   "proargnames, "
8982                                                   "false AS proiswindow, "
8983                                                   "provolatile, proisstrict, prosecdef, "
8984                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
8985                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
8986                                                   "FROM pg_catalog.pg_proc "
8987                                                   "WHERE oid = '%u'::pg_catalog.oid",
8988                                                   finfo->dobj.catId.oid);
8989         }
8990         else if (g_fout->remoteVersion >= 70300)
8991         {
8992                 appendPQExpBuffer(query,
8993                                                   "SELECT proretset, prosrc, probin, "
8994                                                   "null AS proallargtypes, "
8995                                                   "null AS proargmodes, "
8996                                                   "null AS proargnames, "
8997                                                   "false AS proiswindow, "
8998                                                   "provolatile, proisstrict, prosecdef, "
8999                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9000                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9001                                                   "FROM pg_catalog.pg_proc "
9002                                                   "WHERE oid = '%u'::pg_catalog.oid",
9003                                                   finfo->dobj.catId.oid);
9004         }
9005         else if (g_fout->remoteVersion >= 70100)
9006         {
9007                 appendPQExpBuffer(query,
9008                                                   "SELECT proretset, prosrc, probin, "
9009                                                   "null AS proallargtypes, "
9010                                                   "null AS proargmodes, "
9011                                                   "null AS proargnames, "
9012                                                   "false AS proiswindow, "
9013                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9014                                                   "proisstrict, "
9015                                                   "false AS prosecdef, "
9016                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9017                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9018                                                   "FROM pg_proc "
9019                                                   "WHERE oid = '%u'::oid",
9020                                                   finfo->dobj.catId.oid);
9021         }
9022         else
9023         {
9024                 appendPQExpBuffer(query,
9025                                                   "SELECT proretset, prosrc, probin, "
9026                                                   "null AS proallargtypes, "
9027                                                   "null AS proargmodes, "
9028                                                   "null AS proargnames, "
9029                                                   "false AS proiswindow, "
9030                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9031                                                   "false AS proisstrict, "
9032                                                   "false AS prosecdef, "
9033                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9034                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9035                                                   "FROM pg_proc "
9036                                                   "WHERE oid = '%u'::oid",
9037                                                   finfo->dobj.catId.oid);
9038         }
9039
9040         res = PQexec(g_conn, query->data);
9041         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9042
9043         /* Expecting a single result only */
9044         ntups = PQntuples(res);
9045         if (ntups != 1)
9046         {
9047                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9048                                                            "query returned %d rows instead of one: %s\n",
9049                                                                  ntups),
9050                                   ntups, query->data);
9051                 exit_nicely();
9052         }
9053
9054         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9055         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9056         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9057         if (g_fout->remoteVersion >= 80400)
9058         {
9059                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9060                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9061                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9062                 proallargtypes = proargmodes = proargnames = NULL;
9063         }
9064         else
9065         {
9066                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9067                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9068                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9069                 funcargs = funciargs = funcresult = NULL;
9070         }
9071         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9072         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9073         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9074         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9075         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9076         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9077         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9078         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9079
9080         /*
9081          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9082          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9083          * versions would set it to "-".  There are no known cases in which prosrc
9084          * is unused, so the tests below for "-" are probably useless.
9085          */
9086         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9087         {
9088                 appendPQExpBuffer(asPart, "AS ");
9089                 appendStringLiteralAH(asPart, probin, fout);
9090                 if (strcmp(prosrc, "-") != 0)
9091                 {
9092                         appendPQExpBuffer(asPart, ", ");
9093
9094                         /*
9095                          * where we have bin, use dollar quoting if allowed and src
9096                          * contains quote or backslash; else use regular quoting.
9097                          */
9098                         if (disable_dollar_quoting ||
9099                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9100                                 appendStringLiteralAH(asPart, prosrc, fout);
9101                         else
9102                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9103                 }
9104         }
9105         else
9106         {
9107                 if (strcmp(prosrc, "-") != 0)
9108                 {
9109                         appendPQExpBuffer(asPart, "AS ");
9110                         /* with no bin, dollar quote src unconditionally if allowed */
9111                         if (disable_dollar_quoting)
9112                                 appendStringLiteralAH(asPart, prosrc, fout);
9113                         else
9114                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9115                 }
9116         }
9117
9118         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9119
9120         if (proallargtypes && *proallargtypes)
9121         {
9122                 int                     nitems = 0;
9123
9124                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9125                         nitems < finfo->nargs)
9126                 {
9127                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9128                         if (allargtypes)
9129                                 free(allargtypes);
9130                         allargtypes = NULL;
9131                 }
9132                 else
9133                         nallargs = nitems;
9134         }
9135
9136         if (proargmodes && *proargmodes)
9137         {
9138                 int                     nitems = 0;
9139
9140                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9141                         nitems != nallargs)
9142                 {
9143                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9144                         if (argmodes)
9145                                 free(argmodes);
9146                         argmodes = NULL;
9147                 }
9148         }
9149
9150         if (proargnames && *proargnames)
9151         {
9152                 int                     nitems = 0;
9153
9154                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9155                         nitems != nallargs)
9156                 {
9157                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9158                         if (argnames)
9159                                 free(argnames);
9160                         argnames = NULL;
9161                 }
9162         }
9163
9164         if (proconfig && *proconfig)
9165         {
9166                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9167                 {
9168                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9169                         if (configitems)
9170                                 free(configitems);
9171                         configitems = NULL;
9172                         nconfigitems = 0;
9173                 }
9174         }
9175
9176         if (funcargs)
9177         {
9178                 /* 8.4 or later; we rely on server-side code for most of the work */
9179                 funcfullsig = format_function_arguments(finfo, funcargs);
9180                 funcsig = format_function_arguments(finfo, funciargs);
9181         }
9182         else
9183         {
9184                 /* pre-8.4, do it ourselves */
9185                 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
9186                                                                                                 argmodes, argnames);
9187                 funcfullsig = funcsig;
9188         }
9189
9190         funcsig_tag = format_function_signature(finfo, false);
9191
9192         /*
9193          * DROP must be fully qualified in case same name appears in pg_catalog
9194          */
9195         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9196                                           fmtId(finfo->dobj.namespace->dobj.name),
9197                                           funcsig);
9198
9199         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9200         if (funcresult)
9201                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9202         else
9203         {
9204                 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
9205                 appendPQExpBuffer(q, "RETURNS %s%s",
9206                                                   (proretset[0] == 't') ? "SETOF " : "",
9207                                                   rettypename);
9208                 free(rettypename);
9209         }
9210
9211         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9212
9213         if (proiswindow[0] == 't')
9214                 appendPQExpBuffer(q, " WINDOW");
9215
9216         if (provolatile[0] != PROVOLATILE_VOLATILE)
9217         {
9218                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9219                         appendPQExpBuffer(q, " IMMUTABLE");
9220                 else if (provolatile[0] == PROVOLATILE_STABLE)
9221                         appendPQExpBuffer(q, " STABLE");
9222                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9223                 {
9224                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
9225                                           finfo->dobj.name);
9226                         exit_nicely();
9227                 }
9228         }
9229
9230         if (proisstrict[0] == 't')
9231                 appendPQExpBuffer(q, " STRICT");
9232
9233         if (prosecdef[0] == 't')
9234                 appendPQExpBuffer(q, " SECURITY DEFINER");
9235
9236         /*
9237          * COST and ROWS are emitted only if present and not default, so as not to
9238          * break backwards-compatibility of the dump without need.      Keep this code
9239          * in sync with the defaults in functioncmds.c.
9240          */
9241         if (strcmp(procost, "0") != 0)
9242         {
9243                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9244                 {
9245                         /* default cost is 1 */
9246                         if (strcmp(procost, "1") != 0)
9247                                 appendPQExpBuffer(q, " COST %s", procost);
9248                 }
9249                 else
9250                 {
9251                         /* default cost is 100 */
9252                         if (strcmp(procost, "100") != 0)
9253                                 appendPQExpBuffer(q, " COST %s", procost);
9254                 }
9255         }
9256         if (proretset[0] == 't' &&
9257                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9258                 appendPQExpBuffer(q, " ROWS %s", prorows);
9259
9260         for (i = 0; i < nconfigitems; i++)
9261         {
9262                 /* we feel free to scribble on configitems[] here */
9263                 char       *configitem = configitems[i];
9264                 char       *pos;
9265
9266                 pos = strchr(configitem, '=');
9267                 if (pos == NULL)
9268                         continue;
9269                 *pos++ = '\0';
9270                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9271
9272                 /*
9273                  * Some GUC variable names are 'LIST' type and hence must not be
9274                  * quoted.
9275                  */
9276                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9277                         || pg_strcasecmp(configitem, "search_path") == 0)
9278                         appendPQExpBuffer(q, "%s", pos);
9279                 else
9280                         appendStringLiteralAH(q, pos, fout);
9281         }
9282
9283         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9284
9285         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9286
9287         if (binary_upgrade)
9288                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9289
9290         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9291                                  funcsig_tag,
9292                                  finfo->dobj.namespace->dobj.name,
9293                                  NULL,
9294                                  finfo->rolname, false,
9295                                  "FUNCTION", SECTION_PRE_DATA,
9296                                  q->data, delqry->data, NULL,
9297                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
9298                                  NULL, NULL);
9299
9300         /* Dump Function Comments and Security Labels */
9301         dumpComment(fout, labelq->data,
9302                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9303                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9304         dumpSecLabel(fout, labelq->data,
9305                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9306                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9307
9308         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9309                         funcsig, NULL, funcsig_tag,
9310                         finfo->dobj.namespace->dobj.name,
9311                         finfo->rolname, finfo->proacl);
9312
9313         PQclear(res);
9314
9315         destroyPQExpBuffer(query);
9316         destroyPQExpBuffer(q);
9317         destroyPQExpBuffer(delqry);
9318         destroyPQExpBuffer(labelq);
9319         destroyPQExpBuffer(asPart);
9320         free(funcsig);
9321         free(funcsig_tag);
9322         if (allargtypes)
9323                 free(allargtypes);
9324         if (argmodes)
9325                 free(argmodes);
9326         if (argnames)
9327                 free(argnames);
9328         if (configitems)
9329                 free(configitems);
9330 }
9331
9332
9333 /*
9334  * Dump a user-defined cast
9335  */
9336 static void
9337 dumpCast(Archive *fout, CastInfo *cast)
9338 {
9339         PQExpBuffer defqry;
9340         PQExpBuffer delqry;
9341         PQExpBuffer labelq;
9342         FuncInfo   *funcInfo = NULL;
9343
9344         /* Skip if not to be dumped */
9345         if (!cast->dobj.dump || dataOnly)
9346                 return;
9347
9348         /* Cannot dump if we don't have the cast function's info */
9349         if (OidIsValid(cast->castfunc))
9350         {
9351                 funcInfo = findFuncByOid(cast->castfunc);
9352                 if (funcInfo == NULL)
9353                         return;
9354         }
9355
9356         /*
9357          * As per discussion we dump casts if one or more of the underlying
9358          * objects (the conversion function and the two data types) are not
9359          * builtin AND if all of the non-builtin objects are included in the dump.
9360          * Builtin meaning, the namespace name does not start with "pg_".
9361          *
9362          * However, for a cast that belongs to an extension, we must not use this
9363          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9364          */
9365         if (!cast->dobj.ext_member)
9366         {
9367                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9368                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9369
9370                 if (sourceInfo == NULL || targetInfo == NULL)
9371                         return;
9372
9373                 /*
9374                  * Skip this cast if all objects are from pg_
9375                  */
9376                 if ((funcInfo == NULL ||
9377                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9378                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
9379                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
9380                         return;
9381
9382                 /*
9383                  * Skip cast if function isn't from pg_ and is not to be dumped.
9384                  */
9385                 if (funcInfo &&
9386                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9387                         !funcInfo->dobj.dump)
9388                         return;
9389
9390                 /*
9391                  * Same for the source type
9392                  */
9393                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9394                         !sourceInfo->dobj.dump)
9395                         return;
9396
9397                 /*
9398                  * and the target type.
9399                  */
9400                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
9401                         !targetInfo->dobj.dump)
9402                         return;
9403         }
9404
9405         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
9406         selectSourceSchema("pg_catalog");
9407
9408         defqry = createPQExpBuffer();
9409         delqry = createPQExpBuffer();
9410         labelq = createPQExpBuffer();
9411
9412         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
9413                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9414                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9415
9416         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
9417                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9418                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9419
9420         switch (cast->castmethod)
9421         {
9422                 case COERCION_METHOD_BINARY:
9423                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
9424                         break;
9425                 case COERCION_METHOD_INOUT:
9426                         appendPQExpBuffer(defqry, "WITH INOUT");
9427                         break;
9428                 case COERCION_METHOD_FUNCTION:
9429
9430                         /*
9431                          * Always qualify the function name, in case it is not in
9432                          * pg_catalog schema (format_function_signature won't qualify it).
9433                          */
9434                         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
9435                                                           fmtId(funcInfo->dobj.namespace->dobj.name));
9436                         appendPQExpBuffer(defqry, "%s",
9437                                                           format_function_signature(funcInfo, true));
9438                         break;
9439                 default:
9440                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
9441         }
9442
9443         if (cast->castcontext == 'a')
9444                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
9445         else if (cast->castcontext == 'i')
9446                 appendPQExpBuffer(defqry, " AS IMPLICIT");
9447         appendPQExpBuffer(defqry, ";\n");
9448
9449         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
9450                                           getFormattedTypeName(cast->castsource, zeroAsNone),
9451                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
9452
9453         if (binary_upgrade)
9454                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
9455
9456         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
9457                                  labelq->data,
9458                                  "pg_catalog", NULL, "",
9459                                  false, "CAST", SECTION_PRE_DATA,
9460                                  defqry->data, delqry->data, NULL,
9461                                  cast->dobj.dependencies, cast->dobj.nDeps,
9462                                  NULL, NULL);
9463
9464         /* Dump Cast Comments */
9465         dumpComment(fout, labelq->data,
9466                                 NULL, "",
9467                                 cast->dobj.catId, 0, cast->dobj.dumpId);
9468
9469         destroyPQExpBuffer(defqry);
9470         destroyPQExpBuffer(delqry);
9471         destroyPQExpBuffer(labelq);
9472 }
9473
9474 /*
9475  * dumpOpr
9476  *        write out a single operator definition
9477  */
9478 static void
9479 dumpOpr(Archive *fout, OprInfo *oprinfo)
9480 {
9481         PQExpBuffer query;
9482         PQExpBuffer q;
9483         PQExpBuffer delq;
9484         PQExpBuffer labelq;
9485         PQExpBuffer oprid;
9486         PQExpBuffer details;
9487         const char *name;
9488         PGresult   *res;
9489         int                     ntups;
9490         int                     i_oprkind;
9491         int                     i_oprcode;
9492         int                     i_oprleft;
9493         int                     i_oprright;
9494         int                     i_oprcom;
9495         int                     i_oprnegate;
9496         int                     i_oprrest;
9497         int                     i_oprjoin;
9498         int                     i_oprcanmerge;
9499         int                     i_oprcanhash;
9500         char       *oprkind;
9501         char       *oprcode;
9502         char       *oprleft;
9503         char       *oprright;
9504         char       *oprcom;
9505         char       *oprnegate;
9506         char       *oprrest;
9507         char       *oprjoin;
9508         char       *oprcanmerge;
9509         char       *oprcanhash;
9510
9511         /* Skip if not to be dumped */
9512         if (!oprinfo->dobj.dump || dataOnly)
9513                 return;
9514
9515         /*
9516          * some operators are invalid because they were the result of user
9517          * defining operators before commutators exist
9518          */
9519         if (!OidIsValid(oprinfo->oprcode))
9520                 return;
9521
9522         query = createPQExpBuffer();
9523         q = createPQExpBuffer();
9524         delq = createPQExpBuffer();
9525         labelq = createPQExpBuffer();
9526         oprid = createPQExpBuffer();
9527         details = createPQExpBuffer();
9528
9529         /* Make sure we are in proper schema so regoperator works correctly */
9530         selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
9531
9532         if (g_fout->remoteVersion >= 80300)
9533         {
9534                 appendPQExpBuffer(query, "SELECT oprkind, "
9535                                                   "oprcode::pg_catalog.regprocedure, "
9536                                                   "oprleft::pg_catalog.regtype, "
9537                                                   "oprright::pg_catalog.regtype, "
9538                                                   "oprcom::pg_catalog.regoperator, "
9539                                                   "oprnegate::pg_catalog.regoperator, "
9540                                                   "oprrest::pg_catalog.regprocedure, "
9541                                                   "oprjoin::pg_catalog.regprocedure, "
9542                                                   "oprcanmerge, oprcanhash "
9543                                                   "FROM pg_catalog.pg_operator "
9544                                                   "WHERE oid = '%u'::pg_catalog.oid",
9545                                                   oprinfo->dobj.catId.oid);
9546         }
9547         else if (g_fout->remoteVersion >= 70300)
9548         {
9549                 appendPQExpBuffer(query, "SELECT oprkind, "
9550                                                   "oprcode::pg_catalog.regprocedure, "
9551                                                   "oprleft::pg_catalog.regtype, "
9552                                                   "oprright::pg_catalog.regtype, "
9553                                                   "oprcom::pg_catalog.regoperator, "
9554                                                   "oprnegate::pg_catalog.regoperator, "
9555                                                   "oprrest::pg_catalog.regprocedure, "
9556                                                   "oprjoin::pg_catalog.regprocedure, "
9557                                                   "(oprlsortop != 0) AS oprcanmerge, "
9558                                                   "oprcanhash "
9559                                                   "FROM pg_catalog.pg_operator "
9560                                                   "WHERE oid = '%u'::pg_catalog.oid",
9561                                                   oprinfo->dobj.catId.oid);
9562         }
9563         else if (g_fout->remoteVersion >= 70100)
9564         {
9565                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9566                                                   "CASE WHEN oprleft = 0 THEN '-' "
9567                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
9568                                                   "CASE WHEN oprright = 0 THEN '-' "
9569                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
9570                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9571                                                   "(oprlsortop != 0) AS oprcanmerge, "
9572                                                   "oprcanhash "
9573                                                   "FROM pg_operator "
9574                                                   "WHERE oid = '%u'::oid",
9575                                                   oprinfo->dobj.catId.oid);
9576         }
9577         else
9578         {
9579                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
9580                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
9581                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
9582                                                   "CASE WHEN oprright = 0 THEN '-'::name "
9583                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
9584                                                   "oprcom, oprnegate, oprrest, oprjoin, "
9585                                                   "(oprlsortop != 0) AS oprcanmerge, "
9586                                                   "oprcanhash "
9587                                                   "FROM pg_operator "
9588                                                   "WHERE oid = '%u'::oid",
9589                                                   oprinfo->dobj.catId.oid);
9590         }
9591
9592         res = PQexec(g_conn, query->data);
9593         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9594
9595         /* Expecting a single result only */
9596         ntups = PQntuples(res);
9597         if (ntups != 1)
9598         {
9599                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9600                                                            "query returned %d rows instead of one: %s\n",
9601                                                                  ntups),
9602                                   ntups, query->data);
9603                 exit_nicely();
9604         }
9605
9606         i_oprkind = PQfnumber(res, "oprkind");
9607         i_oprcode = PQfnumber(res, "oprcode");
9608         i_oprleft = PQfnumber(res, "oprleft");
9609         i_oprright = PQfnumber(res, "oprright");
9610         i_oprcom = PQfnumber(res, "oprcom");
9611         i_oprnegate = PQfnumber(res, "oprnegate");
9612         i_oprrest = PQfnumber(res, "oprrest");
9613         i_oprjoin = PQfnumber(res, "oprjoin");
9614         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
9615         i_oprcanhash = PQfnumber(res, "oprcanhash");
9616
9617         oprkind = PQgetvalue(res, 0, i_oprkind);
9618         oprcode = PQgetvalue(res, 0, i_oprcode);
9619         oprleft = PQgetvalue(res, 0, i_oprleft);
9620         oprright = PQgetvalue(res, 0, i_oprright);
9621         oprcom = PQgetvalue(res, 0, i_oprcom);
9622         oprnegate = PQgetvalue(res, 0, i_oprnegate);
9623         oprrest = PQgetvalue(res, 0, i_oprrest);
9624         oprjoin = PQgetvalue(res, 0, i_oprjoin);
9625         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
9626         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
9627
9628         appendPQExpBuffer(details, "    PROCEDURE = %s",
9629                                           convertRegProcReference(oprcode));
9630
9631         appendPQExpBuffer(oprid, "%s (",
9632                                           oprinfo->dobj.name);
9633
9634         /*
9635          * right unary means there's a left arg and left unary means there's a
9636          * right arg
9637          */
9638         if (strcmp(oprkind, "r") == 0 ||
9639                 strcmp(oprkind, "b") == 0)
9640         {
9641                 if (g_fout->remoteVersion >= 70100)
9642                         name = oprleft;
9643                 else
9644                         name = fmtId(oprleft);
9645                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
9646                 appendPQExpBuffer(oprid, "%s", name);
9647         }
9648         else
9649                 appendPQExpBuffer(oprid, "NONE");
9650
9651         if (strcmp(oprkind, "l") == 0 ||
9652                 strcmp(oprkind, "b") == 0)
9653         {
9654                 if (g_fout->remoteVersion >= 70100)
9655                         name = oprright;
9656                 else
9657                         name = fmtId(oprright);
9658                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
9659                 appendPQExpBuffer(oprid, ", %s)", name);
9660         }
9661         else
9662                 appendPQExpBuffer(oprid, ", NONE)");
9663
9664         name = convertOperatorReference(oprcom);
9665         if (name)
9666                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
9667
9668         name = convertOperatorReference(oprnegate);
9669         if (name)
9670                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
9671
9672         if (strcmp(oprcanmerge, "t") == 0)
9673                 appendPQExpBuffer(details, ",\n    MERGES");
9674
9675         if (strcmp(oprcanhash, "t") == 0)
9676                 appendPQExpBuffer(details, ",\n    HASHES");
9677
9678         name = convertRegProcReference(oprrest);
9679         if (name)
9680                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
9681
9682         name = convertRegProcReference(oprjoin);
9683         if (name)
9684                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
9685
9686         /*
9687          * DROP must be fully qualified in case same name appears in pg_catalog
9688          */
9689         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
9690                                           fmtId(oprinfo->dobj.namespace->dobj.name),
9691                                           oprid->data);
9692
9693         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
9694                                           oprinfo->dobj.name, details->data);
9695
9696         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
9697
9698         if (binary_upgrade)
9699                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
9700
9701         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
9702                                  oprinfo->dobj.name,
9703                                  oprinfo->dobj.namespace->dobj.name,
9704                                  NULL,
9705                                  oprinfo->rolname,
9706                                  false, "OPERATOR", SECTION_PRE_DATA,
9707                                  q->data, delq->data, NULL,
9708                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
9709                                  NULL, NULL);
9710
9711         /* Dump Operator Comments */
9712         dumpComment(fout, labelq->data,
9713                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
9714                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
9715
9716         PQclear(res);
9717
9718         destroyPQExpBuffer(query);
9719         destroyPQExpBuffer(q);
9720         destroyPQExpBuffer(delq);
9721         destroyPQExpBuffer(labelq);
9722         destroyPQExpBuffer(oprid);
9723         destroyPQExpBuffer(details);
9724 }
9725
9726 /*
9727  * Convert a function reference obtained from pg_operator
9728  *
9729  * Returns what to print, or NULL if function references is InvalidOid
9730  *
9731  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
9732  * argument-types part.  In prior versions, the input is a REGPROC display.
9733  */
9734 static const char *
9735 convertRegProcReference(const char *proc)
9736 {
9737         /* In all cases "-" means a null reference */
9738         if (strcmp(proc, "-") == 0)
9739                 return NULL;
9740
9741         if (g_fout->remoteVersion >= 70300)
9742         {
9743                 char       *name;
9744                 char       *paren;
9745                 bool            inquote;
9746
9747                 name = pg_strdup(proc);
9748                 /* find non-double-quoted left paren */
9749                 inquote = false;
9750                 for (paren = name; *paren; paren++)
9751                 {
9752                         if (*paren == '(' && !inquote)
9753                         {
9754                                 *paren = '\0';
9755                                 break;
9756                         }
9757                         if (*paren == '"')
9758                                 inquote = !inquote;
9759                 }
9760                 return name;
9761         }
9762
9763         /* REGPROC before 7.3 does not quote its result */
9764         return fmtId(proc);
9765 }
9766
9767 /*
9768  * Convert an operator cross-reference obtained from pg_operator
9769  *
9770  * Returns what to print, or NULL to print nothing
9771  *
9772  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
9773  * argument-types part, and add OPERATOR() decoration if the name is
9774  * schema-qualified.  In older versions, the input is just a numeric OID,
9775  * which we search our operator list for.
9776  */
9777 static const char *
9778 convertOperatorReference(const char *opr)
9779 {
9780         OprInfo    *oprInfo;
9781
9782         /* In all cases "0" means a null reference */
9783         if (strcmp(opr, "0") == 0)
9784                 return NULL;
9785
9786         if (g_fout->remoteVersion >= 70300)
9787         {
9788                 char       *name;
9789                 char       *oname;
9790                 char       *ptr;
9791                 bool            inquote;
9792                 bool            sawdot;
9793
9794                 name = pg_strdup(opr);
9795                 /* find non-double-quoted left paren, and check for non-quoted dot */
9796                 inquote = false;
9797                 sawdot = false;
9798                 for (ptr = name; *ptr; ptr++)
9799                 {
9800                         if (*ptr == '"')
9801                                 inquote = !inquote;
9802                         else if (*ptr == '.' && !inquote)
9803                                 sawdot = true;
9804                         else if (*ptr == '(' && !inquote)
9805                         {
9806                                 *ptr = '\0';
9807                                 break;
9808                         }
9809                 }
9810                 /* If not schema-qualified, don't need to add OPERATOR() */
9811                 if (!sawdot)
9812                         return name;
9813                 oname = pg_malloc(strlen(name) + 11);
9814                 sprintf(oname, "OPERATOR(%s)", name);
9815                 free(name);
9816                 return oname;
9817         }
9818
9819         oprInfo = findOprByOid(atooid(opr));
9820         if (oprInfo == NULL)
9821         {
9822                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
9823                                   opr);
9824                 return NULL;
9825         }
9826         return oprInfo->dobj.name;
9827 }
9828
9829 /*
9830  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
9831  *
9832  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
9833  * argument lists of these functions are predetermined.  Note that the
9834  * caller should ensure we are in the proper schema, because the results
9835  * are search path dependent!
9836  */
9837 static const char *
9838 convertTSFunction(Oid funcOid)
9839 {
9840         char       *result;
9841         char            query[128];
9842         PGresult   *res;
9843         int                     ntups;
9844
9845         snprintf(query, sizeof(query),
9846                          "SELECT '%u'::pg_catalog.regproc", funcOid);
9847         res = PQexec(g_conn, query);
9848         check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
9849
9850         ntups = PQntuples(res);
9851         if (ntups != 1)
9852         {
9853                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9854                                                            "query returned %d rows instead of one: %s\n",
9855                                                                  ntups),
9856                                   ntups, query);
9857                 exit_nicely();
9858         }
9859
9860         result = pg_strdup(PQgetvalue(res, 0, 0));
9861
9862         PQclear(res);
9863
9864         return result;
9865 }
9866
9867
9868 /*
9869  * dumpOpclass
9870  *        write out a single operator class definition
9871  */
9872 static void
9873 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
9874 {
9875         PQExpBuffer query;
9876         PQExpBuffer q;
9877         PQExpBuffer delq;
9878         PQExpBuffer labelq;
9879         PGresult   *res;
9880         int                     ntups;
9881         int                     i_opcintype;
9882         int                     i_opckeytype;
9883         int                     i_opcdefault;
9884         int                     i_opcfamily;
9885         int                     i_opcfamilyname;
9886         int                     i_opcfamilynsp;
9887         int                     i_amname;
9888         int                     i_amopstrategy;
9889         int                     i_amopreqcheck;
9890         int                     i_amopopr;
9891         int                     i_sortfamily;
9892         int                     i_sortfamilynsp;
9893         int                     i_amprocnum;
9894         int                     i_amproc;
9895         int                     i_amproclefttype;
9896         int                     i_amprocrighttype;
9897         char       *opcintype;
9898         char       *opckeytype;
9899         char       *opcdefault;
9900         char       *opcfamily;
9901         char       *opcfamilyname;
9902         char       *opcfamilynsp;
9903         char       *amname;
9904         char       *amopstrategy;
9905         char       *amopreqcheck;
9906         char       *amopopr;
9907         char       *sortfamily;
9908         char       *sortfamilynsp;
9909         char       *amprocnum;
9910         char       *amproc;
9911         char       *amproclefttype;
9912         char       *amprocrighttype;
9913         bool            needComma;
9914         int                     i;
9915
9916         /* Skip if not to be dumped */
9917         if (!opcinfo->dobj.dump || dataOnly)
9918                 return;
9919
9920         /*
9921          * XXX currently we do not implement dumping of operator classes from
9922          * pre-7.3 databases.  This could be done but it seems not worth the
9923          * trouble.
9924          */
9925         if (g_fout->remoteVersion < 70300)
9926                 return;
9927
9928         query = createPQExpBuffer();
9929         q = createPQExpBuffer();
9930         delq = createPQExpBuffer();
9931         labelq = createPQExpBuffer();
9932
9933         /* Make sure we are in proper schema so regoperator works correctly */
9934         selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
9935
9936         /* Get additional fields from the pg_opclass row */
9937         if (g_fout->remoteVersion >= 80300)
9938         {
9939                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
9940                                                   "opckeytype::pg_catalog.regtype, "
9941                                                   "opcdefault, opcfamily, "
9942                                                   "opfname AS opcfamilyname, "
9943                                                   "nspname AS opcfamilynsp, "
9944                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
9945                                                   "FROM pg_catalog.pg_opclass c "
9946                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
9947                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
9948                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
9949                                                   opcinfo->dobj.catId.oid);
9950         }
9951         else
9952         {
9953                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
9954                                                   "opckeytype::pg_catalog.regtype, "
9955                                                   "opcdefault, NULL AS opcfamily, "
9956                                                   "NULL AS opcfamilyname, "
9957                                                   "NULL AS opcfamilynsp, "
9958                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
9959                                                   "FROM pg_catalog.pg_opclass "
9960                                                   "WHERE oid = '%u'::pg_catalog.oid",
9961                                                   opcinfo->dobj.catId.oid);
9962         }
9963
9964         res = PQexec(g_conn, query->data);
9965         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9966
9967         /* Expecting a single result only */
9968         ntups = PQntuples(res);
9969         if (ntups != 1)
9970         {
9971                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9972                                                            "query returned %d rows instead of one: %s\n",
9973                                                                  ntups),
9974                                   ntups, query->data);
9975                 exit_nicely();
9976         }
9977
9978         i_opcintype = PQfnumber(res, "opcintype");
9979         i_opckeytype = PQfnumber(res, "opckeytype");
9980         i_opcdefault = PQfnumber(res, "opcdefault");
9981         i_opcfamily = PQfnumber(res, "opcfamily");
9982         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
9983         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
9984         i_amname = PQfnumber(res, "amname");
9985
9986         opcintype = PQgetvalue(res, 0, i_opcintype);
9987         opckeytype = PQgetvalue(res, 0, i_opckeytype);
9988         opcdefault = PQgetvalue(res, 0, i_opcdefault);
9989         /* opcfamily will still be needed after we PQclear res */
9990         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
9991         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
9992         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
9993         /* amname will still be needed after we PQclear res */
9994         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
9995
9996         /*
9997          * DROP must be fully qualified in case same name appears in pg_catalog
9998          */
9999         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10000                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10001         appendPQExpBuffer(delq, ".%s",
10002                                           fmtId(opcinfo->dobj.name));
10003         appendPQExpBuffer(delq, " USING %s;\n",
10004                                           fmtId(amname));
10005
10006         /* Build the fixed portion of the CREATE command */
10007         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10008                                           fmtId(opcinfo->dobj.name));
10009         if (strcmp(opcdefault, "t") == 0)
10010                 appendPQExpBuffer(q, "DEFAULT ");
10011         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10012                                           opcintype,
10013                                           fmtId(amname));
10014         if (strlen(opcfamilyname) > 0 &&
10015                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10016                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10017         {
10018                 appendPQExpBuffer(q, " FAMILY ");
10019                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10020                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10021                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10022         }
10023         appendPQExpBuffer(q, " AS\n    ");
10024
10025         needComma = false;
10026
10027         if (strcmp(opckeytype, "-") != 0)
10028         {
10029                 appendPQExpBuffer(q, "STORAGE %s",
10030                                                   opckeytype);
10031                 needComma = true;
10032         }
10033
10034         PQclear(res);
10035
10036         /*
10037          * Now fetch and print the OPERATOR entries (pg_amop rows).
10038          *
10039          * Print only those opfamily members that are tied to the opclass by
10040          * pg_depend entries.
10041          *
10042          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10043          * older server's opclass in which it is used.  This is to avoid
10044          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10045          * older server and then reload into that old version.  This can go away
10046          * once 8.3 is so old as to not be of interest to anyone.
10047          */
10048         resetPQExpBuffer(query);
10049
10050         if (g_fout->remoteVersion >= 90100)
10051         {
10052                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10053                                                   "amopopr::pg_catalog.regoperator, "
10054                                                   "opfname AS sortfamily, "
10055                                                   "nspname AS sortfamilynsp "
10056                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10057                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10058                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10059                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10060                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10061                                                   "AND refobjid = '%u'::pg_catalog.oid "
10062                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10063                                                   "ORDER BY amopstrategy",
10064                                                   opcinfo->dobj.catId.oid,
10065                                                   opcfamily);
10066         }
10067         else if (g_fout->remoteVersion >= 80400)
10068         {
10069                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10070                                                   "amopopr::pg_catalog.regoperator, "
10071                                                   "NULL AS sortfamily, "
10072                                                   "NULL AS sortfamilynsp "
10073                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10074                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10075                                                   "AND refobjid = '%u'::pg_catalog.oid "
10076                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10077                                                   "AND objid = ao.oid "
10078                                                   "ORDER BY amopstrategy",
10079                                                   opcinfo->dobj.catId.oid);
10080         }
10081         else if (g_fout->remoteVersion >= 80300)
10082         {
10083                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10084                                                   "amopopr::pg_catalog.regoperator, "
10085                                                   "NULL AS sortfamily, "
10086                                                   "NULL AS sortfamilynsp "
10087                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10088                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10089                                                   "AND refobjid = '%u'::pg_catalog.oid "
10090                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10091                                                   "AND objid = ao.oid "
10092                                                   "ORDER BY amopstrategy",
10093                                                   opcinfo->dobj.catId.oid);
10094         }
10095         else
10096         {
10097                 /*
10098                  * Here, we print all entries since there are no opfamilies and hence
10099                  * no loose operators to worry about.
10100                  */
10101                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10102                                                   "amopopr::pg_catalog.regoperator, "
10103                                                   "NULL AS sortfamily, "
10104                                                   "NULL AS sortfamilynsp "
10105                                                   "FROM pg_catalog.pg_amop "
10106                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10107                                                   "ORDER BY amopstrategy",
10108                                                   opcinfo->dobj.catId.oid);
10109         }
10110
10111         res = PQexec(g_conn, query->data);
10112         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10113
10114         ntups = PQntuples(res);
10115
10116         i_amopstrategy = PQfnumber(res, "amopstrategy");
10117         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10118         i_amopopr = PQfnumber(res, "amopopr");
10119         i_sortfamily = PQfnumber(res, "sortfamily");
10120         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10121
10122         for (i = 0; i < ntups; i++)
10123         {
10124                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10125                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10126                 amopopr = PQgetvalue(res, i, i_amopopr);
10127                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10128                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10129
10130                 if (needComma)
10131                         appendPQExpBuffer(q, " ,\n    ");
10132
10133                 appendPQExpBuffer(q, "OPERATOR %s %s",
10134                                                   amopstrategy, amopopr);
10135
10136                 if (strlen(sortfamily) > 0)
10137                 {
10138                         appendPQExpBuffer(q, " FOR ORDER BY ");
10139                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10140                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10141                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10142                 }
10143
10144                 if (strcmp(amopreqcheck, "t") == 0)
10145                         appendPQExpBuffer(q, " RECHECK");
10146
10147                 needComma = true;
10148         }
10149
10150         PQclear(res);
10151
10152         /*
10153          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10154          *
10155          * Print only those opfamily members that are tied to the opclass by
10156          * pg_depend entries.
10157          *
10158          * We print the amproclefttype/amprocrighttype even though in most cases
10159          * the backend could deduce the right values, because of the corner case
10160          * of a btree sort support function for a cross-type comparison.  That's
10161          * only allowed in 9.2 and later, but for simplicity print them in all
10162          * versions that have the columns.
10163          */
10164         resetPQExpBuffer(query);
10165
10166         if (g_fout->remoteVersion >= 80300)
10167         {
10168                 appendPQExpBuffer(query, "SELECT amprocnum, "
10169                                                   "amproc::pg_catalog.regprocedure, "
10170                                                   "amproclefttype::pg_catalog.regtype, "
10171                                                   "amprocrighttype::pg_catalog.regtype "
10172                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10173                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10174                                                   "AND refobjid = '%u'::pg_catalog.oid "
10175                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10176                                                   "AND objid = ap.oid "
10177                                                   "ORDER BY amprocnum",
10178                                                   opcinfo->dobj.catId.oid);
10179         }
10180         else
10181         {
10182                 appendPQExpBuffer(query, "SELECT amprocnum, "
10183                                                   "amproc::pg_catalog.regprocedure, "
10184                                                   "'' AS amproclefttype, "
10185                                                   "'' AS amprocrighttype "
10186                                                   "FROM pg_catalog.pg_amproc "
10187                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10188                                                   "ORDER BY amprocnum",
10189                                                   opcinfo->dobj.catId.oid);
10190         }
10191
10192         res = PQexec(g_conn, query->data);
10193         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10194
10195         ntups = PQntuples(res);
10196
10197         i_amprocnum = PQfnumber(res, "amprocnum");
10198         i_amproc = PQfnumber(res, "amproc");
10199         i_amproclefttype = PQfnumber(res, "amproclefttype");
10200         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10201
10202         for (i = 0; i < ntups; i++)
10203         {
10204                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10205                 amproc = PQgetvalue(res, i, i_amproc);
10206                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10207                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10208
10209                 if (needComma)
10210                         appendPQExpBuffer(q, " ,\n    ");
10211
10212                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10213
10214                 if (*amproclefttype && *amprocrighttype)
10215                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10216
10217                 appendPQExpBuffer(q, " %s", amproc);
10218
10219                 needComma = true;
10220         }
10221
10222         PQclear(res);
10223
10224         appendPQExpBuffer(q, ";\n");
10225
10226         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10227                                           fmtId(opcinfo->dobj.name));
10228         appendPQExpBuffer(labelq, " USING %s",
10229                                           fmtId(amname));
10230
10231         if (binary_upgrade)
10232                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10233
10234         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10235                                  opcinfo->dobj.name,
10236                                  opcinfo->dobj.namespace->dobj.name,
10237                                  NULL,
10238                                  opcinfo->rolname,
10239                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10240                                  q->data, delq->data, NULL,
10241                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
10242                                  NULL, NULL);
10243
10244         /* Dump Operator Class Comments */
10245         dumpComment(fout, labelq->data,
10246                                 NULL, opcinfo->rolname,
10247                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10248
10249         free(amname);
10250         destroyPQExpBuffer(query);
10251         destroyPQExpBuffer(q);
10252         destroyPQExpBuffer(delq);
10253         destroyPQExpBuffer(labelq);
10254 }
10255
10256 /*
10257  * dumpOpfamily
10258  *        write out a single operator family definition
10259  *
10260  * Note: this also dumps any "loose" operator members that aren't bound to a
10261  * specific opclass within the opfamily.
10262  */
10263 static void
10264 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10265 {
10266         PQExpBuffer query;
10267         PQExpBuffer q;
10268         PQExpBuffer delq;
10269         PQExpBuffer labelq;
10270         PGresult   *res;
10271         PGresult   *res_ops;
10272         PGresult   *res_procs;
10273         int                     ntups;
10274         int                     i_amname;
10275         int                     i_amopstrategy;
10276         int                     i_amopreqcheck;
10277         int                     i_amopopr;
10278         int                     i_sortfamily;
10279         int                     i_sortfamilynsp;
10280         int                     i_amprocnum;
10281         int                     i_amproc;
10282         int                     i_amproclefttype;
10283         int                     i_amprocrighttype;
10284         char       *amname;
10285         char       *amopstrategy;
10286         char       *amopreqcheck;
10287         char       *amopopr;
10288         char       *sortfamily;
10289         char       *sortfamilynsp;
10290         char       *amprocnum;
10291         char       *amproc;
10292         char       *amproclefttype;
10293         char       *amprocrighttype;
10294         bool            needComma;
10295         int                     i;
10296
10297         /* Skip if not to be dumped */
10298         if (!opfinfo->dobj.dump || dataOnly)
10299                 return;
10300
10301         /*
10302          * We want to dump the opfamily only if (1) it contains "loose" operators
10303          * or functions, or (2) it contains an opclass with a different name or
10304          * owner.  Otherwise it's sufficient to let it be created during creation
10305          * of the contained opclass, and not dumping it improves portability of
10306          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10307          * that first.
10308          */
10309
10310         query = createPQExpBuffer();
10311         q = createPQExpBuffer();
10312         delq = createPQExpBuffer();
10313         labelq = createPQExpBuffer();
10314
10315         /* Make sure we are in proper schema so regoperator works correctly */
10316         selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
10317
10318         /*
10319          * Fetch only those opfamily members that are tied directly to the
10320          * opfamily by pg_depend entries.
10321          *
10322          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10323          * older server's opclass in which it is used.  This is to avoid
10324          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10325          * older server and then reload into that old version.  This can go away
10326          * once 8.3 is so old as to not be of interest to anyone.
10327          */
10328         if (g_fout->remoteVersion >= 90100)
10329         {
10330                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10331                                                   "amopopr::pg_catalog.regoperator, "
10332                                                   "opfname AS sortfamily, "
10333                                                   "nspname AS sortfamilynsp "
10334                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10335                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10336                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10337                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10338                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10339                                                   "AND refobjid = '%u'::pg_catalog.oid "
10340                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10341                                                   "ORDER BY amopstrategy",
10342                                                   opfinfo->dobj.catId.oid,
10343                                                   opfinfo->dobj.catId.oid);
10344         }
10345         else if (g_fout->remoteVersion >= 80400)
10346         {
10347                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10348                                                   "amopopr::pg_catalog.regoperator, "
10349                                                   "NULL AS sortfamily, "
10350                                                   "NULL AS sortfamilynsp "
10351                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10352                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10353                                                   "AND refobjid = '%u'::pg_catalog.oid "
10354                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10355                                                   "AND objid = ao.oid "
10356                                                   "ORDER BY amopstrategy",
10357                                                   opfinfo->dobj.catId.oid);
10358         }
10359         else
10360         {
10361                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10362                                                   "amopopr::pg_catalog.regoperator, "
10363                                                   "NULL AS sortfamily, "
10364                                                   "NULL AS sortfamilynsp "
10365                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10366                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10367                                                   "AND refobjid = '%u'::pg_catalog.oid "
10368                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10369                                                   "AND objid = ao.oid "
10370                                                   "ORDER BY amopstrategy",
10371                                                   opfinfo->dobj.catId.oid);
10372         }
10373
10374         res_ops = PQexec(g_conn, query->data);
10375         check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
10376
10377         resetPQExpBuffer(query);
10378
10379         appendPQExpBuffer(query, "SELECT amprocnum, "
10380                                           "amproc::pg_catalog.regprocedure, "
10381                                           "amproclefttype::pg_catalog.regtype, "
10382                                           "amprocrighttype::pg_catalog.regtype "
10383                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10384                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10385                                           "AND refobjid = '%u'::pg_catalog.oid "
10386                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10387                                           "AND objid = ap.oid "
10388                                           "ORDER BY amprocnum",
10389                                           opfinfo->dobj.catId.oid);
10390
10391         res_procs = PQexec(g_conn, query->data);
10392         check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
10393
10394         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10395         {
10396                 /* No loose members, so check contained opclasses */
10397                 resetPQExpBuffer(query);
10398
10399                 appendPQExpBuffer(query, "SELECT 1 "
10400                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10401                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10402                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10403                                                   "AND refobjid = f.oid "
10404                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10405                                                   "AND objid = c.oid "
10406                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10407                                                   "LIMIT 1",
10408                                                   opfinfo->dobj.catId.oid);
10409
10410                 res = PQexec(g_conn, query->data);
10411                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10412
10413                 if (PQntuples(res) == 0)
10414                 {
10415                         /* no need to dump it, so bail out */
10416                         PQclear(res);
10417                         PQclear(res_ops);
10418                         PQclear(res_procs);
10419                         destroyPQExpBuffer(query);
10420                         destroyPQExpBuffer(q);
10421                         destroyPQExpBuffer(delq);
10422                         destroyPQExpBuffer(labelq);
10423                         return;
10424                 }
10425
10426                 PQclear(res);
10427         }
10428
10429         /* Get additional fields from the pg_opfamily row */
10430         resetPQExpBuffer(query);
10431
10432         appendPQExpBuffer(query, "SELECT "
10433          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
10434                                           "FROM pg_catalog.pg_opfamily "
10435                                           "WHERE oid = '%u'::pg_catalog.oid",
10436                                           opfinfo->dobj.catId.oid);
10437
10438         res = PQexec(g_conn, query->data);
10439         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10440
10441         /* Expecting a single result only */
10442         ntups = PQntuples(res);
10443         if (ntups != 1)
10444         {
10445                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10446                                                            "query returned %d rows instead of one: %s\n",
10447                                                                  ntups),
10448                                   ntups, query->data);
10449                 exit_nicely();
10450         }
10451
10452         i_amname = PQfnumber(res, "amname");
10453
10454         /* amname will still be needed after we PQclear res */
10455         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10456
10457         /*
10458          * DROP must be fully qualified in case same name appears in pg_catalog
10459          */
10460         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
10461                                           fmtId(opfinfo->dobj.namespace->dobj.name));
10462         appendPQExpBuffer(delq, ".%s",
10463                                           fmtId(opfinfo->dobj.name));
10464         appendPQExpBuffer(delq, " USING %s;\n",
10465                                           fmtId(amname));
10466
10467         /* Build the fixed portion of the CREATE command */
10468         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
10469                                           fmtId(opfinfo->dobj.name));
10470         appendPQExpBuffer(q, " USING %s;\n",
10471                                           fmtId(amname));
10472
10473         PQclear(res);
10474
10475         /* Do we need an ALTER to add loose members? */
10476         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
10477         {
10478                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
10479                                                   fmtId(opfinfo->dobj.name));
10480                 appendPQExpBuffer(q, " USING %s ADD\n    ",
10481                                                   fmtId(amname));
10482
10483                 needComma = false;
10484
10485                 /*
10486                  * Now fetch and print the OPERATOR entries (pg_amop rows).
10487                  */
10488                 ntups = PQntuples(res_ops);
10489
10490                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
10491                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
10492                 i_amopopr = PQfnumber(res_ops, "amopopr");
10493                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
10494                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
10495
10496                 for (i = 0; i < ntups; i++)
10497                 {
10498                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
10499                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
10500                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
10501                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
10502                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
10503
10504                         if (needComma)
10505                                 appendPQExpBuffer(q, " ,\n    ");
10506
10507                         appendPQExpBuffer(q, "OPERATOR %s %s",
10508                                                           amopstrategy, amopopr);
10509
10510                         if (strlen(sortfamily) > 0)
10511                         {
10512                                 appendPQExpBuffer(q, " FOR ORDER BY ");
10513                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
10514                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10515                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10516                         }
10517
10518                         if (strcmp(amopreqcheck, "t") == 0)
10519                                 appendPQExpBuffer(q, " RECHECK");
10520
10521                         needComma = true;
10522                 }
10523
10524                 /*
10525                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
10526                  */
10527                 ntups = PQntuples(res_procs);
10528
10529                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
10530                 i_amproc = PQfnumber(res_procs, "amproc");
10531                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
10532                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
10533
10534                 for (i = 0; i < ntups; i++)
10535                 {
10536                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
10537                         amproc = PQgetvalue(res_procs, i, i_amproc);
10538                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
10539                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
10540
10541                         if (needComma)
10542                                 appendPQExpBuffer(q, " ,\n    ");
10543
10544                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
10545                                                           amprocnum, amproclefttype, amprocrighttype,
10546                                                           amproc);
10547
10548                         needComma = true;
10549                 }
10550
10551                 appendPQExpBuffer(q, ";\n");
10552         }
10553
10554         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
10555                                           fmtId(opfinfo->dobj.name));
10556         appendPQExpBuffer(labelq, " USING %s",
10557                                           fmtId(amname));
10558
10559         if (binary_upgrade)
10560                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
10561
10562         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
10563                                  opfinfo->dobj.name,
10564                                  opfinfo->dobj.namespace->dobj.name,
10565                                  NULL,
10566                                  opfinfo->rolname,
10567                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
10568                                  q->data, delq->data, NULL,
10569                                  opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
10570                                  NULL, NULL);
10571
10572         /* Dump Operator Family Comments */
10573         dumpComment(fout, labelq->data,
10574                                 NULL, opfinfo->rolname,
10575                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
10576
10577         free(amname);
10578         PQclear(res_ops);
10579         PQclear(res_procs);
10580         destroyPQExpBuffer(query);
10581         destroyPQExpBuffer(q);
10582         destroyPQExpBuffer(delq);
10583         destroyPQExpBuffer(labelq);
10584 }
10585
10586 /*
10587  * dumpCollation
10588  *        write out a single collation definition
10589  */
10590 static void
10591 dumpCollation(Archive *fout, CollInfo *collinfo)
10592 {
10593         PQExpBuffer query;
10594         PQExpBuffer q;
10595         PQExpBuffer delq;
10596         PQExpBuffer labelq;
10597         PGresult   *res;
10598         int                     ntups;
10599         int                     i_collcollate;
10600         int                     i_collctype;
10601         const char *collcollate;
10602         const char *collctype;
10603
10604         /* Skip if not to be dumped */
10605         if (!collinfo->dobj.dump || dataOnly)
10606                 return;
10607
10608         query = createPQExpBuffer();
10609         q = createPQExpBuffer();
10610         delq = createPQExpBuffer();
10611         labelq = createPQExpBuffer();
10612
10613         /* Make sure we are in proper schema */
10614         selectSourceSchema(collinfo->dobj.namespace->dobj.name);
10615
10616         /* Get conversion-specific details */
10617         appendPQExpBuffer(query, "SELECT "
10618                                           "collcollate, "
10619                                           "collctype "
10620                                           "FROM pg_catalog.pg_collation c "
10621                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10622                                           collinfo->dobj.catId.oid);
10623
10624         res = PQexec(g_conn, query->data);
10625         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10626
10627         /* Expecting a single result only */
10628         ntups = PQntuples(res);
10629         if (ntups != 1)
10630         {
10631                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10632                                                            "query returned %d rows instead of one: %s\n",
10633                                                                  ntups),
10634                                   ntups, query->data);
10635                 exit_nicely();
10636         }
10637
10638         i_collcollate = PQfnumber(res, "collcollate");
10639         i_collctype = PQfnumber(res, "collctype");
10640
10641         collcollate = PQgetvalue(res, 0, i_collcollate);
10642         collctype = PQgetvalue(res, 0, i_collctype);
10643
10644         /*
10645          * DROP must be fully qualified in case same name appears in pg_catalog
10646          */
10647         appendPQExpBuffer(delq, "DROP COLLATION %s",
10648                                           fmtId(collinfo->dobj.namespace->dobj.name));
10649         appendPQExpBuffer(delq, ".%s;\n",
10650                                           fmtId(collinfo->dobj.name));
10651
10652         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
10653                                           fmtId(collinfo->dobj.name));
10654         appendStringLiteralAH(q, collcollate, fout);
10655         appendPQExpBuffer(q, ", lc_ctype = ");
10656         appendStringLiteralAH(q, collctype, fout);
10657         appendPQExpBuffer(q, ");\n");
10658
10659         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
10660
10661         if (binary_upgrade)
10662                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
10663
10664         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
10665                                  collinfo->dobj.name,
10666                                  collinfo->dobj.namespace->dobj.name,
10667                                  NULL,
10668                                  collinfo->rolname,
10669                                  false, "COLLATION", SECTION_PRE_DATA,
10670                                  q->data, delq->data, NULL,
10671                                  collinfo->dobj.dependencies, collinfo->dobj.nDeps,
10672                                  NULL, NULL);
10673
10674         /* Dump Collation Comments */
10675         dumpComment(fout, labelq->data,
10676                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
10677                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
10678
10679         PQclear(res);
10680
10681         destroyPQExpBuffer(query);
10682         destroyPQExpBuffer(q);
10683         destroyPQExpBuffer(delq);
10684         destroyPQExpBuffer(labelq);
10685 }
10686
10687 /*
10688  * dumpConversion
10689  *        write out a single conversion definition
10690  */
10691 static void
10692 dumpConversion(Archive *fout, ConvInfo *convinfo)
10693 {
10694         PQExpBuffer query;
10695         PQExpBuffer q;
10696         PQExpBuffer delq;
10697         PQExpBuffer labelq;
10698         PGresult   *res;
10699         int                     ntups;
10700         int                     i_conforencoding;
10701         int                     i_contoencoding;
10702         int                     i_conproc;
10703         int                     i_condefault;
10704         const char *conforencoding;
10705         const char *contoencoding;
10706         const char *conproc;
10707         bool            condefault;
10708
10709         /* Skip if not to be dumped */
10710         if (!convinfo->dobj.dump || dataOnly)
10711                 return;
10712
10713         query = createPQExpBuffer();
10714         q = createPQExpBuffer();
10715         delq = createPQExpBuffer();
10716         labelq = createPQExpBuffer();
10717
10718         /* Make sure we are in proper schema */
10719         selectSourceSchema(convinfo->dobj.namespace->dobj.name);
10720
10721         /* Get conversion-specific details */
10722         appendPQExpBuffer(query, "SELECT "
10723                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
10724                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
10725                                           "conproc, condefault "
10726                                           "FROM pg_catalog.pg_conversion c "
10727                                           "WHERE c.oid = '%u'::pg_catalog.oid",
10728                                           convinfo->dobj.catId.oid);
10729
10730         res = PQexec(g_conn, query->data);
10731         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10732
10733         /* Expecting a single result only */
10734         ntups = PQntuples(res);
10735         if (ntups != 1)
10736         {
10737                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10738                                                            "query returned %d rows instead of one: %s\n",
10739                                                                  ntups),
10740                                   ntups, query->data);
10741                 exit_nicely();
10742         }
10743
10744         i_conforencoding = PQfnumber(res, "conforencoding");
10745         i_contoencoding = PQfnumber(res, "contoencoding");
10746         i_conproc = PQfnumber(res, "conproc");
10747         i_condefault = PQfnumber(res, "condefault");
10748
10749         conforencoding = PQgetvalue(res, 0, i_conforencoding);
10750         contoencoding = PQgetvalue(res, 0, i_contoencoding);
10751         conproc = PQgetvalue(res, 0, i_conproc);
10752         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
10753
10754         /*
10755          * DROP must be fully qualified in case same name appears in pg_catalog
10756          */
10757         appendPQExpBuffer(delq, "DROP CONVERSION %s",
10758                                           fmtId(convinfo->dobj.namespace->dobj.name));
10759         appendPQExpBuffer(delq, ".%s;\n",
10760                                           fmtId(convinfo->dobj.name));
10761
10762         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
10763                                           (condefault) ? "DEFAULT " : "",
10764                                           fmtId(convinfo->dobj.name));
10765         appendStringLiteralAH(q, conforencoding, fout);
10766         appendPQExpBuffer(q, " TO ");
10767         appendStringLiteralAH(q, contoencoding, fout);
10768         /* regproc is automatically quoted in 7.3 and above */
10769         appendPQExpBuffer(q, " FROM %s;\n", conproc);
10770
10771         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
10772
10773         if (binary_upgrade)
10774                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
10775
10776         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
10777                                  convinfo->dobj.name,
10778                                  convinfo->dobj.namespace->dobj.name,
10779                                  NULL,
10780                                  convinfo->rolname,
10781                                  false, "CONVERSION", SECTION_PRE_DATA,
10782                                  q->data, delq->data, NULL,
10783                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
10784                                  NULL, NULL);
10785
10786         /* Dump Conversion Comments */
10787         dumpComment(fout, labelq->data,
10788                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
10789                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
10790
10791         PQclear(res);
10792
10793         destroyPQExpBuffer(query);
10794         destroyPQExpBuffer(q);
10795         destroyPQExpBuffer(delq);
10796         destroyPQExpBuffer(labelq);
10797 }
10798
10799 /*
10800  * format_aggregate_signature: generate aggregate name and argument list
10801  *
10802  * The argument type names are qualified if needed.  The aggregate name
10803  * is never qualified.
10804  */
10805 static char *
10806 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
10807 {
10808         PQExpBufferData buf;
10809         int                     j;
10810
10811         initPQExpBuffer(&buf);
10812         if (honor_quotes)
10813                 appendPQExpBuffer(&buf, "%s",
10814                                                   fmtId(agginfo->aggfn.dobj.name));
10815         else
10816                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
10817
10818         if (agginfo->aggfn.nargs == 0)
10819                 appendPQExpBuffer(&buf, "(*)");
10820         else
10821         {
10822                 appendPQExpBuffer(&buf, "(");
10823                 for (j = 0; j < agginfo->aggfn.nargs; j++)
10824                 {
10825                         char       *typname;
10826
10827                         typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
10828
10829                         appendPQExpBuffer(&buf, "%s%s",
10830                                                           (j > 0) ? ", " : "",
10831                                                           typname);
10832                         free(typname);
10833                 }
10834                 appendPQExpBuffer(&buf, ")");
10835         }
10836         return buf.data;
10837 }
10838
10839 /*
10840  * dumpAgg
10841  *        write out a single aggregate definition
10842  */
10843 static void
10844 dumpAgg(Archive *fout, AggInfo *agginfo)
10845 {
10846         PQExpBuffer query;
10847         PQExpBuffer q;
10848         PQExpBuffer delq;
10849         PQExpBuffer labelq;
10850         PQExpBuffer details;
10851         char       *aggsig;
10852         char       *aggsig_tag;
10853         PGresult   *res;
10854         int                     ntups;
10855         int                     i_aggtransfn;
10856         int                     i_aggfinalfn;
10857         int                     i_aggsortop;
10858         int                     i_aggtranstype;
10859         int                     i_agginitval;
10860         int                     i_convertok;
10861         const char *aggtransfn;
10862         const char *aggfinalfn;
10863         const char *aggsortop;
10864         const char *aggtranstype;
10865         const char *agginitval;
10866         bool            convertok;
10867
10868         /* Skip if not to be dumped */
10869         if (!agginfo->aggfn.dobj.dump || dataOnly)
10870                 return;
10871
10872         query = createPQExpBuffer();
10873         q = createPQExpBuffer();
10874         delq = createPQExpBuffer();
10875         labelq = createPQExpBuffer();
10876         details = createPQExpBuffer();
10877
10878         /* Make sure we are in proper schema */
10879         selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
10880
10881         /* Get aggregate-specific details */
10882         if (g_fout->remoteVersion >= 80100)
10883         {
10884                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10885                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10886                                                   "aggsortop::pg_catalog.regoperator, "
10887                                                   "agginitval, "
10888                                                   "'t'::boolean AS convertok "
10889                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10890                                                   "WHERE a.aggfnoid = p.oid "
10891                                                   "AND p.oid = '%u'::pg_catalog.oid",
10892                                                   agginfo->aggfn.dobj.catId.oid);
10893         }
10894         else if (g_fout->remoteVersion >= 70300)
10895         {
10896                 appendPQExpBuffer(query, "SELECT aggtransfn, "
10897                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
10898                                                   "0 AS aggsortop, "
10899                                                   "agginitval, "
10900                                                   "'t'::boolean AS convertok "
10901                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
10902                                                   "WHERE a.aggfnoid = p.oid "
10903                                                   "AND p.oid = '%u'::pg_catalog.oid",
10904                                                   agginfo->aggfn.dobj.catId.oid);
10905         }
10906         else if (g_fout->remoteVersion >= 70100)
10907         {
10908                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
10909                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
10910                                                   "0 AS aggsortop, "
10911                                                   "agginitval, "
10912                                                   "'t'::boolean AS convertok "
10913                                                   "FROM pg_aggregate "
10914                                                   "WHERE oid = '%u'::oid",
10915                                                   agginfo->aggfn.dobj.catId.oid);
10916         }
10917         else
10918         {
10919                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
10920                                                   "aggfinalfn, "
10921                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
10922                                                   "0 AS aggsortop, "
10923                                                   "agginitval1 AS agginitval, "
10924                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
10925                                                   "FROM pg_aggregate "
10926                                                   "WHERE oid = '%u'::oid",
10927                                                   agginfo->aggfn.dobj.catId.oid);
10928         }
10929
10930         res = PQexec(g_conn, query->data);
10931         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10932
10933         /* Expecting a single result only */
10934         ntups = PQntuples(res);
10935         if (ntups != 1)
10936         {
10937                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
10938                                                            "query returned %d rows instead of one: %s\n",
10939                                                                  ntups),
10940                                   ntups, query->data);
10941                 exit_nicely();
10942         }
10943
10944         i_aggtransfn = PQfnumber(res, "aggtransfn");
10945         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
10946         i_aggsortop = PQfnumber(res, "aggsortop");
10947         i_aggtranstype = PQfnumber(res, "aggtranstype");
10948         i_agginitval = PQfnumber(res, "agginitval");
10949         i_convertok = PQfnumber(res, "convertok");
10950
10951         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
10952         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
10953         aggsortop = PQgetvalue(res, 0, i_aggsortop);
10954         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
10955         agginitval = PQgetvalue(res, 0, i_agginitval);
10956         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
10957
10958         aggsig = format_aggregate_signature(agginfo, fout, true);
10959         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
10960
10961         if (!convertok)
10962         {
10963                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
10964                                   aggsig);
10965                 return;
10966         }
10967
10968         if (g_fout->remoteVersion >= 70300)
10969         {
10970                 /* If using 7.3's regproc or regtype, data is already quoted */
10971                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
10972                                                   aggtransfn,
10973                                                   aggtranstype);
10974         }
10975         else if (g_fout->remoteVersion >= 70100)
10976         {
10977                 /* format_type quotes, regproc does not */
10978                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
10979                                                   fmtId(aggtransfn),
10980                                                   aggtranstype);
10981         }
10982         else
10983         {
10984                 /* need quotes all around */
10985                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
10986                                                   fmtId(aggtransfn));
10987                 appendPQExpBuffer(details, "    STYPE = %s",
10988                                                   fmtId(aggtranstype));
10989         }
10990
10991         if (!PQgetisnull(res, 0, i_agginitval))
10992         {
10993                 appendPQExpBuffer(details, ",\n    INITCOND = ");
10994                 appendStringLiteralAH(details, agginitval, fout);
10995         }
10996
10997         if (strcmp(aggfinalfn, "-") != 0)
10998         {
10999                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11000                                                   aggfinalfn);
11001         }
11002
11003         aggsortop = convertOperatorReference(aggsortop);
11004         if (aggsortop)
11005         {
11006                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11007                                                   aggsortop);
11008         }
11009
11010         /*
11011          * DROP must be fully qualified in case same name appears in pg_catalog
11012          */
11013         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11014                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11015                                           aggsig);
11016
11017         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11018                                           aggsig, details->data);
11019
11020         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11021
11022         if (binary_upgrade)
11023                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11024
11025         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11026                                  aggsig_tag,
11027                                  agginfo->aggfn.dobj.namespace->dobj.name,
11028                                  NULL,
11029                                  agginfo->aggfn.rolname,
11030                                  false, "AGGREGATE", SECTION_PRE_DATA,
11031                                  q->data, delq->data, NULL,
11032                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
11033                                  NULL, NULL);
11034
11035         /* Dump Aggregate Comments */
11036         dumpComment(fout, labelq->data,
11037                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11038                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11039         dumpSecLabel(fout, labelq->data,
11040                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11041                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11042
11043         /*
11044          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11045          * command look like a function's GRANT; in particular this affects the
11046          * syntax for zero-argument aggregates.
11047          */
11048         free(aggsig);
11049         free(aggsig_tag);
11050
11051         aggsig = format_function_signature(&agginfo->aggfn, true);
11052         aggsig_tag = format_function_signature(&agginfo->aggfn, false);
11053
11054         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11055                         "FUNCTION",
11056                         aggsig, NULL, aggsig_tag,
11057                         agginfo->aggfn.dobj.namespace->dobj.name,
11058                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11059
11060         free(aggsig);
11061         free(aggsig_tag);
11062
11063         PQclear(res);
11064
11065         destroyPQExpBuffer(query);
11066         destroyPQExpBuffer(q);
11067         destroyPQExpBuffer(delq);
11068         destroyPQExpBuffer(labelq);
11069         destroyPQExpBuffer(details);
11070 }
11071
11072 /*
11073  * dumpTSParser
11074  *        write out a single text search parser
11075  */
11076 static void
11077 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11078 {
11079         PQExpBuffer q;
11080         PQExpBuffer delq;
11081         PQExpBuffer labelq;
11082
11083         /* Skip if not to be dumped */
11084         if (!prsinfo->dobj.dump || dataOnly)
11085                 return;
11086
11087         q = createPQExpBuffer();
11088         delq = createPQExpBuffer();
11089         labelq = createPQExpBuffer();
11090
11091         /* Make sure we are in proper schema */
11092         selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
11093
11094         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11095                                           fmtId(prsinfo->dobj.name));
11096
11097         appendPQExpBuffer(q, "    START = %s,\n",
11098                                           convertTSFunction(prsinfo->prsstart));
11099         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11100                                           convertTSFunction(prsinfo->prstoken));
11101         appendPQExpBuffer(q, "    END = %s,\n",
11102                                           convertTSFunction(prsinfo->prsend));
11103         if (prsinfo->prsheadline != InvalidOid)
11104                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11105                                                   convertTSFunction(prsinfo->prsheadline));
11106         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11107                                           convertTSFunction(prsinfo->prslextype));
11108
11109         /*
11110          * DROP must be fully qualified in case same name appears in pg_catalog
11111          */
11112         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11113                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11114         appendPQExpBuffer(delq, ".%s;\n",
11115                                           fmtId(prsinfo->dobj.name));
11116
11117         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11118                                           fmtId(prsinfo->dobj.name));
11119
11120         if (binary_upgrade)
11121                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11122
11123         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11124                                  prsinfo->dobj.name,
11125                                  prsinfo->dobj.namespace->dobj.name,
11126                                  NULL,
11127                                  "",
11128                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11129                                  q->data, delq->data, NULL,
11130                                  prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
11131                                  NULL, NULL);
11132
11133         /* Dump Parser Comments */
11134         dumpComment(fout, labelq->data,
11135                                 NULL, "",
11136                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11137
11138         destroyPQExpBuffer(q);
11139         destroyPQExpBuffer(delq);
11140         destroyPQExpBuffer(labelq);
11141 }
11142
11143 /*
11144  * dumpTSDictionary
11145  *        write out a single text search dictionary
11146  */
11147 static void
11148 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11149 {
11150         PQExpBuffer q;
11151         PQExpBuffer delq;
11152         PQExpBuffer labelq;
11153         PQExpBuffer query;
11154         PGresult   *res;
11155         int                     ntups;
11156         char       *nspname;
11157         char       *tmplname;
11158
11159         /* Skip if not to be dumped */
11160         if (!dictinfo->dobj.dump || dataOnly)
11161                 return;
11162
11163         q = createPQExpBuffer();
11164         delq = createPQExpBuffer();
11165         labelq = createPQExpBuffer();
11166         query = createPQExpBuffer();
11167
11168         /* Fetch name and namespace of the dictionary's template */
11169         selectSourceSchema("pg_catalog");
11170         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11171                                           "FROM pg_ts_template p, pg_namespace n "
11172                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11173                                           dictinfo->dicttemplate);
11174         res = PQexec(g_conn, query->data);
11175         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11176         ntups = PQntuples(res);
11177         if (ntups != 1)
11178         {
11179                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11180                                                            "query returned %d rows instead of one: %s\n",
11181                                                                  ntups),
11182                                   ntups, query->data);
11183                 exit_nicely();
11184         }
11185         nspname = PQgetvalue(res, 0, 0);
11186         tmplname = PQgetvalue(res, 0, 1);
11187
11188         /* Make sure we are in proper schema */
11189         selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
11190
11191         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11192                                           fmtId(dictinfo->dobj.name));
11193
11194         appendPQExpBuffer(q, "    TEMPLATE = ");
11195         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11196                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11197         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11198
11199         PQclear(res);
11200
11201         /* the dictinitoption can be dumped straight into the command */
11202         if (dictinfo->dictinitoption)
11203                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11204
11205         appendPQExpBuffer(q, " );\n");
11206
11207         /*
11208          * DROP must be fully qualified in case same name appears in pg_catalog
11209          */
11210         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11211                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11212         appendPQExpBuffer(delq, ".%s;\n",
11213                                           fmtId(dictinfo->dobj.name));
11214
11215         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11216                                           fmtId(dictinfo->dobj.name));
11217
11218         if (binary_upgrade)
11219                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11220
11221         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11222                                  dictinfo->dobj.name,
11223                                  dictinfo->dobj.namespace->dobj.name,
11224                                  NULL,
11225                                  dictinfo->rolname,
11226                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11227                                  q->data, delq->data, NULL,
11228                                  dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
11229                                  NULL, NULL);
11230
11231         /* Dump Dictionary Comments */
11232         dumpComment(fout, labelq->data,
11233                                 NULL, dictinfo->rolname,
11234                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11235
11236         destroyPQExpBuffer(q);
11237         destroyPQExpBuffer(delq);
11238         destroyPQExpBuffer(labelq);
11239         destroyPQExpBuffer(query);
11240 }
11241
11242 /*
11243  * dumpTSTemplate
11244  *        write out a single text search template
11245  */
11246 static void
11247 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11248 {
11249         PQExpBuffer q;
11250         PQExpBuffer delq;
11251         PQExpBuffer labelq;
11252
11253         /* Skip if not to be dumped */
11254         if (!tmplinfo->dobj.dump || dataOnly)
11255                 return;
11256
11257         q = createPQExpBuffer();
11258         delq = createPQExpBuffer();
11259         labelq = createPQExpBuffer();
11260
11261         /* Make sure we are in proper schema */
11262         selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
11263
11264         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11265                                           fmtId(tmplinfo->dobj.name));
11266
11267         if (tmplinfo->tmplinit != InvalidOid)
11268                 appendPQExpBuffer(q, "    INIT = %s,\n",
11269                                                   convertTSFunction(tmplinfo->tmplinit));
11270         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11271                                           convertTSFunction(tmplinfo->tmpllexize));
11272
11273         /*
11274          * DROP must be fully qualified in case same name appears in pg_catalog
11275          */
11276         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11277                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11278         appendPQExpBuffer(delq, ".%s;\n",
11279                                           fmtId(tmplinfo->dobj.name));
11280
11281         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11282                                           fmtId(tmplinfo->dobj.name));
11283
11284         if (binary_upgrade)
11285                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11286
11287         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11288                                  tmplinfo->dobj.name,
11289                                  tmplinfo->dobj.namespace->dobj.name,
11290                                  NULL,
11291                                  "",
11292                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11293                                  q->data, delq->data, NULL,
11294                                  tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
11295                                  NULL, NULL);
11296
11297         /* Dump Template Comments */
11298         dumpComment(fout, labelq->data,
11299                                 NULL, "",
11300                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11301
11302         destroyPQExpBuffer(q);
11303         destroyPQExpBuffer(delq);
11304         destroyPQExpBuffer(labelq);
11305 }
11306
11307 /*
11308  * dumpTSConfig
11309  *        write out a single text search configuration
11310  */
11311 static void
11312 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11313 {
11314         PQExpBuffer q;
11315         PQExpBuffer delq;
11316         PQExpBuffer labelq;
11317         PQExpBuffer query;
11318         PGresult   *res;
11319         char       *nspname;
11320         char       *prsname;
11321         int                     ntups,
11322                                 i;
11323         int                     i_tokenname;
11324         int                     i_dictname;
11325
11326         /* Skip if not to be dumped */
11327         if (!cfginfo->dobj.dump || dataOnly)
11328                 return;
11329
11330         q = createPQExpBuffer();
11331         delq = createPQExpBuffer();
11332         labelq = createPQExpBuffer();
11333         query = createPQExpBuffer();
11334
11335         /* Fetch name and namespace of the config's parser */
11336         selectSourceSchema("pg_catalog");
11337         appendPQExpBuffer(query, "SELECT nspname, prsname "
11338                                           "FROM pg_ts_parser p, pg_namespace n "
11339                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11340                                           cfginfo->cfgparser);
11341         res = PQexec(g_conn, query->data);
11342         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11343         ntups = PQntuples(res);
11344         if (ntups != 1)
11345         {
11346                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11347                                                            "query returned %d rows instead of one: %s\n",
11348                                                                  ntups),
11349                                   ntups, query->data);
11350                 exit_nicely();
11351         }
11352         nspname = PQgetvalue(res, 0, 0);
11353         prsname = PQgetvalue(res, 0, 1);
11354
11355         /* Make sure we are in proper schema */
11356         selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
11357
11358         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11359                                           fmtId(cfginfo->dobj.name));
11360
11361         appendPQExpBuffer(q, "    PARSER = ");
11362         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11363                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11364         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11365
11366         PQclear(res);
11367
11368         resetPQExpBuffer(query);
11369         appendPQExpBuffer(query,
11370                                           "SELECT \n"
11371                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11372                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11373                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11374                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11375                                           "WHERE m.mapcfg = '%u' \n"
11376                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11377                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11378
11379         res = PQexec(g_conn, query->data);
11380         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11381         ntups = PQntuples(res);
11382
11383         i_tokenname = PQfnumber(res, "tokenname");
11384         i_dictname = PQfnumber(res, "dictname");
11385
11386         for (i = 0; i < ntups; i++)
11387         {
11388                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11389                 char       *dictname = PQgetvalue(res, i, i_dictname);
11390
11391                 if (i == 0 ||
11392                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11393                 {
11394                         /* starting a new token type, so start a new command */
11395                         if (i > 0)
11396                                 appendPQExpBuffer(q, ";\n");
11397                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11398                                                           fmtId(cfginfo->dobj.name));
11399                         /* tokenname needs quoting, dictname does NOT */
11400                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11401                                                           fmtId(tokenname), dictname);
11402                 }
11403                 else
11404                         appendPQExpBuffer(q, ", %s", dictname);
11405         }
11406
11407         if (ntups > 0)
11408                 appendPQExpBuffer(q, ";\n");
11409
11410         PQclear(res);
11411
11412         /*
11413          * DROP must be fully qualified in case same name appears in pg_catalog
11414          */
11415         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11416                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11417         appendPQExpBuffer(delq, ".%s;\n",
11418                                           fmtId(cfginfo->dobj.name));
11419
11420         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11421                                           fmtId(cfginfo->dobj.name));
11422
11423         if (binary_upgrade)
11424                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11425
11426         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11427                                  cfginfo->dobj.name,
11428                                  cfginfo->dobj.namespace->dobj.name,
11429                                  NULL,
11430                                  cfginfo->rolname,
11431                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11432                                  q->data, delq->data, NULL,
11433                                  cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
11434                                  NULL, NULL);
11435
11436         /* Dump Configuration Comments */
11437         dumpComment(fout, labelq->data,
11438                                 NULL, cfginfo->rolname,
11439                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11440
11441         destroyPQExpBuffer(q);
11442         destroyPQExpBuffer(delq);
11443         destroyPQExpBuffer(labelq);
11444         destroyPQExpBuffer(query);
11445 }
11446
11447 /*
11448  * dumpForeignDataWrapper
11449  *        write out a single foreign-data wrapper definition
11450  */
11451 static void
11452 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11453 {
11454         PQExpBuffer q;
11455         PQExpBuffer delq;
11456         PQExpBuffer labelq;
11457         char       *qfdwname;
11458
11459         /* Skip if not to be dumped */
11460         if (!fdwinfo->dobj.dump || dataOnly)
11461                 return;
11462
11463         /*
11464          * FDWs that belong to an extension are dumped based on their "dump"
11465          * field. Otherwise omit them if we are only dumping some specific object.
11466          */
11467         if (!fdwinfo->dobj.ext_member)
11468                 if (!include_everything)
11469                         return;
11470
11471         q = createPQExpBuffer();
11472         delq = createPQExpBuffer();
11473         labelq = createPQExpBuffer();
11474
11475         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11476
11477         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11478                                           qfdwname);
11479
11480         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11481                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11482
11483         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11484                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11485
11486         if (strlen(fdwinfo->fdwoptions) > 0)
11487                 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
11488
11489         appendPQExpBuffer(q, ";\n");
11490
11491         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
11492                                           qfdwname);
11493
11494         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
11495                                           qfdwname);
11496
11497         if (binary_upgrade)
11498                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
11499
11500         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11501                                  fdwinfo->dobj.name,
11502                                  NULL,
11503                                  NULL,
11504                                  fdwinfo->rolname,
11505                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
11506                                  q->data, delq->data, NULL,
11507                                  fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
11508                                  NULL, NULL);
11509
11510         /* Handle the ACL */
11511         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
11512                         "FOREIGN DATA WRAPPER",
11513                         qfdwname, NULL, fdwinfo->dobj.name,
11514                         NULL, fdwinfo->rolname,
11515                         fdwinfo->fdwacl);
11516
11517         /* Dump Foreign Data Wrapper Comments */
11518         dumpComment(fout, labelq->data,
11519                                 NULL, fdwinfo->rolname,
11520                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
11521
11522         free(qfdwname);
11523
11524         destroyPQExpBuffer(q);
11525         destroyPQExpBuffer(delq);
11526         destroyPQExpBuffer(labelq);
11527 }
11528
11529 /*
11530  * dumpForeignServer
11531  *        write out a foreign server definition
11532  */
11533 static void
11534 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
11535 {
11536         PQExpBuffer q;
11537         PQExpBuffer delq;
11538         PQExpBuffer labelq;
11539         PQExpBuffer query;
11540         PGresult   *res;
11541         int                     ntups;
11542         char       *qsrvname;
11543         char       *fdwname;
11544
11545         /* Skip if not to be dumped */
11546         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
11547                 return;
11548
11549         q = createPQExpBuffer();
11550         delq = createPQExpBuffer();
11551         labelq = createPQExpBuffer();
11552         query = createPQExpBuffer();
11553
11554         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
11555
11556         /* look up the foreign-data wrapper */
11557         selectSourceSchema("pg_catalog");
11558         appendPQExpBuffer(query, "SELECT fdwname "
11559                                           "FROM pg_foreign_data_wrapper w "
11560                                           "WHERE w.oid = '%u'",
11561                                           srvinfo->srvfdw);
11562         res = PQexec(g_conn, query->data);
11563         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11564         ntups = PQntuples(res);
11565         if (ntups != 1)
11566         {
11567                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11568                                                            "query returned %d rows instead of one: %s\n",
11569                                                                  ntups),
11570                                   ntups, query->data);
11571                 exit_nicely();
11572         }
11573         fdwname = PQgetvalue(res, 0, 0);
11574
11575         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
11576         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
11577         {
11578                 appendPQExpBuffer(q, " TYPE ");
11579                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
11580         }
11581         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
11582         {
11583                 appendPQExpBuffer(q, " VERSION ");
11584                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
11585         }
11586
11587         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
11588         appendPQExpBuffer(q, "%s", fmtId(fdwname));
11589
11590         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
11591                 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
11592
11593         appendPQExpBuffer(q, ";\n");
11594
11595         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
11596                                           qsrvname);
11597
11598         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
11599
11600         if (binary_upgrade)
11601                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
11602
11603         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11604                                  srvinfo->dobj.name,
11605                                  NULL,
11606                                  NULL,
11607                                  srvinfo->rolname,
11608                                  false, "SERVER", SECTION_PRE_DATA,
11609                                  q->data, delq->data, NULL,
11610                                  srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
11611                                  NULL, NULL);
11612
11613         /* Handle the ACL */
11614         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
11615                         "FOREIGN SERVER",
11616                         qsrvname, NULL, srvinfo->dobj.name,
11617                         NULL, srvinfo->rolname,
11618                         srvinfo->srvacl);
11619
11620         /* Dump user mappings */
11621         dumpUserMappings(fout,
11622                                          srvinfo->dobj.name, NULL,
11623                                          srvinfo->rolname,
11624                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
11625
11626         /* Dump Foreign Server Comments */
11627         dumpComment(fout, labelq->data,
11628                                 NULL, srvinfo->rolname,
11629                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
11630
11631         free(qsrvname);
11632
11633         destroyPQExpBuffer(q);
11634         destroyPQExpBuffer(delq);
11635         destroyPQExpBuffer(labelq);
11636 }
11637
11638 /*
11639  * dumpUserMappings
11640  *
11641  * This routine is used to dump any user mappings associated with the
11642  * server handed to this routine. Should be called after ArchiveEntry()
11643  * for the server.
11644  */
11645 static void
11646 dumpUserMappings(Archive *fout,
11647                                  const char *servername, const char *namespace,
11648                                  const char *owner,
11649                                  CatalogId catalogId, DumpId dumpId)
11650 {
11651         PQExpBuffer q;
11652         PQExpBuffer delq;
11653         PQExpBuffer query;
11654         PQExpBuffer tag;
11655         PGresult   *res;
11656         int                     ntups;
11657         int                     i_usename;
11658         int                     i_umoptions;
11659         int                     i;
11660
11661         q = createPQExpBuffer();
11662         tag = createPQExpBuffer();
11663         delq = createPQExpBuffer();
11664         query = createPQExpBuffer();
11665
11666         /*
11667          * We read from the publicly accessible view pg_user_mappings, so as not
11668          * to fail if run by a non-superuser.  Note that the view will show
11669          * umoptions as null if the user hasn't got privileges for the associated
11670          * server; this means that pg_dump will dump such a mapping, but with no
11671          * OPTIONS clause.      A possible alternative is to skip such mappings
11672          * altogether, but it's not clear that that's an improvement.
11673          */
11674         selectSourceSchema("pg_catalog");
11675
11676         appendPQExpBuffer(query,
11677                                           "SELECT usename, "
11678                                           "array_to_string(ARRAY("
11679                                           "SELECT quote_ident(option_name) || ' ' || "
11680                                           "quote_literal(option_value) "
11681                                           "FROM pg_options_to_table(umoptions)"
11682                                           "), ', ') AS umoptions "
11683                                           "FROM pg_user_mappings "
11684                                           "WHERE srvid = '%u'",
11685                                           catalogId.oid);
11686
11687         res = PQexec(g_conn, query->data);
11688         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11689
11690         ntups = PQntuples(res);
11691         i_usename = PQfnumber(res, "usename");
11692         i_umoptions = PQfnumber(res, "umoptions");
11693
11694         for (i = 0; i < ntups; i++)
11695         {
11696                 char       *usename;
11697                 char       *umoptions;
11698
11699                 usename = PQgetvalue(res, i, i_usename);
11700                 umoptions = PQgetvalue(res, i, i_umoptions);
11701
11702                 resetPQExpBuffer(q);
11703                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
11704                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
11705
11706                 if (umoptions && strlen(umoptions) > 0)
11707                         appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
11708
11709                 appendPQExpBuffer(q, ";\n");
11710
11711                 resetPQExpBuffer(delq);
11712                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
11713                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
11714
11715                 resetPQExpBuffer(tag);
11716                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
11717                                                   usename, servername);
11718
11719                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11720                                          tag->data,
11721                                          namespace,
11722                                          NULL,
11723                                          owner, false,
11724                                          "USER MAPPING", SECTION_PRE_DATA,
11725                                          q->data, delq->data, NULL,
11726                                          &dumpId, 1,
11727                                          NULL, NULL);
11728         }
11729
11730         PQclear(res);
11731
11732         destroyPQExpBuffer(query);
11733         destroyPQExpBuffer(delq);
11734         destroyPQExpBuffer(q);
11735 }
11736
11737 /*
11738  * Write out default privileges information
11739  */
11740 static void
11741 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
11742 {
11743         PQExpBuffer q;
11744         PQExpBuffer tag;
11745         const char *type;
11746
11747         /* Skip if not to be dumped */
11748         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
11749                 return;
11750
11751         q = createPQExpBuffer();
11752         tag = createPQExpBuffer();
11753
11754         switch (daclinfo->defaclobjtype)
11755         {
11756                 case DEFACLOBJ_RELATION:
11757                         type = "TABLES";
11758                         break;
11759                 case DEFACLOBJ_SEQUENCE:
11760                         type = "SEQUENCES";
11761                         break;
11762                 case DEFACLOBJ_FUNCTION:
11763                         type = "FUNCTIONS";
11764                         break;
11765                 default:
11766                         /* shouldn't get here */
11767                         write_msg(NULL, "unknown object type (%d) in default privileges\n",
11768                                           (int) daclinfo->defaclobjtype);
11769                         exit_nicely();
11770                         type = "";                      /* keep compiler quiet */
11771         }
11772
11773         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
11774
11775         /* build the actual command(s) for this tuple */
11776         if (!buildDefaultACLCommands(type,
11777                                                                  daclinfo->dobj.namespace != NULL ?
11778                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
11779                                                                  daclinfo->defaclacl,
11780                                                                  daclinfo->defaclrole,
11781                                                                  fout->remoteVersion,
11782                                                                  q))
11783         {
11784                 write_msg(NULL, "could not parse default ACL list (%s)\n",
11785                                   daclinfo->defaclacl);
11786                 exit_nicely();
11787         }
11788
11789         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
11790                                  tag->data,
11791            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
11792                                  NULL,
11793                                  daclinfo->defaclrole,
11794                                  false, "DEFAULT ACL", SECTION_NONE,
11795                                  q->data, "", NULL,
11796                                  daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
11797                                  NULL, NULL);
11798
11799         destroyPQExpBuffer(tag);
11800         destroyPQExpBuffer(q);
11801 }
11802
11803 /*----------
11804  * Write out grant/revoke information
11805  *
11806  * 'objCatId' is the catalog ID of the underlying object.
11807  * 'objDumpId' is the dump ID of the underlying object.
11808  * 'type' must be one of
11809  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
11810  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
11811  * 'name' is the formatted name of the object.  Must be quoted etc. already.
11812  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
11813  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
11814  * 'nspname' is the namespace the object is in (NULL if none).
11815  * 'owner' is the owner, NULL if there is no owner (for languages).
11816  * 'acls' is the string read out of the fooacl system catalog field;
11817  *              it will be parsed here.
11818  *----------
11819  */
11820 static void
11821 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
11822                 const char *type, const char *name, const char *subname,
11823                 const char *tag, const char *nspname, const char *owner,
11824                 const char *acls)
11825 {
11826         PQExpBuffer sql;
11827
11828         /* Do nothing if ACL dump is not enabled */
11829         if (aclsSkip)
11830                 return;
11831
11832         /* --data-only skips ACLs *except* BLOB ACLs */
11833         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
11834                 return;
11835
11836         sql = createPQExpBuffer();
11837
11838         if (!buildACLCommands(name, subname, type, acls, owner,
11839                                                   "", fout->remoteVersion, sql))
11840         {
11841                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
11842                                   acls, name, type);
11843                 exit_nicely();
11844         }
11845
11846         if (sql->len > 0)
11847                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11848                                          tag, nspname,
11849                                          NULL,
11850                                          owner ? owner : "",
11851                                          false, "ACL", SECTION_NONE,
11852                                          sql->data, "", NULL,
11853                                          &(objDumpId), 1,
11854                                          NULL, NULL);
11855
11856         destroyPQExpBuffer(sql);
11857 }
11858
11859 /*
11860  * dumpSecLabel
11861  *
11862  * This routine is used to dump any security labels associated with the
11863  * object handed to this routine. The routine takes a constant character
11864  * string for the target part of the security-label command, plus
11865  * the namespace and owner of the object (for labeling the ArchiveEntry),
11866  * plus catalog ID and subid which are the lookup key for pg_seclabel,
11867  * plus the dump ID for the object (for setting a dependency).
11868  * If a matching pg_seclabel entry is found, it is dumped.
11869  *
11870  * Note: although this routine takes a dumpId for dependency purposes,
11871  * that purpose is just to mark the dependency in the emitted dump file
11872  * for possible future use by pg_restore.  We do NOT use it for determining
11873  * ordering of the label in the dump file, because this routine is called
11874  * after dependency sorting occurs.  This routine should be called just after
11875  * calling ArchiveEntry() for the specified object.
11876  */
11877 static void
11878 dumpSecLabel(Archive *fout, const char *target,
11879                          const char *namespace, const char *owner,
11880                          CatalogId catalogId, int subid, DumpId dumpId)
11881 {
11882         SecLabelItem *labels;
11883         int                     nlabels;
11884         int                     i;
11885         PQExpBuffer query;
11886
11887         /* do nothing, if --no-security-labels is supplied */
11888         if (no_security_labels)
11889                 return;
11890
11891         /* Comments are schema not data ... except blob comments are data */
11892         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
11893         {
11894                 if (dataOnly)
11895                         return;
11896         }
11897         else
11898         {
11899                 if (schemaOnly)
11900                         return;
11901         }
11902
11903         /* Search for security labels associated with catalogId, using table */
11904         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
11905
11906         query = createPQExpBuffer();
11907
11908         for (i = 0; i < nlabels; i++)
11909         {
11910                 /*
11911                  * Ignore label entries for which the subid doesn't match.
11912                  */
11913                 if (labels[i].objsubid != subid)
11914                         continue;
11915
11916                 appendPQExpBuffer(query,
11917                                                   "SECURITY LABEL FOR %s ON %s IS ",
11918                                                   fmtId(labels[i].provider), target);
11919                 appendStringLiteralAH(query, labels[i].label, fout);
11920                 appendPQExpBuffer(query, ";\n");
11921         }
11922
11923         if (query->len > 0)
11924         {
11925                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11926                                          target, namespace, NULL, owner,
11927                                          false, "SECURITY LABEL", SECTION_NONE,
11928                                          query->data, "", NULL,
11929                                          &(dumpId), 1,
11930                                          NULL, NULL);
11931         }
11932         destroyPQExpBuffer(query);
11933 }
11934
11935 /*
11936  * dumpTableSecLabel
11937  *
11938  * As above, but dump security label for both the specified table (or view)
11939  * and its columns.
11940  */
11941 static void
11942 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
11943 {
11944         SecLabelItem *labels;
11945         int                     nlabels;
11946         int                     i;
11947         PQExpBuffer query;
11948         PQExpBuffer target;
11949
11950         /* do nothing, if --no-security-labels is supplied */
11951         if (no_security_labels)
11952                 return;
11953
11954         /* SecLabel are SCHEMA not data */
11955         if (dataOnly)
11956                 return;
11957
11958         /* Search for comments associated with relation, using table */
11959         nlabels = findSecLabels(fout,
11960                                                         tbinfo->dobj.catId.tableoid,
11961                                                         tbinfo->dobj.catId.oid,
11962                                                         &labels);
11963
11964         /* If security labels exist, build SECURITY LABEL statements */
11965         if (nlabels <= 0)
11966                 return;
11967
11968         query = createPQExpBuffer();
11969         target = createPQExpBuffer();
11970
11971         for (i = 0; i < nlabels; i++)
11972         {
11973                 const char *colname;
11974                 const char *provider = labels[i].provider;
11975                 const char *label = labels[i].label;
11976                 int                     objsubid = labels[i].objsubid;
11977
11978                 resetPQExpBuffer(target);
11979                 if (objsubid == 0)
11980                 {
11981                         appendPQExpBuffer(target, "%s %s", reltypename,
11982                                                           fmtId(tbinfo->dobj.name));
11983                 }
11984                 else
11985                 {
11986                         colname = getAttrName(objsubid, tbinfo);
11987                         /* first fmtId result must be consumed before calling it again */
11988                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
11989                         appendPQExpBuffer(target, ".%s", fmtId(colname));
11990                 }
11991                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
11992                                                   fmtId(provider), target->data);
11993                 appendStringLiteralAH(query, label, fout);
11994                 appendPQExpBuffer(query, ";\n");
11995         }
11996         if (query->len > 0)
11997         {
11998                 resetPQExpBuffer(target);
11999                 appendPQExpBuffer(target, "%s %s", reltypename,
12000                                                   fmtId(tbinfo->dobj.name));
12001                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12002                                          target->data,
12003                                          tbinfo->dobj.namespace->dobj.name,
12004                                          NULL, tbinfo->rolname,
12005                                          false, "SECURITY LABEL", SECTION_NONE,
12006                                          query->data, "", NULL,
12007                                          &(tbinfo->dobj.dumpId), 1,
12008                                          NULL, NULL);
12009         }
12010         destroyPQExpBuffer(query);
12011         destroyPQExpBuffer(target);
12012 }
12013
12014 /*
12015  * findSecLabels
12016  *
12017  * Find the security label(s), if any, associated with the given object.
12018  * All the objsubid values associated with the given classoid/objoid are
12019  * found with one search.
12020  */
12021 static int
12022 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12023 {
12024         /* static storage for table of security labels */
12025         static SecLabelItem *labels = NULL;
12026         static int      nlabels = -1;
12027
12028         SecLabelItem *middle = NULL;
12029         SecLabelItem *low;
12030         SecLabelItem *high;
12031         int                     nmatch;
12032
12033         /* Get security labels if we didn't already */
12034         if (nlabels < 0)
12035                 nlabels = collectSecLabels(fout, &labels);
12036
12037         if (nlabels <= 0)                       /* no labels, so no match is possible */
12038         {
12039                 *items = NULL;
12040                 return 0;
12041         }
12042
12043         /*
12044          * Do binary search to find some item matching the object.
12045          */
12046         low = &labels[0];
12047         high = &labels[nlabels - 1];
12048         while (low <= high)
12049         {
12050                 middle = low + (high - low) / 2;
12051
12052                 if (classoid < middle->classoid)
12053                         high = middle - 1;
12054                 else if (classoid > middle->classoid)
12055                         low = middle + 1;
12056                 else if (objoid < middle->objoid)
12057                         high = middle - 1;
12058                 else if (objoid > middle->objoid)
12059                         low = middle + 1;
12060                 else
12061                         break;                          /* found a match */
12062         }
12063
12064         if (low > high)                         /* no matches */
12065         {
12066                 *items = NULL;
12067                 return 0;
12068         }
12069
12070         /*
12071          * Now determine how many items match the object.  The search loop
12072          * invariant still holds: only items between low and high inclusive could
12073          * match.
12074          */
12075         nmatch = 1;
12076         while (middle > low)
12077         {
12078                 if (classoid != middle[-1].classoid ||
12079                         objoid != middle[-1].objoid)
12080                         break;
12081                 middle--;
12082                 nmatch++;
12083         }
12084
12085         *items = middle;
12086
12087         middle += nmatch;
12088         while (middle <= high)
12089         {
12090                 if (classoid != middle->classoid ||
12091                         objoid != middle->objoid)
12092                         break;
12093                 middle++;
12094                 nmatch++;
12095         }
12096
12097         return nmatch;
12098 }
12099
12100 /*
12101  * collectSecLabels
12102  *
12103  * Construct a table of all security labels available for database objects.
12104  * It's much faster to pull them all at once.
12105  *
12106  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12107  */
12108 static int
12109 collectSecLabels(Archive *fout, SecLabelItem **items)
12110 {
12111         PGresult   *res;
12112         PQExpBuffer query;
12113         int                     i_label;
12114         int                     i_provider;
12115         int                     i_classoid;
12116         int                     i_objoid;
12117         int                     i_objsubid;
12118         int                     ntups;
12119         int                     i;
12120         SecLabelItem *labels;
12121
12122         query = createPQExpBuffer();
12123
12124         appendPQExpBuffer(query,
12125                                           "SELECT label, provider, classoid, objoid, objsubid "
12126                                           "FROM pg_catalog.pg_seclabel "
12127                                           "ORDER BY classoid, objoid, objsubid");
12128
12129         res = PQexec(g_conn, query->data);
12130         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12131
12132         /* Construct lookup table containing OIDs in numeric form */
12133         i_label = PQfnumber(res, "label");
12134         i_provider = PQfnumber(res, "provider");
12135         i_classoid = PQfnumber(res, "classoid");
12136         i_objoid = PQfnumber(res, "objoid");
12137         i_objsubid = PQfnumber(res, "objsubid");
12138
12139         ntups = PQntuples(res);
12140
12141         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12142
12143         for (i = 0; i < ntups; i++)
12144         {
12145                 labels[i].label = PQgetvalue(res, i, i_label);
12146                 labels[i].provider = PQgetvalue(res, i, i_provider);
12147                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12148                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12149                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12150         }
12151
12152         /* Do NOT free the PGresult since we are keeping pointers into it */
12153         destroyPQExpBuffer(query);
12154
12155         *items = labels;
12156         return ntups;
12157 }
12158
12159 /*
12160  * dumpTable
12161  *        write out to fout the declarations (not data) of a user-defined table
12162  */
12163 static void
12164 dumpTable(Archive *fout, TableInfo *tbinfo)
12165 {
12166         if (tbinfo->dobj.dump)
12167         {
12168                 char       *namecopy;
12169
12170                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12171                         dumpSequence(fout, tbinfo);
12172                 else if (!dataOnly)
12173                         dumpTableSchema(fout, tbinfo);
12174
12175                 /* Handle the ACL here */
12176                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12177                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12178                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12179                                 "TABLE",
12180                                 namecopy, NULL, tbinfo->dobj.name,
12181                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12182                                 tbinfo->relacl);
12183
12184                 /*
12185                  * Handle column ACLs, if any.  Note: we pull these with a separate
12186                  * query rather than trying to fetch them during getTableAttrs, so
12187                  * that we won't miss ACLs on system columns.
12188                  */
12189                 if (g_fout->remoteVersion >= 80400)
12190                 {
12191                         PQExpBuffer query = createPQExpBuffer();
12192                         PGresult   *res;
12193                         int                     i;
12194
12195                         appendPQExpBuffer(query,
12196                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12197                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12198                                                           "ORDER BY attnum",
12199                                                           tbinfo->dobj.catId.oid);
12200                         res = PQexec(g_conn, query->data);
12201                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12202
12203                         for (i = 0; i < PQntuples(res); i++)
12204                         {
12205                                 char       *attname = PQgetvalue(res, i, 0);
12206                                 char       *attacl = PQgetvalue(res, i, 1);
12207                                 char       *attnamecopy;
12208                                 char       *acltag;
12209
12210                                 attnamecopy = pg_strdup(fmtId(attname));
12211                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12212                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12213                                 /* Column's GRANT type is always TABLE */
12214                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12215                                                 namecopy, attnamecopy, acltag,
12216                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12217                                                 attacl);
12218                                 free(attnamecopy);
12219                                 free(acltag);
12220                         }
12221                         PQclear(res);
12222                         destroyPQExpBuffer(query);
12223                 }
12224
12225                 free(namecopy);
12226         }
12227 }
12228
12229 /*
12230  * dumpTableSchema
12231  *        write the declaration (not data) of one user-defined table or view
12232  */
12233 static void
12234 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12235 {
12236         PQExpBuffer query = createPQExpBuffer();
12237         PQExpBuffer q = createPQExpBuffer();
12238         PQExpBuffer delq = createPQExpBuffer();
12239         PQExpBuffer labelq = createPQExpBuffer();
12240         PGresult   *res;
12241         int                     numParents;
12242         TableInfo **parents;
12243         int                     actual_atts;    /* number of attrs in this CREATE statment */
12244         const char *reltypename;
12245         char       *storage;
12246         char       *srvname;
12247         char       *ftoptions;
12248         int                     j,
12249                                 k;
12250
12251         /* Make sure we are in proper schema */
12252         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
12253
12254         if (binary_upgrade)
12255                 binary_upgrade_set_type_oids_by_rel_oid(q,
12256                                                                                                 tbinfo->dobj.catId.oid);
12257
12258         /* Is it a table or a view? */
12259         if (tbinfo->relkind == RELKIND_VIEW)
12260         {
12261                 char       *viewdef;
12262
12263                 reltypename = "VIEW";
12264
12265                 /* Fetch the view definition */
12266                 if (g_fout->remoteVersion >= 70300)
12267                 {
12268                         /* Beginning in 7.3, viewname is not unique; rely on OID */
12269                         appendPQExpBuffer(query,
12270                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12271                                                           tbinfo->dobj.catId.oid);
12272                 }
12273                 else
12274                 {
12275                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
12276                                                           "FROM pg_views WHERE viewname = ");
12277                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12278                         appendPQExpBuffer(query, ";");
12279                 }
12280
12281                 res = PQexec(g_conn, query->data);
12282                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12283
12284                 if (PQntuples(res) != 1)
12285                 {
12286                         if (PQntuples(res) < 1)
12287                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12288                                                   tbinfo->dobj.name);
12289                         else
12290                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12291                                                   tbinfo->dobj.name);
12292                         exit_nicely();
12293                 }
12294
12295                 viewdef = PQgetvalue(res, 0, 0);
12296
12297                 if (strlen(viewdef) == 0)
12298                 {
12299                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12300                                           tbinfo->dobj.name);
12301                         exit_nicely();
12302                 }
12303
12304                 /*
12305                  * DROP must be fully qualified in case same name appears in
12306                  * pg_catalog
12307                  */
12308                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12309                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12310                 appendPQExpBuffer(delq, "%s;\n",
12311                                                   fmtId(tbinfo->dobj.name));
12312
12313                 if (binary_upgrade)
12314                         binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
12315
12316                 appendPQExpBuffer(q, "CREATE VIEW %s AS\n    %s\n",
12317                                                   fmtId(tbinfo->dobj.name), viewdef);
12318
12319                 appendPQExpBuffer(labelq, "VIEW %s",
12320                                                   fmtId(tbinfo->dobj.name));
12321
12322                 PQclear(res);
12323         }
12324         else
12325         {
12326                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12327                 {
12328                         int                     i_srvname;
12329                         int                     i_ftoptions;
12330
12331                         reltypename = "FOREIGN TABLE";
12332
12333                         /* retrieve name of foreign server and generic options */
12334                         appendPQExpBuffer(query,
12335                                                           "SELECT fs.srvname, "
12336                                                           "pg_catalog.array_to_string(ARRAY("
12337                                                           "SELECT pg_catalog.quote_ident(option_name) || "
12338                                                           "' ' || pg_catalog.quote_literal(option_value) "
12339                                                           "FROM pg_catalog.pg_options_to_table(ftoptions)"
12340                                                           "), ', ') AS ftoptions "
12341                                                           "FROM pg_catalog.pg_foreign_table ft "
12342                                                           "JOIN pg_catalog.pg_foreign_server fs "
12343                                                           "ON (fs.oid = ft.ftserver) "
12344                                                           "WHERE ft.ftrelid = '%u'",
12345                                                           tbinfo->dobj.catId.oid);
12346                         res = PQexec(g_conn, query->data);
12347                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
12348                         if (PQntuples(res) != 1)
12349                         {
12350                                 write_msg(NULL, ngettext("query returned %d foreign server entry for foreign table \"%s\"\n",
12351                                                                                  "query returned %d foreign server entries for foreign table \"%s\"\n",
12352                                                                                  PQntuples(res)),
12353                                                   PQntuples(res), tbinfo->dobj.name);
12354                                 exit_nicely();
12355                         }
12356                         i_srvname = PQfnumber(res, "srvname");
12357                         i_ftoptions = PQfnumber(res, "ftoptions");
12358                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12359                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12360                         PQclear(res);
12361                 }
12362                 else
12363                 {
12364                         reltypename = "TABLE";
12365                         srvname = NULL;
12366                         ftoptions = NULL;
12367                 }
12368                 numParents = tbinfo->numParents;
12369                 parents = tbinfo->parents;
12370
12371                 /*
12372                  * DROP must be fully qualified in case same name appears in
12373                  * pg_catalog
12374                  */
12375                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12376                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12377                 appendPQExpBuffer(delq, "%s;\n",
12378                                                   fmtId(tbinfo->dobj.name));
12379
12380                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12381                                                   fmtId(tbinfo->dobj.name));
12382
12383                 if (binary_upgrade)
12384                         binary_upgrade_set_pg_class_oids(q, tbinfo->dobj.catId.oid, false);
12385
12386                 appendPQExpBuffer(q, "CREATE %s%s %s",
12387                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12388                                                   "UNLOGGED " : "",
12389                                                   reltypename,
12390                                                   fmtId(tbinfo->dobj.name));
12391
12392                 /*
12393                  * In case of a binary upgrade, we dump the table normally and attach
12394                  * it to the type afterward.
12395                  */
12396                 if (tbinfo->reloftype && !binary_upgrade)
12397                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12398                 actual_atts = 0;
12399                 for (j = 0; j < tbinfo->numatts; j++)
12400                 {
12401                         /*
12402                          * Normally, dump if it's one of the table's own attrs, and not
12403                          * dropped.  But for binary upgrade, dump all the columns.
12404                          */
12405                         if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
12406                                 binary_upgrade)
12407                         {
12408                                 /*
12409                                  * Default value --- suppress if inherited (except in
12410                                  * binary-upgrade case, where we're not doing normal
12411                                  * inheritance) or if it's to be printed separately.
12412                                  */
12413                                 bool            has_default = (tbinfo->attrdefs[j] != NULL
12414                                                                 && (!tbinfo->inhAttrDef[j] || binary_upgrade)
12415                                                                                    && !tbinfo->attrdefs[j]->separate);
12416
12417                                 /*
12418                                  * Not Null constraint --- suppress if inherited, except in
12419                                  * binary-upgrade case.
12420                                  */
12421                                 bool            has_notnull = (tbinfo->notnull[j]
12422                                                           && (!tbinfo->inhNotNull[j] || binary_upgrade));
12423
12424                                 if (tbinfo->reloftype && !has_default && !has_notnull && !binary_upgrade)
12425                                         continue;
12426
12427                                 /* Format properly if not first attr */
12428                                 if (actual_atts == 0)
12429                                         appendPQExpBuffer(q, " (");
12430                                 else
12431                                         appendPQExpBuffer(q, ",");
12432                                 appendPQExpBuffer(q, "\n    ");
12433                                 actual_atts++;
12434
12435                                 /* Attribute name */
12436                                 appendPQExpBuffer(q, "%s ",
12437                                                                   fmtId(tbinfo->attnames[j]));
12438
12439                                 if (tbinfo->attisdropped[j])
12440                                 {
12441                                         /*
12442                                          * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
12443                                          * so we will not have gotten a valid type name; insert
12444                                          * INTEGER as a stopgap.  We'll clean things up later.
12445                                          */
12446                                         appendPQExpBuffer(q, "INTEGER /* dummy */");
12447                                         /* Skip all the rest, too */
12448                                         continue;
12449                                 }
12450
12451                                 /* Attribute type */
12452                                 if (tbinfo->reloftype && !binary_upgrade)
12453                                 {
12454                                         appendPQExpBuffer(q, "WITH OPTIONS");
12455                                 }
12456                                 else if (g_fout->remoteVersion >= 70100)
12457                                 {
12458                                         appendPQExpBuffer(q, "%s",
12459                                                                           tbinfo->atttypnames[j]);
12460                                 }
12461                                 else
12462                                 {
12463                                         /* If no format_type, fake it */
12464                                         appendPQExpBuffer(q, "%s",
12465                                                                           myFormatType(tbinfo->atttypnames[j],
12466                                                                                                    tbinfo->atttypmod[j]));
12467                                 }
12468
12469                                 /* Add collation if not default for the type */
12470                                 if (OidIsValid(tbinfo->attcollation[j]))
12471                                 {
12472                                         CollInfo   *coll;
12473
12474                                         coll = findCollationByOid(tbinfo->attcollation[j]);
12475                                         if (coll)
12476                                         {
12477                                                 /* always schema-qualify, don't try to be smart */
12478                                                 appendPQExpBuffer(q, " COLLATE %s.",
12479                                                                          fmtId(coll->dobj.namespace->dobj.name));
12480                                                 appendPQExpBuffer(q, "%s",
12481                                                                                   fmtId(coll->dobj.name));
12482                                         }
12483                                 }
12484
12485                                 if (has_default)
12486                                         appendPQExpBuffer(q, " DEFAULT %s",
12487                                                                           tbinfo->attrdefs[j]->adef_expr);
12488
12489                                 if (has_notnull)
12490                                         appendPQExpBuffer(q, " NOT NULL");
12491                         }
12492                 }
12493
12494                 /*
12495                  * Add non-inherited CHECK constraints, if any.
12496                  */
12497                 for (j = 0; j < tbinfo->ncheck; j++)
12498                 {
12499                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12500
12501                         if (constr->separate || !constr->conislocal)
12502                                 continue;
12503
12504                         if (actual_atts == 0)
12505                                 appendPQExpBuffer(q, " (\n    ");
12506                         else
12507                                 appendPQExpBuffer(q, ",\n    ");
12508
12509                         appendPQExpBuffer(q, "CONSTRAINT %s ",
12510                                                           fmtId(constr->dobj.name));
12511                         appendPQExpBuffer(q, "%s", constr->condef);
12512
12513                         actual_atts++;
12514                 }
12515
12516                 if (actual_atts)
12517                         appendPQExpBuffer(q, "\n)");
12518                 else if (!(tbinfo->reloftype && !binary_upgrade))
12519                 {
12520                         /*
12521                          * We must have a parenthesized attribute list, even though empty,
12522                          * when not using the OF TYPE syntax.
12523                          */
12524                         appendPQExpBuffer(q, " (\n)");
12525                 }
12526
12527                 if (numParents > 0 && !binary_upgrade)
12528                 {
12529                         appendPQExpBuffer(q, "\nINHERITS (");
12530                         for (k = 0; k < numParents; k++)
12531                         {
12532                                 TableInfo  *parentRel = parents[k];
12533
12534                                 if (k > 0)
12535                                         appendPQExpBuffer(q, ", ");
12536                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12537                                         appendPQExpBuffer(q, "%s.",
12538                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12539                                 appendPQExpBuffer(q, "%s",
12540                                                                   fmtId(parentRel->dobj.name));
12541                         }
12542                         appendPQExpBuffer(q, ")");
12543                 }
12544
12545                 if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
12546                         appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
12547
12548                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
12549                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
12550                 {
12551                         bool            addcomma = false;
12552
12553                         appendPQExpBuffer(q, "\nWITH (");
12554                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12555                         {
12556                                 addcomma = true;
12557                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
12558                         }
12559                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
12560                         {
12561                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
12562                                                                   tbinfo->toast_reloptions);
12563                         }
12564                         appendPQExpBuffer(q, ")");
12565                 }
12566
12567                 /* Dump generic options if any */
12568                 if (ftoptions && ftoptions[0])
12569                         appendPQExpBuffer(q, "\nOPTIONS (%s)", ftoptions);
12570
12571                 appendPQExpBuffer(q, ";\n");
12572
12573                 /*
12574                  * To create binary-compatible heap files, we have to ensure the same
12575                  * physical column order, including dropped columns, as in the
12576                  * original.  Therefore, we create dropped columns above and drop them
12577                  * here, also updating their attlen/attalign values so that the
12578                  * dropped column can be skipped properly.      (We do not bother with
12579                  * restoring the original attbyval setting.)  Also, inheritance
12580                  * relationships are set up by doing ALTER INHERIT rather than using
12581                  * an INHERITS clause --- the latter would possibly mess up the column
12582                  * order.  That also means we have to take care about setting
12583                  * attislocal correctly, plus fix up any inherited CHECK constraints.
12584                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
12585                  */
12586                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
12587                 {
12588                         for (j = 0; j < tbinfo->numatts; j++)
12589                         {
12590                                 if (tbinfo->attisdropped[j])
12591                                 {
12592                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
12593                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12594                                                                           "SET attlen = %d, "
12595                                                                           "attalign = '%c', attbyval = false\n"
12596                                                                           "WHERE attname = ",
12597                                                                           tbinfo->attlen[j],
12598                                                                           tbinfo->attalign[j]);
12599                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12600                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12601                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12602                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12603
12604                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12605                                                                           fmtId(tbinfo->dobj.name));
12606                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
12607                                                                           fmtId(tbinfo->attnames[j]));
12608                                 }
12609                                 else if (!tbinfo->attislocal[j])
12610                                 {
12611                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
12612                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
12613                                                                           "SET attislocal = false\n"
12614                                                                           "WHERE attname = ");
12615                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
12616                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
12617                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12618                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12619                                 }
12620                         }
12621
12622                         for (k = 0; k < tbinfo->ncheck; k++)
12623                         {
12624                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
12625
12626                                 if (constr->separate || constr->conislocal)
12627                                         continue;
12628
12629                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
12630                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12631                                                                   fmtId(tbinfo->dobj.name));
12632                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
12633                                                                   fmtId(constr->dobj.name));
12634                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
12635                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
12636                                                                   "SET conislocal = false\n"
12637                                                                   "WHERE contype = 'c' AND conname = ");
12638                                 appendStringLiteralAH(q, constr->dobj.name, fout);
12639                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
12640                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12641                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12642                         }
12643
12644                         if (numParents > 0)
12645                         {
12646                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
12647                                 for (k = 0; k < numParents; k++)
12648                                 {
12649                                         TableInfo  *parentRel = parents[k];
12650
12651                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
12652                                                                           fmtId(tbinfo->dobj.name));
12653                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
12654                                                 appendPQExpBuffer(q, "%s.",
12655                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
12656                                         appendPQExpBuffer(q, "%s;\n",
12657                                                                           fmtId(parentRel->dobj.name));
12658                                 }
12659                         }
12660
12661                         if (tbinfo->reloftype)
12662                         {
12663                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
12664                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
12665                                                                   fmtId(tbinfo->dobj.name),
12666                                                                   tbinfo->reloftype);
12667                         }
12668
12669                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
12670                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12671                                                           "SET relfrozenxid = '%u'\n"
12672                                                           "WHERE oid = ",
12673                                                           tbinfo->frozenxid);
12674                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
12675                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
12676
12677                         if (tbinfo->toast_oid)
12678                         {
12679                                 /* We preserve the toast oids, so we can use it during restore */
12680                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
12681                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
12682                                                                   "SET relfrozenxid = '%u'\n"
12683                                                                   "WHERE oid = '%u';\n",
12684                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
12685                         }
12686                 }
12687
12688                 /* Loop dumping statistics and storage statements */
12689                 for (j = 0; j < tbinfo->numatts; j++)
12690                 {
12691                         /*
12692                          * Dump per-column statistics information. We only issue an ALTER
12693                          * TABLE statement if the attstattarget entry for this column is
12694                          * non-negative (i.e. it's not the default value)
12695                          */
12696                         if (tbinfo->attstattarget[j] >= 0 &&
12697                                 !tbinfo->attisdropped[j])
12698                         {
12699                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12700                                                                   fmtId(tbinfo->dobj.name));
12701                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12702                                                                   fmtId(tbinfo->attnames[j]));
12703                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
12704                                                                   tbinfo->attstattarget[j]);
12705                         }
12706
12707                         /*
12708                          * Dump per-column storage information.  The statement is only
12709                          * dumped if the storage has been changed from the type's default.
12710                          */
12711                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
12712                         {
12713                                 switch (tbinfo->attstorage[j])
12714                                 {
12715                                         case 'p':
12716                                                 storage = "PLAIN";
12717                                                 break;
12718                                         case 'e':
12719                                                 storage = "EXTERNAL";
12720                                                 break;
12721                                         case 'm':
12722                                                 storage = "MAIN";
12723                                                 break;
12724                                         case 'x':
12725                                                 storage = "EXTENDED";
12726                                                 break;
12727                                         default:
12728                                                 storage = NULL;
12729                                 }
12730
12731                                 /*
12732                                  * Only dump the statement if it's a storage type we recognize
12733                                  */
12734                                 if (storage != NULL)
12735                                 {
12736                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12737                                                                           fmtId(tbinfo->dobj.name));
12738                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
12739                                                                           fmtId(tbinfo->attnames[j]));
12740                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
12741                                                                           storage);
12742                                 }
12743                         }
12744
12745                         /*
12746                          * Dump per-column attributes.
12747                          */
12748                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
12749                         {
12750                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
12751                                                                   fmtId(tbinfo->dobj.name));
12752                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12753                                                                   fmtId(tbinfo->attnames[j]));
12754                                 appendPQExpBuffer(q, "SET (%s);\n",
12755                                                                   tbinfo->attoptions[j]);
12756                         }
12757
12758                         /*
12759                          * Dump per-column fdw options.
12760                          */
12761                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
12762                                 tbinfo->attfdwoptions[j] &&
12763                                 tbinfo->attfdwoptions[j][0] != '\0')
12764                         {
12765                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
12766                                                                   fmtId(tbinfo->dobj.name));
12767                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
12768                                                                   fmtId(tbinfo->attnames[j]));
12769                                 appendPQExpBuffer(q, "OPTIONS (%s);\n",
12770                                                                   tbinfo->attfdwoptions[j]);
12771                         }
12772                 }
12773         }
12774
12775         if (binary_upgrade)
12776                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
12777
12778         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12779                                  tbinfo->dobj.name,
12780                                  tbinfo->dobj.namespace->dobj.name,
12781                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
12782                                  tbinfo->rolname,
12783                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
12784                                  reltypename, SECTION_PRE_DATA,
12785                                  q->data, delq->data, NULL,
12786                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
12787                                  NULL, NULL);
12788
12789
12790         /* Dump Table Comments */
12791         dumpTableComment(fout, tbinfo, reltypename);
12792
12793         /* Dump Table Security Labels */
12794         dumpTableSecLabel(fout, tbinfo, reltypename);
12795
12796         /* Dump comments on inlined table constraints */
12797         for (j = 0; j < tbinfo->ncheck; j++)
12798         {
12799                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
12800
12801                 if (constr->separate || !constr->conislocal)
12802                         continue;
12803
12804                 dumpTableConstraintComment(fout, constr);
12805         }
12806
12807         destroyPQExpBuffer(query);
12808         destroyPQExpBuffer(q);
12809         destroyPQExpBuffer(delq);
12810         destroyPQExpBuffer(labelq);
12811 }
12812
12813 /*
12814  * dumpAttrDef --- dump an attribute's default-value declaration
12815  */
12816 static void
12817 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
12818 {
12819         TableInfo  *tbinfo = adinfo->adtable;
12820         int                     adnum = adinfo->adnum;
12821         PQExpBuffer q;
12822         PQExpBuffer delq;
12823
12824         /* Only print it if "separate" mode is selected */
12825         if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
12826                 return;
12827
12828         /* Don't print inherited defaults, either, except for binary upgrade */
12829         if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
12830                 return;
12831
12832         q = createPQExpBuffer();
12833         delq = createPQExpBuffer();
12834
12835         appendPQExpBuffer(q, "ALTER TABLE %s ",
12836                                           fmtId(tbinfo->dobj.name));
12837         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
12838                                           fmtId(tbinfo->attnames[adnum - 1]),
12839                                           adinfo->adef_expr);
12840
12841         /*
12842          * DROP must be fully qualified in case same name appears in pg_catalog
12843          */
12844         appendPQExpBuffer(delq, "ALTER TABLE %s.",
12845                                           fmtId(tbinfo->dobj.namespace->dobj.name));
12846         appendPQExpBuffer(delq, "%s ",
12847                                           fmtId(tbinfo->dobj.name));
12848         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
12849                                           fmtId(tbinfo->attnames[adnum - 1]));
12850
12851         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
12852                                  tbinfo->attnames[adnum - 1],
12853                                  tbinfo->dobj.namespace->dobj.name,
12854                                  NULL,
12855                                  tbinfo->rolname,
12856                                  false, "DEFAULT", SECTION_PRE_DATA,
12857                                  q->data, delq->data, NULL,
12858                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
12859                                  NULL, NULL);
12860
12861         destroyPQExpBuffer(q);
12862         destroyPQExpBuffer(delq);
12863 }
12864
12865 /*
12866  * getAttrName: extract the correct name for an attribute
12867  *
12868  * The array tblInfo->attnames[] only provides names of user attributes;
12869  * if a system attribute number is supplied, we have to fake it.
12870  * We also do a little bit of bounds checking for safety's sake.
12871  */
12872 static const char *
12873 getAttrName(int attrnum, TableInfo *tblInfo)
12874 {
12875         if (attrnum > 0 && attrnum <= tblInfo->numatts)
12876                 return tblInfo->attnames[attrnum - 1];
12877         switch (attrnum)
12878         {
12879                 case SelfItemPointerAttributeNumber:
12880                         return "ctid";
12881                 case ObjectIdAttributeNumber:
12882                         return "oid";
12883                 case MinTransactionIdAttributeNumber:
12884                         return "xmin";
12885                 case MinCommandIdAttributeNumber:
12886                         return "cmin";
12887                 case MaxTransactionIdAttributeNumber:
12888                         return "xmax";
12889                 case MaxCommandIdAttributeNumber:
12890                         return "cmax";
12891                 case TableOidAttributeNumber:
12892                         return "tableoid";
12893         }
12894         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
12895                           attrnum, tblInfo->dobj.name);
12896         exit_nicely();
12897         return NULL;                            /* keep compiler quiet */
12898 }
12899
12900 /*
12901  * dumpIndex
12902  *        write out to fout a user-defined index
12903  */
12904 static void
12905 dumpIndex(Archive *fout, IndxInfo *indxinfo)
12906 {
12907         TableInfo  *tbinfo = indxinfo->indextable;
12908         PQExpBuffer q;
12909         PQExpBuffer delq;
12910         PQExpBuffer labelq;
12911
12912         if (dataOnly)
12913                 return;
12914
12915         q = createPQExpBuffer();
12916         delq = createPQExpBuffer();
12917         labelq = createPQExpBuffer();
12918
12919         appendPQExpBuffer(labelq, "INDEX %s",
12920                                           fmtId(indxinfo->dobj.name));
12921
12922         /*
12923          * If there's an associated constraint, don't dump the index per se, but
12924          * do dump any comment for it.  (This is safe because dependency ordering
12925          * will have ensured the constraint is emitted first.)
12926          */
12927         if (indxinfo->indexconstraint == 0)
12928         {
12929                 if (binary_upgrade)
12930                         binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
12931
12932                 /* Plain secondary index */
12933                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
12934
12935                 /* If the index is clustered, we need to record that. */
12936                 if (indxinfo->indisclustered)
12937                 {
12938                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
12939                                                           fmtId(tbinfo->dobj.name));
12940                         appendPQExpBuffer(q, " ON %s;\n",
12941                                                           fmtId(indxinfo->dobj.name));
12942                 }
12943
12944                 /*
12945                  * DROP must be fully qualified in case same name appears in
12946                  * pg_catalog
12947                  */
12948                 appendPQExpBuffer(delq, "DROP INDEX %s.",
12949                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12950                 appendPQExpBuffer(delq, "%s;\n",
12951                                                   fmtId(indxinfo->dobj.name));
12952
12953                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
12954                                          indxinfo->dobj.name,
12955                                          tbinfo->dobj.namespace->dobj.name,
12956                                          indxinfo->tablespace,
12957                                          tbinfo->rolname, false,
12958                                          "INDEX", SECTION_POST_DATA,
12959                                          q->data, delq->data, NULL,
12960                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
12961                                          NULL, NULL);
12962         }
12963
12964         /* Dump Index Comments */
12965         dumpComment(fout, labelq->data,
12966                                 tbinfo->dobj.namespace->dobj.name,
12967                                 tbinfo->rolname,
12968                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
12969
12970         destroyPQExpBuffer(q);
12971         destroyPQExpBuffer(delq);
12972         destroyPQExpBuffer(labelq);
12973 }
12974
12975 /*
12976  * dumpConstraint
12977  *        write out to fout a user-defined constraint
12978  */
12979 static void
12980 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
12981 {
12982         TableInfo  *tbinfo = coninfo->contable;
12983         PQExpBuffer q;
12984         PQExpBuffer delq;
12985
12986         /* Skip if not to be dumped */
12987         if (!coninfo->dobj.dump || dataOnly)
12988                 return;
12989
12990         q = createPQExpBuffer();
12991         delq = createPQExpBuffer();
12992
12993         if (coninfo->contype == 'p' ||
12994                 coninfo->contype == 'u' ||
12995                 coninfo->contype == 'x')
12996         {
12997                 /* Index-related constraint */
12998                 IndxInfo   *indxinfo;
12999                 int                     k;
13000
13001                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13002
13003                 if (indxinfo == NULL)
13004                 {
13005                         write_msg(NULL, "missing index for constraint \"%s\"\n",
13006                                           coninfo->dobj.name);
13007                         exit_nicely();
13008                 }
13009
13010                 if (binary_upgrade)
13011                         binary_upgrade_set_pg_class_oids(q, indxinfo->dobj.catId.oid, true);
13012
13013                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13014                                                   fmtId(tbinfo->dobj.name));
13015                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13016                                                   fmtId(coninfo->dobj.name));
13017
13018                 if (coninfo->condef)
13019                 {
13020                         /* pg_get_constraintdef should have provided everything */
13021                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13022                 }
13023                 else
13024                 {
13025                         appendPQExpBuffer(q, "%s (",
13026                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13027                         for (k = 0; k < indxinfo->indnkeys; k++)
13028                         {
13029                                 int                     indkey = (int) indxinfo->indkeys[k];
13030                                 const char *attname;
13031
13032                                 if (indkey == InvalidAttrNumber)
13033                                         break;
13034                                 attname = getAttrName(indkey, tbinfo);
13035
13036                                 appendPQExpBuffer(q, "%s%s",
13037                                                                   (k == 0) ? "" : ", ",
13038                                                                   fmtId(attname));
13039                         }
13040
13041                         appendPQExpBuffer(q, ")");
13042
13043                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13044                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13045
13046                         if (coninfo->condeferrable)
13047                         {
13048                                 appendPQExpBuffer(q, " DEFERRABLE");
13049                                 if (coninfo->condeferred)
13050                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13051                         }
13052
13053                         appendPQExpBuffer(q, ";\n");
13054                 }
13055
13056                 /* If the index is clustered, we need to record that. */
13057                 if (indxinfo->indisclustered)
13058                 {
13059                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13060                                                           fmtId(tbinfo->dobj.name));
13061                         appendPQExpBuffer(q, " ON %s;\n",
13062                                                           fmtId(indxinfo->dobj.name));
13063                 }
13064
13065                 /*
13066                  * DROP must be fully qualified in case same name appears in
13067                  * pg_catalog
13068                  */
13069                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13070                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13071                 appendPQExpBuffer(delq, "%s ",
13072                                                   fmtId(tbinfo->dobj.name));
13073                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13074                                                   fmtId(coninfo->dobj.name));
13075
13076                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13077                                          coninfo->dobj.name,
13078                                          tbinfo->dobj.namespace->dobj.name,
13079                                          indxinfo->tablespace,
13080                                          tbinfo->rolname, false,
13081                                          "CONSTRAINT", SECTION_POST_DATA,
13082                                          q->data, delq->data, NULL,
13083                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13084                                          NULL, NULL);
13085         }
13086         else if (coninfo->contype == 'f')
13087         {
13088                 /*
13089                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13090                  * current table data is not processed
13091                  */
13092                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13093                                                   fmtId(tbinfo->dobj.name));
13094                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13095                                                   fmtId(coninfo->dobj.name),
13096                                                   coninfo->condef);
13097
13098                 /*
13099                  * DROP must be fully qualified in case same name appears in
13100                  * pg_catalog
13101                  */
13102                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13103                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13104                 appendPQExpBuffer(delq, "%s ",
13105                                                   fmtId(tbinfo->dobj.name));
13106                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13107                                                   fmtId(coninfo->dobj.name));
13108
13109                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13110                                          coninfo->dobj.name,
13111                                          tbinfo->dobj.namespace->dobj.name,
13112                                          NULL,
13113                                          tbinfo->rolname, false,
13114                                          "FK CONSTRAINT", SECTION_POST_DATA,
13115                                          q->data, delq->data, NULL,
13116                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13117                                          NULL, NULL);
13118         }
13119         else if (coninfo->contype == 'c' && tbinfo)
13120         {
13121                 /* CHECK constraint on a table */
13122
13123                 /* Ignore if not to be dumped separately */
13124                 if (coninfo->separate)
13125                 {
13126                         /* not ONLY since we want it to propagate to children */
13127                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13128                                                           fmtId(tbinfo->dobj.name));
13129                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13130                                                           fmtId(coninfo->dobj.name),
13131                                                           coninfo->condef);
13132
13133                         /*
13134                          * DROP must be fully qualified in case same name appears in
13135                          * pg_catalog
13136                          */
13137                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13138                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13139                         appendPQExpBuffer(delq, "%s ",
13140                                                           fmtId(tbinfo->dobj.name));
13141                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13142                                                           fmtId(coninfo->dobj.name));
13143
13144                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13145                                                  coninfo->dobj.name,
13146                                                  tbinfo->dobj.namespace->dobj.name,
13147                                                  NULL,
13148                                                  tbinfo->rolname, false,
13149                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13150                                                  q->data, delq->data, NULL,
13151                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13152                                                  NULL, NULL);
13153                 }
13154         }
13155         else if (coninfo->contype == 'c' && tbinfo == NULL)
13156         {
13157                 /* CHECK constraint on a domain */
13158                 TypeInfo   *tyinfo = coninfo->condomain;
13159
13160                 /* Ignore if not to be dumped separately */
13161                 if (coninfo->separate)
13162                 {
13163                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13164                                                           fmtId(tyinfo->dobj.name));
13165                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13166                                                           fmtId(coninfo->dobj.name),
13167                                                           coninfo->condef);
13168
13169                         /*
13170                          * DROP must be fully qualified in case same name appears in
13171                          * pg_catalog
13172                          */
13173                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13174                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13175                         appendPQExpBuffer(delq, "%s ",
13176                                                           fmtId(tyinfo->dobj.name));
13177                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13178                                                           fmtId(coninfo->dobj.name));
13179
13180                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13181                                                  coninfo->dobj.name,
13182                                                  tyinfo->dobj.namespace->dobj.name,
13183                                                  NULL,
13184                                                  tyinfo->rolname, false,
13185                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13186                                                  q->data, delq->data, NULL,
13187                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
13188                                                  NULL, NULL);
13189                 }
13190         }
13191         else
13192         {
13193                 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
13194                 exit_nicely();
13195         }
13196
13197         /* Dump Constraint Comments --- only works for table constraints */
13198         if (tbinfo && coninfo->separate)
13199                 dumpTableConstraintComment(fout, coninfo);
13200
13201         destroyPQExpBuffer(q);
13202         destroyPQExpBuffer(delq);
13203 }
13204
13205 /*
13206  * dumpTableConstraintComment --- dump a constraint's comment if any
13207  *
13208  * This is split out because we need the function in two different places
13209  * depending on whether the constraint is dumped as part of CREATE TABLE
13210  * or as a separate ALTER command.
13211  */
13212 static void
13213 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13214 {
13215         TableInfo  *tbinfo = coninfo->contable;
13216         PQExpBuffer labelq = createPQExpBuffer();
13217
13218         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13219                                           fmtId(coninfo->dobj.name));
13220         appendPQExpBuffer(labelq, "ON %s",
13221                                           fmtId(tbinfo->dobj.name));
13222         dumpComment(fout, labelq->data,
13223                                 tbinfo->dobj.namespace->dobj.name,
13224                                 tbinfo->rolname,
13225                                 coninfo->dobj.catId, 0,
13226                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13227
13228         destroyPQExpBuffer(labelq);
13229 }
13230
13231 /*
13232  * findLastBuiltInOid -
13233  * find the last built in oid
13234  *
13235  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13236  * pg_database entry for the current database
13237  */
13238 static Oid
13239 findLastBuiltinOid_V71(const char *dbname)
13240 {
13241         PGresult   *res;
13242         int                     ntups;
13243         Oid                     last_oid;
13244         PQExpBuffer query = createPQExpBuffer();
13245
13246         resetPQExpBuffer(query);
13247         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13248         appendStringLiteralAH(query, dbname, g_fout);
13249
13250         res = PQexec(g_conn, query->data);
13251         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13252
13253         ntups = PQntuples(res);
13254         if (ntups < 1)
13255         {
13256                 write_msg(NULL, "missing pg_database entry for this database\n");
13257                 exit_nicely();
13258         }
13259         if (ntups > 1)
13260         {
13261                 write_msg(NULL, "found more than one pg_database entry for this database\n");
13262                 exit_nicely();
13263         }
13264         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13265         PQclear(res);
13266         destroyPQExpBuffer(query);
13267         return last_oid;
13268 }
13269
13270 /*
13271  * findLastBuiltInOid -
13272  * find the last built in oid
13273  *
13274  * For 7.0, we do this by assuming that the last thing that initdb does is to
13275  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13276  * initdb won't be changing anymore, it'll do.
13277  */
13278 static Oid
13279 findLastBuiltinOid_V70(void)
13280 {
13281         PGresult   *res;
13282         int                     ntups;
13283         int                     last_oid;
13284
13285         res = PQexec(g_conn,
13286                                  "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13287         check_sql_result(res, g_conn,
13288                                          "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
13289                                          PGRES_TUPLES_OK);
13290         ntups = PQntuples(res);
13291         if (ntups < 1)
13292         {
13293                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
13294                 exit_nicely();
13295         }
13296         if (ntups > 1)
13297         {
13298                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
13299                 exit_nicely();
13300         }
13301         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13302         PQclear(res);
13303         return last_oid;
13304 }
13305
13306 static void
13307 dumpSequence(Archive *fout, TableInfo *tbinfo)
13308 {
13309         PGresult   *res;
13310         char       *startv,
13311                            *last,
13312                            *incby,
13313                            *maxv = NULL,
13314                            *minv = NULL,
13315                            *cache;
13316         char            bufm[100],
13317                                 bufx[100];
13318         bool            cycled,
13319                                 called;
13320         PQExpBuffer query = createPQExpBuffer();
13321         PQExpBuffer delqry = createPQExpBuffer();
13322         PQExpBuffer labelq = createPQExpBuffer();
13323
13324         /* Make sure we are in proper schema */
13325         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
13326
13327         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13328         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13329
13330         if (g_fout->remoteVersion >= 80400)
13331         {
13332                 appendPQExpBuffer(query,
13333                                                   "SELECT sequence_name, "
13334                                                   "start_value, last_value, increment_by, "
13335                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13336                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13337                                                   "     ELSE max_value "
13338                                                   "END AS max_value, "
13339                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13340                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13341                                                   "     ELSE min_value "
13342                                                   "END AS min_value, "
13343                                                   "cache_value, is_cycled, is_called from %s",
13344                                                   bufx, bufm,
13345                                                   fmtId(tbinfo->dobj.name));
13346         }
13347         else
13348         {
13349                 appendPQExpBuffer(query,
13350                                                   "SELECT sequence_name, "
13351                                                   "0 AS start_value, last_value, increment_by, "
13352                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13353                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13354                                                   "     ELSE max_value "
13355                                                   "END AS max_value, "
13356                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13357                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13358                                                   "     ELSE min_value "
13359                                                   "END AS min_value, "
13360                                                   "cache_value, is_cycled, is_called from %s",
13361                                                   bufx, bufm,
13362                                                   fmtId(tbinfo->dobj.name));
13363         }
13364
13365         res = PQexec(g_conn, query->data);
13366         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13367
13368         if (PQntuples(res) != 1)
13369         {
13370                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13371                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13372                                                                  PQntuples(res)),
13373                                   tbinfo->dobj.name, PQntuples(res));
13374                 exit_nicely();
13375         }
13376
13377         /* Disable this check: it fails if sequence has been renamed */
13378 #ifdef NOT_USED
13379         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13380         {
13381                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13382                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13383                 exit_nicely();
13384         }
13385 #endif
13386
13387         startv = PQgetvalue(res, 0, 1);
13388         last = PQgetvalue(res, 0, 2);
13389         incby = PQgetvalue(res, 0, 3);
13390         if (!PQgetisnull(res, 0, 4))
13391                 maxv = PQgetvalue(res, 0, 4);
13392         if (!PQgetisnull(res, 0, 5))
13393                 minv = PQgetvalue(res, 0, 5);
13394         cache = PQgetvalue(res, 0, 6);
13395         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
13396         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
13397
13398         /*
13399          * The logic we use for restoring sequences is as follows:
13400          *
13401          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
13402          * last_val for start if called is false, else use min_val for start_val).
13403          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
13404          * BY command for it.
13405          *
13406          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
13407          */
13408         if (!dataOnly)
13409         {
13410                 /*
13411                  * DROP must be fully qualified in case same name appears in
13412                  * pg_catalog
13413                  */
13414                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13415                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13416                 appendPQExpBuffer(delqry, "%s;\n",
13417                                                   fmtId(tbinfo->dobj.name));
13418
13419                 resetPQExpBuffer(query);
13420
13421                 if (binary_upgrade)
13422                 {
13423                         binary_upgrade_set_pg_class_oids(query, tbinfo->dobj.catId.oid, false);
13424                         binary_upgrade_set_type_oids_by_rel_oid(query, tbinfo->dobj.catId.oid);
13425                 }
13426
13427                 appendPQExpBuffer(query,
13428                                                   "CREATE SEQUENCE %s\n",
13429                                                   fmtId(tbinfo->dobj.name));
13430
13431                 if (g_fout->remoteVersion >= 80400)
13432                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
13433                 else
13434                 {
13435                         /*
13436                          * Versions before 8.4 did not remember the true start value.  If
13437                          * is_called is false then the sequence has never been incremented
13438                          * so we can use last_val.      Otherwise punt and let it default.
13439                          */
13440                         if (!called)
13441                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
13442                 }
13443
13444                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13445
13446                 if (minv)
13447                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13448                 else
13449                         appendPQExpBuffer(query, "    NO MINVALUE\n");
13450
13451                 if (maxv)
13452                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13453                 else
13454                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
13455
13456                 appendPQExpBuffer(query,
13457                                                   "    CACHE %s%s",
13458                                                   cache, (cycled ? "\n    CYCLE" : ""));
13459
13460                 appendPQExpBuffer(query, ";\n");
13461
13462                 appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13463
13464                 /* binary_upgrade:      no need to clear TOAST table oid */
13465
13466                 if (binary_upgrade)
13467                         binary_upgrade_extension_member(query, &tbinfo->dobj,
13468                                                                                         labelq->data);
13469
13470                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13471                                          tbinfo->dobj.name,
13472                                          tbinfo->dobj.namespace->dobj.name,
13473                                          NULL,
13474                                          tbinfo->rolname,
13475                                          false, "SEQUENCE", SECTION_PRE_DATA,
13476                                          query->data, delqry->data, NULL,
13477                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
13478                                          NULL, NULL);
13479
13480                 /*
13481                  * If the sequence is owned by a table column, emit the ALTER for it
13482                  * as a separate TOC entry immediately following the sequence's own
13483                  * entry.  It's OK to do this rather than using full sorting logic,
13484                  * because the dependency that tells us it's owned will have forced
13485                  * the table to be created first.  We can't just include the ALTER in
13486                  * the TOC entry because it will fail if we haven't reassigned the
13487                  * sequence owner to match the table's owner.
13488                  *
13489                  * We need not schema-qualify the table reference because both
13490                  * sequence and table must be in the same schema.
13491                  */
13492                 if (OidIsValid(tbinfo->owning_tab))
13493                 {
13494                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
13495
13496                         if (owning_tab && owning_tab->dobj.dump)
13497                         {
13498                                 resetPQExpBuffer(query);
13499                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
13500                                                                   fmtId(tbinfo->dobj.name));
13501                                 appendPQExpBuffer(query, " OWNED BY %s",
13502                                                                   fmtId(owning_tab->dobj.name));
13503                                 appendPQExpBuffer(query, ".%s;\n",
13504                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
13505
13506                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13507                                                          tbinfo->dobj.name,
13508                                                          tbinfo->dobj.namespace->dobj.name,
13509                                                          NULL,
13510                                                          tbinfo->rolname,
13511                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
13512                                                          query->data, "", NULL,
13513                                                          &(tbinfo->dobj.dumpId), 1,
13514                                                          NULL, NULL);
13515                         }
13516                 }
13517
13518                 /* Dump Sequence Comments and Security Labels */
13519                 dumpComment(fout, labelq->data,
13520                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13521                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13522                 dumpSecLabel(fout, labelq->data,
13523                                          tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13524                                          tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
13525         }
13526
13527         if (!schemaOnly)
13528         {
13529                 resetPQExpBuffer(query);
13530                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
13531                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
13532                 appendPQExpBuffer(query, ", %s, %s);\n",
13533                                                   last, (called ? "true" : "false"));
13534
13535                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13536                                          tbinfo->dobj.name,
13537                                          tbinfo->dobj.namespace->dobj.name,
13538                                          NULL,
13539                                          tbinfo->rolname,
13540                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
13541                                          query->data, "", NULL,
13542                                          &(tbinfo->dobj.dumpId), 1,
13543                                          NULL, NULL);
13544         }
13545
13546         PQclear(res);
13547
13548         destroyPQExpBuffer(query);
13549         destroyPQExpBuffer(delqry);
13550         destroyPQExpBuffer(labelq);
13551 }
13552
13553 static void
13554 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
13555 {
13556         TableInfo  *tbinfo = tginfo->tgtable;
13557         PQExpBuffer query;
13558         PQExpBuffer delqry;
13559         PQExpBuffer labelq;
13560         char       *tgargs;
13561         size_t          lentgargs;
13562         const char *p;
13563         int                     findx;
13564
13565         if (dataOnly)
13566                 return;
13567
13568         query = createPQExpBuffer();
13569         delqry = createPQExpBuffer();
13570         labelq = createPQExpBuffer();
13571
13572         /*
13573          * DROP must be fully qualified in case same name appears in pg_catalog
13574          */
13575         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
13576                                           fmtId(tginfo->dobj.name));
13577         appendPQExpBuffer(delqry, "ON %s.",
13578                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13579         appendPQExpBuffer(delqry, "%s;\n",
13580                                           fmtId(tbinfo->dobj.name));
13581
13582         if (tginfo->tgdef)
13583         {
13584                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
13585         }
13586         else
13587         {
13588                 if (tginfo->tgisconstraint)
13589                 {
13590                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
13591                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
13592                 }
13593                 else
13594                 {
13595                         appendPQExpBuffer(query, "CREATE TRIGGER ");
13596                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
13597                 }
13598                 appendPQExpBuffer(query, "\n    ");
13599
13600                 /* Trigger type */
13601                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
13602                         appendPQExpBuffer(query, "BEFORE");
13603                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
13604                         appendPQExpBuffer(query, "AFTER");
13605                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
13606                         appendPQExpBuffer(query, "INSTEAD OF");
13607                 else
13608                 {
13609                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
13610                         exit_nicely();
13611                 }
13612
13613                 findx = 0;
13614                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
13615                 {
13616                         appendPQExpBuffer(query, " INSERT");
13617                         findx++;
13618                 }
13619                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
13620                 {
13621                         if (findx > 0)
13622                                 appendPQExpBuffer(query, " OR DELETE");
13623                         else
13624                                 appendPQExpBuffer(query, " DELETE");
13625                         findx++;
13626                 }
13627                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
13628                 {
13629                         if (findx > 0)
13630                                 appendPQExpBuffer(query, " OR UPDATE");
13631                         else
13632                                 appendPQExpBuffer(query, " UPDATE");
13633                         findx++;
13634                 }
13635                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
13636                 {
13637                         if (findx > 0)
13638                                 appendPQExpBuffer(query, " OR TRUNCATE");
13639                         else
13640                                 appendPQExpBuffer(query, " TRUNCATE");
13641                         findx++;
13642                 }
13643                 appendPQExpBuffer(query, " ON %s\n",
13644                                                   fmtId(tbinfo->dobj.name));
13645
13646                 if (tginfo->tgisconstraint)
13647                 {
13648                         if (OidIsValid(tginfo->tgconstrrelid))
13649                         {
13650                                 /* If we are using regclass, name is already quoted */
13651                                 if (g_fout->remoteVersion >= 70300)
13652                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13653                                                                           tginfo->tgconstrrelname);
13654                                 else
13655                                         appendPQExpBuffer(query, "    FROM %s\n    ",
13656                                                                           fmtId(tginfo->tgconstrrelname));
13657                         }
13658                         if (!tginfo->tgdeferrable)
13659                                 appendPQExpBuffer(query, "NOT ");
13660                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
13661                         if (tginfo->tginitdeferred)
13662                                 appendPQExpBuffer(query, "DEFERRED\n");
13663                         else
13664                                 appendPQExpBuffer(query, "IMMEDIATE\n");
13665                 }
13666
13667                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
13668                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
13669                 else
13670                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
13671
13672                 /* In 7.3, result of regproc is already quoted */
13673                 if (g_fout->remoteVersion >= 70300)
13674                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13675                                                           tginfo->tgfname);
13676                 else
13677                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
13678                                                           fmtId(tginfo->tgfname));
13679
13680                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
13681                                                                                   &lentgargs);
13682                 p = tgargs;
13683                 for (findx = 0; findx < tginfo->tgnargs; findx++)
13684                 {
13685                         /* find the embedded null that terminates this trigger argument */
13686                         size_t          tlen = strlen(p);
13687
13688                         if (p + tlen >= tgargs + lentgargs)
13689                         {
13690                                 /* hm, not found before end of bytea value... */
13691                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
13692                                                   tginfo->tgargs,
13693                                                   tginfo->dobj.name,
13694                                                   tbinfo->dobj.name);
13695                                 exit_nicely();
13696                         }
13697
13698                         if (findx > 0)
13699                                 appendPQExpBuffer(query, ", ");
13700                         appendStringLiteralAH(query, p, fout);
13701                         p += tlen + 1;
13702                 }
13703                 free(tgargs);
13704                 appendPQExpBuffer(query, ");\n");
13705         }
13706
13707         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
13708         {
13709                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
13710                                                   fmtId(tbinfo->dobj.name));
13711                 switch (tginfo->tgenabled)
13712                 {
13713                         case 'D':
13714                         case 'f':
13715                                 appendPQExpBuffer(query, "DISABLE");
13716                                 break;
13717                         case 'A':
13718                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
13719                                 break;
13720                         case 'R':
13721                                 appendPQExpBuffer(query, "ENABLE REPLICA");
13722                                 break;
13723                         default:
13724                                 appendPQExpBuffer(query, "ENABLE");
13725                                 break;
13726                 }
13727                 appendPQExpBuffer(query, " TRIGGER %s;\n",
13728                                                   fmtId(tginfo->dobj.name));
13729         }
13730
13731         appendPQExpBuffer(labelq, "TRIGGER %s ",
13732                                           fmtId(tginfo->dobj.name));
13733         appendPQExpBuffer(labelq, "ON %s",
13734                                           fmtId(tbinfo->dobj.name));
13735
13736         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
13737                                  tginfo->dobj.name,
13738                                  tbinfo->dobj.namespace->dobj.name,
13739                                  NULL,
13740                                  tbinfo->rolname, false,
13741                                  "TRIGGER", SECTION_POST_DATA,
13742                                  query->data, delqry->data, NULL,
13743                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
13744                                  NULL, NULL);
13745
13746         dumpComment(fout, labelq->data,
13747                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13748                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
13749
13750         destroyPQExpBuffer(query);
13751         destroyPQExpBuffer(delqry);
13752         destroyPQExpBuffer(labelq);
13753 }
13754
13755 /*
13756  * dumpRule
13757  *              Dump a rule
13758  */
13759 static void
13760 dumpRule(Archive *fout, RuleInfo *rinfo)
13761 {
13762         TableInfo  *tbinfo = rinfo->ruletable;
13763         PQExpBuffer query;
13764         PQExpBuffer cmd;
13765         PQExpBuffer delcmd;
13766         PQExpBuffer labelq;
13767         PGresult   *res;
13768
13769         /* Skip if not to be dumped */
13770         if (!rinfo->dobj.dump || dataOnly)
13771                 return;
13772
13773         /*
13774          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
13775          * we do not want to dump it as a separate object.
13776          */
13777         if (!rinfo->separate)
13778                 return;
13779
13780         /*
13781          * Make sure we are in proper schema.
13782          */
13783         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
13784
13785         query = createPQExpBuffer();
13786         cmd = createPQExpBuffer();
13787         delcmd = createPQExpBuffer();
13788         labelq = createPQExpBuffer();
13789
13790         if (g_fout->remoteVersion >= 70300)
13791         {
13792                 appendPQExpBuffer(query,
13793                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
13794                                                   rinfo->dobj.catId.oid);
13795         }
13796         else
13797         {
13798                 /* Rule name was unique before 7.3 ... */
13799                 appendPQExpBuffer(query,
13800                                                   "SELECT pg_get_ruledef('%s') AS definition",
13801                                                   rinfo->dobj.name);
13802         }
13803
13804         res = PQexec(g_conn, query->data);
13805         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13806
13807         if (PQntuples(res) != 1)
13808         {
13809                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
13810                                   rinfo->dobj.name, tbinfo->dobj.name);
13811                 exit_nicely();
13812         }
13813
13814         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
13815
13816         /*
13817          * Add the command to alter the rules replication firing semantics if it
13818          * differs from the default.
13819          */
13820         if (rinfo->ev_enabled != 'O')
13821         {
13822                 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
13823                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13824                 appendPQExpBuffer(cmd, "%s ",
13825                                                   fmtId(tbinfo->dobj.name));
13826                 switch (rinfo->ev_enabled)
13827                 {
13828                         case 'A':
13829                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
13830                                                                   fmtId(rinfo->dobj.name));
13831                                 break;
13832                         case 'R':
13833                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
13834                                                                   fmtId(rinfo->dobj.name));
13835                                 break;
13836                         case 'D':
13837                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
13838                                                                   fmtId(rinfo->dobj.name));
13839                                 break;
13840                 }
13841         }
13842
13843         /*
13844          * DROP must be fully qualified in case same name appears in pg_catalog
13845          */
13846         appendPQExpBuffer(delcmd, "DROP RULE %s ",
13847                                           fmtId(rinfo->dobj.name));
13848         appendPQExpBuffer(delcmd, "ON %s.",
13849                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13850         appendPQExpBuffer(delcmd, "%s;\n",
13851                                           fmtId(tbinfo->dobj.name));
13852
13853         appendPQExpBuffer(labelq, "RULE %s",
13854                                           fmtId(rinfo->dobj.name));
13855         appendPQExpBuffer(labelq, " ON %s",
13856                                           fmtId(tbinfo->dobj.name));
13857
13858         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
13859                                  rinfo->dobj.name,
13860                                  tbinfo->dobj.namespace->dobj.name,
13861                                  NULL,
13862                                  tbinfo->rolname, false,
13863                                  "RULE", SECTION_POST_DATA,
13864                                  cmd->data, delcmd->data, NULL,
13865                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
13866                                  NULL, NULL);
13867
13868         /* Dump rule comments */
13869         dumpComment(fout, labelq->data,
13870                                 tbinfo->dobj.namespace->dobj.name,
13871                                 tbinfo->rolname,
13872                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
13873
13874         PQclear(res);
13875
13876         destroyPQExpBuffer(query);
13877         destroyPQExpBuffer(cmd);
13878         destroyPQExpBuffer(delcmd);
13879         destroyPQExpBuffer(labelq);
13880 }
13881
13882 /*
13883  * getExtensionMembership --- obtain extension membership data
13884  */
13885 void
13886 getExtensionMembership(ExtensionInfo extinfo[], int numExtensions)
13887 {
13888         PQExpBuffer query;
13889         PGresult   *res;
13890         int                     ntups,
13891                                 i;
13892         int                     i_classid,
13893                                 i_objid,
13894                                 i_refclassid,
13895                                 i_refobjid;
13896         DumpableObject *dobj,
13897                            *refdobj;
13898
13899         /* Nothing to do if no extensions */
13900         if (numExtensions == 0)
13901                 return;
13902
13903         /* Make sure we are in proper schema */
13904         selectSourceSchema("pg_catalog");
13905
13906         query = createPQExpBuffer();
13907
13908         /* refclassid constraint is redundant but may speed the search */
13909         appendPQExpBuffer(query, "SELECT "
13910                                           "classid, objid, refclassid, refobjid "
13911                                           "FROM pg_depend "
13912                                           "WHERE refclassid = 'pg_extension'::regclass "
13913                                           "AND deptype = 'e' "
13914                                           "ORDER BY 3,4");
13915
13916         res = PQexec(g_conn, query->data);
13917         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
13918
13919         ntups = PQntuples(res);
13920
13921         i_classid = PQfnumber(res, "classid");
13922         i_objid = PQfnumber(res, "objid");
13923         i_refclassid = PQfnumber(res, "refclassid");
13924         i_refobjid = PQfnumber(res, "refobjid");
13925
13926         /*
13927          * Since we ordered the SELECT by referenced ID, we can expect that
13928          * multiple entries for the same extension will appear together; this
13929          * saves on searches.
13930          */
13931         refdobj = NULL;
13932
13933         for (i = 0; i < ntups; i++)
13934         {
13935                 CatalogId       objId;
13936                 CatalogId       refobjId;
13937
13938                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
13939                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
13940                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
13941                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
13942
13943                 if (refdobj == NULL ||
13944                         refdobj->catId.tableoid != refobjId.tableoid ||
13945                         refdobj->catId.oid != refobjId.oid)
13946                         refdobj = findObjectByCatalogId(refobjId);
13947
13948                 /*
13949                  * Failure to find objects mentioned in pg_depend is not unexpected,
13950                  * since for example we don't collect info about TOAST tables.
13951                  */
13952                 if (refdobj == NULL)
13953                 {
13954 #ifdef NOT_USED
13955                         fprintf(stderr, "no referenced object %u %u\n",
13956                                         refobjId.tableoid, refobjId.oid);
13957 #endif
13958                         continue;
13959                 }
13960
13961                 dobj = findObjectByCatalogId(objId);
13962
13963                 if (dobj == NULL)
13964                 {
13965 #ifdef NOT_USED
13966                         fprintf(stderr, "no referencing object %u %u\n",
13967                                         objId.tableoid, objId.oid);
13968 #endif
13969                         continue;
13970                 }
13971
13972                 /* Record dependency so that getDependencies needn't repeat this */
13973                 addObjectDependency(dobj, refdobj->dumpId);
13974
13975                 dobj->ext_member = true;
13976
13977                 /*
13978                  * Normally, mark the member object as not to be dumped.  But in
13979                  * binary upgrades, we still dump the members individually, since the
13980                  * idea is to exactly reproduce the database contents rather than
13981                  * replace the extension contents with something different.
13982                  */
13983                 if (!binary_upgrade)
13984                         dobj->dump = false;
13985                 else
13986                         dobj->dump = refdobj->dump;
13987         }
13988
13989         PQclear(res);
13990
13991         /*
13992          * Now identify extension configuration tables and create TableDataInfo
13993          * objects for them, ensuring their data will be dumped even though the
13994          * tables themselves won't be.
13995          *
13996          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
13997          * user data in a configuration table is treated like schema data. This
13998          * seems appropriate since system data in a config table would get
13999          * reloaded by CREATE EXTENSION.
14000          */
14001         for (i = 0; i < numExtensions; i++)
14002         {
14003                 char       *extconfig = extinfo[i].extconfig;
14004                 char       *extcondition = extinfo[i].extcondition;
14005                 char      **extconfigarray = NULL;
14006                 char      **extconditionarray = NULL;
14007                 int                     nconfigitems;
14008                 int                     nconditionitems;
14009
14010                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14011                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14012                         nconfigitems == nconditionitems)
14013                 {
14014                         int                     j;
14015
14016                         for (j = 0; j < nconfigitems; j++)
14017                         {
14018                                 TableInfo  *configtbl;
14019
14020                                 configtbl = findTableByOid(atooid(extconfigarray[j]));
14021                                 if (configtbl && configtbl->dataObj == NULL)
14022                                 {
14023                                         /*
14024                                          * Note: config tables are dumped without OIDs regardless
14025                                          * of the --oids setting.  This is because row filtering
14026                                          * conditions aren't compatible with dumping OIDs.
14027                                          */
14028                                         makeTableDataInfo(configtbl, false);
14029                                         if (strlen(extconditionarray[j]) > 0)
14030                                                 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14031                                 }
14032                         }
14033                 }
14034                 if (extconfigarray)
14035                         free(extconfigarray);
14036                 if (extconditionarray)
14037                         free(extconditionarray);
14038         }
14039
14040         destroyPQExpBuffer(query);
14041 }
14042
14043 /*
14044  * getDependencies --- obtain available dependency data
14045  */
14046 static void
14047 getDependencies(void)
14048 {
14049         PQExpBuffer query;
14050         PGresult   *res;
14051         int                     ntups,
14052                                 i;
14053         int                     i_classid,
14054                                 i_objid,
14055                                 i_refclassid,
14056                                 i_refobjid,
14057                                 i_deptype;
14058         DumpableObject *dobj,
14059                            *refdobj;
14060
14061         /* No dependency info available before 7.3 */
14062         if (g_fout->remoteVersion < 70300)
14063                 return;
14064
14065         if (g_verbose)
14066                 write_msg(NULL, "reading dependency data\n");
14067
14068         /* Make sure we are in proper schema */
14069         selectSourceSchema("pg_catalog");
14070
14071         query = createPQExpBuffer();
14072
14073         /*
14074          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14075          * already processed by getExtensionMembership.
14076          */
14077         appendPQExpBuffer(query, "SELECT "
14078                                           "classid, objid, refclassid, refobjid, deptype "
14079                                           "FROM pg_depend "
14080                                           "WHERE deptype != 'p' AND deptype != 'e' "
14081                                           "ORDER BY 1,2");
14082
14083         res = PQexec(g_conn, query->data);
14084         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
14085
14086         ntups = PQntuples(res);
14087
14088         i_classid = PQfnumber(res, "classid");
14089         i_objid = PQfnumber(res, "objid");
14090         i_refclassid = PQfnumber(res, "refclassid");
14091         i_refobjid = PQfnumber(res, "refobjid");
14092         i_deptype = PQfnumber(res, "deptype");
14093
14094         /*
14095          * Since we ordered the SELECT by referencing ID, we can expect that
14096          * multiple entries for the same object will appear together; this saves
14097          * on searches.
14098          */
14099         dobj = NULL;
14100
14101         for (i = 0; i < ntups; i++)
14102         {
14103                 CatalogId       objId;
14104                 CatalogId       refobjId;
14105                 char            deptype;
14106
14107                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14108                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14109                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14110                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14111                 deptype = *(PQgetvalue(res, i, i_deptype));
14112
14113                 if (dobj == NULL ||
14114                         dobj->catId.tableoid != objId.tableoid ||
14115                         dobj->catId.oid != objId.oid)
14116                         dobj = findObjectByCatalogId(objId);
14117
14118                 /*
14119                  * Failure to find objects mentioned in pg_depend is not unexpected,
14120                  * since for example we don't collect info about TOAST tables.
14121                  */
14122                 if (dobj == NULL)
14123                 {
14124 #ifdef NOT_USED
14125                         fprintf(stderr, "no referencing object %u %u\n",
14126                                         objId.tableoid, objId.oid);
14127 #endif
14128                         continue;
14129                 }
14130
14131                 refdobj = findObjectByCatalogId(refobjId);
14132
14133                 if (refdobj == NULL)
14134                 {
14135 #ifdef NOT_USED
14136                         fprintf(stderr, "no referenced object %u %u\n",
14137                                         refobjId.tableoid, refobjId.oid);
14138 #endif
14139                         continue;
14140                 }
14141
14142                 /*
14143                  * Ordinarily, table rowtypes have implicit dependencies on their
14144                  * tables.      However, for a composite type the implicit dependency goes
14145                  * the other way in pg_depend; which is the right thing for DROP but
14146                  * it doesn't produce the dependency ordering we need. So in that one
14147                  * case, we reverse the direction of the dependency.
14148                  */
14149                 if (deptype == 'i' &&
14150                         dobj->objType == DO_TABLE &&
14151                         refdobj->objType == DO_TYPE)
14152                         addObjectDependency(refdobj, dobj->dumpId);
14153                 else
14154                         /* normal case */
14155                         addObjectDependency(dobj, refdobj->dumpId);
14156         }
14157
14158         PQclear(res);
14159
14160         destroyPQExpBuffer(query);
14161 }
14162
14163
14164 /*
14165  * selectSourceSchema - make the specified schema the active search path
14166  * in the source database.
14167  *
14168  * NB: pg_catalog is explicitly searched after the specified schema;
14169  * so user names are only qualified if they are cross-schema references,
14170  * and system names are only qualified if they conflict with a user name
14171  * in the current schema.
14172  *
14173  * Whenever the selected schema is not pg_catalog, be careful to qualify
14174  * references to system catalogs and types in our emitted commands!
14175  */
14176 static void
14177 selectSourceSchema(const char *schemaName)
14178 {
14179         static char *curSchemaName = NULL;
14180         PQExpBuffer query;
14181
14182         /* Not relevant if fetching from pre-7.3 DB */
14183         if (g_fout->remoteVersion < 70300)
14184                 return;
14185         /* Ignore null schema names */
14186         if (schemaName == NULL || *schemaName == '\0')
14187                 return;
14188         /* Optimize away repeated selection of same schema */
14189         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
14190                 return;
14191
14192         query = createPQExpBuffer();
14193         appendPQExpBuffer(query, "SET search_path = %s",
14194                                           fmtId(schemaName));
14195         if (strcmp(schemaName, "pg_catalog") != 0)
14196                 appendPQExpBuffer(query, ", pg_catalog");
14197
14198         do_sql_command(g_conn, query->data);
14199
14200         destroyPQExpBuffer(query);
14201         if (curSchemaName)
14202                 free(curSchemaName);
14203         curSchemaName = pg_strdup(schemaName);
14204 }
14205
14206 /*
14207  * getFormattedTypeName - retrieve a nicely-formatted type name for the
14208  * given type name.
14209  *
14210  * NB: in 7.3 and up the result may depend on the currently-selected
14211  * schema; this is why we don't try to cache the names.
14212  */
14213 static char *
14214 getFormattedTypeName(Oid oid, OidOptions opts)
14215 {
14216         char       *result;
14217         PQExpBuffer query;
14218         PGresult   *res;
14219         int                     ntups;
14220
14221         if (oid == 0)
14222         {
14223                 if ((opts & zeroAsOpaque) != 0)
14224                         return pg_strdup(g_opaque_type);
14225                 else if ((opts & zeroAsAny) != 0)
14226                         return pg_strdup("'any'");
14227                 else if ((opts & zeroAsStar) != 0)
14228                         return pg_strdup("*");
14229                 else if ((opts & zeroAsNone) != 0)
14230                         return pg_strdup("NONE");
14231         }
14232
14233         query = createPQExpBuffer();
14234         if (g_fout->remoteVersion >= 70300)
14235         {
14236                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
14237                                                   oid);
14238         }
14239         else if (g_fout->remoteVersion >= 70100)
14240         {
14241                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
14242                                                   oid);
14243         }
14244         else
14245         {
14246                 appendPQExpBuffer(query, "SELECT typname "
14247                                                   "FROM pg_type "
14248                                                   "WHERE oid = '%u'::oid",
14249                                                   oid);
14250         }
14251
14252         res = PQexec(g_conn, query->data);
14253         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
14254
14255         /* Expecting a single result only */
14256         ntups = PQntuples(res);
14257         if (ntups != 1)
14258         {
14259                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
14260                                                            "query returned %d rows instead of one: %s\n",
14261                                                                  ntups),
14262                                   ntups, query->data);
14263                 exit_nicely();
14264         }
14265
14266         if (g_fout->remoteVersion >= 70100)
14267         {
14268                 /* already quoted */
14269                 result = pg_strdup(PQgetvalue(res, 0, 0));
14270         }
14271         else
14272         {
14273                 /* may need to quote it */
14274                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
14275         }
14276
14277         PQclear(res);
14278         destroyPQExpBuffer(query);
14279
14280         return result;
14281 }
14282
14283 /*
14284  * myFormatType --- local implementation of format_type for use with 7.0.
14285  */
14286 static char *
14287 myFormatType(const char *typname, int32 typmod)
14288 {
14289         char       *result;
14290         bool            isarray = false;
14291         PQExpBuffer buf = createPQExpBuffer();
14292
14293         /* Handle array types */
14294         if (typname[0] == '_')
14295         {
14296                 isarray = true;
14297                 typname++;
14298         }
14299
14300         /* Show lengths on bpchar and varchar */
14301         if (!strcmp(typname, "bpchar"))
14302         {
14303                 int                     len = (typmod - VARHDRSZ);
14304
14305                 appendPQExpBuffer(buf, "character");
14306                 if (len > 1)
14307                         appendPQExpBuffer(buf, "(%d)",
14308                                                           typmod - VARHDRSZ);
14309         }
14310         else if (!strcmp(typname, "varchar"))
14311         {
14312                 appendPQExpBuffer(buf, "character varying");
14313                 if (typmod != -1)
14314                         appendPQExpBuffer(buf, "(%d)",
14315                                                           typmod - VARHDRSZ);
14316         }
14317         else if (!strcmp(typname, "numeric"))
14318         {
14319                 appendPQExpBuffer(buf, "numeric");
14320                 if (typmod != -1)
14321                 {
14322                         int32           tmp_typmod;
14323                         int                     precision;
14324                         int                     scale;
14325
14326                         tmp_typmod = typmod - VARHDRSZ;
14327                         precision = (tmp_typmod >> 16) & 0xffff;
14328                         scale = tmp_typmod & 0xffff;
14329                         appendPQExpBuffer(buf, "(%d,%d)",
14330                                                           precision, scale);
14331                 }
14332         }
14333
14334         /*
14335          * char is an internal single-byte data type; Let's make sure we force it
14336          * through with quotes. - thomas 1998-12-13
14337          */
14338         else if (strcmp(typname, "char") == 0)
14339                 appendPQExpBuffer(buf, "\"char\"");
14340         else
14341                 appendPQExpBuffer(buf, "%s", fmtId(typname));
14342
14343         /* Append array qualifier for array types */
14344         if (isarray)
14345                 appendPQExpBuffer(buf, "[]");
14346
14347         result = pg_strdup(buf->data);
14348         destroyPQExpBuffer(buf);
14349
14350         return result;
14351 }
14352
14353 /*
14354  * fmtQualifiedId - convert a qualified name to the proper format for
14355  * the source database.
14356  *
14357  * Like fmtId, use the result before calling again.
14358  */
14359 static const char *
14360 fmtQualifiedId(const char *schema, const char *id)
14361 {
14362         static PQExpBuffer id_return = NULL;
14363
14364         if (id_return)                          /* first time through? */
14365                 resetPQExpBuffer(id_return);
14366         else
14367                 id_return = createPQExpBuffer();
14368
14369         /* Suppress schema name if fetching from pre-7.3 DB */
14370         if (g_fout->remoteVersion >= 70300 && schema && *schema)
14371         {
14372                 appendPQExpBuffer(id_return, "%s.",
14373                                                   fmtId(schema));
14374         }
14375         appendPQExpBuffer(id_return, "%s",
14376                                           fmtId(id));
14377
14378         return id_return->data;
14379 }
14380
14381 /*
14382  * Return a column list clause for the given relation.
14383  *
14384  * Special case: if there are no undropped columns in the relation, return
14385  * "", not an invalid "()" column list.
14386  */
14387 static const char *
14388 fmtCopyColumnList(const TableInfo *ti)
14389 {
14390         static PQExpBuffer q = NULL;
14391         int                     numatts = ti->numatts;
14392         char      **attnames = ti->attnames;
14393         bool       *attisdropped = ti->attisdropped;
14394         bool            needComma;
14395         int                     i;
14396
14397         if (q)                                          /* first time through? */
14398                 resetPQExpBuffer(q);
14399         else
14400                 q = createPQExpBuffer();
14401
14402         appendPQExpBuffer(q, "(");
14403         needComma = false;
14404         for (i = 0; i < numatts; i++)
14405         {
14406                 if (attisdropped[i])
14407                         continue;
14408                 if (needComma)
14409                         appendPQExpBuffer(q, ", ");
14410                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
14411                 needComma = true;
14412         }
14413
14414         if (!needComma)
14415                 return "";                              /* no undropped columns */
14416
14417         appendPQExpBuffer(q, ")");
14418         return q->data;
14419 }
14420
14421 /*
14422  * Convenience subroutine to execute a SQL command and check for
14423  * COMMAND_OK status.
14424  */
14425 static void
14426 do_sql_command(PGconn *conn, const char *query)
14427 {
14428         PGresult   *res;
14429
14430         res = PQexec(conn, query);
14431         check_sql_result(res, conn, query, PGRES_COMMAND_OK);
14432         PQclear(res);
14433 }
14434
14435 /*
14436  * Convenience subroutine to verify a SQL command succeeded,
14437  * and exit with a useful error message if not.
14438  */
14439 static void
14440 check_sql_result(PGresult *res, PGconn *conn, const char *query,
14441                                  ExecStatusType expected)
14442 {
14443         const char *err;
14444
14445         if (res && PQresultStatus(res) == expected)
14446                 return;                                 /* A-OK */
14447
14448         write_msg(NULL, "SQL command failed\n");
14449         if (res)
14450                 err = PQresultErrorMessage(res);
14451         else
14452                 err = PQerrorMessage(conn);
14453         write_msg(NULL, "Error message from server: %s", err);
14454         write_msg(NULL, "The command was: %s\n", query);
14455         exit_nicely();
14456 }