]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Add parallel pg_dump option.
[postgresql] / src / bin / pg_dump / pg_dump.c
1 /*-------------------------------------------------------------------------
2  *
3  * pg_dump.c
4  *        pg_dump is a utility for dumping out a postgres database
5  *        into a script file.
6  *
7  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  *      pg_dump will read the system catalogs in a database and dump out a
11  *      script that reproduces the schema in terms of SQL that is understood
12  *      by PostgreSQL
13  *
14  *      Note that pg_dump runs in a transaction-snapshot mode transaction,
15  *      so it sees a consistent snapshot of the database including system
16  *      catalogs. However, it relies in part on various specialized backend
17  *      functions like pg_get_indexdef(), and those things tend to run on
18  *      SnapshotNow time, ie they look at the currently committed state.  So
19  *      it is possible to get 'cache lookup failed' error if someone
20  *      performs DDL changes while a dump is happening. The window for this
21  *      sort of thing is from the acquisition of the transaction snapshot to
22  *      getSchemaData() (when pg_dump acquires AccessShareLock on every
23  *      table it intends to dump). It isn't very large, but it can happen.
24  *
25  *      http://archives.postgresql.org/pgsql-bugs/2010-02/msg00187.php
26  *
27  * IDENTIFICATION
28  *        src/bin/pg_dump/pg_dump.c
29  *
30  *-------------------------------------------------------------------------
31  */
32
33 #include "postgres_fe.h"
34
35 #include <unistd.h>
36 #include <ctype.h>
37 #ifdef ENABLE_NLS
38 #include <locale.h>
39 #endif
40 #ifdef HAVE_TERMIOS_H
41 #include <termios.h>
42 #endif
43
44 #include "getopt_long.h"
45
46 #include "access/attnum.h"
47 #include "access/sysattr.h"
48 #include "access/transam.h"
49 #include "catalog/pg_cast.h"
50 #include "catalog/pg_class.h"
51 #include "catalog/pg_default_acl.h"
52 #include "catalog/pg_event_trigger.h"
53 #include "catalog/pg_largeobject.h"
54 #include "catalog/pg_largeobject_metadata.h"
55 #include "catalog/pg_proc.h"
56 #include "catalog/pg_trigger.h"
57 #include "catalog/pg_type.h"
58 #include "libpq/libpq-fs.h"
59
60 #include "pg_backup_archiver.h"
61 #include "pg_backup_db.h"
62 #include "dumputils.h"
63
64 extern char *optarg;
65 extern int      optind,
66                         opterr;
67
68
69 typedef struct
70 {
71         const char *descr;                      /* comment for an object */
72         Oid                     classoid;               /* object class (catalog OID) */
73         Oid                     objoid;                 /* object OID */
74         int                     objsubid;               /* subobject (table column #) */
75 } CommentItem;
76
77 typedef struct
78 {
79         const char *provider;           /* label provider of this security label */
80         const char *label;                      /* security label for an object */
81         Oid                     classoid;               /* object class (catalog OID) */
82         Oid                     objoid;                 /* object OID */
83         int                     objsubid;               /* subobject (table column #) */
84 } SecLabelItem;
85
86 /* global decls */
87 bool            g_verbose;                      /* User wants verbose narration of our
88                                                                  * activities. */
89
90 /* various user-settable parameters */
91 bool            schemaOnly;
92 bool            dataOnly;
93 int                     dumpSections;           /* bitmask of chosen sections */
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 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
119 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
120
121 /* default, if no "inclusion" switches appear, is to dump everything */
122 static bool include_everything = true;
123
124 char            g_opaque_type[10];      /* name for the opaque type */
125
126 /* placeholders for the delimiters for comments */
127 char            g_comment_start[10];
128 char            g_comment_end[10];
129
130 static const CatalogId nilCatalogId = {0, 0};
131
132 /* flags for various command-line long options */
133 static int      binary_upgrade = 0;
134 static int      disable_dollar_quoting = 0;
135 static int      dump_inserts = 0;
136 static int      column_inserts = 0;
137 static int      no_security_labels = 0;
138 static int      no_synchronized_snapshots = 0;
139 static int      no_unlogged_table_data = 0;
140 static int      serializable_deferrable = 0;
141
142
143 static void help(const char *progname);
144 static void setup_connection(Archive *AH, const char *dumpencoding,
145                                  char *use_role);
146 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
147 static void expand_schema_name_patterns(Archive *fout,
148                                                         SimpleStringList *patterns,
149                                                         SimpleOidList *oids);
150 static void expand_table_name_patterns(Archive *fout,
151                                                    SimpleStringList *patterns,
152                                                    SimpleOidList *oids);
153 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
154 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
155 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
156 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
157 static void dumpComment(Archive *fout, const char *target,
158                         const char *namespace, const char *owner,
159                         CatalogId catalogId, int subid, DumpId dumpId);
160 static int findComments(Archive *fout, Oid classoid, Oid objoid,
161                          CommentItem **items);
162 static int      collectComments(Archive *fout, CommentItem **items);
163 static void dumpSecLabel(Archive *fout, const char *target,
164                          const char *namespace, const char *owner,
165                          CatalogId catalogId, int subid, DumpId dumpId);
166 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
167                           SecLabelItem **items);
168 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
169 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
170 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
171 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
172 static void dumpType(Archive *fout, TypeInfo *tyinfo);
173 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
174 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
177 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
179 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
180 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
181 static void dumpFunc(Archive *fout, FuncInfo *finfo);
182 static void dumpCast(Archive *fout, CastInfo *cast);
183 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
184 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
185 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
186 static void dumpCollation(Archive *fout, CollInfo *convinfo);
187 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
188 static void dumpRule(Archive *fout, RuleInfo *rinfo);
189 static void dumpAgg(Archive *fout, AggInfo *agginfo);
190 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
191 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
192 static void dumpTable(Archive *fout, TableInfo *tbinfo);
193 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
194 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
195 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
196 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
197 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
198 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
199 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
200 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
201 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
202 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
203 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
204 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
205 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
206 static void dumpUserMappings(Archive *fout,
207                                  const char *servername, const char *namespace,
208                                  const char *owner, CatalogId catalogId, DumpId dumpId);
209 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
210
211 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
212                 const char *type, const char *name, const char *subname,
213                 const char *tag, const char *nspname, const char *owner,
214                 const char *acls);
215
216 static void getDependencies(Archive *fout);
217 static void BuildArchiveDependencies(Archive *fout);
218 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
219                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
220
221 static DumpableObject *createBoundaryObjects(void);
222 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
223                                                 DumpableObject *boundaryObjs);
224
225 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
226 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
227 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
228 static void buildMatViewRefreshDependencies(Archive *fout);
229 static void getTableDataFKConstraints(void);
230 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
231 static char *format_function_arguments_old(Archive *fout,
232                                                           FuncInfo *finfo, int nallargs,
233                                                           char **allargtypes,
234                                                           char **argmodes,
235                                                           char **argnames);
236 static char *format_function_signature(Archive *fout,
237                                                   FuncInfo *finfo, bool honor_quotes);
238 static const char *convertRegProcReference(Archive *fout,
239                                                 const char *proc);
240 static const char *convertOperatorReference(Archive *fout, const char *opr);
241 static const char *convertTSFunction(Archive *fout, Oid funcOid);
242 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
243 static Oid      findLastBuiltinOid_V70(Archive *fout);
244 static void selectSourceSchema(Archive *fout, const char *schemaName);
245 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
246 static char *myFormatType(const char *typname, int32 typmod);
247 static void getBlobs(Archive *fout);
248 static void dumpBlob(Archive *fout, BlobInfo *binfo);
249 static int      dumpBlobs(Archive *fout, void *arg);
250 static void dumpDatabase(Archive *AH);
251 static void dumpEncoding(Archive *AH);
252 static void dumpStdStrings(Archive *AH);
253 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
254                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
255 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
256                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
257 static void binary_upgrade_set_pg_class_oids(Archive *fout,
258                                                                  PQExpBuffer upgrade_buffer,
259                                                                  Oid pg_class_oid, bool is_index);
260 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
261                                                                 DumpableObject *dobj,
262                                                                 const char *objlabel);
263 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
264 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
265 static char *get_synchronized_snapshot(Archive *fout);
266 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
267 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
268
269
270 int
271 main(int argc, char **argv)
272 {
273         int                     c;
274         const char *filename = NULL;
275         const char *format = "p";
276         const char *dbname = NULL;
277         const char *pghost = NULL;
278         const char *pgport = NULL;
279         const char *username = NULL;
280         const char *dumpencoding = NULL;
281         bool            oids = false;
282         TableInfo  *tblinfo;
283         int                     numTables;
284         DumpableObject **dobjs;
285         int                     numObjs;
286         DumpableObject *boundaryObjs;
287         int                     i;
288         int                     numWorkers = 1;
289         enum trivalue prompt_password = TRI_DEFAULT;
290         int                     compressLevel = -1;
291         int                     plainText = 0;
292         int                     outputClean = 0;
293         int                     outputCreateDB = 0;
294         bool            outputBlobs = false;
295         int                     outputNoOwner = 0;
296         char       *outputSuperuser = NULL;
297         char       *use_role = NULL;
298         int                     my_version;
299         int                     optindex;
300         RestoreOptions *ropt;
301         ArchiveFormat archiveFormat = archUnknown;
302         ArchiveMode archiveMode;
303         Archive    *fout;                       /* the script file */
304
305         static int      disable_triggers = 0;
306         static int      outputNoTablespaces = 0;
307         static int      use_setsessauth = 0;
308
309         static struct option long_options[] = {
310                 {"data-only", no_argument, NULL, 'a'},
311                 {"blobs", no_argument, NULL, 'b'},
312                 {"clean", no_argument, NULL, 'c'},
313                 {"create", no_argument, NULL, 'C'},
314                 {"dbname", required_argument, NULL, 'd'},
315                 {"file", required_argument, NULL, 'f'},
316                 {"format", required_argument, NULL, 'F'},
317                 {"host", required_argument, NULL, 'h'},
318                 {"ignore-version", no_argument, NULL, 'i'},
319                 {"jobs", 1, NULL, 'j'},
320                 {"no-reconnect", no_argument, NULL, 'R'},
321                 {"oids", no_argument, NULL, 'o'},
322                 {"no-owner", no_argument, NULL, 'O'},
323                 {"port", required_argument, NULL, 'p'},
324                 {"schema", required_argument, NULL, 'n'},
325                 {"exclude-schema", required_argument, NULL, 'N'},
326                 {"schema-only", no_argument, NULL, 's'},
327                 {"superuser", required_argument, NULL, 'S'},
328                 {"table", required_argument, NULL, 't'},
329                 {"exclude-table", required_argument, NULL, 'T'},
330                 {"no-password", no_argument, NULL, 'w'},
331                 {"password", no_argument, NULL, 'W'},
332                 {"username", required_argument, NULL, 'U'},
333                 {"verbose", no_argument, NULL, 'v'},
334                 {"no-privileges", no_argument, NULL, 'x'},
335                 {"no-acl", no_argument, NULL, 'x'},
336                 {"compress", required_argument, NULL, 'Z'},
337                 {"encoding", required_argument, NULL, 'E'},
338                 {"help", no_argument, NULL, '?'},
339                 {"version", no_argument, NULL, 'V'},
340
341                 /*
342                  * the following options don't have an equivalent short option letter
343                  */
344                 {"attribute-inserts", no_argument, &column_inserts, 1},
345                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
346                 {"column-inserts", no_argument, &column_inserts, 1},
347                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
348                 {"disable-triggers", no_argument, &disable_triggers, 1},
349                 {"exclude-table-data", required_argument, NULL, 4},
350                 {"inserts", no_argument, &dump_inserts, 1},
351                 {"lock-wait-timeout", required_argument, NULL, 2},
352                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
353                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
354                 {"role", required_argument, NULL, 3},
355                 {"section", required_argument, NULL, 5},
356                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
357                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
358                 {"no-security-labels", no_argument, &no_security_labels, 1},
359                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
360                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
361
362                 {NULL, 0, NULL, 0}
363         };
364
365         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
366
367         /*
368          * Initialize what we need for parallel execution, especially for thread
369          * support on Windows.
370          */
371         init_parallel_dump_utils();
372
373         g_verbose = false;
374
375         strcpy(g_comment_start, "-- ");
376         g_comment_end[0] = '\0';
377         strcpy(g_opaque_type, "opaque");
378
379         dataOnly = schemaOnly = false;
380         dumpSections = DUMP_UNSECTIONED;
381         lockWaitTimeout = NULL;
382
383         progname = get_progname(argv[0]);
384
385         /* Set default options based on progname */
386         if (strcmp(progname, "pg_backup") == 0)
387                 format = "c";
388
389         if (argc > 1)
390         {
391                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
392                 {
393                         help(progname);
394                         exit_nicely(0);
395                 }
396                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
397                 {
398                         puts("pg_dump (PostgreSQL) " PG_VERSION);
399                         exit_nicely(0);
400                 }
401         }
402
403         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
404                                                         long_options, &optindex)) != -1)
405         {
406                 switch (c)
407                 {
408                         case 'a':                       /* Dump data only */
409                                 dataOnly = true;
410                                 break;
411
412                         case 'b':                       /* Dump blobs */
413                                 outputBlobs = true;
414                                 break;
415
416                         case 'c':                       /* clean (i.e., drop) schema prior to create */
417                                 outputClean = 1;
418                                 break;
419
420                         case 'C':                       /* Create DB */
421                                 outputCreateDB = 1;
422                                 break;
423
424                         case 'd':                       /* database name */
425                                 dbname = pg_strdup(optarg);
426                                 break;
427
428                         case 'E':                       /* Dump encoding */
429                                 dumpencoding = pg_strdup(optarg);
430                                 break;
431
432                         case 'f':
433                                 filename = pg_strdup(optarg);
434                                 break;
435
436                         case 'F':
437                                 format = pg_strdup(optarg);
438                                 break;
439
440                         case 'h':                       /* server host */
441                                 pghost = pg_strdup(optarg);
442                                 break;
443
444                         case 'i':
445                                 /* ignored, deprecated option */
446                                 break;
447
448                         case 'j':                       /* number of dump jobs */
449                                 numWorkers = atoi(optarg);
450                                 break;
451
452                         case 'n':                       /* include schema(s) */
453                                 simple_string_list_append(&schema_include_patterns, optarg);
454                                 include_everything = false;
455                                 break;
456
457                         case 'N':                       /* exclude schema(s) */
458                                 simple_string_list_append(&schema_exclude_patterns, optarg);
459                                 break;
460
461                         case 'o':                       /* Dump oids */
462                                 oids = true;
463                                 break;
464
465                         case 'O':                       /* Don't reconnect to match owner */
466                                 outputNoOwner = 1;
467                                 break;
468
469                         case 'p':                       /* server port */
470                                 pgport = pg_strdup(optarg);
471                                 break;
472
473                         case 'R':
474                                 /* no-op, still accepted for backwards compatibility */
475                                 break;
476
477                         case 's':                       /* dump schema only */
478                                 schemaOnly = true;
479                                 break;
480
481                         case 'S':                       /* Username for superuser in plain text output */
482                                 outputSuperuser = pg_strdup(optarg);
483                                 break;
484
485                         case 't':                       /* include table(s) */
486                                 simple_string_list_append(&table_include_patterns, optarg);
487                                 include_everything = false;
488                                 break;
489
490                         case 'T':                       /* exclude table(s) */
491                                 simple_string_list_append(&table_exclude_patterns, optarg);
492                                 break;
493
494                         case 'U':
495                                 username = pg_strdup(optarg);
496                                 break;
497
498                         case 'v':                       /* verbose */
499                                 g_verbose = true;
500                                 break;
501
502                         case 'w':
503                                 prompt_password = TRI_NO;
504                                 break;
505
506                         case 'W':
507                                 prompt_password = TRI_YES;
508                                 break;
509
510                         case 'x':                       /* skip ACL dump */
511                                 aclsSkip = true;
512                                 break;
513
514                         case 'Z':                       /* Compression Level */
515                                 compressLevel = atoi(optarg);
516                                 break;
517
518                         case 0:
519                                 /* This covers the long options. */
520                                 break;
521
522                         case 2:                         /* lock-wait-timeout */
523                                 lockWaitTimeout = pg_strdup(optarg);
524                                 break;
525
526                         case 3:                         /* SET ROLE */
527                                 use_role = pg_strdup(optarg);
528                                 break;
529
530                         case 4:                         /* exclude table(s) data */
531                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
532                                 break;
533
534                         case 5:                         /* section */
535                                 set_dump_section(optarg, &dumpSections);
536                                 break;
537
538                         default:
539                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
540                                 exit_nicely(1);
541                 }
542         }
543
544         /*
545          * Non-option argument specifies database name as long as it wasn't
546          * already specified with -d / --dbname
547          */
548         if (optind < argc && dbname == NULL)
549                 dbname = argv[optind++];
550
551         /* Complain if any arguments remain */
552         if (optind < argc)
553         {
554                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
555                                 progname, argv[optind]);
556                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
557                                 progname);
558                 exit_nicely(1);
559         }
560
561         /* --column-inserts implies --inserts */
562         if (column_inserts)
563                 dump_inserts = 1;
564
565         if (dataOnly && schemaOnly)
566                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
567
568         if (dataOnly && outputClean)
569                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
570
571         if (dump_inserts && oids)
572         {
573                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
574                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
575                 exit_nicely(1);
576         }
577
578         /* Identify archive format to emit */
579         archiveFormat = parseArchiveFormat(format, &archiveMode);
580
581         /* archiveFormat specific setup */
582         if (archiveFormat == archNull)
583                 plainText = 1;
584
585         /* Custom and directory formats are compressed by default, others not */
586         if (compressLevel == -1)
587         {
588                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
589                         compressLevel = Z_DEFAULT_COMPRESSION;
590                 else
591                         compressLevel = 0;
592         }
593
594         /*
595          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
596          * parallel jobs because that's the maximum limit for the
597          * WaitForMultipleObjects() call.
598          */
599         if (numWorkers <= 0
600 #ifdef WIN32
601                 || numWorkers > MAXIMUM_WAIT_OBJECTS
602 #endif
603                 )
604                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
605
606         /* Parallel backup only in the directory archive format so far */
607         if (archiveFormat != archDirectory && numWorkers > 1)
608                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
609
610         /* Open the output file */
611         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
612                                                  setupDumpWorker);
613
614         /* Register the cleanup hook */
615         on_exit_close_archive(fout);
616
617         if (fout == NULL)
618                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
619
620         /* Let the archiver know how noisy to be */
621         fout->verbose = g_verbose;
622
623         my_version = parse_version(PG_VERSION);
624         if (my_version < 0)
625                 exit_horribly(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
626
627         /*
628          * We allow the server to be back to 7.0, and up to any minor release of
629          * our own major version.  (See also version check in pg_dumpall.c.)
630          */
631         fout->minRemoteVersion = 70000;
632         fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
633
634         fout->numWorkers = numWorkers;
635
636         /*
637          * Open the database using the Archiver, so it knows about it. Errors mean
638          * death.
639          */
640         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
641         setup_connection(fout, dumpencoding, use_role);
642
643         /*
644          * Disable security label support if server version < v9.1.x (prevents
645          * access to nonexistent pg_seclabel catalog)
646          */
647         if (fout->remoteVersion < 90100)
648                 no_security_labels = 1;
649
650         /*
651          * When running against 9.0 or later, check if we are in recovery mode,
652          * which means we are on a hot standby.
653          */
654         if (fout->remoteVersion >= 90000)
655         {
656                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
657
658                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
659                 {
660                         /*
661                          * On hot standby slaves, never try to dump unlogged table data,
662                          * since it will just throw an error.
663                          */
664                         no_unlogged_table_data = true;
665                 }
666                 PQclear(res);
667         }
668
669         /* Select the appropriate subquery to convert user IDs to names */
670         if (fout->remoteVersion >= 80100)
671                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
672         else if (fout->remoteVersion >= 70300)
673                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
674         else
675                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
676
677         /* check the version for the synchronized snapshots feature */
678         if (numWorkers > 1 && fout->remoteVersion < 90200
679                 && !no_synchronized_snapshots)
680                 exit_horribly(NULL,
681                           "No synchronized snapshots available in this server version.\n"
682                            "Run with --no-synchronized-snapshots instead if you do not\n"
683                                           "need synchronized snapshots.\n");
684
685         /* Find the last built-in OID, if needed */
686         if (fout->remoteVersion < 70300)
687         {
688                 if (fout->remoteVersion >= 70100)
689                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
690                                                                                                   PQdb(GetConnection(fout)));
691                 else
692                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
693                 if (g_verbose)
694                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
695         }
696
697         /* Expand schema selection patterns into OID lists */
698         if (schema_include_patterns.head != NULL)
699         {
700                 expand_schema_name_patterns(fout, &schema_include_patterns,
701                                                                         &schema_include_oids);
702                 if (schema_include_oids.head == NULL)
703                         exit_horribly(NULL, "No matching schemas were found\n");
704         }
705         expand_schema_name_patterns(fout, &schema_exclude_patterns,
706                                                                 &schema_exclude_oids);
707         /* non-matching exclusion patterns aren't an error */
708
709         /* Expand table selection patterns into OID lists */
710         if (table_include_patterns.head != NULL)
711         {
712                 expand_table_name_patterns(fout, &table_include_patterns,
713                                                                    &table_include_oids);
714                 if (table_include_oids.head == NULL)
715                         exit_horribly(NULL, "No matching tables were found\n");
716         }
717         expand_table_name_patterns(fout, &table_exclude_patterns,
718                                                            &table_exclude_oids);
719
720         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
721                                                            &tabledata_exclude_oids);
722
723         /* non-matching exclusion patterns aren't an error */
724
725         /*
726          * Dumping blobs is now default unless we saw an inclusion switch or -s
727          * ... but even if we did see one of these, -b turns it back on.
728          */
729         if (include_everything && !schemaOnly)
730                 outputBlobs = true;
731
732         /*
733          * Now scan the database and create DumpableObject structs for all the
734          * objects we intend to dump.
735          */
736         tblinfo = getSchemaData(fout, &numTables);
737
738         if (fout->remoteVersion < 80400)
739                 guessConstraintInheritance(tblinfo, numTables);
740
741         if (!schemaOnly)
742         {
743                 getTableData(tblinfo, numTables, oids);
744                 buildMatViewRefreshDependencies(fout);
745                 if (dataOnly)
746                         getTableDataFKConstraints();
747         }
748
749         if (outputBlobs)
750                 getBlobs(fout);
751
752         /*
753          * Collect dependency data to assist in ordering the objects.
754          */
755         getDependencies(fout);
756
757         /* Lastly, create dummy objects to represent the section boundaries */
758         boundaryObjs = createBoundaryObjects();
759
760         /* Get pointers to all the known DumpableObjects */
761         getDumpableObjects(&dobjs, &numObjs);
762
763         /*
764          * Add dummy dependencies to enforce the dump section ordering.
765          */
766         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
767
768         /*
769          * Sort the objects into a safe dump order (no forward references).
770          *
771          * In 7.3 or later, we can rely on dependency information to help us
772          * determine a safe order, so the initial sort is mostly for cosmetic
773          * purposes: we sort by name to ensure that logically identical schemas
774          * will dump identically.  Before 7.3 we don't have dependencies and we
775          * use OID ordering as an (unreliable) guide to creation order.
776          */
777         if (fout->remoteVersion >= 70300)
778                 sortDumpableObjectsByTypeName(dobjs, numObjs);
779         else
780                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
781
782         /* If we do a parallel dump, we want the largest tables to go first */
783         if (archiveFormat == archDirectory && numWorkers > 1)
784                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
785
786         sortDumpableObjects(dobjs, numObjs,
787                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
788
789         /*
790          * Create archive TOC entries for all the objects to be dumped, in a safe
791          * order.
792          */
793
794         /* First the special ENCODING and STDSTRINGS entries. */
795         dumpEncoding(fout);
796         dumpStdStrings(fout);
797
798         /* The database item is always next, unless we don't want it at all */
799         if (include_everything && !dataOnly)
800                 dumpDatabase(fout);
801
802         /* Now the rearrangeable objects. */
803         for (i = 0; i < numObjs; i++)
804                 dumpDumpableObject(fout, dobjs[i]);
805
806         /*
807          * Set up options info to ensure we dump what we want.
808          */
809         ropt = NewRestoreOptions();
810         ropt->filename = filename;
811         ropt->dropSchema = outputClean;
812         ropt->dataOnly = dataOnly;
813         ropt->schemaOnly = schemaOnly;
814         ropt->dumpSections = dumpSections;
815         ropt->aclsSkip = aclsSkip;
816         ropt->superuser = outputSuperuser;
817         ropt->createDB = outputCreateDB;
818         ropt->noOwner = outputNoOwner;
819         ropt->noTablespace = outputNoTablespaces;
820         ropt->disable_triggers = disable_triggers;
821         ropt->use_setsessauth = use_setsessauth;
822
823         if (compressLevel == -1)
824                 ropt->compression = 0;
825         else
826                 ropt->compression = compressLevel;
827
828         ropt->suppressDumpWarnings = true;      /* We've already shown them */
829
830         SetArchiveRestoreOptions(fout, ropt);
831
832         /*
833          * The archive's TOC entries are now marked as to which ones will actually
834          * be output, so we can set up their dependency lists properly. This isn't
835          * necessary for plain-text output, though.
836          */
837         if (!plainText)
838                 BuildArchiveDependencies(fout);
839
840         /*
841          * And finally we can do the actual output.
842          *
843          * Note: for non-plain-text output formats, the output file is written
844          * inside CloseArchive().  This is, um, bizarre; but not worth changing
845          * right now.
846          */
847         if (plainText)
848                 RestoreArchive(fout);
849
850         CloseArchive(fout);
851
852         exit_nicely(0);
853 }
854
855
856 static void
857 help(const char *progname)
858 {
859         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
860         printf(_("Usage:\n"));
861         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
862
863         printf(_("\nGeneral options:\n"));
864         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
865         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
866                          "                               plain text (default))\n"));
867         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
868         printf(_("  -v, --verbose                verbose mode\n"));
869         printf(_("  -V, --version                output version information, then exit\n"));
870         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
871         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
872         printf(_("  -?, --help                   show this help, then exit\n"));
873
874         printf(_("\nOptions controlling the output content:\n"));
875         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
876         printf(_("  -b, --blobs                  include large objects in dump\n"));
877         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
878         printf(_("  -C, --create                 include commands to create database in dump\n"));
879         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
880         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
881         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
882         printf(_("  -o, --oids                   include OIDs in dump\n"));
883         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
884                          "                               plain-text format\n"));
885         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
886         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
887         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
888         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
889         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
890         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
891         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
892         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
893         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
894         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
895         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
896         printf(_("  --no-security-labels         do not dump security label assignments\n"));
897         printf(_("  --no-synchronized-snapshots parallel processes should not use synchronized snapshots\n"));
898         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
899         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
900         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
901         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
902         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
903         printf(_("  --use-set-session-authorization\n"
904                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
905                          "                               ALTER OWNER commands to set ownership\n"));
906
907         printf(_("\nConnection options:\n"));
908         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
909         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
910         printf(_("  -p, --port=PORT          database server port number\n"));
911         printf(_("  -U, --username=NAME      connect as specified database user\n"));
912         printf(_("  -w, --no-password        never prompt for password\n"));
913         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
914         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
915
916         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
917                          "variable value is used.\n\n"));
918         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
919 }
920
921 static void
922 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
923 {
924         PGconn     *conn = GetConnection(AH);
925         const char *std_strings;
926
927         /*
928          * Set the client encoding if requested. If dumpencoding == NULL then
929          * either it hasn't been requested or we're a cloned connection and then
930          * this has already been set in CloneArchive according to the original
931          * connection encoding.
932          */
933         if (dumpencoding)
934         {
935                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
936                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
937                                                   dumpencoding);
938         }
939
940         /*
941          * Get the active encoding and the standard_conforming_strings setting, so
942          * we know how to escape strings.
943          */
944         AH->encoding = PQclientEncoding(conn);
945
946         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
947         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
948
949         /* Set the role if requested */
950         if (!use_role && AH->use_role)
951                 use_role = AH->use_role;
952
953         /* Set the role if requested */
954         if (use_role && AH->remoteVersion >= 80100)
955         {
956                 PQExpBuffer query = createPQExpBuffer();
957
958                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
959                 ExecuteSqlStatement(AH, query->data);
960                 destroyPQExpBuffer(query);
961
962                 /* save this for later use on parallel connections */
963                 if (!AH->use_role)
964                         AH->use_role = strdup(use_role);
965         }
966
967         /* Set the datestyle to ISO to ensure the dump's portability */
968         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
969
970         /* Likewise, avoid using sql_standard intervalstyle */
971         if (AH->remoteVersion >= 80400)
972                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
973
974         /*
975          * If supported, set extra_float_digits so that we can dump float data
976          * exactly (given correctly implemented float I/O code, anyway)
977          */
978         if (AH->remoteVersion >= 90000)
979                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
980         else if (AH->remoteVersion >= 70400)
981                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
982
983         /*
984          * If synchronized scanning is supported, disable it, to prevent
985          * unpredictable changes in row ordering across a dump and reload.
986          */
987         if (AH->remoteVersion >= 80300)
988                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
989
990         /*
991          * Disable timeouts if supported.
992          */
993         if (AH->remoteVersion >= 70300)
994                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
995         if (AH->remoteVersion >= 90300)
996                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
997
998         /*
999          * Quote all identifiers, if requested.
1000          */
1001         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1002                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1003
1004         /*
1005          * Start transaction-snapshot mode transaction to dump consistent data.
1006          */
1007         ExecuteSqlStatement(AH, "BEGIN");
1008         if (AH->remoteVersion >= 90100)
1009         {
1010                 if (serializable_deferrable)
1011                         ExecuteSqlStatement(AH,
1012                                                                 "SET TRANSACTION ISOLATION LEVEL "
1013                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1014                 else
1015                         ExecuteSqlStatement(AH,
1016                                                                 "SET TRANSACTION ISOLATION LEVEL "
1017                                                                 "REPEATABLE READ, READ ONLY");
1018         }
1019         else if (AH->remoteVersion >= 70400)
1020         {
1021                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1022                 ExecuteSqlStatement(AH,
1023                                                         "SET TRANSACTION ISOLATION LEVEL "
1024                                                         "SERIALIZABLE READ ONLY");
1025         }
1026         else
1027                 ExecuteSqlStatement(AH,
1028                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1029
1030
1031
1032         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1033         {
1034                 if (AH->sync_snapshot_id)
1035                 {
1036                         PQExpBuffer query = createPQExpBuffer();
1037
1038                         appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1039                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1040                         destroyPQExpBuffer(query);
1041                 }
1042                 else
1043                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1044         }
1045 }
1046
1047 static void
1048 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1049 {
1050         setup_connection(AHX, NULL, NULL);
1051 }
1052
1053 static char *
1054 get_synchronized_snapshot(Archive *fout)
1055 {
1056         char       *query = "SELECT pg_export_snapshot()";
1057         char       *result;
1058         PGresult   *res;
1059
1060         res = ExecuteSqlQueryForSingleRow(fout, query);
1061         result = strdup(PQgetvalue(res, 0, 0));
1062         PQclear(res);
1063
1064         return result;
1065 }
1066
1067 static ArchiveFormat
1068 parseArchiveFormat(const char *format, ArchiveMode *mode)
1069 {
1070         ArchiveFormat archiveFormat;
1071
1072         *mode = archModeWrite;
1073
1074         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1075         {
1076                 /* This is used by pg_dumpall, and is not documented */
1077                 archiveFormat = archNull;
1078                 *mode = archModeAppend;
1079         }
1080         else if (pg_strcasecmp(format, "c") == 0)
1081                 archiveFormat = archCustom;
1082         else if (pg_strcasecmp(format, "custom") == 0)
1083                 archiveFormat = archCustom;
1084         else if (pg_strcasecmp(format, "d") == 0)
1085                 archiveFormat = archDirectory;
1086         else if (pg_strcasecmp(format, "directory") == 0)
1087                 archiveFormat = archDirectory;
1088         else if (pg_strcasecmp(format, "p") == 0)
1089                 archiveFormat = archNull;
1090         else if (pg_strcasecmp(format, "plain") == 0)
1091                 archiveFormat = archNull;
1092         else if (pg_strcasecmp(format, "t") == 0)
1093                 archiveFormat = archTar;
1094         else if (pg_strcasecmp(format, "tar") == 0)
1095                 archiveFormat = archTar;
1096         else
1097                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1098         return archiveFormat;
1099 }
1100
1101 /*
1102  * Find the OIDs of all schemas matching the given list of patterns,
1103  * and append them to the given OID list.
1104  */
1105 static void
1106 expand_schema_name_patterns(Archive *fout,
1107                                                         SimpleStringList *patterns,
1108                                                         SimpleOidList *oids)
1109 {
1110         PQExpBuffer query;
1111         PGresult   *res;
1112         SimpleStringListCell *cell;
1113         int                     i;
1114
1115         if (patterns->head == NULL)
1116                 return;                                 /* nothing to do */
1117
1118         if (fout->remoteVersion < 70300)
1119                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1120
1121         query = createPQExpBuffer();
1122
1123         /*
1124          * We use UNION ALL rather than UNION; this might sometimes result in
1125          * duplicate entries in the OID list, but we don't care.
1126          */
1127
1128         for (cell = patterns->head; cell; cell = cell->next)
1129         {
1130                 if (cell != patterns->head)
1131                         appendPQExpBuffer(query, "UNION ALL\n");
1132                 appendPQExpBuffer(query,
1133                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1134                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1135                                                           false, NULL, "n.nspname", NULL, NULL);
1136         }
1137
1138         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1139
1140         for (i = 0; i < PQntuples(res); i++)
1141         {
1142                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1143         }
1144
1145         PQclear(res);
1146         destroyPQExpBuffer(query);
1147 }
1148
1149 /*
1150  * Find the OIDs of all tables matching the given list of patterns,
1151  * and append them to the given OID list.
1152  */
1153 static void
1154 expand_table_name_patterns(Archive *fout,
1155                                                    SimpleStringList *patterns, SimpleOidList *oids)
1156 {
1157         PQExpBuffer query;
1158         PGresult   *res;
1159         SimpleStringListCell *cell;
1160         int                     i;
1161
1162         if (patterns->head == NULL)
1163                 return;                                 /* nothing to do */
1164
1165         query = createPQExpBuffer();
1166
1167         /*
1168          * We use UNION ALL rather than UNION; this might sometimes result in
1169          * duplicate entries in the OID list, but we don't care.
1170          */
1171
1172         for (cell = patterns->head; cell; cell = cell->next)
1173         {
1174                 if (cell != patterns->head)
1175                         appendPQExpBuffer(query, "UNION ALL\n");
1176                 appendPQExpBuffer(query,
1177                                                   "SELECT c.oid"
1178                                                   "\nFROM pg_catalog.pg_class c"
1179                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1180                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1181                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1182                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1183                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1184                                                           false, "n.nspname", "c.relname", NULL,
1185                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1186         }
1187
1188         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1189
1190         for (i = 0; i < PQntuples(res); i++)
1191         {
1192                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1193         }
1194
1195         PQclear(res);
1196         destroyPQExpBuffer(query);
1197 }
1198
1199 /*
1200  * selectDumpableNamespace: policy-setting subroutine
1201  *              Mark a namespace as to be dumped or not
1202  */
1203 static void
1204 selectDumpableNamespace(NamespaceInfo *nsinfo)
1205 {
1206         /*
1207          * If specific tables are being dumped, do not dump any complete
1208          * namespaces. If specific namespaces are being dumped, dump just those
1209          * namespaces. Otherwise, dump all non-system namespaces.
1210          */
1211         if (table_include_oids.head != NULL)
1212                 nsinfo->dobj.dump = false;
1213         else if (schema_include_oids.head != NULL)
1214                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1215                                                                                                    nsinfo->dobj.catId.oid);
1216         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1217                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1218                 nsinfo->dobj.dump = false;
1219         else
1220                 nsinfo->dobj.dump = true;
1221
1222         /*
1223          * In any case, a namespace can be excluded by an exclusion switch
1224          */
1225         if (nsinfo->dobj.dump &&
1226                 simple_oid_list_member(&schema_exclude_oids,
1227                                                            nsinfo->dobj.catId.oid))
1228                 nsinfo->dobj.dump = false;
1229 }
1230
1231 /*
1232  * selectDumpableTable: policy-setting subroutine
1233  *              Mark a table as to be dumped or not
1234  */
1235 static void
1236 selectDumpableTable(TableInfo *tbinfo)
1237 {
1238         /*
1239          * If specific tables are being dumped, dump just those tables; else, dump
1240          * according to the parent namespace's dump flag.
1241          */
1242         if (table_include_oids.head != NULL)
1243                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1244                                                                                                    tbinfo->dobj.catId.oid);
1245         else
1246                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1247
1248         /*
1249          * In any case, a table can be excluded by an exclusion switch
1250          */
1251         if (tbinfo->dobj.dump &&
1252                 simple_oid_list_member(&table_exclude_oids,
1253                                                            tbinfo->dobj.catId.oid))
1254                 tbinfo->dobj.dump = false;
1255 }
1256
1257 /*
1258  * selectDumpableType: policy-setting subroutine
1259  *              Mark a type as to be dumped or not
1260  *
1261  * If it's a table's rowtype or an autogenerated array type, we also apply a
1262  * special type code to facilitate sorting into the desired order.      (We don't
1263  * want to consider those to be ordinary types because that would bring tables
1264  * up into the datatype part of the dump order.)  We still set the object's
1265  * dump flag; that's not going to cause the dummy type to be dumped, but we
1266  * need it so that casts involving such types will be dumped correctly -- see
1267  * dumpCast.  This means the flag should be set the same as for the underlying
1268  * object (the table or base type).
1269  */
1270 static void
1271 selectDumpableType(TypeInfo *tyinfo)
1272 {
1273         /* skip complex types, except for standalone composite types */
1274         if (OidIsValid(tyinfo->typrelid) &&
1275                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1276         {
1277                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1278
1279                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1280                 if (tytable != NULL)
1281                         tyinfo->dobj.dump = tytable->dobj.dump;
1282                 else
1283                         tyinfo->dobj.dump = false;
1284                 return;
1285         }
1286
1287         /* skip auto-generated array types */
1288         if (tyinfo->isArray)
1289         {
1290                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1291
1292                 /*
1293                  * Fall through to set the dump flag; we assume that the subsequent
1294                  * rules will do the same thing as they would for the array's base
1295                  * type.  (We cannot reliably look up the base type here, since
1296                  * getTypes may not have processed it yet.)
1297                  */
1298         }
1299
1300         /* dump only types in dumpable namespaces */
1301         if (!tyinfo->dobj.namespace->dobj.dump)
1302                 tyinfo->dobj.dump = false;
1303
1304         /* skip undefined placeholder types */
1305         else if (!tyinfo->isDefined)
1306                 tyinfo->dobj.dump = false;
1307
1308         else
1309                 tyinfo->dobj.dump = true;
1310 }
1311
1312 /*
1313  * selectDumpableDefaultACL: policy-setting subroutine
1314  *              Mark a default ACL as to be dumped or not
1315  *
1316  * For per-schema default ACLs, dump if the schema is to be dumped.
1317  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1318  * and aclsSkip are checked separately.
1319  */
1320 static void
1321 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1322 {
1323         if (dinfo->dobj.namespace)
1324                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1325         else
1326                 dinfo->dobj.dump = include_everything;
1327 }
1328
1329 /*
1330  * selectDumpableExtension: policy-setting subroutine
1331  *              Mark an extension as to be dumped or not
1332  *
1333  * Normally, we dump all extensions, or none of them if include_everything
1334  * is false (i.e., a --schema or --table switch was given).  However, in
1335  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1336  * assume those will already be installed in the target database.  We identify
1337  * such extensions by their having OIDs in the range reserved for initdb.
1338  */
1339 static void
1340 selectDumpableExtension(ExtensionInfo *extinfo)
1341 {
1342         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1343                 extinfo->dobj.dump = false;
1344         else
1345                 extinfo->dobj.dump = include_everything;
1346 }
1347
1348 /*
1349  * selectDumpableObject: policy-setting subroutine
1350  *              Mark a generic dumpable object as to be dumped or not
1351  *
1352  * Use this only for object types without a special-case routine above.
1353  */
1354 static void
1355 selectDumpableObject(DumpableObject *dobj)
1356 {
1357         /*
1358          * Default policy is to dump if parent namespace is dumpable, or always
1359          * for non-namespace-associated items.
1360          */
1361         if (dobj->namespace)
1362                 dobj->dump = dobj->namespace->dobj.dump;
1363         else
1364                 dobj->dump = true;
1365 }
1366
1367 /*
1368  *      Dump a table's contents for loading using the COPY command
1369  *      - this routine is called by the Archiver when it wants the table
1370  *        to be dumped.
1371  */
1372
1373 static int
1374 dumpTableData_copy(Archive *fout, void *dcontext)
1375 {
1376         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1377         TableInfo  *tbinfo = tdinfo->tdtable;
1378         const char *classname = tbinfo->dobj.name;
1379         const bool      hasoids = tbinfo->hasoids;
1380         const bool      oids = tdinfo->oids;
1381         PQExpBuffer q = createPQExpBuffer();
1382
1383         /*
1384          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1385          * which uses it already.
1386          */
1387         PQExpBuffer clistBuf = createPQExpBuffer();
1388         PGconn     *conn = GetConnection(fout);
1389         PGresult   *res;
1390         int                     ret;
1391         char       *copybuf;
1392         const char *column_list;
1393
1394         if (g_verbose)
1395                 write_msg(NULL, "dumping contents of table %s\n", classname);
1396
1397         /*
1398          * Make sure we are in proper schema.  We will qualify the table name
1399          * below anyway (in case its name conflicts with a pg_catalog table); but
1400          * this ensures reproducible results in case the table contains regproc,
1401          * regclass, etc columns.
1402          */
1403         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1404
1405         /*
1406          * If possible, specify the column list explicitly so that we have no
1407          * possibility of retrieving data in the wrong column order.  (The default
1408          * column ordering of COPY will not be what we want in certain corner
1409          * cases involving ADD COLUMN and inheritance.)
1410          */
1411         if (fout->remoteVersion >= 70300)
1412                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1413         else
1414                 column_list = "";               /* can't select columns in COPY */
1415
1416         if (oids && hasoids)
1417         {
1418                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1419                                                   fmtQualifiedId(fout->remoteVersion,
1420                                                                                  tbinfo->dobj.namespace->dobj.name,
1421                                                                                  classname),
1422                                                   column_list);
1423         }
1424         else if (tdinfo->filtercond)
1425         {
1426                 /* Note: this syntax is only supported in 8.2 and up */
1427                 appendPQExpBufferStr(q, "COPY (SELECT ");
1428                 /* klugery to get rid of parens in column list */
1429                 if (strlen(column_list) > 2)
1430                 {
1431                         appendPQExpBufferStr(q, column_list + 1);
1432                         q->data[q->len - 1] = ' ';
1433                 }
1434                 else
1435                         appendPQExpBufferStr(q, "* ");
1436                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1437                                                   fmtQualifiedId(fout->remoteVersion,
1438                                                                                  tbinfo->dobj.namespace->dobj.name,
1439                                                                                  classname),
1440                                                   tdinfo->filtercond);
1441         }
1442         else
1443         {
1444                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1445                                                   fmtQualifiedId(fout->remoteVersion,
1446                                                                                  tbinfo->dobj.namespace->dobj.name,
1447                                                                                  classname),
1448                                                   column_list);
1449         }
1450         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1451         PQclear(res);
1452         destroyPQExpBuffer(clistBuf);
1453
1454         for (;;)
1455         {
1456                 ret = PQgetCopyData(conn, &copybuf, 0);
1457
1458                 if (ret < 0)
1459                         break;                          /* done or error */
1460
1461                 if (copybuf)
1462                 {
1463                         WriteData(fout, copybuf, ret);
1464                         PQfreemem(copybuf);
1465                 }
1466
1467                 /* ----------
1468                  * THROTTLE:
1469                  *
1470                  * There was considerable discussion in late July, 2000 regarding
1471                  * slowing down pg_dump when backing up large tables. Users with both
1472                  * slow & fast (multi-processor) machines experienced performance
1473                  * degradation when doing a backup.
1474                  *
1475                  * Initial attempts based on sleeping for a number of ms for each ms
1476                  * of work were deemed too complex, then a simple 'sleep in each loop'
1477                  * implementation was suggested. The latter failed because the loop
1478                  * was too tight. Finally, the following was implemented:
1479                  *
1480                  * If throttle is non-zero, then
1481                  *              See how long since the last sleep.
1482                  *              Work out how long to sleep (based on ratio).
1483                  *              If sleep is more than 100ms, then
1484                  *                      sleep
1485                  *                      reset timer
1486                  *              EndIf
1487                  * EndIf
1488                  *
1489                  * where the throttle value was the number of ms to sleep per ms of
1490                  * work. The calculation was done in each loop.
1491                  *
1492                  * Most of the hard work is done in the backend, and this solution
1493                  * still did not work particularly well: on slow machines, the ratio
1494                  * was 50:1, and on medium paced machines, 1:1, and on fast
1495                  * multi-processor machines, it had little or no effect, for reasons
1496                  * that were unclear.
1497                  *
1498                  * Further discussion ensued, and the proposal was dropped.
1499                  *
1500                  * For those people who want this feature, it can be implemented using
1501                  * gettimeofday in each loop, calculating the time since last sleep,
1502                  * multiplying that by the sleep ratio, then if the result is more
1503                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1504                  * function to sleep for a subsecond period ie.
1505                  *
1506                  * select(0, NULL, NULL, NULL, &tvi);
1507                  *
1508                  * This will return after the interval specified in the structure tvi.
1509                  * Finally, call gettimeofday again to save the 'last sleep time'.
1510                  * ----------
1511                  */
1512         }
1513         archprintf(fout, "\\.\n\n\n");
1514
1515         if (ret == -2)
1516         {
1517                 /* copy data transfer failed */
1518                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1519                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1520                 write_msg(NULL, "The command was: %s\n", q->data);
1521                 exit_nicely(1);
1522         }
1523
1524         /* Check command status and return to normal libpq state */
1525         res = PQgetResult(conn);
1526         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1527         {
1528                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1529                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1530                 write_msg(NULL, "The command was: %s\n", q->data);
1531                 exit_nicely(1);
1532         }
1533         PQclear(res);
1534
1535         destroyPQExpBuffer(q);
1536         return 1;
1537 }
1538
1539 /*
1540  * Dump table data using INSERT commands.
1541  *
1542  * Caution: when we restore from an archive file direct to database, the
1543  * INSERT commands emitted by this function have to be parsed by
1544  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1545  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1546  */
1547 static int
1548 dumpTableData_insert(Archive *fout, void *dcontext)
1549 {
1550         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1551         TableInfo  *tbinfo = tdinfo->tdtable;
1552         const char *classname = tbinfo->dobj.name;
1553         PQExpBuffer q = createPQExpBuffer();
1554         PGresult   *res;
1555         int                     tuple;
1556         int                     nfields;
1557         int                     field;
1558
1559         /*
1560          * Make sure we are in proper schema.  We will qualify the table name
1561          * below anyway (in case its name conflicts with a pg_catalog table); but
1562          * this ensures reproducible results in case the table contains regproc,
1563          * regclass, etc columns.
1564          */
1565         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1566
1567         if (fout->remoteVersion >= 70100)
1568         {
1569                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1570                                                   "SELECT * FROM ONLY %s",
1571                                                   fmtQualifiedId(fout->remoteVersion,
1572                                                                                  tbinfo->dobj.namespace->dobj.name,
1573                                                                                  classname));
1574         }
1575         else
1576         {
1577                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1578                                                   "SELECT * FROM %s",
1579                                                   fmtQualifiedId(fout->remoteVersion,
1580                                                                                  tbinfo->dobj.namespace->dobj.name,
1581                                                                                  classname));
1582         }
1583         if (tdinfo->filtercond)
1584                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1585
1586         ExecuteSqlStatement(fout, q->data);
1587
1588         while (1)
1589         {
1590                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1591                                                           PGRES_TUPLES_OK);
1592                 nfields = PQnfields(res);
1593                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1594                 {
1595                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1596                         if (nfields == 0)
1597                         {
1598                                 /* corner case for zero-column table */
1599                                 archprintf(fout, "DEFAULT VALUES;\n");
1600                                 continue;
1601                         }
1602                         if (column_inserts)
1603                         {
1604                                 resetPQExpBuffer(q);
1605                                 appendPQExpBuffer(q, "(");
1606                                 for (field = 0; field < nfields; field++)
1607                                 {
1608                                         if (field > 0)
1609                                                 appendPQExpBuffer(q, ", ");
1610                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1611                                 }
1612                                 appendPQExpBuffer(q, ") ");
1613                                 archputs(q->data, fout);
1614                         }
1615                         archprintf(fout, "VALUES (");
1616                         for (field = 0; field < nfields; field++)
1617                         {
1618                                 if (field > 0)
1619                                         archprintf(fout, ", ");
1620                                 if (PQgetisnull(res, tuple, field))
1621                                 {
1622                                         archprintf(fout, "NULL");
1623                                         continue;
1624                                 }
1625
1626                                 /* XXX This code is partially duplicated in ruleutils.c */
1627                                 switch (PQftype(res, field))
1628                                 {
1629                                         case INT2OID:
1630                                         case INT4OID:
1631                                         case INT8OID:
1632                                         case OIDOID:
1633                                         case FLOAT4OID:
1634                                         case FLOAT8OID:
1635                                         case NUMERICOID:
1636                                                 {
1637                                                         /*
1638                                                          * These types are printed without quotes unless
1639                                                          * they contain values that aren't accepted by the
1640                                                          * scanner unquoted (e.g., 'NaN').      Note that
1641                                                          * strtod() and friends might accept NaN, so we
1642                                                          * can't use that to test.
1643                                                          *
1644                                                          * In reality we only need to defend against
1645                                                          * infinity and NaN, so we need not get too crazy
1646                                                          * about pattern matching here.
1647                                                          */
1648                                                         const char *s = PQgetvalue(res, tuple, field);
1649
1650                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1651                                                                 archprintf(fout, "%s", s);
1652                                                         else
1653                                                                 archprintf(fout, "'%s'", s);
1654                                                 }
1655                                                 break;
1656
1657                                         case BITOID:
1658                                         case VARBITOID:
1659                                                 archprintf(fout, "B'%s'",
1660                                                                    PQgetvalue(res, tuple, field));
1661                                                 break;
1662
1663                                         case BOOLOID:
1664                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1665                                                         archprintf(fout, "true");
1666                                                 else
1667                                                         archprintf(fout, "false");
1668                                                 break;
1669
1670                                         default:
1671                                                 /* All other types are printed as string literals. */
1672                                                 resetPQExpBuffer(q);
1673                                                 appendStringLiteralAH(q,
1674                                                                                           PQgetvalue(res, tuple, field),
1675                                                                                           fout);
1676                                                 archputs(q->data, fout);
1677                                                 break;
1678                                 }
1679                         }
1680                         archprintf(fout, ");\n");
1681                 }
1682
1683                 if (PQntuples(res) <= 0)
1684                 {
1685                         PQclear(res);
1686                         break;
1687                 }
1688                 PQclear(res);
1689         }
1690
1691         archprintf(fout, "\n\n");
1692
1693         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1694
1695         destroyPQExpBuffer(q);
1696         return 1;
1697 }
1698
1699
1700 /*
1701  * dumpTableData -
1702  *        dump the contents of a single table
1703  *
1704  * Actually, this just makes an ArchiveEntry for the table contents.
1705  */
1706 static void
1707 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1708 {
1709         TableInfo  *tbinfo = tdinfo->tdtable;
1710         PQExpBuffer copyBuf = createPQExpBuffer();
1711         PQExpBuffer clistBuf = createPQExpBuffer();
1712         DataDumperPtr dumpFn;
1713         char       *copyStmt;
1714
1715         if (!dump_inserts)
1716         {
1717                 /* Dump/restore using COPY */
1718                 dumpFn = dumpTableData_copy;
1719                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1720                 appendPQExpBuffer(copyBuf, "COPY %s ",
1721                                                   fmtId(tbinfo->dobj.name));
1722                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1723                                                   fmtCopyColumnList(tbinfo, clistBuf),
1724                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1725                 copyStmt = copyBuf->data;
1726         }
1727         else
1728         {
1729                 /* Restore using INSERT */
1730                 dumpFn = dumpTableData_insert;
1731                 copyStmt = NULL;
1732         }
1733
1734         /*
1735          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1736          * dependency on its table as "special" and pass it to ArchiveEntry now.
1737          * See comments for BuildArchiveDependencies.
1738          */
1739         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1740                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1741                                  NULL, tbinfo->rolname,
1742                                  false, "TABLE DATA", SECTION_DATA,
1743                                  "", "", copyStmt,
1744                                  &(tbinfo->dobj.dumpId), 1,
1745                                  dumpFn, tdinfo);
1746
1747         destroyPQExpBuffer(copyBuf);
1748         destroyPQExpBuffer(clistBuf);
1749 }
1750
1751 /*
1752  * refreshMatViewData -
1753  *        load or refresh the contents of a single materialized view
1754  *
1755  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1756  * statement.
1757  */
1758 static void
1759 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1760 {
1761         TableInfo  *tbinfo = tdinfo->tdtable;
1762         PQExpBuffer q;
1763
1764         /* If the materialized view is not flagged as scannable, skip this. */
1765         if (!tbinfo->isscannable)
1766                 return;
1767
1768         q = createPQExpBuffer();
1769
1770         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1771                                           fmtId(tbinfo->dobj.name));
1772
1773         ArchiveEntry(fout,
1774                                  tdinfo->dobj.catId,    /* catalog ID */
1775                                  tdinfo->dobj.dumpId,   /* dump ID */
1776                                  tbinfo->dobj.name,             /* Name */
1777                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1778                                  NULL,                  /* Tablespace */
1779                                  tbinfo->rolname,               /* Owner */
1780                                  false,                 /* with oids */
1781                                  "MATERIALIZED VIEW DATA",              /* Desc */
1782                                  SECTION_POST_DATA,             /* Section */
1783                                  q->data,               /* Create */
1784                                  "",                    /* Del */
1785                                  NULL,                  /* Copy */
1786                                  tdinfo->dobj.dependencies,             /* Deps */
1787                                  tdinfo->dobj.nDeps,    /* # Deps */
1788                                  NULL,                  /* Dumper */
1789                                  NULL);                 /* Dumper Arg */
1790
1791         destroyPQExpBuffer(q);
1792 }
1793
1794 /*
1795  * getTableData -
1796  *        set up dumpable objects representing the contents of tables
1797  */
1798 static void
1799 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1800 {
1801         int                     i;
1802
1803         for (i = 0; i < numTables; i++)
1804         {
1805                 if (tblinfo[i].dobj.dump)
1806                         makeTableDataInfo(&(tblinfo[i]), oids);
1807         }
1808 }
1809
1810 /*
1811  * Make a dumpable object for the data of this specific table
1812  *
1813  * Note: we make a TableDataInfo if and only if we are going to dump the
1814  * table data; the "dump" flag in such objects isn't used.
1815  */
1816 static void
1817 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1818 {
1819         TableDataInfo *tdinfo;
1820
1821         /*
1822          * Nothing to do if we already decided to dump the table.  This will
1823          * happen for "config" tables.
1824          */
1825         if (tbinfo->dataObj != NULL)
1826                 return;
1827
1828         /* Skip VIEWs (no data to dump) */
1829         if (tbinfo->relkind == RELKIND_VIEW)
1830                 return;
1831         /* Skip FOREIGN TABLEs (no data to dump) */
1832         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1833                 return;
1834
1835         /* Don't dump data in unlogged tables, if so requested */
1836         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1837                 no_unlogged_table_data)
1838                 return;
1839
1840         /* Check that the data is not explicitly excluded */
1841         if (simple_oid_list_member(&tabledata_exclude_oids,
1842                                                            tbinfo->dobj.catId.oid))
1843                 return;
1844
1845         /* OK, let's dump it */
1846         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1847
1848         if (tbinfo->relkind == RELKIND_MATVIEW)
1849                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1850         else
1851                 tdinfo->dobj.objType = DO_TABLE_DATA;
1852
1853         /*
1854          * Note: use tableoid 0 so that this object won't be mistaken for
1855          * something that pg_depend entries apply to.
1856          */
1857         tdinfo->dobj.catId.tableoid = 0;
1858         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1859         AssignDumpId(&tdinfo->dobj);
1860         tdinfo->dobj.name = tbinfo->dobj.name;
1861         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1862         tdinfo->tdtable = tbinfo;
1863         tdinfo->oids = oids;
1864         tdinfo->filtercond = NULL;      /* might get set later */
1865         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1866
1867         tbinfo->dataObj = tdinfo;
1868 }
1869
1870 /*
1871  * The refresh for a materialized view must be dependent on the refresh for
1872  * any materialized view that this one is dependent on.
1873  *
1874  * This must be called after all the objects are created, but before they are
1875  * sorted.
1876  */
1877 static void
1878 buildMatViewRefreshDependencies(Archive *fout)
1879 {
1880         PQExpBuffer query;
1881         PGresult   *res;
1882         int                     ntups,
1883                                 i;
1884         int                     i_classid,
1885                                 i_objid,
1886                                 i_refobjid;
1887
1888         /* No Mat Views before 9.3. */
1889         if (fout->remoteVersion < 90300)
1890                 return;
1891
1892         /* Make sure we are in proper schema */
1893         selectSourceSchema(fout, "pg_catalog");
1894
1895         query = createPQExpBuffer();
1896
1897         appendPQExpBuffer(query, "with recursive w as "
1898                                           "( "
1899                                         "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
1900                                           "from pg_depend d1 "
1901                                           "join pg_class c1 on c1.oid = d1.objid "
1902                                           "and c1.relkind = 'm' "
1903                                           "join pg_rewrite r1 on r1.ev_class = d1.objid "
1904                                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
1905                                           "and d2.objid = r1.oid "
1906                                           "and d2.refobjid <> d1.objid "
1907                                           "join pg_class c2 on c2.oid = d2.refobjid "
1908                                           "and c2.relkind in ('m','v') "
1909                                           "where d1.classid = 'pg_class'::regclass "
1910                                           "union "
1911                                           "select w.objid, d3.refobjid, c3.relkind "
1912                                           "from w "
1913                                           "join pg_rewrite r3 on r3.ev_class = w.refobjid "
1914                                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
1915                                           "and d3.objid = r3.oid "
1916                                           "and d3.refobjid <> w.refobjid "
1917                                           "join pg_class c3 on c3.oid = d3.refobjid "
1918                                           "and c3.relkind in ('m','v') "
1919                                           ") "
1920                           "select 'pg_class'::regclass::oid as classid, objid, refobjid "
1921                                           "from w "
1922                                           "where refrelkind = 'm'");
1923
1924         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1925
1926         ntups = PQntuples(res);
1927
1928         i_classid = PQfnumber(res, "classid");
1929         i_objid = PQfnumber(res, "objid");
1930         i_refobjid = PQfnumber(res, "refobjid");
1931
1932         for (i = 0; i < ntups; i++)
1933         {
1934                 CatalogId       objId;
1935                 CatalogId       refobjId;
1936                 DumpableObject *dobj;
1937                 DumpableObject *refdobj;
1938                 TableInfo  *tbinfo;
1939                 TableInfo  *reftbinfo;
1940
1941                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1942                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1943                 refobjId.tableoid = objId.tableoid;
1944                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1945
1946                 dobj = findObjectByCatalogId(objId);
1947                 if (dobj == NULL)
1948                         continue;
1949
1950                 Assert(dobj->objType == DO_TABLE);
1951                 tbinfo = (TableInfo *) dobj;
1952                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1953                 dobj = (DumpableObject *) tbinfo->dataObj;
1954                 if (dobj == NULL)
1955                         continue;
1956                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1957
1958                 refdobj = findObjectByCatalogId(refobjId);
1959                 if (refdobj == NULL)
1960                         continue;
1961
1962                 Assert(refdobj->objType == DO_TABLE);
1963                 reftbinfo = (TableInfo *) refdobj;
1964                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
1965                 refdobj = (DumpableObject *) reftbinfo->dataObj;
1966                 if (refdobj == NULL)
1967                         continue;
1968                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
1969
1970                 addObjectDependency(dobj, refdobj->dumpId);
1971
1972                 if (!reftbinfo->isscannable)
1973                         tbinfo->isscannable = false;
1974         }
1975
1976         PQclear(res);
1977
1978         destroyPQExpBuffer(query);
1979 }
1980
1981 /*
1982  * getTableDataFKConstraints -
1983  *        add dump-order dependencies reflecting foreign key constraints
1984  *
1985  * This code is executed only in a data-only dump --- in schema+data dumps
1986  * we handle foreign key issues by not creating the FK constraints until
1987  * after the data is loaded.  In a data-only dump, however, we want to
1988  * order the table data objects in such a way that a table's referenced
1989  * tables are restored first.  (In the presence of circular references or
1990  * self-references this may be impossible; we'll detect and complain about
1991  * that during the dependency sorting step.)
1992  */
1993 static void
1994 getTableDataFKConstraints(void)
1995 {
1996         DumpableObject **dobjs;
1997         int                     numObjs;
1998         int                     i;
1999
2000         /* Search through all the dumpable objects for FK constraints */
2001         getDumpableObjects(&dobjs, &numObjs);
2002         for (i = 0; i < numObjs; i++)
2003         {
2004                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2005                 {
2006                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2007                         TableInfo  *ftable;
2008
2009                         /* Not interesting unless both tables are to be dumped */
2010                         if (cinfo->contable == NULL ||
2011                                 cinfo->contable->dataObj == NULL)
2012                                 continue;
2013                         ftable = findTableByOid(cinfo->confrelid);
2014                         if (ftable == NULL ||
2015                                 ftable->dataObj == NULL)
2016                                 continue;
2017
2018                         /*
2019                          * Okay, make referencing table's TABLE_DATA object depend on the
2020                          * referenced table's TABLE_DATA object.
2021                          */
2022                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2023                                                                 ftable->dataObj->dobj.dumpId);
2024                 }
2025         }
2026         free(dobjs);
2027 }
2028
2029
2030 /*
2031  * guessConstraintInheritance:
2032  *      In pre-8.4 databases, we can't tell for certain which constraints
2033  *      are inherited.  We assume a CHECK constraint is inherited if its name
2034  *      matches the name of any constraint in the parent.  Originally this code
2035  *      tried to compare the expression texts, but that can fail for various
2036  *      reasons --- for example, if the parent and child tables are in different
2037  *      schemas, reverse-listing of function calls may produce different text
2038  *      (schema-qualified or not) depending on search path.
2039  *
2040  *      In 8.4 and up we can rely on the conislocal field to decide which
2041  *      constraints must be dumped; much safer.
2042  *
2043  *      This function assumes all conislocal flags were initialized to TRUE.
2044  *      It clears the flag on anything that seems to be inherited.
2045  */
2046 static void
2047 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2048 {
2049         int                     i,
2050                                 j,
2051                                 k;
2052
2053         for (i = 0; i < numTables; i++)
2054         {
2055                 TableInfo  *tbinfo = &(tblinfo[i]);
2056                 int                     numParents;
2057                 TableInfo **parents;
2058                 TableInfo  *parent;
2059
2060                 /* Sequences and views never have parents */
2061                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2062                         tbinfo->relkind == RELKIND_VIEW)
2063                         continue;
2064
2065                 /* Don't bother computing anything for non-target tables, either */
2066                 if (!tbinfo->dobj.dump)
2067                         continue;
2068
2069                 numParents = tbinfo->numParents;
2070                 parents = tbinfo->parents;
2071
2072                 if (numParents == 0)
2073                         continue;                       /* nothing to see here, move along */
2074
2075                 /* scan for inherited CHECK constraints */
2076                 for (j = 0; j < tbinfo->ncheck; j++)
2077                 {
2078                         ConstraintInfo *constr;
2079
2080                         constr = &(tbinfo->checkexprs[j]);
2081
2082                         for (k = 0; k < numParents; k++)
2083                         {
2084                                 int                     l;
2085
2086                                 parent = parents[k];
2087                                 for (l = 0; l < parent->ncheck; l++)
2088                                 {
2089                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2090
2091                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2092                                         {
2093                                                 constr->conislocal = false;
2094                                                 break;
2095                                         }
2096                                 }
2097                                 if (!constr->conislocal)
2098                                         break;
2099                         }
2100                 }
2101         }
2102 }
2103
2104
2105 /*
2106  * dumpDatabase:
2107  *      dump the database definition
2108  */
2109 static void
2110 dumpDatabase(Archive *fout)
2111 {
2112         PQExpBuffer dbQry = createPQExpBuffer();
2113         PQExpBuffer delQry = createPQExpBuffer();
2114         PQExpBuffer creaQry = createPQExpBuffer();
2115         PGconn     *conn = GetConnection(fout);
2116         PGresult   *res;
2117         int                     i_tableoid,
2118                                 i_oid,
2119                                 i_dba,
2120                                 i_encoding,
2121                                 i_collate,
2122                                 i_ctype,
2123                                 i_frozenxid,
2124                                 i_tablespace;
2125         CatalogId       dbCatId;
2126         DumpId          dbDumpId;
2127         const char *datname,
2128                            *dba,
2129                            *encoding,
2130                            *collate,
2131                            *ctype,
2132                            *tablespace;
2133         uint32          frozenxid;
2134
2135         datname = PQdb(conn);
2136
2137         if (g_verbose)
2138                 write_msg(NULL, "saving database definition\n");
2139
2140         /* Make sure we are in proper schema */
2141         selectSourceSchema(fout, "pg_catalog");
2142
2143         /* Get the database owner and parameters from pg_database */
2144         if (fout->remoteVersion >= 80400)
2145         {
2146                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2147                                                   "(%s datdba) AS dba, "
2148                                                   "pg_encoding_to_char(encoding) AS encoding, "
2149                                                   "datcollate, datctype, datfrozenxid, "
2150                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2151                                           "shobj_description(oid, 'pg_database') AS description "
2152
2153                                                   "FROM pg_database "
2154                                                   "WHERE datname = ",
2155                                                   username_subquery);
2156                 appendStringLiteralAH(dbQry, datname, fout);
2157         }
2158         else if (fout->remoteVersion >= 80200)
2159         {
2160                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2161                                                   "(%s datdba) AS dba, "
2162                                                   "pg_encoding_to_char(encoding) AS encoding, "
2163                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2164                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2165                                           "shobj_description(oid, 'pg_database') AS description "
2166
2167                                                   "FROM pg_database "
2168                                                   "WHERE datname = ",
2169                                                   username_subquery);
2170                 appendStringLiteralAH(dbQry, datname, fout);
2171         }
2172         else if (fout->remoteVersion >= 80000)
2173         {
2174                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2175                                                   "(%s datdba) AS dba, "
2176                                                   "pg_encoding_to_char(encoding) AS encoding, "
2177                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2178                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2179                                                   "FROM pg_database "
2180                                                   "WHERE datname = ",
2181                                                   username_subquery);
2182                 appendStringLiteralAH(dbQry, datname, fout);
2183         }
2184         else if (fout->remoteVersion >= 70100)
2185         {
2186                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2187                                                   "(%s datdba) AS dba, "
2188                                                   "pg_encoding_to_char(encoding) AS encoding, "
2189                                                   "NULL AS datcollate, NULL AS datctype, "
2190                                                   "0 AS datfrozenxid, "
2191                                                   "NULL AS tablespace "
2192                                                   "FROM pg_database "
2193                                                   "WHERE datname = ",
2194                                                   username_subquery);
2195                 appendStringLiteralAH(dbQry, datname, fout);
2196         }
2197         else
2198         {
2199                 appendPQExpBuffer(dbQry, "SELECT "
2200                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2201                                                   "oid, "
2202                                                   "(%s datdba) AS dba, "
2203                                                   "pg_encoding_to_char(encoding) AS encoding, "
2204                                                   "NULL AS datcollate, NULL AS datctype, "
2205                                                   "0 AS datfrozenxid, "
2206                                                   "NULL AS tablespace "
2207                                                   "FROM pg_database "
2208                                                   "WHERE datname = ",
2209                                                   username_subquery);
2210                 appendStringLiteralAH(dbQry, datname, fout);
2211         }
2212
2213         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2214
2215         i_tableoid = PQfnumber(res, "tableoid");
2216         i_oid = PQfnumber(res, "oid");
2217         i_dba = PQfnumber(res, "dba");
2218         i_encoding = PQfnumber(res, "encoding");
2219         i_collate = PQfnumber(res, "datcollate");
2220         i_ctype = PQfnumber(res, "datctype");
2221         i_frozenxid = PQfnumber(res, "datfrozenxid");
2222         i_tablespace = PQfnumber(res, "tablespace");
2223
2224         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2225         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2226         dba = PQgetvalue(res, 0, i_dba);
2227         encoding = PQgetvalue(res, 0, i_encoding);
2228         collate = PQgetvalue(res, 0, i_collate);
2229         ctype = PQgetvalue(res, 0, i_ctype);
2230         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2231         tablespace = PQgetvalue(res, 0, i_tablespace);
2232
2233         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2234                                           fmtId(datname));
2235         if (strlen(encoding) > 0)
2236         {
2237                 appendPQExpBuffer(creaQry, " ENCODING = ");
2238                 appendStringLiteralAH(creaQry, encoding, fout);
2239         }
2240         if (strlen(collate) > 0)
2241         {
2242                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
2243                 appendStringLiteralAH(creaQry, collate, fout);
2244         }
2245         if (strlen(ctype) > 0)
2246         {
2247                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
2248                 appendStringLiteralAH(creaQry, ctype, fout);
2249         }
2250         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2251                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2252                                                   fmtId(tablespace));
2253         appendPQExpBuffer(creaQry, ";\n");
2254
2255         if (binary_upgrade)
2256         {
2257                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2258                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2259                                                   "SET datfrozenxid = '%u'\n"
2260                                                   "WHERE        datname = ",
2261                                                   frozenxid);
2262                 appendStringLiteralAH(creaQry, datname, fout);
2263                 appendPQExpBuffer(creaQry, ";\n");
2264
2265         }
2266
2267         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2268                                           fmtId(datname));
2269
2270         dbDumpId = createDumpId();
2271
2272         ArchiveEntry(fout,
2273                                  dbCatId,               /* catalog ID */
2274                                  dbDumpId,              /* dump ID */
2275                                  datname,               /* Name */
2276                                  NULL,                  /* Namespace */
2277                                  NULL,                  /* Tablespace */
2278                                  dba,                   /* Owner */
2279                                  false,                 /* with oids */
2280                                  "DATABASE",    /* Desc */
2281                                  SECTION_PRE_DATA,              /* Section */
2282                                  creaQry->data, /* Create */
2283                                  delQry->data,  /* Del */
2284                                  NULL,                  /* Copy */
2285                                  NULL,                  /* Deps */
2286                                  0,                             /* # Deps */
2287                                  NULL,                  /* Dumper */
2288                                  NULL);                 /* Dumper Arg */
2289
2290         /*
2291          * pg_largeobject and pg_largeobject_metadata come from the old system
2292          * intact, so set their relfrozenxids.
2293          */
2294         if (binary_upgrade)
2295         {
2296                 PGresult   *lo_res;
2297                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2298                 PQExpBuffer loOutQry = createPQExpBuffer();
2299                 int                     i_relfrozenxid;
2300
2301                 /*
2302                  * pg_largeobject
2303                  */
2304                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2305                                                   "FROM pg_catalog.pg_class\n"
2306                                                   "WHERE oid = %u;\n",
2307                                                   LargeObjectRelationId);
2308
2309                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2310
2311                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2312
2313                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2314                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2315                                                   "SET relfrozenxid = '%u'\n"
2316                                                   "WHERE oid = %u;\n",
2317                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2318                                                   LargeObjectRelationId);
2319                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2320                                          "pg_largeobject", NULL, NULL, "",
2321                                          false, "pg_largeobject", SECTION_PRE_DATA,
2322                                          loOutQry->data, "", NULL,
2323                                          NULL, 0,
2324                                          NULL, NULL);
2325
2326                 PQclear(lo_res);
2327
2328                 /*
2329                  * pg_largeobject_metadata
2330                  */
2331                 if (fout->remoteVersion >= 90000)
2332                 {
2333                         resetPQExpBuffer(loFrozenQry);
2334                         resetPQExpBuffer(loOutQry);
2335
2336                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2337                                                           "FROM pg_catalog.pg_class\n"
2338                                                           "WHERE oid = %u;\n",
2339                                                           LargeObjectMetadataRelationId);
2340
2341                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2342
2343                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2344
2345                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2346                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2347                                                           "SET relfrozenxid = '%u'\n"
2348                                                           "WHERE oid = %u;\n",
2349                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2350                                                           LargeObjectMetadataRelationId);
2351                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2352                                                  "pg_largeobject_metadata", NULL, NULL, "",
2353                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2354                                                  loOutQry->data, "", NULL,
2355                                                  NULL, 0,
2356                                                  NULL, NULL);
2357
2358                         PQclear(lo_res);
2359                 }
2360
2361                 destroyPQExpBuffer(loFrozenQry);
2362                 destroyPQExpBuffer(loOutQry);
2363         }
2364
2365         /* Dump DB comment if any */
2366         if (fout->remoteVersion >= 80200)
2367         {
2368                 /*
2369                  * 8.2 keeps comments on shared objects in a shared table, so we
2370                  * cannot use the dumpComment used for other database objects.
2371                  */
2372                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2373
2374                 if (comment && strlen(comment))
2375                 {
2376                         resetPQExpBuffer(dbQry);
2377
2378                         /*
2379                          * Generates warning when loaded into a differently-named
2380                          * database.
2381                          */
2382                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2383                         appendStringLiteralAH(dbQry, comment, fout);
2384                         appendPQExpBuffer(dbQry, ";\n");
2385
2386                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2387                                                  dba, false, "COMMENT", SECTION_NONE,
2388                                                  dbQry->data, "", NULL,
2389                                                  &dbDumpId, 1, NULL, NULL);
2390                 }
2391         }
2392         else
2393         {
2394                 resetPQExpBuffer(dbQry);
2395                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2396                 dumpComment(fout, dbQry->data, NULL, "",
2397                                         dbCatId, 0, dbDumpId);
2398         }
2399
2400         PQclear(res);
2401
2402         /* Dump shared security label. */
2403         if (!no_security_labels && fout->remoteVersion >= 90200)
2404         {
2405                 PQExpBuffer seclabelQry = createPQExpBuffer();
2406
2407                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2408                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2409                 resetPQExpBuffer(seclabelQry);
2410                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2411                 if (strlen(seclabelQry->data))
2412                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2413                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2414                                                  seclabelQry->data, "", NULL,
2415                                                  &dbDumpId, 1, NULL, NULL);
2416                 destroyPQExpBuffer(seclabelQry);
2417         }
2418
2419         destroyPQExpBuffer(dbQry);
2420         destroyPQExpBuffer(delQry);
2421         destroyPQExpBuffer(creaQry);
2422 }
2423
2424
2425 /*
2426  * dumpEncoding: put the correct encoding into the archive
2427  */
2428 static void
2429 dumpEncoding(Archive *AH)
2430 {
2431         const char *encname = pg_encoding_to_char(AH->encoding);
2432         PQExpBuffer qry = createPQExpBuffer();
2433
2434         if (g_verbose)
2435                 write_msg(NULL, "saving encoding = %s\n", encname);
2436
2437         appendPQExpBuffer(qry, "SET client_encoding = ");
2438         appendStringLiteralAH(qry, encname, AH);
2439         appendPQExpBuffer(qry, ";\n");
2440
2441         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2442                                  "ENCODING", NULL, NULL, "",
2443                                  false, "ENCODING", SECTION_PRE_DATA,
2444                                  qry->data, "", NULL,
2445                                  NULL, 0,
2446                                  NULL, NULL);
2447
2448         destroyPQExpBuffer(qry);
2449 }
2450
2451
2452 /*
2453  * dumpStdStrings: put the correct escape string behavior into the archive
2454  */
2455 static void
2456 dumpStdStrings(Archive *AH)
2457 {
2458         const char *stdstrings = AH->std_strings ? "on" : "off";
2459         PQExpBuffer qry = createPQExpBuffer();
2460
2461         if (g_verbose)
2462                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2463                                   stdstrings);
2464
2465         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2466                                           stdstrings);
2467
2468         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2469                                  "STDSTRINGS", NULL, NULL, "",
2470                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2471                                  qry->data, "", NULL,
2472                                  NULL, 0,
2473                                  NULL, NULL);
2474
2475         destroyPQExpBuffer(qry);
2476 }
2477
2478
2479 /*
2480  * getBlobs:
2481  *      Collect schema-level data about large objects
2482  */
2483 static void
2484 getBlobs(Archive *fout)
2485 {
2486         PQExpBuffer blobQry = createPQExpBuffer();
2487         BlobInfo   *binfo;
2488         DumpableObject *bdata;
2489         PGresult   *res;
2490         int                     ntups;
2491         int                     i;
2492
2493         /* Verbose message */
2494         if (g_verbose)
2495                 write_msg(NULL, "reading large objects\n");
2496
2497         /* Make sure we are in proper schema */
2498         selectSourceSchema(fout, "pg_catalog");
2499
2500         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2501         if (fout->remoteVersion >= 90000)
2502                 appendPQExpBuffer(blobQry,
2503                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2504                                                   " FROM pg_largeobject_metadata",
2505                                                   username_subquery);
2506         else if (fout->remoteVersion >= 70100)
2507                 appendPQExpBuffer(blobQry,
2508                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2509                                                   " FROM pg_largeobject");
2510         else
2511                 appendPQExpBuffer(blobQry,
2512                                                   "SELECT oid, NULL::oid, NULL::oid"
2513                                                   " FROM pg_class WHERE relkind = 'l'");
2514
2515         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2516
2517         ntups = PQntuples(res);
2518         if (ntups > 0)
2519         {
2520                 /*
2521                  * Each large object has its own BLOB archive entry.
2522                  */
2523                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2524
2525                 for (i = 0; i < ntups; i++)
2526                 {
2527                         binfo[i].dobj.objType = DO_BLOB;
2528                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2529                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2530                         AssignDumpId(&binfo[i].dobj);
2531
2532                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2533                         if (!PQgetisnull(res, i, 1))
2534                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2535                         else
2536                                 binfo[i].rolname = "";
2537                         if (!PQgetisnull(res, i, 2))
2538                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2539                         else
2540                                 binfo[i].blobacl = NULL;
2541                 }
2542
2543                 /*
2544                  * If we have any large objects, a "BLOBS" archive entry is needed.
2545                  * This is just a placeholder for sorting; it carries no data now.
2546                  */
2547                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2548                 bdata->objType = DO_BLOB_DATA;
2549                 bdata->catId = nilCatalogId;
2550                 AssignDumpId(bdata);
2551                 bdata->name = pg_strdup("BLOBS");
2552         }
2553
2554         PQclear(res);
2555         destroyPQExpBuffer(blobQry);
2556 }
2557
2558 /*
2559  * dumpBlob
2560  *
2561  * dump the definition (metadata) of the given large object
2562  */
2563 static void
2564 dumpBlob(Archive *fout, BlobInfo *binfo)
2565 {
2566         PQExpBuffer cquery = createPQExpBuffer();
2567         PQExpBuffer dquery = createPQExpBuffer();
2568
2569         appendPQExpBuffer(cquery,
2570                                           "SELECT pg_catalog.lo_create('%s');\n",
2571                                           binfo->dobj.name);
2572
2573         appendPQExpBuffer(dquery,
2574                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2575                                           binfo->dobj.name);
2576
2577         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2578                                  binfo->dobj.name,
2579                                  NULL, NULL,
2580                                  binfo->rolname, false,
2581                                  "BLOB", SECTION_PRE_DATA,
2582                                  cquery->data, dquery->data, NULL,
2583                                  NULL, 0,
2584                                  NULL, NULL);
2585
2586         /* set up tag for comment and/or ACL */
2587         resetPQExpBuffer(cquery);
2588         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2589
2590         /* Dump comment if any */
2591         dumpComment(fout, cquery->data,
2592                                 NULL, binfo->rolname,
2593                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2594
2595         /* Dump security label if any */
2596         dumpSecLabel(fout, cquery->data,
2597                                  NULL, binfo->rolname,
2598                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2599
2600         /* Dump ACL if any */
2601         if (binfo->blobacl)
2602                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2603                                 binfo->dobj.name, NULL, cquery->data,
2604                                 NULL, binfo->rolname, binfo->blobacl);
2605
2606         destroyPQExpBuffer(cquery);
2607         destroyPQExpBuffer(dquery);
2608 }
2609
2610 /*
2611  * dumpBlobs:
2612  *      dump the data contents of all large objects
2613  */
2614 static int
2615 dumpBlobs(Archive *fout, void *arg)
2616 {
2617         const char *blobQry;
2618         const char *blobFetchQry;
2619         PGconn     *conn = GetConnection(fout);
2620         PGresult   *res;
2621         char            buf[LOBBUFSIZE];
2622         int                     ntups;
2623         int                     i;
2624         int                     cnt;
2625
2626         if (g_verbose)
2627                 write_msg(NULL, "saving large objects\n");
2628
2629         /* Make sure we are in proper schema */
2630         selectSourceSchema(fout, "pg_catalog");
2631
2632         /*
2633          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2634          * the already-in-memory dumpable objects instead...
2635          */
2636         if (fout->remoteVersion >= 90000)
2637                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2638         else if (fout->remoteVersion >= 70100)
2639                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2640         else
2641                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2642
2643         ExecuteSqlStatement(fout, blobQry);
2644
2645         /* Command to fetch from cursor */
2646         blobFetchQry = "FETCH 1000 IN bloboid";
2647
2648         do
2649         {
2650                 /* Do a fetch */
2651                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2652
2653                 /* Process the tuples, if any */
2654                 ntups = PQntuples(res);
2655                 for (i = 0; i < ntups; i++)
2656                 {
2657                         Oid                     blobOid;
2658                         int                     loFd;
2659
2660                         blobOid = atooid(PQgetvalue(res, i, 0));
2661                         /* Open the BLOB */
2662                         loFd = lo_open(conn, blobOid, INV_READ);
2663                         if (loFd == -1)
2664                                 exit_horribly(NULL, "could not open large object %u: %s",
2665                                                           blobOid, PQerrorMessage(conn));
2666
2667                         StartBlob(fout, blobOid);
2668
2669                         /* Now read it in chunks, sending data to archive */
2670                         do
2671                         {
2672                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2673                                 if (cnt < 0)
2674                                         exit_horribly(NULL, "error reading large object %u: %s",
2675                                                                   blobOid, PQerrorMessage(conn));
2676
2677                                 WriteData(fout, buf, cnt);
2678                         } while (cnt > 0);
2679
2680                         lo_close(conn, loFd);
2681
2682                         EndBlob(fout, blobOid);
2683                 }
2684
2685                 PQclear(res);
2686         } while (ntups > 0);
2687
2688         return 1;
2689 }
2690
2691 static void
2692 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2693                                                                                  PQExpBuffer upgrade_buffer,
2694                                                                                  Oid pg_type_oid)
2695 {
2696         PQExpBuffer upgrade_query = createPQExpBuffer();
2697         PGresult   *upgrade_res;
2698         Oid                     pg_type_array_oid;
2699
2700         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2701         appendPQExpBuffer(upgrade_buffer,
2702          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2703                                           pg_type_oid);
2704
2705         /* we only support old >= 8.3 for binary upgrades */
2706         appendPQExpBuffer(upgrade_query,
2707                                           "SELECT typarray "
2708                                           "FROM pg_catalog.pg_type "
2709                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2710                                           pg_type_oid);
2711
2712         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2713
2714         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2715
2716         if (OidIsValid(pg_type_array_oid))
2717         {
2718                 appendPQExpBuffer(upgrade_buffer,
2719                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2720                 appendPQExpBuffer(upgrade_buffer,
2721                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2722                                                   pg_type_array_oid);
2723         }
2724
2725         PQclear(upgrade_res);
2726         destroyPQExpBuffer(upgrade_query);
2727 }
2728
2729 static bool
2730 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2731                                                                                 PQExpBuffer upgrade_buffer,
2732                                                                                 Oid pg_rel_oid)
2733 {
2734         PQExpBuffer upgrade_query = createPQExpBuffer();
2735         PGresult   *upgrade_res;
2736         Oid                     pg_type_oid;
2737         bool            toast_set = false;
2738
2739         /* we only support old >= 8.3 for binary upgrades */
2740         appendPQExpBuffer(upgrade_query,
2741                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2742                                           "FROM pg_catalog.pg_class c "
2743                                           "LEFT JOIN pg_catalog.pg_class t ON "
2744                                           "  (c.reltoastrelid = t.oid) "
2745                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2746                                           pg_rel_oid);
2747
2748         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2749
2750         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2751
2752         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2753                                                                                          pg_type_oid);
2754
2755         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2756         {
2757                 /* Toast tables do not have pg_type array rows */
2758                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2759                                                                                         PQfnumber(upgrade_res, "trel")));
2760
2761                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2762                 appendPQExpBuffer(upgrade_buffer,
2763                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2764                                                   pg_type_toast_oid);
2765
2766                 toast_set = true;
2767         }
2768
2769         PQclear(upgrade_res);
2770         destroyPQExpBuffer(upgrade_query);
2771
2772         return toast_set;
2773 }
2774
2775 static void
2776 binary_upgrade_set_pg_class_oids(Archive *fout,
2777                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2778                                                                  bool is_index)
2779 {
2780         PQExpBuffer upgrade_query = createPQExpBuffer();
2781         PGresult   *upgrade_res;
2782         Oid                     pg_class_reltoastrelid;
2783         Oid                     pg_class_reltoastidxid;
2784
2785         appendPQExpBuffer(upgrade_query,
2786                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2787                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2788                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2789                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2790                                           pg_class_oid);
2791
2792         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2793
2794         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2795         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2796
2797         appendPQExpBuffer(upgrade_buffer,
2798                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2799
2800         if (!is_index)
2801         {
2802                 appendPQExpBuffer(upgrade_buffer,
2803                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2804                                                   pg_class_oid);
2805                 /* only tables have toast tables, not indexes */
2806                 if (OidIsValid(pg_class_reltoastrelid))
2807                 {
2808                         /*
2809                          * One complexity is that the table definition might not require
2810                          * the creation of a TOAST table, and the TOAST table might have
2811                          * been created long after table creation, when the table was
2812                          * loaded with wide data.  By setting the TOAST oid we force
2813                          * creation of the TOAST heap and TOAST index by the backend so we
2814                          * can cleanly copy the files during binary upgrade.
2815                          */
2816
2817                         appendPQExpBuffer(upgrade_buffer,
2818                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2819                                                           pg_class_reltoastrelid);
2820
2821                         /* every toast table has an index */
2822                         appendPQExpBuffer(upgrade_buffer,
2823                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2824                                                           pg_class_reltoastidxid);
2825                 }
2826         }
2827         else
2828                 appendPQExpBuffer(upgrade_buffer,
2829                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2830                                                   pg_class_oid);
2831
2832         appendPQExpBuffer(upgrade_buffer, "\n");
2833
2834         PQclear(upgrade_res);
2835         destroyPQExpBuffer(upgrade_query);
2836 }
2837
2838 /*
2839  * If the DumpableObject is a member of an extension, add a suitable
2840  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2841  */
2842 static void
2843 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2844                                                                 DumpableObject *dobj,
2845                                                                 const char *objlabel)
2846 {
2847         DumpableObject *extobj = NULL;
2848         int                     i;
2849
2850         if (!dobj->ext_member)
2851                 return;
2852
2853         /*
2854          * Find the parent extension.  We could avoid this search if we wanted to
2855          * add a link field to DumpableObject, but the space costs of that would
2856          * be considerable.  We assume that member objects could only have a
2857          * direct dependency on their own extension, not any others.
2858          */
2859         for (i = 0; i < dobj->nDeps; i++)
2860         {
2861                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2862                 if (extobj && extobj->objType == DO_EXTENSION)
2863                         break;
2864                 extobj = NULL;
2865         }
2866         if (extobj == NULL)
2867                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2868
2869         appendPQExpBuffer(upgrade_buffer,
2870           "\n-- For binary upgrade, handle extension membership the hard way\n");
2871         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2872                                           fmtId(extobj->name),
2873                                           objlabel);
2874 }
2875
2876 /*
2877  * getNamespaces:
2878  *        read all namespaces in the system catalogs and return them in the
2879  * NamespaceInfo* structure
2880  *
2881  *      numNamespaces is set to the number of namespaces read in
2882  */
2883 NamespaceInfo *
2884 getNamespaces(Archive *fout, int *numNamespaces)
2885 {
2886         PGresult   *res;
2887         int                     ntups;
2888         int                     i;
2889         PQExpBuffer query;
2890         NamespaceInfo *nsinfo;
2891         int                     i_tableoid;
2892         int                     i_oid;
2893         int                     i_nspname;
2894         int                     i_rolname;
2895         int                     i_nspacl;
2896
2897         /*
2898          * Before 7.3, there are no real namespaces; create two dummy entries, one
2899          * for user stuff and one for system stuff.
2900          */
2901         if (fout->remoteVersion < 70300)
2902         {
2903                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2904
2905                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2906                 nsinfo[0].dobj.catId.tableoid = 0;
2907                 nsinfo[0].dobj.catId.oid = 0;
2908                 AssignDumpId(&nsinfo[0].dobj);
2909                 nsinfo[0].dobj.name = pg_strdup("public");
2910                 nsinfo[0].rolname = pg_strdup("");
2911                 nsinfo[0].nspacl = pg_strdup("");
2912
2913                 selectDumpableNamespace(&nsinfo[0]);
2914
2915                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2916                 nsinfo[1].dobj.catId.tableoid = 0;
2917                 nsinfo[1].dobj.catId.oid = 1;
2918                 AssignDumpId(&nsinfo[1].dobj);
2919                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2920                 nsinfo[1].rolname = pg_strdup("");
2921                 nsinfo[1].nspacl = pg_strdup("");
2922
2923                 selectDumpableNamespace(&nsinfo[1]);
2924
2925                 *numNamespaces = 2;
2926
2927                 return nsinfo;
2928         }
2929
2930         query = createPQExpBuffer();
2931
2932         /* Make sure we are in proper schema */
2933         selectSourceSchema(fout, "pg_catalog");
2934
2935         /*
2936          * we fetch all namespaces including system ones, so that every object we
2937          * read in can be linked to a containing namespace.
2938          */
2939         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2940                                           "(%s nspowner) AS rolname, "
2941                                           "nspacl FROM pg_namespace",
2942                                           username_subquery);
2943
2944         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2945
2946         ntups = PQntuples(res);
2947
2948         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2949
2950         i_tableoid = PQfnumber(res, "tableoid");
2951         i_oid = PQfnumber(res, "oid");
2952         i_nspname = PQfnumber(res, "nspname");
2953         i_rolname = PQfnumber(res, "rolname");
2954         i_nspacl = PQfnumber(res, "nspacl");
2955
2956         for (i = 0; i < ntups; i++)
2957         {
2958                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2959                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2960                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2961                 AssignDumpId(&nsinfo[i].dobj);
2962                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2963                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2964                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2965
2966                 /* Decide whether to dump this namespace */
2967                 selectDumpableNamespace(&nsinfo[i]);
2968
2969                 if (strlen(nsinfo[i].rolname) == 0)
2970                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2971                                           nsinfo[i].dobj.name);
2972         }
2973
2974         PQclear(res);
2975         destroyPQExpBuffer(query);
2976
2977         *numNamespaces = ntups;
2978
2979         return nsinfo;
2980 }
2981
2982 /*
2983  * findNamespace:
2984  *              given a namespace OID and an object OID, look up the info read by
2985  *              getNamespaces
2986  *
2987  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2988  * a system object or not.      In 7.3 and later there is no guessing, and we
2989  * don't use objoid at all.
2990  */
2991 static NamespaceInfo *
2992 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2993 {
2994         NamespaceInfo *nsinfo;
2995
2996         if (fout->remoteVersion >= 70300)
2997         {
2998                 nsinfo = findNamespaceByOid(nsoid);
2999         }
3000         else
3001         {
3002                 /* This code depends on the dummy objects set up by getNamespaces. */
3003                 Oid                     i;
3004
3005                 if (objoid > g_last_builtin_oid)
3006                         i = 0;                          /* user object */
3007                 else
3008                         i = 1;                          /* system object */
3009                 nsinfo = findNamespaceByOid(i);
3010         }
3011
3012         if (nsinfo == NULL)
3013                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3014
3015         return nsinfo;
3016 }
3017
3018 /*
3019  * getExtensions:
3020  *        read all extensions in the system catalogs and return them in the
3021  * ExtensionInfo* structure
3022  *
3023  *      numExtensions is set to the number of extensions read in
3024  */
3025 ExtensionInfo *
3026 getExtensions(Archive *fout, int *numExtensions)
3027 {
3028         PGresult   *res;
3029         int                     ntups;
3030         int                     i;
3031         PQExpBuffer query;
3032         ExtensionInfo *extinfo;
3033         int                     i_tableoid;
3034         int                     i_oid;
3035         int                     i_extname;
3036         int                     i_nspname;
3037         int                     i_extrelocatable;
3038         int                     i_extversion;
3039         int                     i_extconfig;
3040         int                     i_extcondition;
3041
3042         /*
3043          * Before 9.1, there are no extensions.
3044          */
3045         if (fout->remoteVersion < 90100)
3046         {
3047                 *numExtensions = 0;
3048                 return NULL;
3049         }
3050
3051         query = createPQExpBuffer();
3052
3053         /* Make sure we are in proper schema */
3054         selectSourceSchema(fout, "pg_catalog");
3055
3056         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
3057                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3058                                           "FROM pg_extension x "
3059                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
3060
3061         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3062
3063         ntups = PQntuples(res);
3064
3065         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3066
3067         i_tableoid = PQfnumber(res, "tableoid");
3068         i_oid = PQfnumber(res, "oid");
3069         i_extname = PQfnumber(res, "extname");
3070         i_nspname = PQfnumber(res, "nspname");
3071         i_extrelocatable = PQfnumber(res, "extrelocatable");
3072         i_extversion = PQfnumber(res, "extversion");
3073         i_extconfig = PQfnumber(res, "extconfig");
3074         i_extcondition = PQfnumber(res, "extcondition");
3075
3076         for (i = 0; i < ntups; i++)
3077         {
3078                 extinfo[i].dobj.objType = DO_EXTENSION;
3079                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3080                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3081                 AssignDumpId(&extinfo[i].dobj);
3082                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3083                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3084                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3085                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3086                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3087                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3088
3089                 /* Decide whether we want to dump it */
3090                 selectDumpableExtension(&(extinfo[i]));
3091         }
3092
3093         PQclear(res);
3094         destroyPQExpBuffer(query);
3095
3096         *numExtensions = ntups;
3097
3098         return extinfo;
3099 }
3100
3101 /*
3102  * getTypes:
3103  *        read all types in the system catalogs and return them in the
3104  * TypeInfo* structure
3105  *
3106  *      numTypes is set to the number of types read in
3107  *
3108  * NB: this must run after getFuncs() because we assume we can do
3109  * findFuncByOid().
3110  */
3111 TypeInfo *
3112 getTypes(Archive *fout, int *numTypes)
3113 {
3114         PGresult   *res;
3115         int                     ntups;
3116         int                     i;
3117         PQExpBuffer query = createPQExpBuffer();
3118         TypeInfo   *tyinfo;
3119         ShellTypeInfo *stinfo;
3120         int                     i_tableoid;
3121         int                     i_oid;
3122         int                     i_typname;
3123         int                     i_typnamespace;
3124         int                     i_typacl;
3125         int                     i_rolname;
3126         int                     i_typinput;
3127         int                     i_typoutput;
3128         int                     i_typelem;
3129         int                     i_typrelid;
3130         int                     i_typrelkind;
3131         int                     i_typtype;
3132         int                     i_typisdefined;
3133         int                     i_isarray;
3134
3135         /*
3136          * we include even the built-in types because those may be used as array
3137          * elements by user-defined types
3138          *
3139          * we filter out the built-in types when we dump out the types
3140          *
3141          * same approach for undefined (shell) types and array types
3142          *
3143          * Note: as of 8.3 we can reliably detect whether a type is an
3144          * auto-generated array type by checking the element type's typarray.
3145          * (Before that the test is capable of generating false positives.) We
3146          * still check for name beginning with '_', though, so as to avoid the
3147          * cost of the subselect probe for all standard types.  This would have to
3148          * be revisited if the backend ever allows renaming of array types.
3149          */
3150
3151         /* Make sure we are in proper schema */
3152         selectSourceSchema(fout, "pg_catalog");
3153
3154         if (fout->remoteVersion >= 90200)
3155         {
3156                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3157                                                   "typnamespace, typacl, "
3158                                                   "(%s typowner) AS rolname, "
3159                                                   "typinput::oid AS typinput, "
3160                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3161                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3162                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3163                                                   "typtype, typisdefined, "
3164                                                   "typname[0] = '_' AND typelem != 0 AND "
3165                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3166                                                   "FROM pg_type",
3167                                                   username_subquery);
3168         }
3169         else if (fout->remoteVersion >= 80300)
3170         {
3171                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3172                                                   "typnamespace, '{=U}' AS typacl, "
3173                                                   "(%s typowner) AS rolname, "
3174                                                   "typinput::oid AS typinput, "
3175                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3176                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3177                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3178                                                   "typtype, typisdefined, "
3179                                                   "typname[0] = '_' AND typelem != 0 AND "
3180                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3181                                                   "FROM pg_type",
3182                                                   username_subquery);
3183         }
3184         else if (fout->remoteVersion >= 70300)
3185         {
3186                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3187                                                   "typnamespace, '{=U}' AS typacl, "
3188                                                   "(%s typowner) AS rolname, "
3189                                                   "typinput::oid AS typinput, "
3190                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3191                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3192                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3193                                                   "typtype, typisdefined, "
3194                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3195                                                   "FROM pg_type",
3196                                                   username_subquery);
3197         }
3198         else if (fout->remoteVersion >= 70100)
3199         {
3200                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3201                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3202                                                   "(%s typowner) AS rolname, "
3203                                                   "typinput::oid AS typinput, "
3204                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3205                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3206                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3207                                                   "typtype, typisdefined, "
3208                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3209                                                   "FROM pg_type",
3210                                                   username_subquery);
3211         }
3212         else
3213         {
3214                 appendPQExpBuffer(query, "SELECT "
3215                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3216                                                   "oid, typname, "
3217                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3218                                                   "(%s typowner) AS rolname, "
3219                                                   "typinput::oid AS typinput, "
3220                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3221                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3222                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3223                                                   "typtype, typisdefined, "
3224                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3225                                                   "FROM pg_type",
3226                                                   username_subquery);
3227         }
3228
3229         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3230
3231         ntups = PQntuples(res);
3232
3233         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3234
3235         i_tableoid = PQfnumber(res, "tableoid");
3236         i_oid = PQfnumber(res, "oid");
3237         i_typname = PQfnumber(res, "typname");
3238         i_typnamespace = PQfnumber(res, "typnamespace");
3239         i_typacl = PQfnumber(res, "typacl");
3240         i_rolname = PQfnumber(res, "rolname");
3241         i_typinput = PQfnumber(res, "typinput");
3242         i_typoutput = PQfnumber(res, "typoutput");
3243         i_typelem = PQfnumber(res, "typelem");
3244         i_typrelid = PQfnumber(res, "typrelid");
3245         i_typrelkind = PQfnumber(res, "typrelkind");
3246         i_typtype = PQfnumber(res, "typtype");
3247         i_typisdefined = PQfnumber(res, "typisdefined");
3248         i_isarray = PQfnumber(res, "isarray");
3249
3250         for (i = 0; i < ntups; i++)
3251         {
3252                 tyinfo[i].dobj.objType = DO_TYPE;
3253                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3254                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3255                 AssignDumpId(&tyinfo[i].dobj);
3256                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3257                 tyinfo[i].dobj.namespace =
3258                         findNamespace(fout,
3259                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3260                                                   tyinfo[i].dobj.catId.oid);
3261                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3262                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3263                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3264                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3265                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3266                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3267                 tyinfo[i].shellType = NULL;
3268
3269                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3270                         tyinfo[i].isDefined = true;
3271                 else
3272                         tyinfo[i].isDefined = false;
3273
3274                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3275                         tyinfo[i].isArray = true;
3276                 else
3277                         tyinfo[i].isArray = false;
3278
3279                 /* Decide whether we want to dump it */
3280                 selectDumpableType(&tyinfo[i]);
3281
3282                 /*
3283                  * If it's a domain, fetch info about its constraints, if any
3284                  */
3285                 tyinfo[i].nDomChecks = 0;
3286                 tyinfo[i].domChecks = NULL;
3287                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3288                         getDomainConstraints(fout, &(tyinfo[i]));
3289
3290                 /*
3291                  * If it's a base type, make a DumpableObject representing a shell
3292                  * definition of the type.      We will need to dump that ahead of the I/O
3293                  * functions for the type.      Similarly, range types need a shell
3294                  * definition in case they have a canonicalize function.
3295                  *
3296                  * Note: the shell type doesn't have a catId.  You might think it
3297                  * should copy the base type's catId, but then it might capture the
3298                  * pg_depend entries for the type, which we don't want.
3299                  */
3300                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3301                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3302                 {
3303                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3304                         stinfo->dobj.objType = DO_SHELL_TYPE;
3305                         stinfo->dobj.catId = nilCatalogId;
3306                         AssignDumpId(&stinfo->dobj);
3307                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3308                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3309                         stinfo->baseType = &(tyinfo[i]);
3310                         tyinfo[i].shellType = stinfo;
3311
3312                         /*
3313                          * Initially mark the shell type as not to be dumped.  We'll only
3314                          * dump it if the I/O or canonicalize functions need to be dumped;
3315                          * this is taken care of while sorting dependencies.
3316                          */
3317                         stinfo->dobj.dump = false;
3318
3319                         /*
3320                          * However, if dumping from pre-7.3, there will be no dependency
3321                          * info so we have to fake it here.  We only need to worry about
3322                          * typinput and typoutput since the other functions only exist
3323                          * post-7.3.
3324                          */
3325                         if (fout->remoteVersion < 70300)
3326                         {
3327                                 Oid                     typinput;
3328                                 Oid                     typoutput;
3329                                 FuncInfo   *funcInfo;
3330
3331                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3332                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3333
3334                                 funcInfo = findFuncByOid(typinput);
3335                                 if (funcInfo && funcInfo->dobj.dump)
3336                                 {
3337                                         /* base type depends on function */
3338                                         addObjectDependency(&tyinfo[i].dobj,
3339                                                                                 funcInfo->dobj.dumpId);
3340                                         /* function depends on shell type */
3341                                         addObjectDependency(&funcInfo->dobj,
3342                                                                                 stinfo->dobj.dumpId);
3343                                         /* mark shell type as to be dumped */
3344                                         stinfo->dobj.dump = true;
3345                                 }
3346
3347                                 funcInfo = findFuncByOid(typoutput);
3348                                 if (funcInfo && funcInfo->dobj.dump)
3349                                 {
3350                                         /* base type depends on function */
3351                                         addObjectDependency(&tyinfo[i].dobj,
3352                                                                                 funcInfo->dobj.dumpId);
3353                                         /* function depends on shell type */
3354                                         addObjectDependency(&funcInfo->dobj,
3355                                                                                 stinfo->dobj.dumpId);
3356                                         /* mark shell type as to be dumped */
3357                                         stinfo->dobj.dump = true;
3358                                 }
3359                         }
3360                 }
3361
3362                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3363                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3364                                           tyinfo[i].dobj.name);
3365         }
3366
3367         *numTypes = ntups;
3368
3369         PQclear(res);
3370
3371         destroyPQExpBuffer(query);
3372
3373         return tyinfo;
3374 }
3375
3376 /*
3377  * getOperators:
3378  *        read all operators in the system catalogs and return them in the
3379  * OprInfo* structure
3380  *
3381  *      numOprs is set to the number of operators read in
3382  */
3383 OprInfo *
3384 getOperators(Archive *fout, int *numOprs)
3385 {
3386         PGresult   *res;
3387         int                     ntups;
3388         int                     i;
3389         PQExpBuffer query = createPQExpBuffer();
3390         OprInfo    *oprinfo;
3391         int                     i_tableoid;
3392         int                     i_oid;
3393         int                     i_oprname;
3394         int                     i_oprnamespace;
3395         int                     i_rolname;
3396         int                     i_oprkind;
3397         int                     i_oprcode;
3398
3399         /*
3400          * find all operators, including builtin operators; we filter out
3401          * system-defined operators at dump-out time.
3402          */
3403
3404         /* Make sure we are in proper schema */
3405         selectSourceSchema(fout, "pg_catalog");
3406
3407         if (fout->remoteVersion >= 70300)
3408         {
3409                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3410                                                   "oprnamespace, "
3411                                                   "(%s oprowner) AS rolname, "
3412                                                   "oprkind, "
3413                                                   "oprcode::oid AS oprcode "
3414                                                   "FROM pg_operator",
3415                                                   username_subquery);
3416         }
3417         else if (fout->remoteVersion >= 70100)
3418         {
3419                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3420                                                   "0::oid AS oprnamespace, "
3421                                                   "(%s oprowner) AS rolname, "
3422                                                   "oprkind, "
3423                                                   "oprcode::oid AS oprcode "
3424                                                   "FROM pg_operator",
3425                                                   username_subquery);
3426         }
3427         else
3428         {
3429                 appendPQExpBuffer(query, "SELECT "
3430                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3431                                                   "oid, oprname, "
3432                                                   "0::oid AS oprnamespace, "
3433                                                   "(%s oprowner) AS rolname, "
3434                                                   "oprkind, "
3435                                                   "oprcode::oid AS oprcode "
3436                                                   "FROM pg_operator",
3437                                                   username_subquery);
3438         }
3439
3440         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3441
3442         ntups = PQntuples(res);
3443         *numOprs = ntups;
3444
3445         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3446
3447         i_tableoid = PQfnumber(res, "tableoid");
3448         i_oid = PQfnumber(res, "oid");
3449         i_oprname = PQfnumber(res, "oprname");
3450         i_oprnamespace = PQfnumber(res, "oprnamespace");
3451         i_rolname = PQfnumber(res, "rolname");
3452         i_oprkind = PQfnumber(res, "oprkind");
3453         i_oprcode = PQfnumber(res, "oprcode");
3454
3455         for (i = 0; i < ntups; i++)
3456         {
3457                 oprinfo[i].dobj.objType = DO_OPERATOR;
3458                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3459                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3460                 AssignDumpId(&oprinfo[i].dobj);
3461                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3462                 oprinfo[i].dobj.namespace =
3463                         findNamespace(fout,
3464                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3465                                                   oprinfo[i].dobj.catId.oid);
3466                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3467                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3468                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3469
3470                 /* Decide whether we want to dump it */
3471                 selectDumpableObject(&(oprinfo[i].dobj));
3472
3473                 if (strlen(oprinfo[i].rolname) == 0)
3474                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3475                                           oprinfo[i].dobj.name);
3476         }
3477
3478         PQclear(res);
3479
3480         destroyPQExpBuffer(query);
3481
3482         return oprinfo;
3483 }
3484
3485 /*
3486  * getCollations:
3487  *        read all collations in the system catalogs and return them in the
3488  * CollInfo* structure
3489  *
3490  *      numCollations is set to the number of collations read in
3491  */
3492 CollInfo *
3493 getCollations(Archive *fout, int *numCollations)
3494 {
3495         PGresult   *res;
3496         int                     ntups;
3497         int                     i;
3498         PQExpBuffer query;
3499         CollInfo   *collinfo;
3500         int                     i_tableoid;
3501         int                     i_oid;
3502         int                     i_collname;
3503         int                     i_collnamespace;
3504         int                     i_rolname;
3505
3506         /* Collations didn't exist pre-9.1 */
3507         if (fout->remoteVersion < 90100)
3508         {
3509                 *numCollations = 0;
3510                 return NULL;
3511         }
3512
3513         query = createPQExpBuffer();
3514
3515         /*
3516          * find all collations, including builtin collations; we filter out
3517          * system-defined collations at dump-out time.
3518          */
3519
3520         /* Make sure we are in proper schema */
3521         selectSourceSchema(fout, "pg_catalog");
3522
3523         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3524                                           "collnamespace, "
3525                                           "(%s collowner) AS rolname "
3526                                           "FROM pg_collation",
3527                                           username_subquery);
3528
3529         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3530
3531         ntups = PQntuples(res);
3532         *numCollations = ntups;
3533
3534         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3535
3536         i_tableoid = PQfnumber(res, "tableoid");
3537         i_oid = PQfnumber(res, "oid");
3538         i_collname = PQfnumber(res, "collname");
3539         i_collnamespace = PQfnumber(res, "collnamespace");
3540         i_rolname = PQfnumber(res, "rolname");
3541
3542         for (i = 0; i < ntups; i++)
3543         {
3544                 collinfo[i].dobj.objType = DO_COLLATION;
3545                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3546                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3547                 AssignDumpId(&collinfo[i].dobj);
3548                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3549                 collinfo[i].dobj.namespace =
3550                         findNamespace(fout,
3551                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3552                                                   collinfo[i].dobj.catId.oid);
3553                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3554
3555                 /* Decide whether we want to dump it */
3556                 selectDumpableObject(&(collinfo[i].dobj));
3557         }
3558
3559         PQclear(res);
3560
3561         destroyPQExpBuffer(query);
3562
3563         return collinfo;
3564 }
3565
3566 /*
3567  * getConversions:
3568  *        read all conversions in the system catalogs and return them in the
3569  * ConvInfo* structure
3570  *
3571  *      numConversions is set to the number of conversions read in
3572  */
3573 ConvInfo *
3574 getConversions(Archive *fout, int *numConversions)
3575 {
3576         PGresult   *res;
3577         int                     ntups;
3578         int                     i;
3579         PQExpBuffer query = createPQExpBuffer();
3580         ConvInfo   *convinfo;
3581         int                     i_tableoid;
3582         int                     i_oid;
3583         int                     i_conname;
3584         int                     i_connamespace;
3585         int                     i_rolname;
3586
3587         /* Conversions didn't exist pre-7.3 */
3588         if (fout->remoteVersion < 70300)
3589         {
3590                 *numConversions = 0;
3591                 return NULL;
3592         }
3593
3594         /*
3595          * find all conversions, including builtin conversions; we filter out
3596          * system-defined conversions at dump-out time.
3597          */
3598
3599         /* Make sure we are in proper schema */
3600         selectSourceSchema(fout, "pg_catalog");
3601
3602         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3603                                           "connamespace, "
3604                                           "(%s conowner) AS rolname "
3605                                           "FROM pg_conversion",
3606                                           username_subquery);
3607
3608         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3609
3610         ntups = PQntuples(res);
3611         *numConversions = ntups;
3612
3613         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3614
3615         i_tableoid = PQfnumber(res, "tableoid");
3616         i_oid = PQfnumber(res, "oid");
3617         i_conname = PQfnumber(res, "conname");
3618         i_connamespace = PQfnumber(res, "connamespace");
3619         i_rolname = PQfnumber(res, "rolname");
3620
3621         for (i = 0; i < ntups; i++)
3622         {
3623                 convinfo[i].dobj.objType = DO_CONVERSION;
3624                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3625                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3626                 AssignDumpId(&convinfo[i].dobj);
3627                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3628                 convinfo[i].dobj.namespace =
3629                         findNamespace(fout,
3630                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3631                                                   convinfo[i].dobj.catId.oid);
3632                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3633
3634                 /* Decide whether we want to dump it */
3635                 selectDumpableObject(&(convinfo[i].dobj));
3636         }
3637
3638         PQclear(res);
3639
3640         destroyPQExpBuffer(query);
3641
3642         return convinfo;
3643 }
3644
3645 /*
3646  * getOpclasses:
3647  *        read all opclasses in the system catalogs and return them in the
3648  * OpclassInfo* structure
3649  *
3650  *      numOpclasses is set to the number of opclasses read in
3651  */
3652 OpclassInfo *
3653 getOpclasses(Archive *fout, int *numOpclasses)
3654 {
3655         PGresult   *res;
3656         int                     ntups;
3657         int                     i;
3658         PQExpBuffer query = createPQExpBuffer();
3659         OpclassInfo *opcinfo;
3660         int                     i_tableoid;
3661         int                     i_oid;
3662         int                     i_opcname;
3663         int                     i_opcnamespace;
3664         int                     i_rolname;
3665
3666         /*
3667          * find all opclasses, including builtin opclasses; we filter out
3668          * system-defined opclasses at dump-out time.
3669          */
3670
3671         /* Make sure we are in proper schema */
3672         selectSourceSchema(fout, "pg_catalog");
3673
3674         if (fout->remoteVersion >= 70300)
3675         {
3676                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3677                                                   "opcnamespace, "
3678                                                   "(%s opcowner) AS rolname "
3679                                                   "FROM pg_opclass",
3680                                                   username_subquery);
3681         }
3682         else if (fout->remoteVersion >= 70100)
3683         {
3684                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3685                                                   "0::oid AS opcnamespace, "
3686                                                   "''::name AS rolname "
3687                                                   "FROM pg_opclass");
3688         }
3689         else
3690         {
3691                 appendPQExpBuffer(query, "SELECT "
3692                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3693                                                   "oid, opcname, "
3694                                                   "0::oid AS opcnamespace, "
3695                                                   "''::name AS rolname "
3696                                                   "FROM pg_opclass");
3697         }
3698
3699         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3700
3701         ntups = PQntuples(res);
3702         *numOpclasses = ntups;
3703
3704         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3705
3706         i_tableoid = PQfnumber(res, "tableoid");
3707         i_oid = PQfnumber(res, "oid");
3708         i_opcname = PQfnumber(res, "opcname");
3709         i_opcnamespace = PQfnumber(res, "opcnamespace");
3710         i_rolname = PQfnumber(res, "rolname");
3711
3712         for (i = 0; i < ntups; i++)
3713         {
3714                 opcinfo[i].dobj.objType = DO_OPCLASS;
3715                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3716                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3717                 AssignDumpId(&opcinfo[i].dobj);
3718                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3719                 opcinfo[i].dobj.namespace =
3720                         findNamespace(fout,
3721                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3722                                                   opcinfo[i].dobj.catId.oid);
3723                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3724
3725                 /* Decide whether we want to dump it */
3726                 selectDumpableObject(&(opcinfo[i].dobj));
3727
3728                 if (fout->remoteVersion >= 70300)
3729                 {
3730                         if (strlen(opcinfo[i].rolname) == 0)
3731                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3732                                                   opcinfo[i].dobj.name);
3733                 }
3734         }
3735
3736         PQclear(res);
3737
3738         destroyPQExpBuffer(query);
3739
3740         return opcinfo;
3741 }
3742
3743 /*
3744  * getOpfamilies:
3745  *        read all opfamilies in the system catalogs and return them in the
3746  * OpfamilyInfo* structure
3747  *
3748  *      numOpfamilies is set to the number of opfamilies read in
3749  */
3750 OpfamilyInfo *
3751 getOpfamilies(Archive *fout, int *numOpfamilies)
3752 {
3753         PGresult   *res;
3754         int                     ntups;
3755         int                     i;
3756         PQExpBuffer query;
3757         OpfamilyInfo *opfinfo;
3758         int                     i_tableoid;
3759         int                     i_oid;
3760         int                     i_opfname;
3761         int                     i_opfnamespace;
3762         int                     i_rolname;
3763
3764         /* Before 8.3, there is no separate concept of opfamilies */
3765         if (fout->remoteVersion < 80300)
3766         {
3767                 *numOpfamilies = 0;
3768                 return NULL;
3769         }
3770
3771         query = createPQExpBuffer();
3772
3773         /*
3774          * find all opfamilies, including builtin opfamilies; we filter out
3775          * system-defined opfamilies at dump-out time.
3776          */
3777
3778         /* Make sure we are in proper schema */
3779         selectSourceSchema(fout, "pg_catalog");
3780
3781         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3782                                           "opfnamespace, "
3783                                           "(%s opfowner) AS rolname "
3784                                           "FROM pg_opfamily",
3785                                           username_subquery);
3786
3787         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3788
3789         ntups = PQntuples(res);
3790         *numOpfamilies = ntups;
3791
3792         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3793
3794         i_tableoid = PQfnumber(res, "tableoid");
3795         i_oid = PQfnumber(res, "oid");
3796         i_opfname = PQfnumber(res, "opfname");
3797         i_opfnamespace = PQfnumber(res, "opfnamespace");
3798         i_rolname = PQfnumber(res, "rolname");
3799
3800         for (i = 0; i < ntups; i++)
3801         {
3802                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3803                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3804                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3805                 AssignDumpId(&opfinfo[i].dobj);
3806                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3807                 opfinfo[i].dobj.namespace =
3808                         findNamespace(fout,
3809                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3810                                                   opfinfo[i].dobj.catId.oid);
3811                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3812
3813                 /* Decide whether we want to dump it */
3814                 selectDumpableObject(&(opfinfo[i].dobj));
3815
3816                 if (fout->remoteVersion >= 70300)
3817                 {
3818                         if (strlen(opfinfo[i].rolname) == 0)
3819                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3820                                                   opfinfo[i].dobj.name);
3821                 }
3822         }
3823
3824         PQclear(res);
3825
3826         destroyPQExpBuffer(query);
3827
3828         return opfinfo;
3829 }
3830
3831 /*
3832  * getAggregates:
3833  *        read all the user-defined aggregates in the system catalogs and
3834  * return them in the AggInfo* structure
3835  *
3836  * numAggs is set to the number of aggregates read in
3837  */
3838 AggInfo *
3839 getAggregates(Archive *fout, int *numAggs)
3840 {
3841         PGresult   *res;
3842         int                     ntups;
3843         int                     i;
3844         PQExpBuffer query = createPQExpBuffer();
3845         AggInfo    *agginfo;
3846         int                     i_tableoid;
3847         int                     i_oid;
3848         int                     i_aggname;
3849         int                     i_aggnamespace;
3850         int                     i_pronargs;
3851         int                     i_proargtypes;
3852         int                     i_rolname;
3853         int                     i_aggacl;
3854         int                     i_proiargs;
3855
3856         /* Make sure we are in proper schema */
3857         selectSourceSchema(fout, "pg_catalog");
3858
3859         /*
3860          * Find all user-defined aggregates.  See comment in getFuncs() for the
3861          * rationale behind the filtering logic.
3862          */
3863
3864         if (fout->remoteVersion >= 80400)
3865         {
3866                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3867                                                   "pronamespace AS aggnamespace, "
3868                                                   "pronargs, proargtypes, "
3869                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3870                                                   "(%s proowner) AS rolname, "
3871                                                   "proacl AS aggacl "
3872                                                   "FROM pg_proc p "
3873                                                   "WHERE proisagg AND ("
3874                                                   "pronamespace != "
3875                                                   "(SELECT oid FROM pg_namespace "
3876                                                   "WHERE nspname = 'pg_catalog')",
3877                                                   username_subquery);
3878                 if (binary_upgrade && fout->remoteVersion >= 90100)
3879                         appendPQExpBuffer(query,
3880                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3881                                                           "classid = 'pg_proc'::regclass AND "
3882                                                           "objid = p.oid AND "
3883                                                           "refclassid = 'pg_extension'::regclass AND "
3884                                                           "deptype = 'e')");
3885                 appendPQExpBuffer(query, ")");
3886         }
3887         else if (fout->remoteVersion >= 80200)
3888         {
3889                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3890                                                   "pronamespace AS aggnamespace, "
3891                                                   "pronargs, proargtypes, "
3892                                                   "NULL::text AS proiargs,"
3893                                                   "(%s proowner) AS rolname, "
3894                                                   "proacl AS aggacl "
3895                                                   "FROM pg_proc p "
3896                                                   "WHERE proisagg AND ("
3897                                                   "pronamespace != "
3898                                                   "(SELECT oid FROM pg_namespace "
3899                                                   "WHERE nspname = 'pg_catalog'))",
3900                                                   username_subquery);
3901         }
3902         else if (fout->remoteVersion >= 70300)
3903         {
3904                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3905                                                   "pronamespace AS aggnamespace, "
3906                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3907                                                   "proargtypes, "
3908                                                   "NULL::text AS proiargs, "
3909                                                   "(%s proowner) AS rolname, "
3910                                                   "proacl AS aggacl "
3911                                                   "FROM pg_proc "
3912                                                   "WHERE proisagg "
3913                                                   "AND pronamespace != "
3914                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3915                                                   username_subquery);
3916         }
3917         else if (fout->remoteVersion >= 70100)
3918         {
3919                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3920                                                   "0::oid AS aggnamespace, "
3921                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3922                                                   "aggbasetype AS proargtypes, "
3923                                                   "NULL::text AS proiargs, "
3924                                                   "(%s aggowner) AS rolname, "
3925                                                   "'{=X}' AS aggacl "
3926                                                   "FROM pg_aggregate "
3927                                                   "where oid > '%u'::oid",
3928                                                   username_subquery,
3929                                                   g_last_builtin_oid);
3930         }
3931         else
3932         {
3933                 appendPQExpBuffer(query, "SELECT "
3934                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3935                                                   "oid, aggname, "
3936                                                   "0::oid AS aggnamespace, "
3937                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3938                                                   "aggbasetype AS proargtypes, "
3939                                                   "NULL::text AS proiargs, "
3940                                                   "(%s aggowner) AS rolname, "
3941                                                   "'{=X}' AS aggacl "
3942                                                   "FROM pg_aggregate "
3943                                                   "where oid > '%u'::oid",
3944                                                   username_subquery,
3945                                                   g_last_builtin_oid);
3946         }
3947
3948         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3949
3950         ntups = PQntuples(res);
3951         *numAggs = ntups;
3952
3953         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3954
3955         i_tableoid = PQfnumber(res, "tableoid");
3956         i_oid = PQfnumber(res, "oid");
3957         i_aggname = PQfnumber(res, "aggname");
3958         i_aggnamespace = PQfnumber(res, "aggnamespace");
3959         i_pronargs = PQfnumber(res, "pronargs");
3960         i_proargtypes = PQfnumber(res, "proargtypes");
3961         i_rolname = PQfnumber(res, "rolname");
3962         i_aggacl = PQfnumber(res, "aggacl");
3963         i_proiargs = PQfnumber(res, "proiargs");
3964
3965         for (i = 0; i < ntups; i++)
3966         {
3967                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3968                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3969                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3970                 AssignDumpId(&agginfo[i].aggfn.dobj);
3971                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3972                 agginfo[i].aggfn.dobj.namespace =
3973                         findNamespace(fout,
3974                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3975                                                   agginfo[i].aggfn.dobj.catId.oid);
3976                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3977                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3978                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3979                                           agginfo[i].aggfn.dobj.name);
3980                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3981                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3982                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3983                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
3984                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3985                 if (agginfo[i].aggfn.nargs == 0)
3986                         agginfo[i].aggfn.argtypes = NULL;
3987                 else
3988                 {
3989                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3990                         if (fout->remoteVersion >= 70300)
3991                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3992                                                           agginfo[i].aggfn.argtypes,
3993                                                           agginfo[i].aggfn.nargs);
3994                         else
3995                                 /* it's just aggbasetype */
3996                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3997                 }
3998
3999                 /* Decide whether we want to dump it */
4000                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
4001         }
4002
4003         PQclear(res);
4004
4005         destroyPQExpBuffer(query);
4006
4007         return agginfo;
4008 }
4009
4010 /*
4011  * getFuncs:
4012  *        read all the user-defined functions in the system catalogs and
4013  * return them in the FuncInfo* structure
4014  *
4015  * numFuncs is set to the number of functions read in
4016  */
4017 FuncInfo *
4018 getFuncs(Archive *fout, int *numFuncs)
4019 {
4020         PGresult   *res;
4021         int                     ntups;
4022         int                     i;
4023         PQExpBuffer query = createPQExpBuffer();
4024         FuncInfo   *finfo;
4025         int                     i_tableoid;
4026         int                     i_oid;
4027         int                     i_proname;
4028         int                     i_pronamespace;
4029         int                     i_rolname;
4030         int                     i_prolang;
4031         int                     i_pronargs;
4032         int                     i_proargtypes;
4033         int                     i_prorettype;
4034         int                     i_proacl;
4035         int                     i_proiargs;
4036
4037         /* Make sure we are in proper schema */
4038         selectSourceSchema(fout, "pg_catalog");
4039
4040         /*
4041          * Find all user-defined functions.  Normally we can exclude functions in
4042          * pg_catalog, which is worth doing since there are several thousand of
4043          * 'em.  However, there are some extensions that create functions in
4044          * pg_catalog.  In normal dumps we can still ignore those --- but in
4045          * binary-upgrade mode, we must dump the member objects of the extension,
4046          * so be sure to fetch any such functions.
4047          *
4048          * Also, in 9.2 and up, exclude functions that are internally dependent on
4049          * something else, since presumably those will be created as a result of
4050          * creating the something else.  This currently only acts to suppress
4051          * constructor functions for range types.  Note that this is OK only
4052          * because the constructors don't have any dependencies the range type
4053          * doesn't have; otherwise we might not get creation ordering correct.
4054          */
4055
4056         if (fout->remoteVersion >= 80400)
4057         {
4058                 appendPQExpBuffer(query,
4059                                                   "SELECT tableoid, oid, proname, prolang, "
4060                                                   "pronargs, proargtypes, prorettype, proacl, "
4061                                                   "pronamespace, "
4062                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4063                                                   "(%s proowner) AS rolname "
4064                                                   "FROM pg_proc p "
4065                                                   "WHERE NOT proisagg AND ("
4066                                                   "pronamespace != "
4067                                                   "(SELECT oid FROM pg_namespace "
4068                                                   "WHERE nspname = 'pg_catalog')",
4069                                                   username_subquery);
4070                 if (fout->remoteVersion >= 90200)
4071                         appendPQExpBuffer(query,
4072                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4073                                                           "WHERE classid = 'pg_proc'::regclass AND "
4074                                                           "objid = p.oid AND deptype = 'i')");
4075                 if (binary_upgrade && fout->remoteVersion >= 90100)
4076                         appendPQExpBuffer(query,
4077                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4078                                                           "classid = 'pg_proc'::regclass AND "
4079                                                           "objid = p.oid AND "
4080                                                           "refclassid = 'pg_extension'::regclass AND "
4081                                                           "deptype = 'e')");
4082                 appendPQExpBuffer(query, ")");
4083         }
4084         else if (fout->remoteVersion >= 70300)
4085         {
4086                 appendPQExpBuffer(query,
4087                                                   "SELECT tableoid, oid, proname, prolang, "
4088                                                   "pronargs, proargtypes, prorettype, proacl, "
4089                                                   "pronamespace, "
4090                                                   "NULL::text AS proiargs,"
4091                                                   "(%s proowner) AS rolname "
4092                                                   "FROM pg_proc p "
4093                                                   "WHERE NOT proisagg AND ("
4094                                                   "pronamespace != "
4095                                                   "(SELECT oid FROM pg_namespace "
4096                                                   "WHERE nspname = 'pg_catalog'))",
4097                                                   username_subquery);
4098         }
4099         else if (fout->remoteVersion >= 70100)
4100         {
4101                 appendPQExpBuffer(query,
4102                                                   "SELECT tableoid, oid, proname, prolang, "
4103                                                   "pronargs, proargtypes, prorettype, "
4104                                                   "'{=X}' AS proacl, "
4105                                                   "0::oid AS pronamespace, "
4106                                                   "NULL::text AS proiargs,"
4107                                                   "(%s proowner) AS rolname "
4108                                                   "FROM pg_proc "
4109                                                   "WHERE pg_proc.oid > '%u'::oid",
4110                                                   username_subquery,
4111                                                   g_last_builtin_oid);
4112         }
4113         else
4114         {
4115                 appendPQExpBuffer(query,
4116                                                   "SELECT "
4117                                                   "(SELECT oid FROM pg_class "
4118                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4119                                                   "oid, proname, prolang, "
4120                                                   "pronargs, proargtypes, prorettype, "
4121                                                   "'{=X}' AS proacl, "
4122                                                   "0::oid AS pronamespace, "
4123                                                   "NULL::text AS proiargs,"
4124                                                   "(%s proowner) AS rolname "
4125                                                   "FROM pg_proc "
4126                                                   "where pg_proc.oid > '%u'::oid",
4127                                                   username_subquery,
4128                                                   g_last_builtin_oid);
4129         }
4130
4131         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4132
4133         ntups = PQntuples(res);
4134
4135         *numFuncs = ntups;
4136
4137         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4138
4139         i_tableoid = PQfnumber(res, "tableoid");
4140         i_oid = PQfnumber(res, "oid");
4141         i_proname = PQfnumber(res, "proname");
4142         i_pronamespace = PQfnumber(res, "pronamespace");
4143         i_rolname = PQfnumber(res, "rolname");
4144         i_prolang = PQfnumber(res, "prolang");
4145         i_pronargs = PQfnumber(res, "pronargs");
4146         i_proargtypes = PQfnumber(res, "proargtypes");
4147         i_prorettype = PQfnumber(res, "prorettype");
4148         i_proacl = PQfnumber(res, "proacl");
4149         i_proiargs = PQfnumber(res, "proiargs");
4150
4151         for (i = 0; i < ntups; i++)
4152         {
4153                 finfo[i].dobj.objType = DO_FUNC;
4154                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4155                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4156                 AssignDumpId(&finfo[i].dobj);
4157                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4158                 finfo[i].dobj.namespace =
4159                         findNamespace(fout,
4160                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4161                                                   finfo[i].dobj.catId.oid);
4162                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4163                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4164                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4165                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4166                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4167                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4168                 if (finfo[i].nargs == 0)
4169                         finfo[i].argtypes = NULL;
4170                 else
4171                 {
4172                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4173                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4174                                                   finfo[i].argtypes, finfo[i].nargs);
4175                 }
4176
4177                 /* Decide whether we want to dump it */
4178                 selectDumpableObject(&(finfo[i].dobj));
4179
4180                 if (strlen(finfo[i].rolname) == 0)
4181                         write_msg(NULL,
4182                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4183                                           finfo[i].dobj.name);
4184         }
4185
4186         PQclear(res);
4187
4188         destroyPQExpBuffer(query);
4189
4190         return finfo;
4191 }
4192
4193 /*
4194  * getTables
4195  *        read all the user-defined tables (no indexes, no catalogs)
4196  * in the system catalogs return them in the TableInfo* structure
4197  *
4198  * numTables is set to the number of tables read in
4199  */
4200 TableInfo *
4201 getTables(Archive *fout, int *numTables)
4202 {
4203         PGresult   *res;
4204         int                     ntups;
4205         int                     i;
4206         PQExpBuffer query = createPQExpBuffer();
4207         TableInfo  *tblinfo;
4208         int                     i_reltableoid;
4209         int                     i_reloid;
4210         int                     i_relname;
4211         int                     i_relnamespace;
4212         int                     i_relkind;
4213         int                     i_relacl;
4214         int                     i_rolname;
4215         int                     i_relchecks;
4216         int                     i_relhastriggers;
4217         int                     i_relhasindex;
4218         int                     i_relhasrules;
4219         int                     i_relhasoids;
4220         int                     i_relfrozenxid;
4221         int                     i_toastoid;
4222         int                     i_toastfrozenxid;
4223         int                     i_relpersistence;
4224         int                     i_isscannable;
4225         int                     i_owning_tab;
4226         int                     i_owning_col;
4227         int                     i_reltablespace;
4228         int                     i_reloptions;
4229         int                     i_toastreloptions;
4230         int                     i_reloftype;
4231         int                     i_relpages;
4232
4233         /* Make sure we are in proper schema */
4234         selectSourceSchema(fout, "pg_catalog");
4235
4236         /*
4237          * Find all the tables and table-like objects.
4238          *
4239          * We include system catalogs, so that we can work if a user table is
4240          * defined to inherit from a system catalog (pretty weird, but...)
4241          *
4242          * We ignore relations that are not ordinary tables, sequences, views,
4243          * materialized views, composite types, or foreign tables.
4244          *
4245          * Composite-type table entries won't be dumped as such, but we have to
4246          * make a DumpableObject for them so that we can track dependencies of the
4247          * composite type (pg_depend entries for columns of the composite type
4248          * link to the pg_class entry not the pg_type entry).
4249          *
4250          * Note: in this phase we should collect only a minimal amount of
4251          * information about each table, basically just enough to decide if it is
4252          * interesting. We must fetch all tables in this phase because otherwise
4253          * we cannot correctly identify inherited columns, owned sequences, etc.
4254          */
4255
4256         if (fout->remoteVersion >= 90300)
4257         {
4258                 /*
4259                  * Left join to pick up dependency info linking sequences to their
4260                  * owning column, if any (note this dependency is AUTO as of 8.2)
4261                  */
4262                 appendPQExpBuffer(query,
4263                                                   "SELECT c.tableoid, c.oid, c.relname, "
4264                                                   "c.relacl, c.relkind, c.relnamespace, "
4265                                                   "(%s c.relowner) AS rolname, "
4266                                                   "c.relchecks, c.relhastriggers, "
4267                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4268                                                   "c.relfrozenxid, tc.oid AS toid, "
4269                                                   "tc.relfrozenxid AS tfrozenxid, "
4270                  "c.relpersistence, pg_relation_is_scannable(c.oid) as isscannable, "
4271                                                   "c.relpages, "
4272                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4273                                                   "d.refobjid AS owning_tab, "
4274                                                   "d.refobjsubid AS owning_col, "
4275                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4276                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4277                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4278                                                   "FROM pg_class c "
4279                                                   "LEFT JOIN pg_depend d ON "
4280                                                   "(c.relkind = '%c' AND "
4281                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4282                                                   "d.objsubid = 0 AND "
4283                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4284                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4285                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4286                                                   "ORDER BY c.oid",
4287                                                   username_subquery,
4288                                                   RELKIND_SEQUENCE,
4289                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4290                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4291                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4292         }
4293         else if (fout->remoteVersion >= 90100)
4294         {
4295                 /*
4296                  * Left join to pick up dependency info linking sequences to their
4297                  * owning column, if any (note this dependency is AUTO as of 8.2)
4298                  */
4299                 appendPQExpBuffer(query,
4300                                                   "SELECT c.tableoid, c.oid, c.relname, "
4301                                                   "c.relacl, c.relkind, c.relnamespace, "
4302                                                   "(%s c.relowner) AS rolname, "
4303                                                   "c.relchecks, c.relhastriggers, "
4304                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4305                                                   "c.relfrozenxid, tc.oid AS toid, "
4306                                                   "tc.relfrozenxid AS tfrozenxid, "
4307                                                   "c.relpersistence, 't'::bool as isscannable, "
4308                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4309                                                   "d.refobjid AS owning_tab, "
4310                                                   "d.refobjsubid AS owning_col, "
4311                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4312                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4313                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4314                                                   "FROM pg_class c "
4315                                                   "LEFT JOIN pg_depend d ON "
4316                                                   "(c.relkind = '%c' AND "
4317                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4318                                                   "d.objsubid = 0 AND "
4319                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4320                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4321                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4322                                                   "ORDER BY c.oid",
4323                                                   username_subquery,
4324                                                   RELKIND_SEQUENCE,
4325                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4326                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4327                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4328         }
4329         else if (fout->remoteVersion >= 90000)
4330         {
4331                 /*
4332                  * Left join to pick up dependency info linking sequences to their
4333                  * owning column, if any (note this dependency is AUTO as of 8.2)
4334                  */
4335                 appendPQExpBuffer(query,
4336                                                   "SELECT c.tableoid, c.oid, c.relname, "
4337                                                   "c.relacl, c.relkind, c.relnamespace, "
4338                                                   "(%s c.relowner) AS rolname, "
4339                                                   "c.relchecks, c.relhastriggers, "
4340                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4341                                                   "c.relfrozenxid, tc.oid AS toid, "
4342                                                   "tc.relfrozenxid AS tfrozenxid, "
4343                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4344                                                   "c.relpages, "
4345                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4346                                                   "d.refobjid AS owning_tab, "
4347                                                   "d.refobjsubid AS owning_col, "
4348                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4349                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4350                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4351                                                   "FROM pg_class c "
4352                                                   "LEFT JOIN pg_depend d ON "
4353                                                   "(c.relkind = '%c' AND "
4354                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4355                                                   "d.objsubid = 0 AND "
4356                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4357                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4358                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4359                                                   "ORDER BY c.oid",
4360                                                   username_subquery,
4361                                                   RELKIND_SEQUENCE,
4362                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4363                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4364         }
4365         else if (fout->remoteVersion >= 80400)
4366         {
4367                 /*
4368                  * Left join to pick up dependency info linking sequences to their
4369                  * owning column, if any (note this dependency is AUTO as of 8.2)
4370                  */
4371                 appendPQExpBuffer(query,
4372                                                   "SELECT c.tableoid, c.oid, c.relname, "
4373                                                   "c.relacl, c.relkind, c.relnamespace, "
4374                                                   "(%s c.relowner) AS rolname, "
4375                                                   "c.relchecks, c.relhastriggers, "
4376                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4377                                                   "c.relfrozenxid, tc.oid AS toid, "
4378                                                   "tc.relfrozenxid AS tfrozenxid, "
4379                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4380                                                   "c.relpages, "
4381                                                   "NULL AS reloftype, "
4382                                                   "d.refobjid AS owning_tab, "
4383                                                   "d.refobjsubid AS owning_col, "
4384                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4385                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4386                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4387                                                   "FROM pg_class c "
4388                                                   "LEFT JOIN pg_depend d ON "
4389                                                   "(c.relkind = '%c' AND "
4390                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4391                                                   "d.objsubid = 0 AND "
4392                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4393                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4394                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4395                                                   "ORDER BY c.oid",
4396                                                   username_subquery,
4397                                                   RELKIND_SEQUENCE,
4398                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4399                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4400         }
4401         else if (fout->remoteVersion >= 80200)
4402         {
4403                 /*
4404                  * Left join to pick up dependency info linking sequences to their
4405                  * owning column, if any (note this dependency is AUTO as of 8.2)
4406                  */
4407                 appendPQExpBuffer(query,
4408                                                   "SELECT c.tableoid, c.oid, c.relname, "
4409                                                   "c.relacl, c.relkind, c.relnamespace, "
4410                                                   "(%s c.relowner) AS rolname, "
4411                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4412                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4413                                                   "c.relfrozenxid, tc.oid AS toid, "
4414                                                   "tc.relfrozenxid AS tfrozenxid, "
4415                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4416                                                   "c.relpages, "
4417                                                   "NULL AS reloftype, "
4418                                                   "d.refobjid AS owning_tab, "
4419                                                   "d.refobjsubid AS owning_col, "
4420                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4421                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4422                                                   "NULL AS toast_reloptions "
4423                                                   "FROM pg_class c "
4424                                                   "LEFT JOIN pg_depend d ON "
4425                                                   "(c.relkind = '%c' AND "
4426                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4427                                                   "d.objsubid = 0 AND "
4428                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4429                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4430                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4431                                                   "ORDER BY c.oid",
4432                                                   username_subquery,
4433                                                   RELKIND_SEQUENCE,
4434                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4435                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4436         }
4437         else if (fout->remoteVersion >= 80000)
4438         {
4439                 /*
4440                  * Left join to pick up dependency info linking sequences to their
4441                  * owning column, if any
4442                  */
4443                 appendPQExpBuffer(query,
4444                                                   "SELECT c.tableoid, c.oid, relname, "
4445                                                   "relacl, relkind, relnamespace, "
4446                                                   "(%s relowner) AS rolname, "
4447                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4448                                                   "relhasindex, relhasrules, relhasoids, "
4449                                                   "0 AS relfrozenxid, "
4450                                                   "0 AS toid, "
4451                                                   "0 AS tfrozenxid, "
4452                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4453                                                   "relpages, "
4454                                                   "NULL AS reloftype, "
4455                                                   "d.refobjid AS owning_tab, "
4456                                                   "d.refobjsubid AS owning_col, "
4457                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4458                                                   "NULL AS reloptions, "
4459                                                   "NULL AS toast_reloptions "
4460                                                   "FROM pg_class c "
4461                                                   "LEFT JOIN pg_depend d ON "
4462                                                   "(c.relkind = '%c' AND "
4463                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4464                                                   "d.objsubid = 0 AND "
4465                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4466                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4467                                                   "ORDER BY c.oid",
4468                                                   username_subquery,
4469                                                   RELKIND_SEQUENCE,
4470                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4471                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4472         }
4473         else if (fout->remoteVersion >= 70300)
4474         {
4475                 /*
4476                  * Left join to pick up dependency info linking sequences to their
4477                  * owning column, if any
4478                  */
4479                 appendPQExpBuffer(query,
4480                                                   "SELECT c.tableoid, c.oid, relname, "
4481                                                   "relacl, relkind, relnamespace, "
4482                                                   "(%s relowner) AS rolname, "
4483                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4484                                                   "relhasindex, relhasrules, relhasoids, "
4485                                                   "0 AS relfrozenxid, "
4486                                                   "0 AS toid, "
4487                                                   "0 AS tfrozenxid, "
4488                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4489                                                   "relpages, "
4490                                                   "NULL AS reloftype, "
4491                                                   "d.refobjid AS owning_tab, "
4492                                                   "d.refobjsubid AS owning_col, "
4493                                                   "NULL AS reltablespace, "
4494                                                   "NULL AS reloptions, "
4495                                                   "NULL AS toast_reloptions "
4496                                                   "FROM pg_class c "
4497                                                   "LEFT JOIN pg_depend d ON "
4498                                                   "(c.relkind = '%c' AND "
4499                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4500                                                   "d.objsubid = 0 AND "
4501                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4502                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4503                                                   "ORDER BY c.oid",
4504                                                   username_subquery,
4505                                                   RELKIND_SEQUENCE,
4506                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4507                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4508         }
4509         else if (fout->remoteVersion >= 70200)
4510         {
4511                 appendPQExpBuffer(query,
4512                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4513                                                   "0::oid AS relnamespace, "
4514                                                   "(%s relowner) AS rolname, "
4515                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4516                                                   "relhasindex, relhasrules, relhasoids, "
4517                                                   "0 AS relfrozenxid, "
4518                                                   "0 AS toid, "
4519                                                   "0 AS tfrozenxid, "
4520                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4521                                                   "relpages, "
4522                                                   "NULL AS reloftype, "
4523                                                   "NULL::oid AS owning_tab, "
4524                                                   "NULL::int4 AS owning_col, "
4525                                                   "NULL AS reltablespace, "
4526                                                   "NULL AS reloptions, "
4527                                                   "NULL AS toast_reloptions "
4528                                                   "FROM pg_class "
4529                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4530                                                   "ORDER BY oid",
4531                                                   username_subquery,
4532                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4533         }
4534         else if (fout->remoteVersion >= 70100)
4535         {
4536                 /* all tables have oids in 7.1 */
4537                 appendPQExpBuffer(query,
4538                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4539                                                   "0::oid AS relnamespace, "
4540                                                   "(%s relowner) AS rolname, "
4541                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4542                                                   "relhasindex, relhasrules, "
4543                                                   "'t'::bool AS relhasoids, "
4544                                                   "0 AS relfrozenxid, "
4545                                                   "0 AS toid, "
4546                                                   "0 AS tfrozenxid, "
4547                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4548                                                   "relpages, "
4549                                                   "NULL AS reloftype, "
4550                                                   "NULL::oid AS owning_tab, "
4551                                                   "NULL::int4 AS owning_col, "
4552                                                   "NULL AS reltablespace, "
4553                                                   "NULL AS reloptions, "
4554                                                   "NULL AS toast_reloptions "
4555                                                   "FROM pg_class "
4556                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4557                                                   "ORDER BY oid",
4558                                                   username_subquery,
4559                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4560         }
4561         else
4562         {
4563                 /*
4564                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4565                  * have a view by looking for a rule in pg_rewrite.
4566                  */
4567                 appendPQExpBuffer(query,
4568                                                   "SELECT "
4569                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4570                                                   "oid, relname, relacl, "
4571                                                   "CASE WHEN relhasrules and relkind = 'r' "
4572                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4573                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4574                                                   "THEN '%c'::\"char\" "
4575                                                   "ELSE relkind END AS relkind,"
4576                                                   "0::oid AS relnamespace, "
4577                                                   "(%s relowner) AS rolname, "
4578                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4579                                                   "relhasindex, relhasrules, "
4580                                                   "'t'::bool AS relhasoids, "
4581                                                   "0 as relfrozenxid, "
4582                                                   "0 AS toid, "
4583                                                   "0 AS tfrozenxid, "
4584                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4585                                                   "0 AS relpages, "
4586                                                   "NULL AS reloftype, "
4587                                                   "NULL::oid AS owning_tab, "
4588                                                   "NULL::int4 AS owning_col, "
4589                                                   "NULL AS reltablespace, "
4590                                                   "NULL AS reloptions, "
4591                                                   "NULL AS toast_reloptions "
4592                                                   "FROM pg_class c "
4593                                                   "WHERE relkind IN ('%c', '%c') "
4594                                                   "ORDER BY oid",
4595                                                   RELKIND_VIEW,
4596                                                   username_subquery,
4597                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4598         }
4599
4600         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4601
4602         ntups = PQntuples(res);
4603
4604         *numTables = ntups;
4605
4606         /*
4607          * Extract data from result and lock dumpable tables.  We do the locking
4608          * before anything else, to minimize the window wherein a table could
4609          * disappear under us.
4610          *
4611          * Note that we have to save info about all tables here, even when dumping
4612          * only one, because we don't yet know which tables might be inheritance
4613          * ancestors of the target table.
4614          */
4615         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4616
4617         i_reltableoid = PQfnumber(res, "tableoid");
4618         i_reloid = PQfnumber(res, "oid");
4619         i_relname = PQfnumber(res, "relname");
4620         i_relnamespace = PQfnumber(res, "relnamespace");
4621         i_relacl = PQfnumber(res, "relacl");
4622         i_relkind = PQfnumber(res, "relkind");
4623         i_rolname = PQfnumber(res, "rolname");
4624         i_relchecks = PQfnumber(res, "relchecks");
4625         i_relhastriggers = PQfnumber(res, "relhastriggers");
4626         i_relhasindex = PQfnumber(res, "relhasindex");
4627         i_relhasrules = PQfnumber(res, "relhasrules");
4628         i_relhasoids = PQfnumber(res, "relhasoids");
4629         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4630         i_toastoid = PQfnumber(res, "toid");
4631         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4632         i_relpersistence = PQfnumber(res, "relpersistence");
4633         i_isscannable = PQfnumber(res, "isscannable");
4634         i_relpages = PQfnumber(res, "relpages");
4635         i_owning_tab = PQfnumber(res, "owning_tab");
4636         i_owning_col = PQfnumber(res, "owning_col");
4637         i_reltablespace = PQfnumber(res, "reltablespace");
4638         i_reloptions = PQfnumber(res, "reloptions");
4639         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4640         i_reloftype = PQfnumber(res, "reloftype");
4641
4642         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4643         {
4644                 /*
4645                  * Arrange to fail instead of waiting forever for a table lock.
4646                  *
4647                  * NB: this coding assumes that the only queries issued within the
4648                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4649                  * applied to other things too.
4650                  */
4651                 resetPQExpBuffer(query);
4652                 appendPQExpBuffer(query, "SET statement_timeout = ");
4653                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4654                 ExecuteSqlStatement(fout, query->data);
4655         }
4656
4657         for (i = 0; i < ntups; i++)
4658         {
4659                 tblinfo[i].dobj.objType = DO_TABLE;
4660                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4661                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4662                 AssignDumpId(&tblinfo[i].dobj);
4663                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4664                 tblinfo[i].dobj.namespace =
4665                         findNamespace(fout,
4666                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4667                                                   tblinfo[i].dobj.catId.oid);
4668                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4669                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4670                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4671                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4672                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4673                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4674                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4675                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4676                 tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0);
4677                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4678                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4679                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4680                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4681                 if (PQgetisnull(res, i, i_reloftype))
4682                         tblinfo[i].reloftype = NULL;
4683                 else
4684                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4685                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4686                 if (PQgetisnull(res, i, i_owning_tab))
4687                 {
4688                         tblinfo[i].owning_tab = InvalidOid;
4689                         tblinfo[i].owning_col = 0;
4690                 }
4691                 else
4692                 {
4693                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4694                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4695                 }
4696                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4697                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4698                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4699
4700                 /* other fields were zeroed above */
4701
4702                 /*
4703                  * Decide whether we want to dump this table.
4704                  */
4705                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4706                         tblinfo[i].dobj.dump = false;
4707                 else
4708                         selectDumpableTable(&tblinfo[i]);
4709                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4710
4711                 /*
4712                  * Read-lock target tables to make sure they aren't DROPPED or altered
4713                  * in schema before we get around to dumping them.
4714                  *
4715                  * Note that we don't explicitly lock parents of the target tables; we
4716                  * assume our lock on the child is enough to prevent schema
4717                  * alterations to parent tables.
4718                  *
4719                  * NOTE: it'd be kinda nice to lock other relations too, not only
4720                  * plain tables, but the backend doesn't presently allow that.
4721                  */
4722                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4723                 {
4724                         resetPQExpBuffer(query);
4725                         appendPQExpBuffer(query,
4726                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4727                                                           fmtQualifiedId(fout->remoteVersion,
4728                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4729                                                                                          tblinfo[i].dobj.name));
4730                         ExecuteSqlStatement(fout, query->data);
4731                 }
4732
4733                 /* Emit notice if join for owner failed */
4734                 if (strlen(tblinfo[i].rolname) == 0)
4735                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4736                                           tblinfo[i].dobj.name);
4737         }
4738
4739         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4740         {
4741                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4742         }
4743
4744         PQclear(res);
4745
4746         destroyPQExpBuffer(query);
4747
4748         return tblinfo;
4749 }
4750
4751 /*
4752  * getOwnedSeqs
4753  *        identify owned sequences and mark them as dumpable if owning table is
4754  *
4755  * We used to do this in getTables(), but it's better to do it after the
4756  * index used by findTableByOid() has been set up.
4757  */
4758 void
4759 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4760 {
4761         int                     i;
4762
4763         /*
4764          * Force sequences that are "owned" by table columns to be dumped whenever
4765          * their owning table is being dumped.
4766          */
4767         for (i = 0; i < numTables; i++)
4768         {
4769                 TableInfo  *seqinfo = &tblinfo[i];
4770                 TableInfo  *owning_tab;
4771
4772                 if (!OidIsValid(seqinfo->owning_tab))
4773                         continue;                       /* not an owned sequence */
4774                 if (seqinfo->dobj.dump)
4775                         continue;                       /* no need to search */
4776                 owning_tab = findTableByOid(seqinfo->owning_tab);
4777                 if (owning_tab && owning_tab->dobj.dump)
4778                 {
4779                         seqinfo->interesting = true;
4780                         seqinfo->dobj.dump = true;
4781                 }
4782         }
4783 }
4784
4785 /*
4786  * getInherits
4787  *        read all the inheritance information
4788  * from the system catalogs return them in the InhInfo* structure
4789  *
4790  * numInherits is set to the number of pairs read in
4791  */
4792 InhInfo *
4793 getInherits(Archive *fout, int *numInherits)
4794 {
4795         PGresult   *res;
4796         int                     ntups;
4797         int                     i;
4798         PQExpBuffer query = createPQExpBuffer();
4799         InhInfo    *inhinfo;
4800
4801         int                     i_inhrelid;
4802         int                     i_inhparent;
4803
4804         /* Make sure we are in proper schema */
4805         selectSourceSchema(fout, "pg_catalog");
4806
4807         /* find all the inheritance information */
4808
4809         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4810
4811         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4812
4813         ntups = PQntuples(res);
4814
4815         *numInherits = ntups;
4816
4817         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4818
4819         i_inhrelid = PQfnumber(res, "inhrelid");
4820         i_inhparent = PQfnumber(res, "inhparent");
4821
4822         for (i = 0; i < ntups; i++)
4823         {
4824                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4825                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4826         }
4827
4828         PQclear(res);
4829
4830         destroyPQExpBuffer(query);
4831
4832         return inhinfo;
4833 }
4834
4835 /*
4836  * getIndexes
4837  *        get information about every index on a dumpable table
4838  *
4839  * Note: index data is not returned directly to the caller, but it
4840  * does get entered into the DumpableObject tables.
4841  */
4842 void
4843 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4844 {
4845         int                     i,
4846                                 j;
4847         PQExpBuffer query = createPQExpBuffer();
4848         PGresult   *res;
4849         IndxInfo   *indxinfo;
4850         ConstraintInfo *constrinfo;
4851         int                     i_tableoid,
4852                                 i_oid,
4853                                 i_indexname,
4854                                 i_indexdef,
4855                                 i_indnkeys,
4856                                 i_indkey,
4857                                 i_indisclustered,
4858                                 i_contype,
4859                                 i_conname,
4860                                 i_condeferrable,
4861                                 i_condeferred,
4862                                 i_contableoid,
4863                                 i_conoid,
4864                                 i_condef,
4865                                 i_tablespace,
4866                                 i_options,
4867                                 i_relpages;
4868         int                     ntups;
4869
4870         for (i = 0; i < numTables; i++)
4871         {
4872                 TableInfo  *tbinfo = &tblinfo[i];
4873
4874                 /* Only plain tables and materialized views have indexes. */
4875                 if (tbinfo->relkind != RELKIND_RELATION &&
4876                         tbinfo->relkind != RELKIND_MATVIEW)
4877                         continue;
4878                 if (!tbinfo->hasindex)
4879                         continue;
4880
4881                 /* Ignore indexes of tables not to be dumped */
4882                 if (!tbinfo->dobj.dump)
4883                         continue;
4884
4885                 if (g_verbose)
4886                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4887                                           tbinfo->dobj.name);
4888
4889                 /* Make sure we are in proper schema so indexdef is right */
4890                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4891
4892                 /*
4893                  * The point of the messy-looking outer join is to find a constraint
4894                  * that is related by an internal dependency link to the index. If we
4895                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4896                  * assume an index won't have more than one internal dependency.
4897                  *
4898                  * As of 9.0 we don't need to look at pg_depend but can check for a
4899                  * match to pg_constraint.conindid.  The check on conrelid is
4900                  * redundant but useful because that column is indexed while conindid
4901                  * is not.
4902                  */
4903                 resetPQExpBuffer(query);
4904                 if (fout->remoteVersion >= 90000)
4905                 {
4906                         appendPQExpBuffer(query,
4907                                                           "SELECT t.tableoid, t.oid, "
4908                                                           "t.relname AS indexname, "
4909                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4910                                                           "t.relnatts AS indnkeys, "
4911                                                           "i.indkey, i.indisclustered, "
4912                                                           "t.relpages, "
4913                                                           "c.contype, c.conname, "
4914                                                           "c.condeferrable, c.condeferred, "
4915                                                           "c.tableoid AS contableoid, "
4916                                                           "c.oid AS conoid, "
4917                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4918                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4919                                                         "array_to_string(t.reloptions, ', ') AS options "
4920                                                           "FROM pg_catalog.pg_index i "
4921                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4922                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4923                                                           "ON (i.indrelid = c.conrelid AND "
4924                                                           "i.indexrelid = c.conindid AND "
4925                                                           "c.contype IN ('p','u','x')) "
4926                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4927                                                           "ORDER BY indexname",
4928                                                           tbinfo->dobj.catId.oid);
4929                 }
4930                 else if (fout->remoteVersion >= 80200)
4931                 {
4932                         appendPQExpBuffer(query,
4933                                                           "SELECT t.tableoid, t.oid, "
4934                                                           "t.relname AS indexname, "
4935                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4936                                                           "t.relnatts AS indnkeys, "
4937                                                           "i.indkey, i.indisclustered, "
4938                                                           "t.relpages, "
4939                                                           "c.contype, c.conname, "
4940                                                           "c.condeferrable, c.condeferred, "
4941                                                           "c.tableoid AS contableoid, "
4942                                                           "c.oid AS conoid, "
4943                                                           "null AS condef, "
4944                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4945                                                         "array_to_string(t.reloptions, ', ') AS options "
4946                                                           "FROM pg_catalog.pg_index i "
4947                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4948                                                           "LEFT JOIN pg_catalog.pg_depend d "
4949                                                           "ON (d.classid = t.tableoid "
4950                                                           "AND d.objid = t.oid "
4951                                                           "AND d.deptype = 'i') "
4952                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4953                                                           "ON (d.refclassid = c.tableoid "
4954                                                           "AND d.refobjid = c.oid) "
4955                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4956                                                           "ORDER BY indexname",
4957                                                           tbinfo->dobj.catId.oid);
4958                 }
4959                 else if (fout->remoteVersion >= 80000)
4960                 {
4961                         appendPQExpBuffer(query,
4962                                                           "SELECT t.tableoid, t.oid, "
4963                                                           "t.relname AS indexname, "
4964                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4965                                                           "t.relnatts AS indnkeys, "
4966                                                           "i.indkey, i.indisclustered, "
4967                                                           "t.relpages, "
4968                                                           "c.contype, c.conname, "
4969                                                           "c.condeferrable, c.condeferred, "
4970                                                           "c.tableoid AS contableoid, "
4971                                                           "c.oid AS conoid, "
4972                                                           "null AS condef, "
4973                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4974                                                           "null AS options "
4975                                                           "FROM pg_catalog.pg_index i "
4976                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4977                                                           "LEFT JOIN pg_catalog.pg_depend d "
4978                                                           "ON (d.classid = t.tableoid "
4979                                                           "AND d.objid = t.oid "
4980                                                           "AND d.deptype = 'i') "
4981                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4982                                                           "ON (d.refclassid = c.tableoid "
4983                                                           "AND d.refobjid = c.oid) "
4984                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4985                                                           "ORDER BY indexname",
4986                                                           tbinfo->dobj.catId.oid);
4987                 }
4988                 else if (fout->remoteVersion >= 70300)
4989                 {
4990                         appendPQExpBuffer(query,
4991                                                           "SELECT t.tableoid, t.oid, "
4992                                                           "t.relname AS indexname, "
4993                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4994                                                           "t.relnatts AS indnkeys, "
4995                                                           "i.indkey, i.indisclustered, "
4996                                                           "t.relpages, "
4997                                                           "c.contype, c.conname, "
4998                                                           "c.condeferrable, c.condeferred, "
4999                                                           "c.tableoid AS contableoid, "
5000                                                           "c.oid AS conoid, "
5001                                                           "null AS condef, "
5002                                                           "NULL AS tablespace, "
5003                                                           "null AS options "
5004                                                           "FROM pg_catalog.pg_index i "
5005                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5006                                                           "LEFT JOIN pg_catalog.pg_depend d "
5007                                                           "ON (d.classid = t.tableoid "
5008                                                           "AND d.objid = t.oid "
5009                                                           "AND d.deptype = 'i') "
5010                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5011                                                           "ON (d.refclassid = c.tableoid "
5012                                                           "AND d.refobjid = c.oid) "
5013                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5014                                                           "ORDER BY indexname",
5015                                                           tbinfo->dobj.catId.oid);
5016                 }
5017                 else if (fout->remoteVersion >= 70100)
5018                 {
5019                         appendPQExpBuffer(query,
5020                                                           "SELECT t.tableoid, t.oid, "
5021                                                           "t.relname AS indexname, "
5022                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5023                                                           "t.relnatts AS indnkeys, "
5024                                                           "i.indkey, false AS indisclustered, "
5025                                                           "t.relpages, "
5026                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5027                                                           "ELSE '0'::char END AS contype, "
5028                                                           "t.relname AS conname, "
5029                                                           "false AS condeferrable, "
5030                                                           "false AS condeferred, "
5031                                                           "0::oid AS contableoid, "
5032                                                           "t.oid AS conoid, "
5033                                                           "null AS condef, "
5034                                                           "NULL AS tablespace, "
5035                                                           "null AS options "
5036                                                           "FROM pg_index i, pg_class t "
5037                                                           "WHERE t.oid = i.indexrelid "
5038                                                           "AND i.indrelid = '%u'::oid "
5039                                                           "ORDER BY indexname",
5040                                                           tbinfo->dobj.catId.oid);
5041                 }
5042                 else
5043                 {
5044                         appendPQExpBuffer(query,
5045                                                           "SELECT "
5046                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5047                                                           "t.oid, "
5048                                                           "t.relname AS indexname, "
5049                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5050                                                           "t.relnatts AS indnkeys, "
5051                                                           "i.indkey, false AS indisclustered, "
5052                                                           "t.relpages, "
5053                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5054                                                           "ELSE '0'::char END AS contype, "
5055                                                           "t.relname AS conname, "
5056                                                           "false AS condeferrable, "
5057                                                           "false AS condeferred, "
5058                                                           "0::oid AS contableoid, "
5059                                                           "t.oid AS conoid, "
5060                                                           "null AS condef, "
5061                                                           "NULL AS tablespace, "
5062                                                           "null AS options "
5063                                                           "FROM pg_index i, pg_class t "
5064                                                           "WHERE t.oid = i.indexrelid "
5065                                                           "AND i.indrelid = '%u'::oid "
5066                                                           "ORDER BY indexname",
5067                                                           tbinfo->dobj.catId.oid);
5068                 }
5069
5070                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5071
5072                 ntups = PQntuples(res);
5073
5074                 i_tableoid = PQfnumber(res, "tableoid");
5075                 i_oid = PQfnumber(res, "oid");
5076                 i_indexname = PQfnumber(res, "indexname");
5077                 i_indexdef = PQfnumber(res, "indexdef");
5078                 i_indnkeys = PQfnumber(res, "indnkeys");
5079                 i_indkey = PQfnumber(res, "indkey");
5080                 i_indisclustered = PQfnumber(res, "indisclustered");
5081                 i_relpages = PQfnumber(res, "relpages");
5082                 i_contype = PQfnumber(res, "contype");
5083                 i_conname = PQfnumber(res, "conname");
5084                 i_condeferrable = PQfnumber(res, "condeferrable");
5085                 i_condeferred = PQfnumber(res, "condeferred");
5086                 i_contableoid = PQfnumber(res, "contableoid");
5087                 i_conoid = PQfnumber(res, "conoid");
5088                 i_condef = PQfnumber(res, "condef");
5089                 i_tablespace = PQfnumber(res, "tablespace");
5090                 i_options = PQfnumber(res, "options");
5091
5092                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5093                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5094
5095                 for (j = 0; j < ntups; j++)
5096                 {
5097                         char            contype;
5098
5099                         indxinfo[j].dobj.objType = DO_INDEX;
5100                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5101                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5102                         AssignDumpId(&indxinfo[j].dobj);
5103                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5104                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5105                         indxinfo[j].indextable = tbinfo;
5106                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5107                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5108                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5109                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5110
5111                         /*
5112                          * In pre-7.4 releases, indkeys may contain more entries than
5113                          * indnkeys says (since indnkeys will be 1 for a functional
5114                          * index).      We don't actually care about this case since we don't
5115                          * examine indkeys except for indexes associated with PRIMARY and
5116                          * UNIQUE constraints, which are never functional indexes. But we
5117                          * have to allocate enough space to keep parseOidArray from
5118                          * complaining.
5119                          */
5120                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5121                         parseOidArray(PQgetvalue(res, j, i_indkey),
5122                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5123                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5124                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5125                         contype = *(PQgetvalue(res, j, i_contype));
5126
5127                         if (contype == 'p' || contype == 'u' || contype == 'x')
5128                         {
5129                                 /*
5130                                  * If we found a constraint matching the index, create an
5131                                  * entry for it.
5132                                  *
5133                                  * In a pre-7.3 database, we take this path iff the index was
5134                                  * marked indisprimary.
5135                                  */
5136                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5137                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5138                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5139                                 AssignDumpId(&constrinfo[j].dobj);
5140                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5141                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5142                                 constrinfo[j].contable = tbinfo;
5143                                 constrinfo[j].condomain = NULL;
5144                                 constrinfo[j].contype = contype;
5145                                 if (contype == 'x')
5146                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5147                                 else
5148                                         constrinfo[j].condef = NULL;
5149                                 constrinfo[j].confrelid = InvalidOid;
5150                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5151                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5152                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5153                                 constrinfo[j].conislocal = true;
5154                                 constrinfo[j].separate = true;
5155
5156                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5157
5158                                 /* If pre-7.3 DB, better make sure table comes first */
5159                                 addObjectDependency(&constrinfo[j].dobj,
5160                                                                         tbinfo->dobj.dumpId);
5161                         }
5162                         else
5163                         {
5164                                 /* Plain secondary index */
5165                                 indxinfo[j].indexconstraint = 0;
5166                         }
5167                 }
5168
5169                 PQclear(res);
5170         }
5171
5172         destroyPQExpBuffer(query);
5173 }
5174
5175 /*
5176  * getConstraints
5177  *
5178  * Get info about constraints on dumpable tables.
5179  *
5180  * Currently handles foreign keys only.
5181  * Unique and primary key constraints are handled with indexes,
5182  * while check constraints are processed in getTableAttrs().
5183  */
5184 void
5185 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5186 {
5187         int                     i,
5188                                 j;
5189         ConstraintInfo *constrinfo;
5190         PQExpBuffer query;
5191         PGresult   *res;
5192         int                     i_contableoid,
5193                                 i_conoid,
5194                                 i_conname,
5195                                 i_confrelid,
5196                                 i_condef;
5197         int                     ntups;
5198
5199         /* pg_constraint was created in 7.3, so nothing to do if older */
5200         if (fout->remoteVersion < 70300)
5201                 return;
5202
5203         query = createPQExpBuffer();
5204
5205         for (i = 0; i < numTables; i++)
5206         {
5207                 TableInfo  *tbinfo = &tblinfo[i];
5208
5209                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5210                         continue;
5211
5212                 if (g_verbose)
5213                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
5214                                           tbinfo->dobj.name);
5215
5216                 /*
5217                  * select table schema to ensure constraint expr is qualified if
5218                  * needed
5219                  */
5220                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5221
5222                 resetPQExpBuffer(query);
5223                 appendPQExpBuffer(query,
5224                                                   "SELECT tableoid, oid, conname, confrelid, "
5225                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5226                                                   "FROM pg_catalog.pg_constraint "
5227                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5228                                                   "AND contype = 'f'",
5229                                                   tbinfo->dobj.catId.oid);
5230                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5231
5232                 ntups = PQntuples(res);
5233
5234                 i_contableoid = PQfnumber(res, "tableoid");
5235                 i_conoid = PQfnumber(res, "oid");
5236                 i_conname = PQfnumber(res, "conname");
5237                 i_confrelid = PQfnumber(res, "confrelid");
5238                 i_condef = PQfnumber(res, "condef");
5239
5240                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5241
5242                 for (j = 0; j < ntups; j++)
5243                 {
5244                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5245                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5246                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5247                         AssignDumpId(&constrinfo[j].dobj);
5248                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5249                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5250                         constrinfo[j].contable = tbinfo;
5251                         constrinfo[j].condomain = NULL;
5252                         constrinfo[j].contype = 'f';
5253                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5254                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5255                         constrinfo[j].conindex = 0;
5256                         constrinfo[j].condeferrable = false;
5257                         constrinfo[j].condeferred = false;
5258                         constrinfo[j].conislocal = true;
5259                         constrinfo[j].separate = true;
5260                 }
5261
5262                 PQclear(res);
5263         }
5264
5265         destroyPQExpBuffer(query);
5266 }
5267
5268 /*
5269  * getDomainConstraints
5270  *
5271  * Get info about constraints on a domain.
5272  */
5273 static void
5274 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5275 {
5276         int                     i;
5277         ConstraintInfo *constrinfo;
5278         PQExpBuffer query;
5279         PGresult   *res;
5280         int                     i_tableoid,
5281                                 i_oid,
5282                                 i_conname,
5283                                 i_consrc;
5284         int                     ntups;
5285
5286         /* pg_constraint was created in 7.3, so nothing to do if older */
5287         if (fout->remoteVersion < 70300)
5288                 return;
5289
5290         /*
5291          * select appropriate schema to ensure names in constraint are properly
5292          * qualified
5293          */
5294         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5295
5296         query = createPQExpBuffer();
5297
5298         if (fout->remoteVersion >= 90100)
5299                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5300                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5301                                                   "convalidated "
5302                                                   "FROM pg_catalog.pg_constraint "
5303                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5304                                                   "ORDER BY conname",
5305                                                   tyinfo->dobj.catId.oid);
5306
5307         else if (fout->remoteVersion >= 70400)
5308                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5309                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5310                                                   "true as convalidated "
5311                                                   "FROM pg_catalog.pg_constraint "
5312                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5313                                                   "ORDER BY conname",
5314                                                   tyinfo->dobj.catId.oid);
5315         else
5316                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5317                                                   "'CHECK (' || consrc || ')' AS consrc, "
5318                                                   "true as convalidated "
5319                                                   "FROM pg_catalog.pg_constraint "
5320                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5321                                                   "ORDER BY conname",
5322                                                   tyinfo->dobj.catId.oid);
5323
5324         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5325
5326         ntups = PQntuples(res);
5327
5328         i_tableoid = PQfnumber(res, "tableoid");
5329         i_oid = PQfnumber(res, "oid");
5330         i_conname = PQfnumber(res, "conname");
5331         i_consrc = PQfnumber(res, "consrc");
5332
5333         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5334
5335         tyinfo->nDomChecks = ntups;
5336         tyinfo->domChecks = constrinfo;
5337
5338         for (i = 0; i < ntups; i++)
5339         {
5340                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5341
5342                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5343                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5344                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5345                 AssignDumpId(&constrinfo[i].dobj);
5346                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5347                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5348                 constrinfo[i].contable = NULL;
5349                 constrinfo[i].condomain = tyinfo;
5350                 constrinfo[i].contype = 'c';
5351                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5352                 constrinfo[i].confrelid = InvalidOid;
5353                 constrinfo[i].conindex = 0;
5354                 constrinfo[i].condeferrable = false;
5355                 constrinfo[i].condeferred = false;
5356                 constrinfo[i].conislocal = true;
5357
5358                 constrinfo[i].separate = !validated;
5359
5360                 /*
5361                  * Make the domain depend on the constraint, ensuring it won't be
5362                  * output till any constraint dependencies are OK.      If the constraint
5363                  * has not been validated, it's going to be dumped after the domain
5364                  * anyway, so this doesn't matter.
5365                  */
5366                 if (validated)
5367                         addObjectDependency(&tyinfo->dobj,
5368                                                                 constrinfo[i].dobj.dumpId);
5369         }
5370
5371         PQclear(res);
5372
5373         destroyPQExpBuffer(query);
5374 }
5375
5376 /*
5377  * getRules
5378  *        get basic information about every rule in the system
5379  *
5380  * numRules is set to the number of rules read in
5381  */
5382 RuleInfo *
5383 getRules(Archive *fout, int *numRules)
5384 {
5385         PGresult   *res;
5386         int                     ntups;
5387         int                     i;
5388         PQExpBuffer query = createPQExpBuffer();
5389         RuleInfo   *ruleinfo;
5390         int                     i_tableoid;
5391         int                     i_oid;
5392         int                     i_rulename;
5393         int                     i_ruletable;
5394         int                     i_ev_type;
5395         int                     i_is_instead;
5396         int                     i_ev_enabled;
5397
5398         /* Make sure we are in proper schema */
5399         selectSourceSchema(fout, "pg_catalog");
5400
5401         if (fout->remoteVersion >= 80300)
5402         {
5403                 appendPQExpBuffer(query, "SELECT "
5404                                                   "tableoid, oid, rulename, "
5405                                                   "ev_class AS ruletable, ev_type, is_instead, "
5406                                                   "ev_enabled "
5407                                                   "FROM pg_rewrite "
5408                                                   "ORDER BY oid");
5409         }
5410         else if (fout->remoteVersion >= 70100)
5411         {
5412                 appendPQExpBuffer(query, "SELECT "
5413                                                   "tableoid, oid, rulename, "
5414                                                   "ev_class AS ruletable, ev_type, is_instead, "
5415                                                   "'O'::char AS ev_enabled "
5416                                                   "FROM pg_rewrite "
5417                                                   "ORDER BY oid");
5418         }
5419         else
5420         {
5421                 appendPQExpBuffer(query, "SELECT "
5422                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5423                                                   "oid, rulename, "
5424                                                   "ev_class AS ruletable, ev_type, is_instead, "
5425                                                   "'O'::char AS ev_enabled "
5426                                                   "FROM pg_rewrite "
5427                                                   "ORDER BY oid");
5428         }
5429
5430         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5431
5432         ntups = PQntuples(res);
5433
5434         *numRules = ntups;
5435
5436         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5437
5438         i_tableoid = PQfnumber(res, "tableoid");
5439         i_oid = PQfnumber(res, "oid");
5440         i_rulename = PQfnumber(res, "rulename");
5441         i_ruletable = PQfnumber(res, "ruletable");
5442         i_ev_type = PQfnumber(res, "ev_type");
5443         i_is_instead = PQfnumber(res, "is_instead");
5444         i_ev_enabled = PQfnumber(res, "ev_enabled");
5445
5446         for (i = 0; i < ntups; i++)
5447         {
5448                 Oid                     ruletableoid;
5449
5450                 ruleinfo[i].dobj.objType = DO_RULE;
5451                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5452                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5453                 AssignDumpId(&ruleinfo[i].dobj);
5454                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5455                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5456                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5457                 if (ruleinfo[i].ruletable == NULL)
5458                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5459                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5460                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5461                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5462                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5463                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5464                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5465                 if (ruleinfo[i].ruletable)
5466                 {
5467                         /*
5468                          * If the table is a view or materialized view, force its ON
5469                          * SELECT rule to be sorted before the view itself --- this
5470                          * ensures that any dependencies for the rule affect the table's
5471                          * positioning. Other rules are forced to appear after their
5472                          * table.
5473                          */
5474                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5475                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5476                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5477                         {
5478                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5479                                                                         ruleinfo[i].dobj.dumpId);
5480                                 /* We'll merge the rule into CREATE VIEW, if possible */
5481                                 ruleinfo[i].separate = false;
5482                         }
5483                         else
5484                         {
5485                                 addObjectDependency(&ruleinfo[i].dobj,
5486                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5487                                 ruleinfo[i].separate = true;
5488                         }
5489                 }
5490                 else
5491                         ruleinfo[i].separate = true;
5492
5493                 /*
5494                  * If we're forced to break a dependency loop by dumping a view as a
5495                  * table and separate _RETURN rule, we'll move the view's reloptions
5496                  * to the rule.  (This is necessary because tables and views have
5497                  * different valid reloptions, so we can't apply the options until the
5498                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5499                  * NULL.
5500                  */
5501                 ruleinfo[i].reloptions = NULL;
5502         }
5503
5504         PQclear(res);
5505
5506         destroyPQExpBuffer(query);
5507
5508         return ruleinfo;
5509 }
5510
5511 /*
5512  * getTriggers
5513  *        get information about every trigger on a dumpable table
5514  *
5515  * Note: trigger data is not returned directly to the caller, but it
5516  * does get entered into the DumpableObject tables.
5517  */
5518 void
5519 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
5520 {
5521         int                     i,
5522                                 j;
5523         PQExpBuffer query = createPQExpBuffer();
5524         PGresult   *res;
5525         TriggerInfo *tginfo;
5526         int                     i_tableoid,
5527                                 i_oid,
5528                                 i_tgname,
5529                                 i_tgfname,
5530                                 i_tgtype,
5531                                 i_tgnargs,
5532                                 i_tgargs,
5533                                 i_tgisconstraint,
5534                                 i_tgconstrname,
5535                                 i_tgconstrrelid,
5536                                 i_tgconstrrelname,
5537                                 i_tgenabled,
5538                                 i_tgdeferrable,
5539                                 i_tginitdeferred,
5540                                 i_tgdef;
5541         int                     ntups;
5542
5543         for (i = 0; i < numTables; i++)
5544         {
5545                 TableInfo  *tbinfo = &tblinfo[i];
5546
5547                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5548                         continue;
5549
5550                 if (g_verbose)
5551                         write_msg(NULL, "reading triggers for table \"%s\"\n",
5552                                           tbinfo->dobj.name);
5553
5554                 /*
5555                  * select table schema to ensure regproc name is qualified if needed
5556                  */
5557                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5558
5559                 resetPQExpBuffer(query);
5560                 if (fout->remoteVersion >= 90000)
5561                 {
5562                         /*
5563                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
5564                          * could result in non-forward-compatible dumps of WHEN clauses
5565                          * due to under-parenthesization.
5566                          */
5567                         appendPQExpBuffer(query,
5568                                                           "SELECT tgname, "
5569                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5570                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
5571                                                           "tgenabled, tableoid, oid "
5572                                                           "FROM pg_catalog.pg_trigger t "
5573                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5574                                                           "AND NOT tgisinternal",
5575                                                           tbinfo->dobj.catId.oid);
5576                 }
5577                 else if (fout->remoteVersion >= 80300)
5578                 {
5579                         /*
5580                          * We ignore triggers that are tied to a foreign-key constraint
5581                          */
5582                         appendPQExpBuffer(query,
5583                                                           "SELECT tgname, "
5584                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5585                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5586                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5587                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5588                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5589                                                           "FROM pg_catalog.pg_trigger t "
5590                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5591                                                           "AND tgconstraint = 0",
5592                                                           tbinfo->dobj.catId.oid);
5593                 }
5594                 else if (fout->remoteVersion >= 70300)
5595                 {
5596                         /*
5597                          * We ignore triggers that are tied to a foreign-key constraint,
5598                          * but in these versions we have to grovel through pg_constraint
5599                          * to find out
5600                          */
5601                         appendPQExpBuffer(query,
5602                                                           "SELECT tgname, "
5603                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
5604                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5605                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5606                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5607                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
5608                                                           "FROM pg_catalog.pg_trigger t "
5609                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
5610                                                           "AND (NOT tgisconstraint "
5611                                                           " OR NOT EXISTS"
5612                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
5613                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
5614                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
5615                                                           tbinfo->dobj.catId.oid);
5616                 }
5617                 else if (fout->remoteVersion >= 70100)
5618                 {
5619                         appendPQExpBuffer(query,
5620                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5621                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5622                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5623                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
5624                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5625                                                           "             AS tgconstrrelname "
5626                                                           "FROM pg_trigger "
5627                                                           "WHERE tgrelid = '%u'::oid",
5628                                                           tbinfo->dobj.catId.oid);
5629                 }
5630                 else
5631                 {
5632                         appendPQExpBuffer(query,
5633                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
5634                                                           "tgtype, tgnargs, tgargs, tgenabled, "
5635                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
5636                                                           "tgconstrrelid, tginitdeferred, "
5637                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
5638                                                           "oid, "
5639                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
5640                                                           "             AS tgconstrrelname "
5641                                                           "FROM pg_trigger "
5642                                                           "WHERE tgrelid = '%u'::oid",
5643                                                           tbinfo->dobj.catId.oid);
5644                 }
5645                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5646
5647                 ntups = PQntuples(res);
5648
5649                 i_tableoid = PQfnumber(res, "tableoid");
5650                 i_oid = PQfnumber(res, "oid");
5651                 i_tgname = PQfnumber(res, "tgname");
5652                 i_tgfname = PQfnumber(res, "tgfname");
5653                 i_tgtype = PQfnumber(res, "tgtype");
5654                 i_tgnargs = PQfnumber(res, "tgnargs");
5655                 i_tgargs = PQfnumber(res, "tgargs");
5656                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
5657                 i_tgconstrname = PQfnumber(res, "tgconstrname");
5658                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
5659                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
5660                 i_tgenabled = PQfnumber(res, "tgenabled");
5661                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
5662                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
5663                 i_tgdef = PQfnumber(res, "tgdef");
5664
5665                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
5666
5667                 for (j = 0; j < ntups; j++)
5668                 {
5669                         tginfo[j].dobj.objType = DO_TRIGGER;
5670                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5671                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5672                         AssignDumpId(&tginfo[j].dobj);
5673                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
5674                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
5675                         tginfo[j].tgtable = tbinfo;
5676                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
5677                         if (i_tgdef >= 0)
5678                         {
5679                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
5680
5681                                 /* remaining fields are not valid if we have tgdef */
5682                                 tginfo[j].tgfname = NULL;
5683                                 tginfo[j].tgtype = 0;
5684                                 tginfo[j].tgnargs = 0;
5685                                 tginfo[j].tgargs = NULL;
5686                                 tginfo[j].tgisconstraint = false;
5687                                 tginfo[j].tgdeferrable = false;
5688                                 tginfo[j].tginitdeferred = false;
5689                                 tginfo[j].tgconstrname = NULL;
5690                                 tginfo[j].tgconstrrelid = InvalidOid;
5691                                 tginfo[j].tgconstrrelname = NULL;
5692                         }
5693                         else
5694                         {
5695                                 tginfo[j].tgdef = NULL;
5696
5697                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
5698                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
5699                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
5700                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
5701                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
5702                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
5703                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
5704
5705                                 if (tginfo[j].tgisconstraint)
5706                                 {
5707                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
5708                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
5709                                         if (OidIsValid(tginfo[j].tgconstrrelid))
5710                                         {
5711                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
5712                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
5713                                                                                   tginfo[j].dobj.name,
5714                                                                                   tbinfo->dobj.name,
5715                                                                                   tginfo[j].tgconstrrelid);
5716                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
5717                                         }
5718                                         else
5719                                                 tginfo[j].tgconstrrelname = NULL;
5720                                 }
5721                                 else
5722                                 {
5723                                         tginfo[j].tgconstrname = NULL;
5724                                         tginfo[j].tgconstrrelid = InvalidOid;
5725                                         tginfo[j].tgconstrrelname = NULL;
5726                                 }
5727                         }
5728                 }
5729
5730                 PQclear(res);
5731         }
5732
5733         destroyPQExpBuffer(query);
5734 }
5735
5736 /*
5737  * getEventTriggers
5738  *        get information about event triggers
5739  */
5740 EventTriggerInfo *
5741 getEventTriggers(Archive *fout, int *numEventTriggers)
5742 {
5743         int                     i;
5744         PQExpBuffer query = createPQExpBuffer();
5745         PGresult   *res;
5746         EventTriggerInfo *evtinfo;
5747         int                     i_tableoid,
5748                                 i_oid,
5749                                 i_evtname,
5750                                 i_evtevent,
5751                                 i_evtowner,
5752                                 i_evttags,
5753                                 i_evtfname,
5754                                 i_evtenabled;
5755         int                     ntups;
5756
5757         /* Before 9.3, there are no event triggers */
5758         if (fout->remoteVersion < 90300)
5759         {
5760                 *numEventTriggers = 0;
5761                 return NULL;
5762         }
5763
5764         /* Make sure we are in proper schema */
5765         selectSourceSchema(fout, "pg_catalog");
5766
5767         appendPQExpBuffer(query,
5768                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
5769                                           "evtevent, (%s evtowner) AS evtowner, "
5770                                           "array_to_string(array("
5771                                           "select quote_literal(x) "
5772                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
5773                                           "e.evtfoid::regproc as evtfname "
5774                                           "FROM pg_event_trigger e "
5775                                           "ORDER BY e.oid",
5776                                           username_subquery);
5777
5778         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5779
5780         ntups = PQntuples(res);
5781
5782         *numEventTriggers = ntups;
5783
5784         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
5785
5786         i_tableoid = PQfnumber(res, "tableoid");
5787         i_oid = PQfnumber(res, "oid");
5788         i_evtname = PQfnumber(res, "evtname");
5789         i_evtevent = PQfnumber(res, "evtevent");
5790         i_evtowner = PQfnumber(res, "evtowner");
5791         i_evttags = PQfnumber(res, "evttags");
5792         i_evtfname = PQfnumber(res, "evtfname");
5793         i_evtenabled = PQfnumber(res, "evtenabled");
5794
5795         for (i = 0; i < ntups; i++)
5796         {
5797                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
5798                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5799                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5800                 AssignDumpId(&evtinfo[i].dobj);
5801                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
5802                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
5803                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
5804                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
5805                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
5806                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
5807                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
5808         }
5809
5810         PQclear(res);
5811
5812         destroyPQExpBuffer(query);
5813
5814         return evtinfo;
5815 }
5816
5817 /*
5818  * getProcLangs
5819  *        get basic information about every procedural language in the system
5820  *
5821  * numProcLangs is set to the number of langs read in
5822  *
5823  * NB: this must run after getFuncs() because we assume we can do
5824  * findFuncByOid().
5825  */
5826 ProcLangInfo *
5827 getProcLangs(Archive *fout, int *numProcLangs)
5828 {
5829         PGresult   *res;
5830         int                     ntups;
5831         int                     i;
5832         PQExpBuffer query = createPQExpBuffer();
5833         ProcLangInfo *planginfo;
5834         int                     i_tableoid;
5835         int                     i_oid;
5836         int                     i_lanname;
5837         int                     i_lanpltrusted;
5838         int                     i_lanplcallfoid;
5839         int                     i_laninline;
5840         int                     i_lanvalidator;
5841         int                     i_lanacl;
5842         int                     i_lanowner;
5843
5844         /* Make sure we are in proper schema */
5845         selectSourceSchema(fout, "pg_catalog");
5846
5847         if (fout->remoteVersion >= 90000)
5848         {
5849                 /* pg_language has a laninline column */
5850                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5851                                                   "lanname, lanpltrusted, lanplcallfoid, "
5852                                                   "laninline, lanvalidator,  lanacl, "
5853                                                   "(%s lanowner) AS lanowner "
5854                                                   "FROM pg_language "
5855                                                   "WHERE lanispl "
5856                                                   "ORDER BY oid",
5857                                                   username_subquery);
5858         }
5859         else if (fout->remoteVersion >= 80300)
5860         {
5861                 /* pg_language has a lanowner column */
5862                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
5863                                                   "lanname, lanpltrusted, lanplcallfoid, "
5864                                                   "lanvalidator,  lanacl, "
5865                                                   "(%s lanowner) AS lanowner "
5866                                                   "FROM pg_language "
5867                                                   "WHERE lanispl "
5868                                                   "ORDER BY oid",
5869                                                   username_subquery);
5870         }
5871         else if (fout->remoteVersion >= 80100)
5872         {
5873                 /* Languages are owned by the bootstrap superuser, OID 10 */
5874                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5875                                                   "(%s '10') AS lanowner "
5876                                                   "FROM pg_language "
5877                                                   "WHERE lanispl "
5878                                                   "ORDER BY oid",
5879                                                   username_subquery);
5880         }
5881         else if (fout->remoteVersion >= 70400)
5882         {
5883                 /* Languages are owned by the bootstrap superuser, sysid 1 */
5884                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
5885                                                   "(%s '1') AS lanowner "
5886                                                   "FROM pg_language "
5887                                                   "WHERE lanispl "
5888                                                   "ORDER BY oid",
5889                                                   username_subquery);
5890         }
5891         else if (fout->remoteVersion >= 70100)
5892         {
5893                 /* No clear notion of an owner at all before 7.4 ... */
5894                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
5895                                                   "WHERE lanispl "
5896                                                   "ORDER BY oid");
5897         }
5898         else
5899         {
5900                 appendPQExpBuffer(query, "SELECT "
5901                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
5902                                                   "oid, * FROM pg_language "
5903                                                   "WHERE lanispl "
5904                                                   "ORDER BY oid");
5905         }
5906
5907         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5908
5909         ntups = PQntuples(res);
5910
5911         *numProcLangs = ntups;
5912
5913         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
5914
5915         i_tableoid = PQfnumber(res, "tableoid");
5916         i_oid = PQfnumber(res, "oid");
5917         i_lanname = PQfnumber(res, "lanname");
5918         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
5919         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
5920         /* these may fail and return -1: */
5921         i_laninline = PQfnumber(res, "laninline");
5922         i_lanvalidator = PQfnumber(res, "lanvalidator");
5923         i_lanacl = PQfnumber(res, "lanacl");
5924         i_lanowner = PQfnumber(res, "lanowner");
5925
5926         for (i = 0; i < ntups; i++)
5927         {
5928                 planginfo[i].dobj.objType = DO_PROCLANG;
5929                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5930                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5931                 AssignDumpId(&planginfo[i].dobj);
5932
5933                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
5934                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
5935                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
5936                 if (i_laninline >= 0)
5937                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
5938                 else
5939                         planginfo[i].laninline = InvalidOid;
5940                 if (i_lanvalidator >= 0)
5941                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
5942                 else
5943                         planginfo[i].lanvalidator = InvalidOid;
5944                 if (i_lanacl >= 0)
5945                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
5946                 else
5947                         planginfo[i].lanacl = pg_strdup("{=U}");
5948                 if (i_lanowner >= 0)
5949                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
5950                 else
5951                         planginfo[i].lanowner = pg_strdup("");
5952
5953                 if (fout->remoteVersion < 70300)
5954                 {
5955                         /*
5956                          * We need to make a dependency to ensure the function will be
5957                          * dumped first.  (In 7.3 and later the regular dependency
5958                          * mechanism will handle this for us.)
5959                          */
5960                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
5961
5962                         if (funcInfo)
5963                                 addObjectDependency(&planginfo[i].dobj,
5964                                                                         funcInfo->dobj.dumpId);
5965                 }
5966         }
5967
5968         PQclear(res);
5969
5970         destroyPQExpBuffer(query);
5971
5972         return planginfo;
5973 }
5974
5975 /*
5976  * getCasts
5977  *        get basic information about every cast in the system
5978  *
5979  * numCasts is set to the number of casts read in
5980  */
5981 CastInfo *
5982 getCasts(Archive *fout, int *numCasts)
5983 {
5984         PGresult   *res;
5985         int                     ntups;
5986         int                     i;
5987         PQExpBuffer query = createPQExpBuffer();
5988         CastInfo   *castinfo;
5989         int                     i_tableoid;
5990         int                     i_oid;
5991         int                     i_castsource;
5992         int                     i_casttarget;
5993         int                     i_castfunc;
5994         int                     i_castcontext;
5995         int                     i_castmethod;
5996
5997         /* Make sure we are in proper schema */
5998         selectSourceSchema(fout, "pg_catalog");
5999
6000         if (fout->remoteVersion >= 80400)
6001         {
6002                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6003                                                   "castsource, casttarget, castfunc, castcontext, "
6004                                                   "castmethod "
6005                                                   "FROM pg_cast ORDER BY 3,4");
6006         }
6007         else if (fout->remoteVersion >= 70300)
6008         {
6009                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6010                                                   "castsource, casttarget, castfunc, castcontext, "
6011                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6012                                                   "FROM pg_cast ORDER BY 3,4");
6013         }
6014         else
6015         {
6016                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
6017                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
6018                                                   "p.oid AS castfunc, 'e' AS castcontext, "
6019                                                   "'f' AS castmethod "
6020                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
6021                                                   "WHERE p.pronargs = 1 AND "
6022                                                   "p.proargtypes[0] = t1.oid AND "
6023                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6024                                                   "ORDER BY 3,4");
6025         }
6026
6027         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6028
6029         ntups = PQntuples(res);
6030
6031         *numCasts = ntups;
6032
6033         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6034
6035         i_tableoid = PQfnumber(res, "tableoid");
6036         i_oid = PQfnumber(res, "oid");
6037         i_castsource = PQfnumber(res, "castsource");
6038         i_casttarget = PQfnumber(res, "casttarget");
6039         i_castfunc = PQfnumber(res, "castfunc");
6040         i_castcontext = PQfnumber(res, "castcontext");
6041         i_castmethod = PQfnumber(res, "castmethod");
6042
6043         for (i = 0; i < ntups; i++)
6044         {
6045                 PQExpBufferData namebuf;
6046                 TypeInfo   *sTypeInfo;
6047                 TypeInfo   *tTypeInfo;
6048
6049                 castinfo[i].dobj.objType = DO_CAST;
6050                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6051                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6052                 AssignDumpId(&castinfo[i].dobj);
6053                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6054                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6055                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6056                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6057                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6058
6059                 /*
6060                  * Try to name cast as concatenation of typnames.  This is only used
6061                  * for purposes of sorting.  If we fail to find either type, the name
6062                  * will be an empty string.
6063                  */
6064                 initPQExpBuffer(&namebuf);
6065                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6066                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6067                 if (sTypeInfo && tTypeInfo)
6068                         appendPQExpBuffer(&namebuf, "%s %s",
6069                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6070                 castinfo[i].dobj.name = namebuf.data;
6071
6072                 if (OidIsValid(castinfo[i].castfunc))
6073                 {
6074                         /*
6075                          * We need to make a dependency to ensure the function will be
6076                          * dumped first.  (In 7.3 and later the regular dependency
6077                          * mechanism will handle this for us.)
6078                          */
6079                         FuncInfo   *funcInfo;
6080
6081                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6082                         if (funcInfo)
6083                                 addObjectDependency(&castinfo[i].dobj,
6084                                                                         funcInfo->dobj.dumpId);
6085                 }
6086         }
6087
6088         PQclear(res);
6089
6090         destroyPQExpBuffer(query);
6091
6092         return castinfo;
6093 }
6094
6095 /*
6096  * getTableAttrs -
6097  *        for each interesting table, read info about its attributes
6098  *        (names, types, default values, CHECK constraints, etc)
6099  *
6100  * This is implemented in a very inefficient way right now, looping
6101  * through the tblinfo and doing a join per table to find the attrs and their
6102  * types.  However, because we want type names and so forth to be named
6103  * relative to the schema of each table, we couldn't do it in just one
6104  * query.  (Maybe one query per schema?)
6105  *
6106  *      modifies tblinfo
6107  */
6108 void
6109 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
6110 {
6111         int                     i,
6112                                 j;
6113         PQExpBuffer q = createPQExpBuffer();
6114         int                     i_attnum;
6115         int                     i_attname;
6116         int                     i_atttypname;
6117         int                     i_atttypmod;
6118         int                     i_attstattarget;
6119         int                     i_attstorage;
6120         int                     i_typstorage;
6121         int                     i_attnotnull;
6122         int                     i_atthasdef;
6123         int                     i_attisdropped;
6124         int                     i_attlen;
6125         int                     i_attalign;
6126         int                     i_attislocal;
6127         int                     i_attoptions;
6128         int                     i_attcollation;
6129         int                     i_attfdwoptions;
6130         PGresult   *res;
6131         int                     ntups;
6132         bool            hasdefaults;
6133
6134         for (i = 0; i < numTables; i++)
6135         {
6136                 TableInfo  *tbinfo = &tblinfo[i];
6137
6138                 /* Don't bother to collect info for sequences */
6139                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6140                         continue;
6141
6142                 /* Don't bother with uninteresting tables, either */
6143                 if (!tbinfo->interesting)
6144                         continue;
6145
6146                 /*
6147                  * Make sure we are in proper schema for this table; this allows
6148                  * correct retrieval of formatted type names and default exprs
6149                  */
6150                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6151
6152                 /* find all the user attributes and their types */
6153
6154                 /*
6155                  * we must read the attribute names in attribute number order! because
6156                  * we will use the attnum to index into the attnames array later.  We
6157                  * actually ask to order by "attrelid, attnum" because (at least up to
6158                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6159                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6160                  */
6161                 if (g_verbose)
6162                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
6163                                           tbinfo->dobj.name);
6164
6165                 resetPQExpBuffer(q);
6166
6167                 if (fout->remoteVersion >= 90200)
6168                 {
6169                         /*
6170                          * attfdwoptions is new in 9.2.
6171                          */
6172                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6173                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6174                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6175                                                           "a.attlen, a.attalign, a.attislocal, "
6176                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6177                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6178                                                           "CASE WHEN a.attcollation <> t.typcollation "
6179                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6180                                                           "pg_catalog.array_to_string(ARRAY("
6181                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6182                                                           "' ' || pg_catalog.quote_literal(option_value) "
6183                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6184                                                           "ORDER BY option_name"
6185                                                           "), E',\n    ') AS attfdwoptions "
6186                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6187                                                           "ON a.atttypid = t.oid "
6188                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6189                                                           "AND a.attnum > 0::pg_catalog.int2 "
6190                                                           "ORDER BY a.attrelid, a.attnum",
6191                                                           tbinfo->dobj.catId.oid);
6192                 }
6193                 else if (fout->remoteVersion >= 90100)
6194                 {
6195                         /*
6196                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6197                          * clauses for attributes whose collation is different from their
6198                          * type's default, we use a CASE here to suppress uninteresting
6199                          * attcollations cheaply.
6200                          */
6201                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6202                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6203                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6204                                                           "a.attlen, a.attalign, a.attislocal, "
6205                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6206                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6207                                                           "CASE WHEN a.attcollation <> t.typcollation "
6208                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6209                                                           "NULL AS attfdwoptions "
6210                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6211                                                           "ON a.atttypid = t.oid "
6212                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6213                                                           "AND a.attnum > 0::pg_catalog.int2 "
6214                                                           "ORDER BY a.attrelid, a.attnum",
6215                                                           tbinfo->dobj.catId.oid);
6216                 }
6217                 else if (fout->remoteVersion >= 90000)
6218                 {
6219                         /* attoptions is new in 9.0 */
6220                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6221                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6222                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6223                                                           "a.attlen, a.attalign, a.attislocal, "
6224                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6225                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6226                                                           "0 AS attcollation, "
6227                                                           "NULL AS attfdwoptions "
6228                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6229                                                           "ON a.atttypid = t.oid "
6230                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6231                                                           "AND a.attnum > 0::pg_catalog.int2 "
6232                                                           "ORDER BY a.attrelid, a.attnum",
6233                                                           tbinfo->dobj.catId.oid);
6234                 }
6235                 else if (fout->remoteVersion >= 70300)
6236                 {
6237                         /* need left join here to not fail on dropped columns ... */
6238                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6239                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6240                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6241                                                           "a.attlen, a.attalign, a.attislocal, "
6242                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6243                                                           "'' AS attoptions, 0 AS attcollation, "
6244                                                           "NULL AS attfdwoptions "
6245                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6246                                                           "ON a.atttypid = t.oid "
6247                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6248                                                           "AND a.attnum > 0::pg_catalog.int2 "
6249                                                           "ORDER BY a.attrelid, a.attnum",
6250                                                           tbinfo->dobj.catId.oid);
6251                 }
6252                 else if (fout->remoteVersion >= 70100)
6253                 {
6254                         /*
6255                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6256                          * we don't dump it because we can't tell whether it's been
6257                          * explicitly set or was just a default.
6258                          *
6259                          * attislocal doesn't exist before 7.3, either; in older databases
6260                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6261                          */
6262                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6263                                                           "-1 AS attstattarget, a.attstorage, "
6264                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6265                                                           "false AS attisdropped, a.attlen, "
6266                                                           "a.attalign, true AS attislocal, "
6267                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6268                                                           "'' AS attoptions, 0 AS attcollation, "
6269                                                           "NULL AS attfdwoptions "
6270                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6271                                                           "ON a.atttypid = t.oid "
6272                                                           "WHERE a.attrelid = '%u'::oid "
6273                                                           "AND a.attnum > 0::int2 "
6274                                                           "ORDER BY a.attrelid, a.attnum",
6275                                                           tbinfo->dobj.catId.oid);
6276                 }
6277                 else
6278                 {
6279                         /* format_type not available before 7.1 */
6280                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6281                                                           "-1 AS attstattarget, "
6282                                                           "attstorage, attstorage AS typstorage, "
6283                                                           "attnotnull, atthasdef, false AS attisdropped, "
6284                                                           "attlen, attalign, "
6285                                                           "true AS attislocal, "
6286                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6287                                                           "'' AS attoptions, 0 AS attcollation, "
6288                                                           "NULL AS attfdwoptions "
6289                                                           "FROM pg_attribute a "
6290                                                           "WHERE attrelid = '%u'::oid "
6291                                                           "AND attnum > 0::int2 "
6292                                                           "ORDER BY attrelid, attnum",
6293                                                           tbinfo->dobj.catId.oid);
6294                 }
6295
6296                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6297
6298                 ntups = PQntuples(res);
6299
6300                 i_attnum = PQfnumber(res, "attnum");
6301                 i_attname = PQfnumber(res, "attname");
6302                 i_atttypname = PQfnumber(res, "atttypname");
6303                 i_atttypmod = PQfnumber(res, "atttypmod");
6304                 i_attstattarget = PQfnumber(res, "attstattarget");
6305                 i_attstorage = PQfnumber(res, "attstorage");
6306                 i_typstorage = PQfnumber(res, "typstorage");
6307                 i_attnotnull = PQfnumber(res, "attnotnull");
6308                 i_atthasdef = PQfnumber(res, "atthasdef");
6309                 i_attisdropped = PQfnumber(res, "attisdropped");
6310                 i_attlen = PQfnumber(res, "attlen");
6311                 i_attalign = PQfnumber(res, "attalign");
6312                 i_attislocal = PQfnumber(res, "attislocal");
6313                 i_attoptions = PQfnumber(res, "attoptions");
6314                 i_attcollation = PQfnumber(res, "attcollation");
6315                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6316
6317                 tbinfo->numatts = ntups;
6318                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6319                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6320                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6321                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6322                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6323                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6324                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6325                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6326                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6327                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6328                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6329                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6330                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6331                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6332                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6333                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6334                 hasdefaults = false;
6335
6336                 for (j = 0; j < ntups; j++)
6337                 {
6338                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6339                                 exit_horribly(NULL,
6340                                                           "invalid column numbering in table \"%s\"\n",
6341                                                           tbinfo->dobj.name);
6342                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6343                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6344                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6345                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6346                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6347                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6348                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6349                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6350                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6351                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6352                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6353                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6354                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6355                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6356                         tbinfo->attrdefs[j] = NULL; /* fix below */
6357                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6358                                 hasdefaults = true;
6359                         /* these flags will be set in flagInhAttrs() */
6360                         tbinfo->inhNotNull[j] = false;
6361                 }
6362
6363                 PQclear(res);
6364
6365                 /*
6366                  * Get info about column defaults
6367                  */
6368                 if (hasdefaults)
6369                 {
6370                         AttrDefInfo *attrdefs;
6371                         int                     numDefaults;
6372
6373                         if (g_verbose)
6374                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
6375                                                   tbinfo->dobj.name);
6376
6377                         resetPQExpBuffer(q);
6378                         if (fout->remoteVersion >= 70300)
6379                         {
6380                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6381                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6382                                                                   "FROM pg_catalog.pg_attrdef "
6383                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6384                                                                   tbinfo->dobj.catId.oid);
6385                         }
6386                         else if (fout->remoteVersion >= 70200)
6387                         {
6388                                 /* 7.2 did not have OIDs in pg_attrdef */
6389                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6390                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6391                                                                   "FROM pg_attrdef "
6392                                                                   "WHERE adrelid = '%u'::oid",
6393                                                                   tbinfo->dobj.catId.oid);
6394                         }
6395                         else if (fout->remoteVersion >= 70100)
6396                         {
6397                                 /* no pg_get_expr, so must rely on adsrc */
6398                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6399                                                                   "FROM pg_attrdef "
6400                                                                   "WHERE adrelid = '%u'::oid",
6401                                                                   tbinfo->dobj.catId.oid);
6402                         }
6403                         else
6404                         {
6405                                 /* no pg_get_expr, no tableoid either */
6406                                 appendPQExpBuffer(q, "SELECT "
6407                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6408                                                                   "oid, adnum, adsrc "
6409                                                                   "FROM pg_attrdef "
6410                                                                   "WHERE adrelid = '%u'::oid",
6411                                                                   tbinfo->dobj.catId.oid);
6412                         }
6413                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6414
6415                         numDefaults = PQntuples(res);
6416                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6417
6418                         for (j = 0; j < numDefaults; j++)
6419                         {
6420                                 int                     adnum;
6421
6422                                 adnum = atoi(PQgetvalue(res, j, 2));
6423
6424                                 if (adnum <= 0 || adnum > ntups)
6425                                         exit_horribly(NULL,
6426                                                                   "invalid adnum value %d for table \"%s\"\n",
6427                                                                   adnum, tbinfo->dobj.name);
6428
6429                                 /*
6430                                  * dropped columns shouldn't have defaults, but just in case,
6431                                  * ignore 'em
6432                                  */
6433                                 if (tbinfo->attisdropped[adnum - 1])
6434                                         continue;
6435
6436                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6437                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6438                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6439                                 AssignDumpId(&attrdefs[j].dobj);
6440                                 attrdefs[j].adtable = tbinfo;
6441                                 attrdefs[j].adnum = adnum;
6442                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6443
6444                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6445                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6446
6447                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6448
6449                                 /*
6450                                  * Defaults on a VIEW must always be dumped as separate ALTER
6451                                  * TABLE commands.      Defaults on regular tables are dumped as
6452                                  * part of the CREATE TABLE if possible, which it won't be if
6453                                  * the column is not going to be emitted explicitly.
6454                                  */
6455                                 if (tbinfo->relkind == RELKIND_VIEW)
6456                                 {
6457                                         attrdefs[j].separate = true;
6458                                         /* needed in case pre-7.3 DB: */
6459                                         addObjectDependency(&attrdefs[j].dobj,
6460                                                                                 tbinfo->dobj.dumpId);
6461                                 }
6462                                 else if (!shouldPrintColumn(tbinfo, adnum - 1))
6463                                 {
6464                                         /* column will be suppressed, print default separately */
6465                                         attrdefs[j].separate = true;
6466                                         /* needed in case pre-7.3 DB: */
6467                                         addObjectDependency(&attrdefs[j].dobj,
6468                                                                                 tbinfo->dobj.dumpId);
6469                                 }
6470                                 else
6471                                 {
6472                                         attrdefs[j].separate = false;
6473
6474                                         /*
6475                                          * Mark the default as needing to appear before the table,
6476                                          * so that any dependencies it has must be emitted before
6477                                          * the CREATE TABLE.  If this is not possible, we'll
6478                                          * change to "separate" mode while sorting dependencies.
6479                                          */
6480                                         addObjectDependency(&tbinfo->dobj,
6481                                                                                 attrdefs[j].dobj.dumpId);
6482                                 }
6483
6484                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6485                         }
6486                         PQclear(res);
6487                 }
6488
6489                 /*
6490                  * Get info about table CHECK constraints
6491                  */
6492                 if (tbinfo->ncheck > 0)
6493                 {
6494                         ConstraintInfo *constrs;
6495                         int                     numConstrs;
6496
6497                         if (g_verbose)
6498                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
6499                                                   tbinfo->dobj.name);
6500
6501                         resetPQExpBuffer(q);
6502                         if (fout->remoteVersion >= 90200)
6503                         {
6504                                 /*
6505                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6506                                  * but it wasn't ever false for check constraints until 9.2).
6507                                  */
6508                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6509                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6510                                                                   "conislocal, convalidated "
6511                                                                   "FROM pg_catalog.pg_constraint "
6512                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6513                                                                   "   AND contype = 'c' "
6514                                                                   "ORDER BY conname",
6515                                                                   tbinfo->dobj.catId.oid);
6516                         }
6517                         else if (fout->remoteVersion >= 80400)
6518                         {
6519                                 /* conislocal is new in 8.4 */
6520                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6521                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6522                                                                   "conislocal, true AS convalidated "
6523                                                                   "FROM pg_catalog.pg_constraint "
6524                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6525                                                                   "   AND contype = 'c' "
6526                                                                   "ORDER BY conname",
6527                                                                   tbinfo->dobj.catId.oid);
6528                         }
6529                         else if (fout->remoteVersion >= 70400)
6530                         {
6531                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6532                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
6533                                                                   "true AS conislocal, true AS convalidated "
6534                                                                   "FROM pg_catalog.pg_constraint "
6535                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6536                                                                   "   AND contype = 'c' "
6537                                                                   "ORDER BY conname",
6538                                                                   tbinfo->dobj.catId.oid);
6539                         }
6540                         else if (fout->remoteVersion >= 70300)
6541                         {
6542                                 /* no pg_get_constraintdef, must use consrc */
6543                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
6544                                                                   "'CHECK (' || consrc || ')' AS consrc, "
6545                                                                   "true AS conislocal, true AS convalidated "
6546                                                                   "FROM pg_catalog.pg_constraint "
6547                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
6548                                                                   "   AND contype = 'c' "
6549                                                                   "ORDER BY conname",
6550                                                                   tbinfo->dobj.catId.oid);
6551                         }
6552                         else if (fout->remoteVersion >= 70200)
6553                         {
6554                                 /* 7.2 did not have OIDs in pg_relcheck */
6555                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
6556                                                                   "rcname AS conname, "
6557                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6558                                                                   "true AS conislocal, true AS convalidated "
6559                                                                   "FROM pg_relcheck "
6560                                                                   "WHERE rcrelid = '%u'::oid "
6561                                                                   "ORDER BY rcname",
6562                                                                   tbinfo->dobj.catId.oid);
6563                         }
6564                         else if (fout->remoteVersion >= 70100)
6565                         {
6566                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
6567                                                                   "rcname AS conname, "
6568                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6569                                                                   "true AS conislocal, true AS convalidated "
6570                                                                   "FROM pg_relcheck "
6571                                                                   "WHERE rcrelid = '%u'::oid "
6572                                                                   "ORDER BY rcname",
6573                                                                   tbinfo->dobj.catId.oid);
6574                         }
6575                         else
6576                         {
6577                                 /* no tableoid in 7.0 */
6578                                 appendPQExpBuffer(q, "SELECT "
6579                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
6580                                                                   "oid, rcname AS conname, "
6581                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
6582                                                                   "true AS conislocal, true AS convalidated "
6583                                                                   "FROM pg_relcheck "
6584                                                                   "WHERE rcrelid = '%u'::oid "
6585                                                                   "ORDER BY rcname",
6586                                                                   tbinfo->dobj.catId.oid);
6587                         }
6588                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6589
6590                         numConstrs = PQntuples(res);
6591                         if (numConstrs != tbinfo->ncheck)
6592                         {
6593                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
6594                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
6595                                                                                  tbinfo->ncheck),
6596                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
6597                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
6598                                 exit_nicely(1);
6599                         }
6600
6601                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
6602                         tbinfo->checkexprs = constrs;
6603
6604                         for (j = 0; j < numConstrs; j++)
6605                         {
6606                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
6607
6608                                 constrs[j].dobj.objType = DO_CONSTRAINT;
6609                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6610                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6611                                 AssignDumpId(&constrs[j].dobj);
6612                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
6613                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
6614                                 constrs[j].contable = tbinfo;
6615                                 constrs[j].condomain = NULL;
6616                                 constrs[j].contype = 'c';
6617                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
6618                                 constrs[j].confrelid = InvalidOid;
6619                                 constrs[j].conindex = 0;
6620                                 constrs[j].condeferrable = false;
6621                                 constrs[j].condeferred = false;
6622                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
6623
6624                                 /*
6625                                  * An unvalidated constraint needs to be dumped separately, so
6626                                  * that potentially-violating existing data is loaded before
6627                                  * the constraint.
6628                                  */
6629                                 constrs[j].separate = !validated;
6630
6631                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
6632
6633                                 /*
6634                                  * Mark the constraint as needing to appear before the table
6635                                  * --- this is so that any other dependencies of the
6636                                  * constraint will be emitted before we try to create the
6637                                  * table.  If the constraint is to be dumped separately, it
6638                                  * will be dumped after data is loaded anyway, so don't do it.
6639                                  * (There's an automatic dependency in the opposite direction
6640                                  * anyway, so don't need to add one manually here.)
6641                                  */
6642                                 if (!constrs[j].separate)
6643                                         addObjectDependency(&tbinfo->dobj,
6644                                                                                 constrs[j].dobj.dumpId);
6645
6646                                 /*
6647                                  * If the constraint is inherited, this will be detected later
6648                                  * (in pre-8.4 databases).      We also detect later if the
6649                                  * constraint must be split out from the table definition.
6650                                  */
6651                         }
6652                         PQclear(res);
6653                 }
6654         }
6655
6656         destroyPQExpBuffer(q);
6657 }
6658
6659 /*
6660  * Test whether a column should be printed as part of table's CREATE TABLE.
6661  * Column number is zero-based.
6662  *
6663  * Normally this is always true, but it's false for dropped columns, as well
6664  * as those that were inherited without any local definition.  (If we print
6665  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
6666  * However, in binary_upgrade mode, we must print all such columns anyway and
6667  * fix the attislocal/attisdropped state later, so as to keep control of the
6668  * physical column order.
6669  *
6670  * This function exists because there are scattered nonobvious places that
6671  * must be kept in sync with this decision.
6672  */
6673 bool
6674 shouldPrintColumn(TableInfo *tbinfo, int colno)
6675 {
6676         if (binary_upgrade)
6677                 return true;
6678         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
6679 }
6680
6681
6682 /*
6683  * getTSParsers:
6684  *        read all text search parsers in the system catalogs and return them
6685  *        in the TSParserInfo* structure
6686  *
6687  *      numTSParsers is set to the number of parsers read in
6688  */
6689 TSParserInfo *
6690 getTSParsers(Archive *fout, int *numTSParsers)
6691 {
6692         PGresult   *res;
6693         int                     ntups;
6694         int                     i;
6695         PQExpBuffer query;
6696         TSParserInfo *prsinfo;
6697         int                     i_tableoid;
6698         int                     i_oid;
6699         int                     i_prsname;
6700         int                     i_prsnamespace;
6701         int                     i_prsstart;
6702         int                     i_prstoken;
6703         int                     i_prsend;
6704         int                     i_prsheadline;
6705         int                     i_prslextype;
6706
6707         /* Before 8.3, there is no built-in text search support */
6708         if (fout->remoteVersion < 80300)
6709         {
6710                 *numTSParsers = 0;
6711                 return NULL;
6712         }
6713
6714         query = createPQExpBuffer();
6715
6716         /*
6717          * find all text search objects, including builtin ones; we filter out
6718          * system-defined objects at dump-out time.
6719          */
6720
6721         /* Make sure we are in proper schema */
6722         selectSourceSchema(fout, "pg_catalog");
6723
6724         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
6725                                           "prsstart::oid, prstoken::oid, "
6726                                           "prsend::oid, prsheadline::oid, prslextype::oid "
6727                                           "FROM pg_ts_parser");
6728
6729         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6730
6731         ntups = PQntuples(res);
6732         *numTSParsers = ntups;
6733
6734         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
6735
6736         i_tableoid = PQfnumber(res, "tableoid");
6737         i_oid = PQfnumber(res, "oid");
6738         i_prsname = PQfnumber(res, "prsname");
6739         i_prsnamespace = PQfnumber(res, "prsnamespace");
6740         i_prsstart = PQfnumber(res, "prsstart");
6741         i_prstoken = PQfnumber(res, "prstoken");
6742         i_prsend = PQfnumber(res, "prsend");
6743         i_prsheadline = PQfnumber(res, "prsheadline");
6744         i_prslextype = PQfnumber(res, "prslextype");
6745
6746         for (i = 0; i < ntups; i++)
6747         {
6748                 prsinfo[i].dobj.objType = DO_TSPARSER;
6749                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6750                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6751                 AssignDumpId(&prsinfo[i].dobj);
6752                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
6753                 prsinfo[i].dobj.namespace =
6754                         findNamespace(fout,
6755                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
6756                                                   prsinfo[i].dobj.catId.oid);
6757                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
6758                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
6759                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
6760                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
6761                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
6762
6763                 /* Decide whether we want to dump it */
6764                 selectDumpableObject(&(prsinfo[i].dobj));
6765         }
6766
6767         PQclear(res);
6768
6769         destroyPQExpBuffer(query);
6770
6771         return prsinfo;
6772 }
6773
6774 /*
6775  * getTSDictionaries:
6776  *        read all text search dictionaries in the system catalogs and return them
6777  *        in the TSDictInfo* structure
6778  *
6779  *      numTSDicts is set to the number of dictionaries read in
6780  */
6781 TSDictInfo *
6782 getTSDictionaries(Archive *fout, int *numTSDicts)
6783 {
6784         PGresult   *res;
6785         int                     ntups;
6786         int                     i;
6787         PQExpBuffer query;
6788         TSDictInfo *dictinfo;
6789         int                     i_tableoid;
6790         int                     i_oid;
6791         int                     i_dictname;
6792         int                     i_dictnamespace;
6793         int                     i_rolname;
6794         int                     i_dicttemplate;
6795         int                     i_dictinitoption;
6796
6797         /* Before 8.3, there is no built-in text search support */
6798         if (fout->remoteVersion < 80300)
6799         {
6800                 *numTSDicts = 0;
6801                 return NULL;
6802         }
6803
6804         query = createPQExpBuffer();
6805
6806         /* Make sure we are in proper schema */
6807         selectSourceSchema(fout, "pg_catalog");
6808
6809         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
6810                                           "dictnamespace, (%s dictowner) AS rolname, "
6811                                           "dicttemplate, dictinitoption "
6812                                           "FROM pg_ts_dict",
6813                                           username_subquery);
6814
6815         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6816
6817         ntups = PQntuples(res);
6818         *numTSDicts = ntups;
6819
6820         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
6821
6822         i_tableoid = PQfnumber(res, "tableoid");
6823         i_oid = PQfnumber(res, "oid");
6824         i_dictname = PQfnumber(res, "dictname");
6825         i_dictnamespace = PQfnumber(res, "dictnamespace");
6826         i_rolname = PQfnumber(res, "rolname");
6827         i_dictinitoption = PQfnumber(res, "dictinitoption");
6828         i_dicttemplate = PQfnumber(res, "dicttemplate");
6829
6830         for (i = 0; i < ntups; i++)
6831         {
6832                 dictinfo[i].dobj.objType = DO_TSDICT;
6833                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6834                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6835                 AssignDumpId(&dictinfo[i].dobj);
6836                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
6837                 dictinfo[i].dobj.namespace =
6838                         findNamespace(fout,
6839                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
6840                                                   dictinfo[i].dobj.catId.oid);
6841                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6842                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
6843                 if (PQgetisnull(res, i, i_dictinitoption))
6844                         dictinfo[i].dictinitoption = NULL;
6845                 else
6846                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
6847
6848                 /* Decide whether we want to dump it */
6849                 selectDumpableObject(&(dictinfo[i].dobj));
6850         }
6851
6852         PQclear(res);
6853
6854         destroyPQExpBuffer(query);
6855
6856         return dictinfo;
6857 }
6858
6859 /*
6860  * getTSTemplates:
6861  *        read all text search templates in the system catalogs and return them
6862  *        in the TSTemplateInfo* structure
6863  *
6864  *      numTSTemplates is set to the number of templates read in
6865  */
6866 TSTemplateInfo *
6867 getTSTemplates(Archive *fout, int *numTSTemplates)
6868 {
6869         PGresult   *res;
6870         int                     ntups;
6871         int                     i;
6872         PQExpBuffer query;
6873         TSTemplateInfo *tmplinfo;
6874         int                     i_tableoid;
6875         int                     i_oid;
6876         int                     i_tmplname;
6877         int                     i_tmplnamespace;
6878         int                     i_tmplinit;
6879         int                     i_tmpllexize;
6880
6881         /* Before 8.3, there is no built-in text search support */
6882         if (fout->remoteVersion < 80300)
6883         {
6884                 *numTSTemplates = 0;
6885                 return NULL;
6886         }
6887
6888         query = createPQExpBuffer();
6889
6890         /* Make sure we are in proper schema */
6891         selectSourceSchema(fout, "pg_catalog");
6892
6893         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
6894                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
6895                                           "FROM pg_ts_template");
6896
6897         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6898
6899         ntups = PQntuples(res);
6900         *numTSTemplates = ntups;
6901
6902         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
6903
6904         i_tableoid = PQfnumber(res, "tableoid");
6905         i_oid = PQfnumber(res, "oid");
6906         i_tmplname = PQfnumber(res, "tmplname");
6907         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
6908         i_tmplinit = PQfnumber(res, "tmplinit");
6909         i_tmpllexize = PQfnumber(res, "tmpllexize");
6910
6911         for (i = 0; i < ntups; i++)
6912         {
6913                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
6914                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6915                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6916                 AssignDumpId(&tmplinfo[i].dobj);
6917                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
6918                 tmplinfo[i].dobj.namespace =
6919                         findNamespace(fout,
6920                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
6921                                                   tmplinfo[i].dobj.catId.oid);
6922                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
6923                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
6924
6925                 /* Decide whether we want to dump it */
6926                 selectDumpableObject(&(tmplinfo[i].dobj));
6927         }
6928
6929         PQclear(res);
6930
6931         destroyPQExpBuffer(query);
6932
6933         return tmplinfo;
6934 }
6935
6936 /*
6937  * getTSConfigurations:
6938  *        read all text search configurations in the system catalogs and return
6939  *        them in the TSConfigInfo* structure
6940  *
6941  *      numTSConfigs is set to the number of configurations read in
6942  */
6943 TSConfigInfo *
6944 getTSConfigurations(Archive *fout, int *numTSConfigs)
6945 {
6946         PGresult   *res;
6947         int                     ntups;
6948         int                     i;
6949         PQExpBuffer query;
6950         TSConfigInfo *cfginfo;
6951         int                     i_tableoid;
6952         int                     i_oid;
6953         int                     i_cfgname;
6954         int                     i_cfgnamespace;
6955         int                     i_rolname;
6956         int                     i_cfgparser;
6957
6958         /* Before 8.3, there is no built-in text search support */
6959         if (fout->remoteVersion < 80300)
6960         {
6961                 *numTSConfigs = 0;
6962                 return NULL;
6963         }
6964
6965         query = createPQExpBuffer();
6966
6967         /* Make sure we are in proper schema */
6968         selectSourceSchema(fout, "pg_catalog");
6969
6970         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
6971                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
6972                                           "FROM pg_ts_config",
6973                                           username_subquery);
6974
6975         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6976
6977         ntups = PQntuples(res);
6978         *numTSConfigs = ntups;
6979
6980         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
6981
6982         i_tableoid = PQfnumber(res, "tableoid");
6983         i_oid = PQfnumber(res, "oid");
6984         i_cfgname = PQfnumber(res, "cfgname");
6985         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
6986         i_rolname = PQfnumber(res, "rolname");
6987         i_cfgparser = PQfnumber(res, "cfgparser");
6988
6989         for (i = 0; i < ntups; i++)
6990         {
6991                 cfginfo[i].dobj.objType = DO_TSCONFIG;
6992                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6993                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6994                 AssignDumpId(&cfginfo[i].dobj);
6995                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
6996                 cfginfo[i].dobj.namespace =
6997                         findNamespace(fout,
6998                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
6999                                                   cfginfo[i].dobj.catId.oid);
7000                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7001                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7002
7003                 /* Decide whether we want to dump it */
7004                 selectDumpableObject(&(cfginfo[i].dobj));
7005         }
7006
7007         PQclear(res);
7008
7009         destroyPQExpBuffer(query);
7010
7011         return cfginfo;
7012 }
7013
7014 /*
7015  * getForeignDataWrappers:
7016  *        read all foreign-data wrappers in the system catalogs and return
7017  *        them in the FdwInfo* structure
7018  *
7019  *      numForeignDataWrappers is set to the number of fdws read in
7020  */
7021 FdwInfo *
7022 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7023 {
7024         PGresult   *res;
7025         int                     ntups;
7026         int                     i;
7027         PQExpBuffer query = createPQExpBuffer();
7028         FdwInfo    *fdwinfo;
7029         int                     i_tableoid;
7030         int                     i_oid;
7031         int                     i_fdwname;
7032         int                     i_rolname;
7033         int                     i_fdwhandler;
7034         int                     i_fdwvalidator;
7035         int                     i_fdwacl;
7036         int                     i_fdwoptions;
7037
7038         /* Before 8.4, there are no foreign-data wrappers */
7039         if (fout->remoteVersion < 80400)
7040         {
7041                 *numForeignDataWrappers = 0;
7042                 return NULL;
7043         }
7044
7045         /* Make sure we are in proper schema */
7046         selectSourceSchema(fout, "pg_catalog");
7047
7048         if (fout->remoteVersion >= 90100)
7049         {
7050                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7051                                                   "(%s fdwowner) AS rolname, "
7052                                                   "fdwhandler::pg_catalog.regproc, "
7053                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7054                                                   "array_to_string(ARRAY("
7055                                                   "SELECT quote_ident(option_name) || ' ' || "
7056                                                   "quote_literal(option_value) "
7057                                                   "FROM pg_options_to_table(fdwoptions) "
7058                                                   "ORDER BY option_name"
7059                                                   "), E',\n    ') AS fdwoptions "
7060                                                   "FROM pg_foreign_data_wrapper",
7061                                                   username_subquery);
7062         }
7063         else
7064         {
7065                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7066                                                   "(%s fdwowner) AS rolname, "
7067                                                   "'-' AS fdwhandler, "
7068                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7069                                                   "array_to_string(ARRAY("
7070                                                   "SELECT quote_ident(option_name) || ' ' || "
7071                                                   "quote_literal(option_value) "
7072                                                   "FROM pg_options_to_table(fdwoptions) "
7073                                                   "ORDER BY option_name"
7074                                                   "), E',\n    ') AS fdwoptions "
7075                                                   "FROM pg_foreign_data_wrapper",
7076                                                   username_subquery);
7077         }
7078
7079         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7080
7081         ntups = PQntuples(res);
7082         *numForeignDataWrappers = ntups;
7083
7084         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7085
7086         i_tableoid = PQfnumber(res, "tableoid");
7087         i_oid = PQfnumber(res, "oid");
7088         i_fdwname = PQfnumber(res, "fdwname");
7089         i_rolname = PQfnumber(res, "rolname");
7090         i_fdwhandler = PQfnumber(res, "fdwhandler");
7091         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7092         i_fdwacl = PQfnumber(res, "fdwacl");
7093         i_fdwoptions = PQfnumber(res, "fdwoptions");
7094
7095         for (i = 0; i < ntups; i++)
7096         {
7097                 fdwinfo[i].dobj.objType = DO_FDW;
7098                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7099                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7100                 AssignDumpId(&fdwinfo[i].dobj);
7101                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7102                 fdwinfo[i].dobj.namespace = NULL;
7103                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7104                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7105                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7106                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7107                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7108
7109                 /* Decide whether we want to dump it */
7110                 selectDumpableObject(&(fdwinfo[i].dobj));
7111         }
7112
7113         PQclear(res);
7114
7115         destroyPQExpBuffer(query);
7116
7117         return fdwinfo;
7118 }
7119
7120 /*
7121  * getForeignServers:
7122  *        read all foreign servers in the system catalogs and return
7123  *        them in the ForeignServerInfo * structure
7124  *
7125  *      numForeignServers is set to the number of servers read in
7126  */
7127 ForeignServerInfo *
7128 getForeignServers(Archive *fout, int *numForeignServers)
7129 {
7130         PGresult   *res;
7131         int                     ntups;
7132         int                     i;
7133         PQExpBuffer query = createPQExpBuffer();
7134         ForeignServerInfo *srvinfo;
7135         int                     i_tableoid;
7136         int                     i_oid;
7137         int                     i_srvname;
7138         int                     i_rolname;
7139         int                     i_srvfdw;
7140         int                     i_srvtype;
7141         int                     i_srvversion;
7142         int                     i_srvacl;
7143         int                     i_srvoptions;
7144
7145         /* Before 8.4, there are no foreign servers */
7146         if (fout->remoteVersion < 80400)
7147         {
7148                 *numForeignServers = 0;
7149                 return NULL;
7150         }
7151
7152         /* Make sure we are in proper schema */
7153         selectSourceSchema(fout, "pg_catalog");
7154
7155         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7156                                           "(%s srvowner) AS rolname, "
7157                                           "srvfdw, srvtype, srvversion, srvacl,"
7158                                           "array_to_string(ARRAY("
7159                                           "SELECT quote_ident(option_name) || ' ' || "
7160                                           "quote_literal(option_value) "
7161                                           "FROM pg_options_to_table(srvoptions) "
7162                                           "ORDER BY option_name"
7163                                           "), E',\n    ') AS srvoptions "
7164                                           "FROM pg_foreign_server",
7165                                           username_subquery);
7166
7167         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7168
7169         ntups = PQntuples(res);
7170         *numForeignServers = ntups;
7171
7172         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7173
7174         i_tableoid = PQfnumber(res, "tableoid");
7175         i_oid = PQfnumber(res, "oid");
7176         i_srvname = PQfnumber(res, "srvname");
7177         i_rolname = PQfnumber(res, "rolname");
7178         i_srvfdw = PQfnumber(res, "srvfdw");
7179         i_srvtype = PQfnumber(res, "srvtype");
7180         i_srvversion = PQfnumber(res, "srvversion");
7181         i_srvacl = PQfnumber(res, "srvacl");
7182         i_srvoptions = PQfnumber(res, "srvoptions");
7183
7184         for (i = 0; i < ntups; i++)
7185         {
7186                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7187                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7188                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7189                 AssignDumpId(&srvinfo[i].dobj);
7190                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7191                 srvinfo[i].dobj.namespace = NULL;
7192                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7193                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7194                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7195                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7196                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7197                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7198
7199                 /* Decide whether we want to dump it */
7200                 selectDumpableObject(&(srvinfo[i].dobj));
7201         }
7202
7203         PQclear(res);
7204
7205         destroyPQExpBuffer(query);
7206
7207         return srvinfo;
7208 }
7209
7210 /*
7211  * getDefaultACLs:
7212  *        read all default ACL information in the system catalogs and return
7213  *        them in the DefaultACLInfo structure
7214  *
7215  *      numDefaultACLs is set to the number of ACLs read in
7216  */
7217 DefaultACLInfo *
7218 getDefaultACLs(Archive *fout, int *numDefaultACLs)
7219 {
7220         DefaultACLInfo *daclinfo;
7221         PQExpBuffer query;
7222         PGresult   *res;
7223         int                     i_oid;
7224         int                     i_tableoid;
7225         int                     i_defaclrole;
7226         int                     i_defaclnamespace;
7227         int                     i_defaclobjtype;
7228         int                     i_defaclacl;
7229         int                     i,
7230                                 ntups;
7231
7232         if (fout->remoteVersion < 90000)
7233         {
7234                 *numDefaultACLs = 0;
7235                 return NULL;
7236         }
7237
7238         query = createPQExpBuffer();
7239
7240         /* Make sure we are in proper schema */
7241         selectSourceSchema(fout, "pg_catalog");
7242
7243         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7244                                           "(%s defaclrole) AS defaclrole, "
7245                                           "defaclnamespace, "
7246                                           "defaclobjtype, "
7247                                           "defaclacl "
7248                                           "FROM pg_default_acl",
7249                                           username_subquery);
7250
7251         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7252
7253         ntups = PQntuples(res);
7254         *numDefaultACLs = ntups;
7255
7256         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7257
7258         i_oid = PQfnumber(res, "oid");
7259         i_tableoid = PQfnumber(res, "tableoid");
7260         i_defaclrole = PQfnumber(res, "defaclrole");
7261         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7262         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7263         i_defaclacl = PQfnumber(res, "defaclacl");
7264
7265         for (i = 0; i < ntups; i++)
7266         {
7267                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7268
7269                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7270                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7271                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7272                 AssignDumpId(&daclinfo[i].dobj);
7273                 /* cheesy ... is it worth coming up with a better object name? */
7274                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7275
7276                 if (nspid != InvalidOid)
7277                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7278                                                                                                  daclinfo[i].dobj.catId.oid);
7279                 else
7280                         daclinfo[i].dobj.namespace = NULL;
7281
7282                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7283                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7284                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7285
7286                 /* Decide whether we want to dump it */
7287                 selectDumpableDefaultACL(&(daclinfo[i]));
7288         }
7289
7290         PQclear(res);
7291
7292         destroyPQExpBuffer(query);
7293
7294         return daclinfo;
7295 }
7296
7297 /*
7298  * dumpComment --
7299  *
7300  * This routine is used to dump any comments associated with the
7301  * object handed to this routine. The routine takes a constant character
7302  * string for the target part of the comment-creation command, plus
7303  * the namespace and owner of the object (for labeling the ArchiveEntry),
7304  * plus catalog ID and subid which are the lookup key for pg_description,
7305  * plus the dump ID for the object (for setting a dependency).
7306  * If a matching pg_description entry is found, it is dumped.
7307  *
7308  * Note: although this routine takes a dumpId for dependency purposes,
7309  * that purpose is just to mark the dependency in the emitted dump file
7310  * for possible future use by pg_restore.  We do NOT use it for determining
7311  * ordering of the comment in the dump file, because this routine is called
7312  * after dependency sorting occurs.  This routine should be called just after
7313  * calling ArchiveEntry() for the specified object.
7314  */
7315 static void
7316 dumpComment(Archive *fout, const char *target,
7317                         const char *namespace, const char *owner,
7318                         CatalogId catalogId, int subid, DumpId dumpId)
7319 {
7320         CommentItem *comments;
7321         int                     ncomments;
7322
7323         /* Comments are schema not data ... except blob comments are data */
7324         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7325         {
7326                 if (dataOnly)
7327                         return;
7328         }
7329         else
7330         {
7331                 if (schemaOnly)
7332                         return;
7333         }
7334
7335         /* Search for comments associated with catalogId, using table */
7336         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7337                                                          &comments);
7338
7339         /* Is there one matching the subid? */
7340         while (ncomments > 0)
7341         {
7342                 if (comments->objsubid == subid)
7343                         break;
7344                 comments++;
7345                 ncomments--;
7346         }
7347
7348         /* If a comment exists, build COMMENT ON statement */
7349         if (ncomments > 0)
7350         {
7351                 PQExpBuffer query = createPQExpBuffer();
7352
7353                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7354                 appendStringLiteralAH(query, comments->descr, fout);
7355                 appendPQExpBuffer(query, ";\n");
7356
7357                 /*
7358                  * We mark comments as SECTION_NONE because they really belong in the
7359                  * same section as their parent, whether that is pre-data or
7360                  * post-data.
7361                  */
7362                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7363                                          target, namespace, NULL, owner,
7364                                          false, "COMMENT", SECTION_NONE,
7365                                          query->data, "", NULL,
7366                                          &(dumpId), 1,
7367                                          NULL, NULL);
7368
7369                 destroyPQExpBuffer(query);
7370         }
7371 }
7372
7373 /*
7374  * dumpTableComment --
7375  *
7376  * As above, but dump comments for both the specified table (or view)
7377  * and its columns.
7378  */
7379 static void
7380 dumpTableComment(Archive *fout, TableInfo *tbinfo,
7381                                  const char *reltypename)
7382 {
7383         CommentItem *comments;
7384         int                     ncomments;
7385         PQExpBuffer query;
7386         PQExpBuffer target;
7387
7388         /* Comments are SCHEMA not data */
7389         if (dataOnly)
7390                 return;
7391
7392         /* Search for comments associated with relation, using table */
7393         ncomments = findComments(fout,
7394                                                          tbinfo->dobj.catId.tableoid,
7395                                                          tbinfo->dobj.catId.oid,
7396                                                          &comments);
7397
7398         /* If comments exist, build COMMENT ON statements */
7399         if (ncomments <= 0)
7400                 return;
7401
7402         query = createPQExpBuffer();
7403         target = createPQExpBuffer();
7404
7405         while (ncomments > 0)
7406         {
7407                 const char *descr = comments->descr;
7408                 int                     objsubid = comments->objsubid;
7409
7410                 if (objsubid == 0)
7411                 {
7412                         resetPQExpBuffer(target);
7413                         appendPQExpBuffer(target, "%s %s", reltypename,
7414                                                           fmtId(tbinfo->dobj.name));
7415
7416                         resetPQExpBuffer(query);
7417                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7418                         appendStringLiteralAH(query, descr, fout);
7419                         appendPQExpBuffer(query, ";\n");
7420
7421                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7422                                                  target->data,
7423                                                  tbinfo->dobj.namespace->dobj.name,
7424                                                  NULL, tbinfo->rolname,
7425                                                  false, "COMMENT", SECTION_NONE,
7426                                                  query->data, "", NULL,
7427                                                  &(tbinfo->dobj.dumpId), 1,
7428                                                  NULL, NULL);
7429                 }
7430                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7431                 {
7432                         resetPQExpBuffer(target);
7433                         appendPQExpBuffer(target, "COLUMN %s.",
7434                                                           fmtId(tbinfo->dobj.name));
7435                         appendPQExpBuffer(target, "%s",
7436                                                           fmtId(tbinfo->attnames[objsubid - 1]));
7437
7438                         resetPQExpBuffer(query);
7439                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7440                         appendStringLiteralAH(query, descr, fout);
7441                         appendPQExpBuffer(query, ";\n");
7442
7443                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7444                                                  target->data,
7445                                                  tbinfo->dobj.namespace->dobj.name,
7446                                                  NULL, tbinfo->rolname,
7447                                                  false, "COMMENT", SECTION_NONE,
7448                                                  query->data, "", NULL,
7449                                                  &(tbinfo->dobj.dumpId), 1,
7450                                                  NULL, NULL);
7451                 }
7452
7453                 comments++;
7454                 ncomments--;
7455         }
7456
7457         destroyPQExpBuffer(query);
7458         destroyPQExpBuffer(target);
7459 }
7460
7461 /*
7462  * findComments --
7463  *
7464  * Find the comment(s), if any, associated with the given object.  All the
7465  * objsubid values associated with the given classoid/objoid are found with
7466  * one search.
7467  */
7468 static int
7469 findComments(Archive *fout, Oid classoid, Oid objoid,
7470                          CommentItem **items)
7471 {
7472         /* static storage for table of comments */
7473         static CommentItem *comments = NULL;
7474         static int      ncomments = -1;
7475
7476         CommentItem *middle = NULL;
7477         CommentItem *low;
7478         CommentItem *high;
7479         int                     nmatch;
7480
7481         /* Get comments if we didn't already */
7482         if (ncomments < 0)
7483                 ncomments = collectComments(fout, &comments);
7484
7485         /*
7486          * Pre-7.2, pg_description does not contain classoid, so collectComments
7487          * just stores a zero.  If there's a collision on object OID, well, you
7488          * get duplicate comments.
7489          */
7490         if (fout->remoteVersion < 70200)
7491                 classoid = 0;
7492
7493         /*
7494          * Do binary search to find some item matching the object.
7495          */
7496         low = &comments[0];
7497         high = &comments[ncomments - 1];
7498         while (low <= high)
7499         {
7500                 middle = low + (high - low) / 2;
7501
7502                 if (classoid < middle->classoid)
7503                         high = middle - 1;
7504                 else if (classoid > middle->classoid)
7505                         low = middle + 1;
7506                 else if (objoid < middle->objoid)
7507                         high = middle - 1;
7508                 else if (objoid > middle->objoid)
7509                         low = middle + 1;
7510                 else
7511                         break;                          /* found a match */
7512         }
7513
7514         if (low > high)                         /* no matches */
7515         {
7516                 *items = NULL;
7517                 return 0;
7518         }
7519
7520         /*
7521          * Now determine how many items match the object.  The search loop
7522          * invariant still holds: only items between low and high inclusive could
7523          * match.
7524          */
7525         nmatch = 1;
7526         while (middle > low)
7527         {
7528                 if (classoid != middle[-1].classoid ||
7529                         objoid != middle[-1].objoid)
7530                         break;
7531                 middle--;
7532                 nmatch++;
7533         }
7534
7535         *items = middle;
7536
7537         middle += nmatch;
7538         while (middle <= high)
7539         {
7540                 if (classoid != middle->classoid ||
7541                         objoid != middle->objoid)
7542                         break;
7543                 middle++;
7544                 nmatch++;
7545         }
7546
7547         return nmatch;
7548 }
7549
7550 /*
7551  * collectComments --
7552  *
7553  * Construct a table of all comments available for database objects.
7554  * We used to do per-object queries for the comments, but it's much faster
7555  * to pull them all over at once, and on most databases the memory cost
7556  * isn't high.
7557  *
7558  * The table is sorted by classoid/objid/objsubid for speed in lookup.
7559  */
7560 static int
7561 collectComments(Archive *fout, CommentItem **items)
7562 {
7563         PGresult   *res;
7564         PQExpBuffer query;
7565         int                     i_description;
7566         int                     i_classoid;
7567         int                     i_objoid;
7568         int                     i_objsubid;
7569         int                     ntups;
7570         int                     i;
7571         CommentItem *comments;
7572
7573         /*
7574          * Note we do NOT change source schema here; preserve the caller's
7575          * setting, instead.
7576          */
7577
7578         query = createPQExpBuffer();
7579
7580         if (fout->remoteVersion >= 70300)
7581         {
7582                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7583                                                   "FROM pg_catalog.pg_description "
7584                                                   "ORDER BY classoid, objoid, objsubid");
7585         }
7586         else if (fout->remoteVersion >= 70200)
7587         {
7588                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
7589                                                   "FROM pg_description "
7590                                                   "ORDER BY classoid, objoid, objsubid");
7591         }
7592         else
7593         {
7594                 /* Note: this will fail to find attribute comments in pre-7.2... */
7595                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
7596                                                   "FROM pg_description "
7597                                                   "ORDER BY objoid");
7598         }
7599
7600         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7601
7602         /* Construct lookup table containing OIDs in numeric form */
7603
7604         i_description = PQfnumber(res, "description");
7605         i_classoid = PQfnumber(res, "classoid");
7606         i_objoid = PQfnumber(res, "objoid");
7607         i_objsubid = PQfnumber(res, "objsubid");
7608
7609         ntups = PQntuples(res);
7610
7611         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
7612
7613         for (i = 0; i < ntups; i++)
7614         {
7615                 comments[i].descr = PQgetvalue(res, i, i_description);
7616                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
7617                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
7618                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
7619         }
7620
7621         /* Do NOT free the PGresult since we are keeping pointers into it */
7622         destroyPQExpBuffer(query);
7623
7624         *items = comments;
7625         return ntups;
7626 }
7627
7628 /*
7629  * dumpDumpableObject
7630  *
7631  * This routine and its subsidiaries are responsible for creating
7632  * ArchiveEntries (TOC objects) for each object to be dumped.
7633  */
7634 static void
7635 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
7636 {
7637         switch (dobj->objType)
7638         {
7639                 case DO_NAMESPACE:
7640                         dumpNamespace(fout, (NamespaceInfo *) dobj);
7641                         break;
7642                 case DO_EXTENSION:
7643                         dumpExtension(fout, (ExtensionInfo *) dobj);
7644                         break;
7645                 case DO_TYPE:
7646                         dumpType(fout, (TypeInfo *) dobj);
7647                         break;
7648                 case DO_SHELL_TYPE:
7649                         dumpShellType(fout, (ShellTypeInfo *) dobj);
7650                         break;
7651                 case DO_FUNC:
7652                         dumpFunc(fout, (FuncInfo *) dobj);
7653                         break;
7654                 case DO_AGG:
7655                         dumpAgg(fout, (AggInfo *) dobj);
7656                         break;
7657                 case DO_OPERATOR:
7658                         dumpOpr(fout, (OprInfo *) dobj);
7659                         break;
7660                 case DO_OPCLASS:
7661                         dumpOpclass(fout, (OpclassInfo *) dobj);
7662                         break;
7663                 case DO_OPFAMILY:
7664                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
7665                         break;
7666                 case DO_COLLATION:
7667                         dumpCollation(fout, (CollInfo *) dobj);
7668                         break;
7669                 case DO_CONVERSION:
7670                         dumpConversion(fout, (ConvInfo *) dobj);
7671                         break;
7672                 case DO_TABLE:
7673                         dumpTable(fout, (TableInfo *) dobj);
7674                         break;
7675                 case DO_ATTRDEF:
7676                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
7677                         break;
7678                 case DO_INDEX:
7679                         dumpIndex(fout, (IndxInfo *) dobj);
7680                         break;
7681                 case DO_REFRESH_MATVIEW:
7682                         refreshMatViewData(fout, (TableDataInfo *) dobj);
7683                         break;
7684                 case DO_RULE:
7685                         dumpRule(fout, (RuleInfo *) dobj);
7686                         break;
7687                 case DO_TRIGGER:
7688                         dumpTrigger(fout, (TriggerInfo *) dobj);
7689                         break;
7690                 case DO_EVENT_TRIGGER:
7691                         dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
7692                         break;
7693                 case DO_CONSTRAINT:
7694                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7695                         break;
7696                 case DO_FK_CONSTRAINT:
7697                         dumpConstraint(fout, (ConstraintInfo *) dobj);
7698                         break;
7699                 case DO_PROCLANG:
7700                         dumpProcLang(fout, (ProcLangInfo *) dobj);
7701                         break;
7702                 case DO_CAST:
7703                         dumpCast(fout, (CastInfo *) dobj);
7704                         break;
7705                 case DO_TABLE_DATA:
7706                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
7707                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
7708                         else
7709                                 dumpTableData(fout, (TableDataInfo *) dobj);
7710                         break;
7711                 case DO_DUMMY_TYPE:
7712                         /* table rowtypes and array types are never dumped separately */
7713                         break;
7714                 case DO_TSPARSER:
7715                         dumpTSParser(fout, (TSParserInfo *) dobj);
7716                         break;
7717                 case DO_TSDICT:
7718                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
7719                         break;
7720                 case DO_TSTEMPLATE:
7721                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
7722                         break;
7723                 case DO_TSCONFIG:
7724                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
7725                         break;
7726                 case DO_FDW:
7727                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
7728                         break;
7729                 case DO_FOREIGN_SERVER:
7730                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
7731                         break;
7732                 case DO_DEFAULT_ACL:
7733                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
7734                         break;
7735                 case DO_BLOB:
7736                         dumpBlob(fout, (BlobInfo *) dobj);
7737                         break;
7738                 case DO_BLOB_DATA:
7739                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
7740                                                  dobj->name, NULL, NULL, "",
7741                                                  false, "BLOBS", SECTION_DATA,
7742                                                  "", "", NULL,
7743                                                  NULL, 0,
7744                                                  dumpBlobs, NULL);
7745                         break;
7746                 case DO_PRE_DATA_BOUNDARY:
7747                 case DO_POST_DATA_BOUNDARY:
7748                         /* never dumped, nothing to do */
7749                         break;
7750         }
7751 }
7752
7753 /*
7754  * dumpNamespace
7755  *        writes out to fout the queries to recreate a user-defined namespace
7756  */
7757 static void
7758 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
7759 {
7760         PQExpBuffer q;
7761         PQExpBuffer delq;
7762         PQExpBuffer labelq;
7763         char       *qnspname;
7764
7765         /* Skip if not to be dumped */
7766         if (!nspinfo->dobj.dump || dataOnly)
7767                 return;
7768
7769         /* don't dump dummy namespace from pre-7.3 source */
7770         if (strlen(nspinfo->dobj.name) == 0)
7771                 return;
7772
7773         q = createPQExpBuffer();
7774         delq = createPQExpBuffer();
7775         labelq = createPQExpBuffer();
7776
7777         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
7778
7779         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
7780
7781         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
7782
7783         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
7784
7785         if (binary_upgrade)
7786                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
7787
7788         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
7789                                  nspinfo->dobj.name,
7790                                  NULL, NULL,
7791                                  nspinfo->rolname,
7792                                  false, "SCHEMA", SECTION_PRE_DATA,
7793                                  q->data, delq->data, NULL,
7794                                  NULL, 0,
7795                                  NULL, NULL);
7796
7797         /* Dump Schema Comments and Security Labels */
7798         dumpComment(fout, labelq->data,
7799                                 NULL, nspinfo->rolname,
7800                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7801         dumpSecLabel(fout, labelq->data,
7802                                  NULL, nspinfo->rolname,
7803                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
7804
7805         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
7806                         qnspname, NULL, nspinfo->dobj.name, NULL,
7807                         nspinfo->rolname, nspinfo->nspacl);
7808
7809         free(qnspname);
7810
7811         destroyPQExpBuffer(q);
7812         destroyPQExpBuffer(delq);
7813         destroyPQExpBuffer(labelq);
7814 }
7815
7816 /*
7817  * dumpExtension
7818  *        writes out to fout the queries to recreate an extension
7819  */
7820 static void
7821 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
7822 {
7823         PQExpBuffer q;
7824         PQExpBuffer delq;
7825         PQExpBuffer labelq;
7826         char       *qextname;
7827
7828         /* Skip if not to be dumped */
7829         if (!extinfo->dobj.dump || dataOnly)
7830                 return;
7831
7832         q = createPQExpBuffer();
7833         delq = createPQExpBuffer();
7834         labelq = createPQExpBuffer();
7835
7836         qextname = pg_strdup(fmtId(extinfo->dobj.name));
7837
7838         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
7839
7840         if (!binary_upgrade)
7841         {
7842                 /*
7843                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
7844                  * problem if the extension already exists in the target database;
7845                  * this is essential for installed-by-default extensions such as
7846                  * plpgsql.
7847                  *
7848                  * In binary-upgrade mode, that doesn't work well, so instead we skip
7849                  * built-in extensions based on their OIDs; see
7850                  * selectDumpableExtension.
7851                  */
7852                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
7853                                                   qextname, fmtId(extinfo->namespace));
7854         }
7855         else
7856         {
7857                 int                     i;
7858                 int                     n;
7859
7860                 appendPQExpBuffer(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
7861
7862                 /*
7863                  * We unconditionally create the extension, so we must drop it if it
7864                  * exists.      This could happen if the user deleted 'plpgsql' and then
7865                  * readded it, causing its oid to be greater than FirstNormalObjectId.
7866                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
7867                  * and recreating extensions like 'plpgsql'.
7868                  */
7869                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
7870
7871                 appendPQExpBuffer(q,
7872                                                   "SELECT binary_upgrade.create_empty_extension(");
7873                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
7874                 appendPQExpBuffer(q, ", ");
7875                 appendStringLiteralAH(q, extinfo->namespace, fout);
7876                 appendPQExpBuffer(q, ", ");
7877                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
7878                 appendStringLiteralAH(q, extinfo->extversion, fout);
7879                 appendPQExpBuffer(q, ", ");
7880
7881                 /*
7882                  * Note that we're pushing extconfig (an OID array) back into
7883                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
7884                  * preserved in binary upgrade.
7885                  */
7886                 if (strlen(extinfo->extconfig) > 2)
7887                         appendStringLiteralAH(q, extinfo->extconfig, fout);
7888                 else
7889                         appendPQExpBuffer(q, "NULL");
7890                 appendPQExpBuffer(q, ", ");
7891                 if (strlen(extinfo->extcondition) > 2)
7892                         appendStringLiteralAH(q, extinfo->extcondition, fout);
7893                 else
7894                         appendPQExpBuffer(q, "NULL");
7895                 appendPQExpBuffer(q, ", ");
7896                 appendPQExpBuffer(q, "ARRAY[");
7897                 n = 0;
7898                 for (i = 0; i < extinfo->dobj.nDeps; i++)
7899                 {
7900                         DumpableObject *extobj;
7901
7902                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
7903                         if (extobj && extobj->objType == DO_EXTENSION)
7904                         {
7905                                 if (n++ > 0)
7906                                         appendPQExpBuffer(q, ",");
7907                                 appendStringLiteralAH(q, extobj->name, fout);
7908                         }
7909                 }
7910                 appendPQExpBuffer(q, "]::pg_catalog.text[]");
7911                 appendPQExpBuffer(q, ");\n");
7912         }
7913
7914         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
7915
7916         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
7917                                  extinfo->dobj.name,
7918                                  NULL, NULL,
7919                                  "",
7920                                  false, "EXTENSION", SECTION_PRE_DATA,
7921                                  q->data, delq->data, NULL,
7922                                  NULL, 0,
7923                                  NULL, NULL);
7924
7925         /* Dump Extension Comments and Security Labels */
7926         dumpComment(fout, labelq->data,
7927                                 NULL, "",
7928                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7929         dumpSecLabel(fout, labelq->data,
7930                                  NULL, "",
7931                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
7932
7933         free(qextname);
7934
7935         destroyPQExpBuffer(q);
7936         destroyPQExpBuffer(delq);
7937         destroyPQExpBuffer(labelq);
7938 }
7939
7940 /*
7941  * dumpType
7942  *        writes out to fout the queries to recreate a user-defined type
7943  */
7944 static void
7945 dumpType(Archive *fout, TypeInfo *tyinfo)
7946 {
7947         /* Skip if not to be dumped */
7948         if (!tyinfo->dobj.dump || dataOnly)
7949                 return;
7950
7951         /* Dump out in proper style */
7952         if (tyinfo->typtype == TYPTYPE_BASE)
7953                 dumpBaseType(fout, tyinfo);
7954         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
7955                 dumpDomain(fout, tyinfo);
7956         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
7957                 dumpCompositeType(fout, tyinfo);
7958         else if (tyinfo->typtype == TYPTYPE_ENUM)
7959                 dumpEnumType(fout, tyinfo);
7960         else if (tyinfo->typtype == TYPTYPE_RANGE)
7961                 dumpRangeType(fout, tyinfo);
7962         else
7963                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
7964                                   tyinfo->dobj.name);
7965 }
7966
7967 /*
7968  * dumpEnumType
7969  *        writes out to fout the queries to recreate a user-defined enum type
7970  */
7971 static void
7972 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
7973 {
7974         PQExpBuffer q = createPQExpBuffer();
7975         PQExpBuffer delq = createPQExpBuffer();
7976         PQExpBuffer labelq = createPQExpBuffer();
7977         PQExpBuffer query = createPQExpBuffer();
7978         PGresult   *res;
7979         int                     num,
7980                                 i;
7981         Oid                     enum_oid;
7982         char       *qtypname;
7983         char       *label;
7984
7985         /* Set proper schema search path */
7986         selectSourceSchema(fout, "pg_catalog");
7987
7988         if (fout->remoteVersion >= 90100)
7989                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7990                                                   "FROM pg_catalog.pg_enum "
7991                                                   "WHERE enumtypid = '%u'"
7992                                                   "ORDER BY enumsortorder",
7993                                                   tyinfo->dobj.catId.oid);
7994         else
7995                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
7996                                                   "FROM pg_catalog.pg_enum "
7997                                                   "WHERE enumtypid = '%u'"
7998                                                   "ORDER BY oid",
7999                                                   tyinfo->dobj.catId.oid);
8000
8001         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8002
8003         num = PQntuples(res);
8004
8005         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8006
8007         /*
8008          * DROP must be fully qualified in case same name appears in pg_catalog.
8009          * CASCADE shouldn't be required here as for normal types since the I/O
8010          * functions are generic and do not get dropped.
8011          */
8012         appendPQExpBuffer(delq, "DROP TYPE %s.",
8013                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8014         appendPQExpBuffer(delq, "%s;\n",
8015                                           qtypname);
8016
8017         if (binary_upgrade)
8018                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8019                                                                                                  tyinfo->dobj.catId.oid);
8020
8021         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8022                                           qtypname);
8023
8024         if (!binary_upgrade)
8025         {
8026                 /* Labels with server-assigned oids */
8027                 for (i = 0; i < num; i++)
8028                 {
8029                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8030                         if (i > 0)
8031                                 appendPQExpBuffer(q, ",");
8032                         appendPQExpBuffer(q, "\n    ");
8033                         appendStringLiteralAH(q, label, fout);
8034                 }
8035         }
8036
8037         appendPQExpBuffer(q, "\n);\n");
8038
8039         if (binary_upgrade)
8040         {
8041                 /* Labels with dump-assigned (preserved) oids */
8042                 for (i = 0; i < num; i++)
8043                 {
8044                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8045                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8046
8047                         if (i == 0)
8048                                 appendPQExpBuffer(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8049                         appendPQExpBuffer(q,
8050                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8051                                                           enum_oid);
8052                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8053                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8054                         appendPQExpBuffer(q, "%s ADD VALUE ",
8055                                                           qtypname);
8056                         appendStringLiteralAH(q, label, fout);
8057                         appendPQExpBuffer(q, ";\n\n");
8058                 }
8059         }
8060
8061         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8062
8063         if (binary_upgrade)
8064                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8065
8066         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8067                                  tyinfo->dobj.name,
8068                                  tyinfo->dobj.namespace->dobj.name,
8069                                  NULL,
8070                                  tyinfo->rolname, false,
8071                                  "TYPE", SECTION_PRE_DATA,
8072                                  q->data, delq->data, NULL,
8073                                  NULL, 0,
8074                                  NULL, NULL);
8075
8076         /* Dump Type Comments and Security Labels */
8077         dumpComment(fout, labelq->data,
8078                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8079                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8080         dumpSecLabel(fout, labelq->data,
8081                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8082                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8083
8084         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8085                         qtypname, NULL, tyinfo->dobj.name,
8086                         tyinfo->dobj.namespace->dobj.name,
8087                         tyinfo->rolname, tyinfo->typacl);
8088
8089         PQclear(res);
8090         destroyPQExpBuffer(q);
8091         destroyPQExpBuffer(delq);
8092         destroyPQExpBuffer(labelq);
8093         destroyPQExpBuffer(query);
8094 }
8095
8096 /*
8097  * dumpRangeType
8098  *        writes out to fout the queries to recreate a user-defined range type
8099  */
8100 static void
8101 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
8102 {
8103         PQExpBuffer q = createPQExpBuffer();
8104         PQExpBuffer delq = createPQExpBuffer();
8105         PQExpBuffer labelq = createPQExpBuffer();
8106         PQExpBuffer query = createPQExpBuffer();
8107         PGresult   *res;
8108         Oid                     collationOid;
8109         char       *qtypname;
8110         char       *procname;
8111
8112         /*
8113          * select appropriate schema to ensure names in CREATE are properly
8114          * qualified
8115          */
8116         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8117
8118         appendPQExpBuffer(query,
8119                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8120                                           "opc.opcname AS opcname, "
8121                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8122                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8123                                           "opc.opcdefault, "
8124                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8125                                           "     ELSE rngcollation END AS collation, "
8126                                           "rngcanonical, rngsubdiff "
8127                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8128                                           "     pg_catalog.pg_opclass opc "
8129                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8130                                           "rngtypid = '%u'",
8131                                           tyinfo->dobj.catId.oid);
8132
8133         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8134
8135         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8136
8137         /*
8138          * DROP must be fully qualified in case same name appears in pg_catalog.
8139          * CASCADE shouldn't be required here as for normal types since the I/O
8140          * functions are generic and do not get dropped.
8141          */
8142         appendPQExpBuffer(delq, "DROP TYPE %s.",
8143                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8144         appendPQExpBuffer(delq, "%s;\n",
8145                                           qtypname);
8146
8147         if (binary_upgrade)
8148                 binary_upgrade_set_type_oids_by_type_oid(fout,
8149                                                                                                  q, tyinfo->dobj.catId.oid);
8150
8151         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8152                                           qtypname);
8153
8154         appendPQExpBuffer(q, "\n    subtype = %s",
8155                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8156
8157         /* print subtype_opclass only if not default for subtype */
8158         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8159         {
8160                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8161                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8162
8163                 /* always schema-qualify, don't try to be smart */
8164                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8165                                                   fmtId(nspname));
8166                 appendPQExpBuffer(q, "%s", fmtId(opcname));
8167         }
8168
8169         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8170         if (OidIsValid(collationOid))
8171         {
8172                 CollInfo   *coll = findCollationByOid(collationOid);
8173
8174                 if (coll)
8175                 {
8176                         /* always schema-qualify, don't try to be smart */
8177                         appendPQExpBuffer(q, ",\n    collation = %s.",
8178                                                           fmtId(coll->dobj.namespace->dobj.name));
8179                         appendPQExpBuffer(q, "%s",
8180                                                           fmtId(coll->dobj.name));
8181                 }
8182         }
8183
8184         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8185         if (strcmp(procname, "-") != 0)
8186                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8187
8188         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8189         if (strcmp(procname, "-") != 0)
8190                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8191
8192         appendPQExpBuffer(q, "\n);\n");
8193
8194         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8195
8196         if (binary_upgrade)
8197                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8198
8199         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8200                                  tyinfo->dobj.name,
8201                                  tyinfo->dobj.namespace->dobj.name,
8202                                  NULL,
8203                                  tyinfo->rolname, false,
8204                                  "TYPE", SECTION_PRE_DATA,
8205                                  q->data, delq->data, NULL,
8206                                  NULL, 0,
8207                                  NULL, NULL);
8208
8209         /* Dump Type Comments and Security Labels */
8210         dumpComment(fout, labelq->data,
8211                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8212                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8213         dumpSecLabel(fout, labelq->data,
8214                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8215                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8216
8217         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8218                         qtypname, NULL, tyinfo->dobj.name,
8219                         tyinfo->dobj.namespace->dobj.name,
8220                         tyinfo->rolname, tyinfo->typacl);
8221
8222         PQclear(res);
8223         destroyPQExpBuffer(q);
8224         destroyPQExpBuffer(delq);
8225         destroyPQExpBuffer(labelq);
8226         destroyPQExpBuffer(query);
8227 }
8228
8229 /*
8230  * dumpBaseType
8231  *        writes out to fout the queries to recreate a user-defined base type
8232  */
8233 static void
8234 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
8235 {
8236         PQExpBuffer q = createPQExpBuffer();
8237         PQExpBuffer delq = createPQExpBuffer();
8238         PQExpBuffer labelq = createPQExpBuffer();
8239         PQExpBuffer query = createPQExpBuffer();
8240         PGresult   *res;
8241         char       *qtypname;
8242         char       *typlen;
8243         char       *typinput;
8244         char       *typoutput;
8245         char       *typreceive;
8246         char       *typsend;
8247         char       *typmodin;
8248         char       *typmodout;
8249         char       *typanalyze;
8250         Oid                     typreceiveoid;
8251         Oid                     typsendoid;
8252         Oid                     typmodinoid;
8253         Oid                     typmodoutoid;
8254         Oid                     typanalyzeoid;
8255         char       *typcategory;
8256         char       *typispreferred;
8257         char       *typdelim;
8258         char       *typbyval;
8259         char       *typalign;
8260         char       *typstorage;
8261         char       *typcollatable;
8262         char       *typdefault;
8263         bool            typdefault_is_literal = false;
8264
8265         /* Set proper schema search path so regproc references list correctly */
8266         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8267
8268         /* Fetch type-specific details */
8269         if (fout->remoteVersion >= 90100)
8270         {
8271                 appendPQExpBuffer(query, "SELECT typlen, "
8272                                                   "typinput, typoutput, typreceive, typsend, "
8273                                                   "typmodin, typmodout, typanalyze, "
8274                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8275                                                   "typsend::pg_catalog.oid AS typsendoid, "
8276                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8277                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8278                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8279                                                   "typcategory, typispreferred, "
8280                                                   "typdelim, typbyval, typalign, typstorage, "
8281                                                   "(typcollation <> 0) AS typcollatable, "
8282                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8283                                                   "FROM pg_catalog.pg_type "
8284                                                   "WHERE oid = '%u'::pg_catalog.oid",
8285                                                   tyinfo->dobj.catId.oid);
8286         }
8287         else if (fout->remoteVersion >= 80400)
8288         {
8289                 appendPQExpBuffer(query, "SELECT typlen, "
8290                                                   "typinput, typoutput, typreceive, typsend, "
8291                                                   "typmodin, typmodout, typanalyze, "
8292                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8293                                                   "typsend::pg_catalog.oid AS typsendoid, "
8294                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8295                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8296                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8297                                                   "typcategory, typispreferred, "
8298                                                   "typdelim, typbyval, typalign, typstorage, "
8299                                                   "false AS typcollatable, "
8300                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8301                                                   "FROM pg_catalog.pg_type "
8302                                                   "WHERE oid = '%u'::pg_catalog.oid",
8303                                                   tyinfo->dobj.catId.oid);
8304         }
8305         else if (fout->remoteVersion >= 80300)
8306         {
8307                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8308                 appendPQExpBuffer(query, "SELECT typlen, "
8309                                                   "typinput, typoutput, typreceive, typsend, "
8310                                                   "typmodin, typmodout, typanalyze, "
8311                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8312                                                   "typsend::pg_catalog.oid AS typsendoid, "
8313                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8314                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8315                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8316                                                   "'U' AS typcategory, false AS typispreferred, "
8317                                                   "typdelim, typbyval, typalign, typstorage, "
8318                                                   "false AS typcollatable, "
8319                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8320                                                   "FROM pg_catalog.pg_type "
8321                                                   "WHERE oid = '%u'::pg_catalog.oid",
8322                                                   tyinfo->dobj.catId.oid);
8323         }
8324         else if (fout->remoteVersion >= 80000)
8325         {
8326                 appendPQExpBuffer(query, "SELECT typlen, "
8327                                                   "typinput, typoutput, typreceive, typsend, "
8328                                                   "'-' AS typmodin, '-' AS typmodout, "
8329                                                   "typanalyze, "
8330                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8331                                                   "typsend::pg_catalog.oid AS typsendoid, "
8332                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8333                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8334                                                   "'U' AS typcategory, false AS typispreferred, "
8335                                                   "typdelim, typbyval, typalign, typstorage, "
8336                                                   "false AS typcollatable, "
8337                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8338                                                   "FROM pg_catalog.pg_type "
8339                                                   "WHERE oid = '%u'::pg_catalog.oid",
8340                                                   tyinfo->dobj.catId.oid);
8341         }
8342         else if (fout->remoteVersion >= 70400)
8343         {
8344                 appendPQExpBuffer(query, "SELECT typlen, "
8345                                                   "typinput, typoutput, typreceive, typsend, "
8346                                                   "'-' AS typmodin, '-' AS typmodout, "
8347                                                   "'-' AS typanalyze, "
8348                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8349                                                   "typsend::pg_catalog.oid AS typsendoid, "
8350                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8351                                                   "0 AS typanalyzeoid, "
8352                                                   "'U' AS typcategory, false AS typispreferred, "
8353                                                   "typdelim, typbyval, typalign, typstorage, "
8354                                                   "false AS typcollatable, "
8355                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8356                                                   "FROM pg_catalog.pg_type "
8357                                                   "WHERE oid = '%u'::pg_catalog.oid",
8358                                                   tyinfo->dobj.catId.oid);
8359         }
8360         else if (fout->remoteVersion >= 70300)
8361         {
8362                 appendPQExpBuffer(query, "SELECT typlen, "
8363                                                   "typinput, typoutput, "
8364                                                   "'-' AS typreceive, '-' AS typsend, "
8365                                                   "'-' AS typmodin, '-' AS typmodout, "
8366                                                   "'-' AS typanalyze, "
8367                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8368                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8369                                                   "0 AS typanalyzeoid, "
8370                                                   "'U' AS typcategory, false AS typispreferred, "
8371                                                   "typdelim, typbyval, typalign, typstorage, "
8372                                                   "false AS typcollatable, "
8373                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8374                                                   "FROM pg_catalog.pg_type "
8375                                                   "WHERE oid = '%u'::pg_catalog.oid",
8376                                                   tyinfo->dobj.catId.oid);
8377         }
8378         else if (fout->remoteVersion >= 70200)
8379         {
8380                 /*
8381                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8382                  * ignore them because they are not right.
8383                  */
8384                 appendPQExpBuffer(query, "SELECT typlen, "
8385                                                   "typinput, typoutput, "
8386                                                   "'-' AS typreceive, '-' AS typsend, "
8387                                                   "'-' AS typmodin, '-' AS typmodout, "
8388                                                   "'-' AS typanalyze, "
8389                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8390                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8391                                                   "0 AS typanalyzeoid, "
8392                                                   "'U' AS typcategory, false AS typispreferred, "
8393                                                   "typdelim, typbyval, typalign, typstorage, "
8394                                                   "false AS typcollatable, "
8395                                                   "NULL AS typdefaultbin, typdefault "
8396                                                   "FROM pg_type "
8397                                                   "WHERE oid = '%u'::oid",
8398                                                   tyinfo->dobj.catId.oid);
8399         }
8400         else if (fout->remoteVersion >= 70100)
8401         {
8402                 /*
8403                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8404                  * representation.
8405                  */
8406                 appendPQExpBuffer(query, "SELECT typlen, "
8407                                                   "typinput, typoutput, "
8408                                                   "'-' AS typreceive, '-' AS typsend, "
8409                                                   "'-' AS typmodin, '-' AS typmodout, "
8410                                                   "'-' AS typanalyze, "
8411                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8412                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8413                                                   "0 AS typanalyzeoid, "
8414                                                   "'U' AS typcategory, false AS typispreferred, "
8415                                                   "typdelim, typbyval, typalign, typstorage, "
8416                                                   "false AS typcollatable, "
8417                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8418                                                   "FROM pg_type "
8419                                                   "WHERE oid = '%u'::oid",
8420                                                   tyinfo->dobj.catId.oid);
8421         }
8422         else
8423         {
8424                 appendPQExpBuffer(query, "SELECT typlen, "
8425                                                   "typinput, typoutput, "
8426                                                   "'-' AS typreceive, '-' AS typsend, "
8427                                                   "'-' AS typmodin, '-' AS typmodout, "
8428                                                   "'-' AS typanalyze, "
8429                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8430                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8431                                                   "0 AS typanalyzeoid, "
8432                                                   "'U' AS typcategory, false AS typispreferred, "
8433                                                   "typdelim, typbyval, typalign, "
8434                                                   "'p'::char AS typstorage, "
8435                                                   "false AS typcollatable, "
8436                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8437                                                   "FROM pg_type "
8438                                                   "WHERE oid = '%u'::oid",
8439                                                   tyinfo->dobj.catId.oid);
8440         }
8441
8442         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8443
8444         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8445         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8446         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8447         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8448         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8449         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8450         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8451         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8452         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8453         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8454         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8455         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8456         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8457         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8458         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8459         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8460         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8461         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8462         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8463         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8464         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8465                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8466         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8467         {
8468                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8469                 typdefault_is_literal = true;   /* it needs quotes */
8470         }
8471         else
8472                 typdefault = NULL;
8473
8474         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8475
8476         /*
8477          * DROP must be fully qualified in case same name appears in pg_catalog.
8478          * The reason we include CASCADE is that the circular dependency between
8479          * the type and its I/O functions makes it impossible to drop the type any
8480          * other way.
8481          */
8482         appendPQExpBuffer(delq, "DROP TYPE %s.",
8483                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8484         appendPQExpBuffer(delq, "%s CASCADE;\n",
8485                                           qtypname);
8486
8487         /* We might already have a shell type, but setting pg_type_oid is harmless */
8488         if (binary_upgrade)
8489                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8490                                                                                                  tyinfo->dobj.catId.oid);
8491
8492         appendPQExpBuffer(q,
8493                                           "CREATE TYPE %s (\n"
8494                                           "    INTERNALLENGTH = %s",
8495                                           qtypname,
8496                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8497
8498         if (fout->remoteVersion >= 70300)
8499         {
8500                 /* regproc result is correctly quoted as of 7.3 */
8501                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8502                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8503                 if (OidIsValid(typreceiveoid))
8504                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
8505                 if (OidIsValid(typsendoid))
8506                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
8507                 if (OidIsValid(typmodinoid))
8508                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
8509                 if (OidIsValid(typmodoutoid))
8510                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
8511                 if (OidIsValid(typanalyzeoid))
8512                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
8513         }
8514         else
8515         {
8516                 /* regproc delivers an unquoted name before 7.3 */
8517                 /* cannot combine these because fmtId uses static result area */
8518                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
8519                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
8520                 /* receive/send/typmodin/typmodout/analyze need not be printed */
8521         }
8522
8523         if (strcmp(typcollatable, "t") == 0)
8524                 appendPQExpBuffer(q, ",\n    COLLATABLE = true");
8525
8526         if (typdefault != NULL)
8527         {
8528                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
8529                 if (typdefault_is_literal)
8530                         appendStringLiteralAH(q, typdefault, fout);
8531                 else
8532                         appendPQExpBufferStr(q, typdefault);
8533         }
8534
8535         if (OidIsValid(tyinfo->typelem))
8536         {
8537                 char       *elemType;
8538
8539                 /* reselect schema in case changed by function dump */
8540                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8541                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
8542                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
8543                 free(elemType);
8544         }
8545
8546         if (strcmp(typcategory, "U") != 0)
8547         {
8548                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
8549                 appendStringLiteralAH(q, typcategory, fout);
8550         }
8551
8552         if (strcmp(typispreferred, "t") == 0)
8553                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
8554
8555         if (typdelim && strcmp(typdelim, ",") != 0)
8556         {
8557                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
8558                 appendStringLiteralAH(q, typdelim, fout);
8559         }
8560
8561         if (strcmp(typalign, "c") == 0)
8562                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
8563         else if (strcmp(typalign, "s") == 0)
8564                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
8565         else if (strcmp(typalign, "i") == 0)
8566                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
8567         else if (strcmp(typalign, "d") == 0)
8568                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
8569
8570         if (strcmp(typstorage, "p") == 0)
8571                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
8572         else if (strcmp(typstorage, "e") == 0)
8573                 appendPQExpBuffer(q, ",\n    STORAGE = external");
8574         else if (strcmp(typstorage, "x") == 0)
8575                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
8576         else if (strcmp(typstorage, "m") == 0)
8577                 appendPQExpBuffer(q, ",\n    STORAGE = main");
8578
8579         if (strcmp(typbyval, "t") == 0)
8580                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
8581
8582         appendPQExpBuffer(q, "\n);\n");
8583
8584         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8585
8586         if (binary_upgrade)
8587                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8588
8589         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8590                                  tyinfo->dobj.name,
8591                                  tyinfo->dobj.namespace->dobj.name,
8592                                  NULL,
8593                                  tyinfo->rolname, false,
8594                                  "TYPE", SECTION_PRE_DATA,
8595                                  q->data, delq->data, NULL,
8596                                  NULL, 0,
8597                                  NULL, NULL);
8598
8599         /* Dump Type Comments and Security Labels */
8600         dumpComment(fout, labelq->data,
8601                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8602                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8603         dumpSecLabel(fout, labelq->data,
8604                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8605                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8606
8607         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8608                         qtypname, NULL, tyinfo->dobj.name,
8609                         tyinfo->dobj.namespace->dobj.name,
8610                         tyinfo->rolname, tyinfo->typacl);
8611
8612         PQclear(res);
8613         destroyPQExpBuffer(q);
8614         destroyPQExpBuffer(delq);
8615         destroyPQExpBuffer(labelq);
8616         destroyPQExpBuffer(query);
8617 }
8618
8619 /*
8620  * dumpDomain
8621  *        writes out to fout the queries to recreate a user-defined domain
8622  */
8623 static void
8624 dumpDomain(Archive *fout, TypeInfo *tyinfo)
8625 {
8626         PQExpBuffer q = createPQExpBuffer();
8627         PQExpBuffer delq = createPQExpBuffer();
8628         PQExpBuffer labelq = createPQExpBuffer();
8629         PQExpBuffer query = createPQExpBuffer();
8630         PGresult   *res;
8631         int                     i;
8632         char       *qtypname;
8633         char       *typnotnull;
8634         char       *typdefn;
8635         char       *typdefault;
8636         Oid                     typcollation;
8637         bool            typdefault_is_literal = false;
8638
8639         /* Set proper schema search path so type references list correctly */
8640         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8641
8642         /* Fetch domain specific details */
8643         if (fout->remoteVersion >= 90100)
8644         {
8645                 /* typcollation is new in 9.1 */
8646                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
8647                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
8648                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8649                                                   "t.typdefault, "
8650                                                   "CASE WHEN t.typcollation <> u.typcollation "
8651                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
8652                                                   "FROM pg_catalog.pg_type t "
8653                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
8654                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
8655                                                   tyinfo->dobj.catId.oid);
8656         }
8657         else
8658         {
8659                 /* We assume here that remoteVersion must be at least 70300 */
8660                 appendPQExpBuffer(query, "SELECT typnotnull, "
8661                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
8662                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
8663                                                   "typdefault, 0 AS typcollation "
8664                                                   "FROM pg_catalog.pg_type "
8665                                                   "WHERE oid = '%u'::pg_catalog.oid",
8666                                                   tyinfo->dobj.catId.oid);
8667         }
8668
8669         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8670
8671         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
8672         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
8673         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8674                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8675         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8676         {
8677                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8678                 typdefault_is_literal = true;   /* it needs quotes */
8679         }
8680         else
8681                 typdefault = NULL;
8682         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
8683
8684         if (binary_upgrade)
8685                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8686                                                                                                  tyinfo->dobj.catId.oid);
8687
8688         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8689
8690         appendPQExpBuffer(q,
8691                                           "CREATE DOMAIN %s AS %s",
8692                                           qtypname,
8693                                           typdefn);
8694
8695         /* Print collation only if different from base type's collation */
8696         if (OidIsValid(typcollation))
8697         {
8698                 CollInfo   *coll;
8699
8700                 coll = findCollationByOid(typcollation);
8701                 if (coll)
8702                 {
8703                         /* always schema-qualify, don't try to be smart */
8704                         appendPQExpBuffer(q, " COLLATE %s.",
8705                                                           fmtId(coll->dobj.namespace->dobj.name));
8706                         appendPQExpBuffer(q, "%s",
8707                                                           fmtId(coll->dobj.name));
8708                 }
8709         }
8710
8711         if (typnotnull[0] == 't')
8712                 appendPQExpBuffer(q, " NOT NULL");
8713
8714         if (typdefault != NULL)
8715         {
8716                 appendPQExpBuffer(q, " DEFAULT ");
8717                 if (typdefault_is_literal)
8718                         appendStringLiteralAH(q, typdefault, fout);
8719                 else
8720                         appendPQExpBufferStr(q, typdefault);
8721         }
8722
8723         PQclear(res);
8724
8725         /*
8726          * Add any CHECK constraints for the domain
8727          */
8728         for (i = 0; i < tyinfo->nDomChecks; i++)
8729         {
8730                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
8731
8732                 if (!domcheck->separate)
8733                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
8734                                                           fmtId(domcheck->dobj.name), domcheck->condef);
8735         }
8736
8737         appendPQExpBuffer(q, ";\n");
8738
8739         /*
8740          * DROP must be fully qualified in case same name appears in pg_catalog
8741          */
8742         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
8743                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8744         appendPQExpBuffer(delq, "%s;\n",
8745                                           qtypname);
8746
8747         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
8748
8749         if (binary_upgrade)
8750                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8751
8752         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8753                                  tyinfo->dobj.name,
8754                                  tyinfo->dobj.namespace->dobj.name,
8755                                  NULL,
8756                                  tyinfo->rolname, false,
8757                                  "DOMAIN", SECTION_PRE_DATA,
8758                                  q->data, delq->data, NULL,
8759                                  NULL, 0,
8760                                  NULL, NULL);
8761
8762         /* Dump Domain Comments and Security Labels */
8763         dumpComment(fout, labelq->data,
8764                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8765                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8766         dumpSecLabel(fout, labelq->data,
8767                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8768                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8769
8770         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8771                         qtypname, NULL, tyinfo->dobj.name,
8772                         tyinfo->dobj.namespace->dobj.name,
8773                         tyinfo->rolname, tyinfo->typacl);
8774
8775         destroyPQExpBuffer(q);
8776         destroyPQExpBuffer(delq);
8777         destroyPQExpBuffer(labelq);
8778         destroyPQExpBuffer(query);
8779 }
8780
8781 /*
8782  * dumpCompositeType
8783  *        writes out to fout the queries to recreate a user-defined stand-alone
8784  *        composite type
8785  */
8786 static void
8787 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
8788 {
8789         PQExpBuffer q = createPQExpBuffer();
8790         PQExpBuffer dropped = createPQExpBuffer();
8791         PQExpBuffer delq = createPQExpBuffer();
8792         PQExpBuffer labelq = createPQExpBuffer();
8793         PQExpBuffer query = createPQExpBuffer();
8794         PGresult   *res;
8795         char       *qtypname;
8796         int                     ntups;
8797         int                     i_attname;
8798         int                     i_atttypdefn;
8799         int                     i_attlen;
8800         int                     i_attalign;
8801         int                     i_attisdropped;
8802         int                     i_attcollation;
8803         int                     i_typrelid;
8804         int                     i;
8805         int                     actual_atts;
8806
8807         /* Set proper schema search path so type references list correctly */
8808         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8809
8810         /* Fetch type specific details */
8811         if (fout->remoteVersion >= 90100)
8812         {
8813                 /*
8814                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
8815                  * clauses for attributes whose collation is different from their
8816                  * type's default, we use a CASE here to suppress uninteresting
8817                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
8818                  * collation does not matter for those.
8819                  */
8820                 appendPQExpBuffer(query, "SELECT a.attname, "
8821                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8822                                                   "a.attlen, a.attalign, a.attisdropped, "
8823                                                   "CASE WHEN a.attcollation <> at.typcollation "
8824                                                   "THEN a.attcollation ELSE 0 END AS attcollation, "
8825                                                   "ct.typrelid "
8826                                                   "FROM pg_catalog.pg_type ct "
8827                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
8828                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
8829                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8830                                                   "ORDER BY a.attnum ",
8831                                                   tyinfo->dobj.catId.oid);
8832         }
8833         else
8834         {
8835                 /*
8836                  * We assume here that remoteVersion must be at least 70300.  Since
8837                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
8838                  * always be false.
8839                  */
8840                 appendPQExpBuffer(query, "SELECT a.attname, "
8841                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
8842                                                   "a.attlen, a.attalign, a.attisdropped, "
8843                                                   "0 AS attcollation, "
8844                                                   "ct.typrelid "
8845                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
8846                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
8847                                                   "AND a.attrelid = ct.typrelid "
8848                                                   "ORDER BY a.attnum ",
8849                                                   tyinfo->dobj.catId.oid);
8850         }
8851
8852         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8853
8854         ntups = PQntuples(res);
8855
8856         i_attname = PQfnumber(res, "attname");
8857         i_atttypdefn = PQfnumber(res, "atttypdefn");
8858         i_attlen = PQfnumber(res, "attlen");
8859         i_attalign = PQfnumber(res, "attalign");
8860         i_attisdropped = PQfnumber(res, "attisdropped");
8861         i_attcollation = PQfnumber(res, "attcollation");
8862         i_typrelid = PQfnumber(res, "typrelid");
8863
8864         if (binary_upgrade)
8865         {
8866                 Oid                     typrelid = atooid(PQgetvalue(res, 0, i_typrelid));
8867
8868                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8869                                                                                                  tyinfo->dobj.catId.oid);
8870                 binary_upgrade_set_pg_class_oids(fout, q, typrelid, false);
8871         }
8872
8873         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8874
8875         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
8876                                           qtypname);
8877
8878         actual_atts = 0;
8879         for (i = 0; i < ntups; i++)
8880         {
8881                 char       *attname;
8882                 char       *atttypdefn;
8883                 char       *attlen;
8884                 char       *attalign;
8885                 bool            attisdropped;
8886                 Oid                     attcollation;
8887
8888                 attname = PQgetvalue(res, i, i_attname);
8889                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
8890                 attlen = PQgetvalue(res, i, i_attlen);
8891                 attalign = PQgetvalue(res, i, i_attalign);
8892                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
8893                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
8894
8895                 if (attisdropped && !binary_upgrade)
8896                         continue;
8897
8898                 /* Format properly if not first attr */
8899                 if (actual_atts++ > 0)
8900                         appendPQExpBuffer(q, ",");
8901                 appendPQExpBuffer(q, "\n\t");
8902
8903                 if (!attisdropped)
8904                 {
8905                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
8906
8907                         /* Add collation if not default for the column type */
8908                         if (OidIsValid(attcollation))
8909                         {
8910                                 CollInfo   *coll;
8911
8912                                 coll = findCollationByOid(attcollation);
8913                                 if (coll)
8914                                 {
8915                                         /* always schema-qualify, don't try to be smart */
8916                                         appendPQExpBuffer(q, " COLLATE %s.",
8917                                                                           fmtId(coll->dobj.namespace->dobj.name));
8918                                         appendPQExpBuffer(q, "%s",
8919                                                                           fmtId(coll->dobj.name));
8920                                 }
8921                         }
8922                 }
8923                 else
8924                 {
8925                         /*
8926                          * This is a dropped attribute and we're in binary_upgrade mode.
8927                          * Insert a placeholder for it in the CREATE TYPE command, and set
8928                          * length and alignment with direct UPDATE to the catalogs
8929                          * afterwards. See similar code in dumpTableSchema().
8930                          */
8931                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
8932
8933                         /* stash separately for insertion after the CREATE TYPE */
8934                         appendPQExpBuffer(dropped,
8935                                           "\n-- For binary upgrade, recreate dropped column.\n");
8936                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
8937                                                           "SET attlen = %s, "
8938                                                           "attalign = '%s', attbyval = false\n"
8939                                                           "WHERE attname = ", attlen, attalign);
8940                         appendStringLiteralAH(dropped, attname, fout);
8941                         appendPQExpBuffer(dropped, "\n  AND attrelid = ");
8942                         appendStringLiteralAH(dropped, qtypname, fout);
8943                         appendPQExpBuffer(dropped, "::pg_catalog.regclass;\n");
8944
8945                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
8946                                                           qtypname);
8947                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
8948                                                           fmtId(attname));
8949                 }
8950         }
8951         appendPQExpBuffer(q, "\n);\n");
8952         appendPQExpBufferStr(q, dropped->data);
8953
8954         /*
8955          * DROP must be fully qualified in case same name appears in pg_catalog
8956          */
8957         appendPQExpBuffer(delq, "DROP TYPE %s.",
8958                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8959         appendPQExpBuffer(delq, "%s;\n",
8960                                           qtypname);
8961
8962         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8963
8964         if (binary_upgrade)
8965                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8966
8967         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8968                                  tyinfo->dobj.name,
8969                                  tyinfo->dobj.namespace->dobj.name,
8970                                  NULL,
8971                                  tyinfo->rolname, false,
8972                                  "TYPE", SECTION_PRE_DATA,
8973                                  q->data, delq->data, NULL,
8974                                  NULL, 0,
8975                                  NULL, NULL);
8976
8977
8978         /* Dump Type Comments and Security Labels */
8979         dumpComment(fout, labelq->data,
8980                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8981                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8982         dumpSecLabel(fout, labelq->data,
8983                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8984                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8985
8986         dumpACL(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8987                         qtypname, NULL, tyinfo->dobj.name,
8988                         tyinfo->dobj.namespace->dobj.name,
8989                         tyinfo->rolname, tyinfo->typacl);
8990
8991         PQclear(res);
8992         destroyPQExpBuffer(q);
8993         destroyPQExpBuffer(dropped);
8994         destroyPQExpBuffer(delq);
8995         destroyPQExpBuffer(labelq);
8996         destroyPQExpBuffer(query);
8997
8998         /* Dump any per-column comments */
8999         dumpCompositeTypeColComments(fout, tyinfo);
9000 }
9001
9002 /*
9003  * dumpCompositeTypeColComments
9004  *        writes out to fout the queries to recreate comments on the columns of
9005  *        a user-defined stand-alone composite type
9006  */
9007 static void
9008 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9009 {
9010         CommentItem *comments;
9011         int                     ncomments;
9012         PGresult   *res;
9013         PQExpBuffer query;
9014         PQExpBuffer target;
9015         Oid                     pgClassOid;
9016         int                     i;
9017         int                     ntups;
9018         int                     i_attname;
9019         int                     i_attnum;
9020
9021         query = createPQExpBuffer();
9022
9023         /* We assume here that remoteVersion must be at least 70300 */
9024         appendPQExpBuffer(query,
9025                                           "SELECT c.tableoid, a.attname, a.attnum "
9026                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9027                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9028                                           "  AND NOT a.attisdropped "
9029                                           "ORDER BY a.attnum ",
9030                                           tyinfo->typrelid);
9031
9032         /* Fetch column attnames */
9033         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9034
9035         ntups = PQntuples(res);
9036         if (ntups < 1)
9037         {
9038                 PQclear(res);
9039                 destroyPQExpBuffer(query);
9040                 return;
9041         }
9042
9043         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9044
9045         /* Search for comments associated with type's pg_class OID */
9046         ncomments = findComments(fout,
9047                                                          pgClassOid,
9048                                                          tyinfo->typrelid,
9049                                                          &comments);
9050
9051         /* If no comments exist, we're done */
9052         if (ncomments <= 0)
9053         {
9054                 PQclear(res);
9055                 destroyPQExpBuffer(query);
9056                 return;
9057         }
9058
9059         /* Build COMMENT ON statements */
9060         target = createPQExpBuffer();
9061
9062         i_attnum = PQfnumber(res, "attnum");
9063         i_attname = PQfnumber(res, "attname");
9064         while (ncomments > 0)
9065         {
9066                 const char *attname;
9067
9068                 attname = NULL;
9069                 for (i = 0; i < ntups; i++)
9070                 {
9071                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9072                         {
9073                                 attname = PQgetvalue(res, i, i_attname);
9074                                 break;
9075                         }
9076                 }
9077                 if (attname)                    /* just in case we don't find it */
9078                 {
9079                         const char *descr = comments->descr;
9080
9081                         resetPQExpBuffer(target);
9082                         appendPQExpBuffer(target, "COLUMN %s.",
9083                                                           fmtId(tyinfo->dobj.name));
9084                         appendPQExpBuffer(target, "%s",
9085                                                           fmtId(attname));
9086
9087                         resetPQExpBuffer(query);
9088                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9089                         appendStringLiteralAH(query, descr, fout);
9090                         appendPQExpBuffer(query, ";\n");
9091
9092                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9093                                                  target->data,
9094                                                  tyinfo->dobj.namespace->dobj.name,
9095                                                  NULL, tyinfo->rolname,
9096                                                  false, "COMMENT", SECTION_NONE,
9097                                                  query->data, "", NULL,
9098                                                  &(tyinfo->dobj.dumpId), 1,
9099                                                  NULL, NULL);
9100                 }
9101
9102                 comments++;
9103                 ncomments--;
9104         }
9105
9106         PQclear(res);
9107         destroyPQExpBuffer(query);
9108         destroyPQExpBuffer(target);
9109 }
9110
9111 /*
9112  * dumpShellType
9113  *        writes out to fout the queries to create a shell type
9114  *
9115  * We dump a shell definition in advance of the I/O functions for the type.
9116  */
9117 static void
9118 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
9119 {
9120         PQExpBuffer q;
9121
9122         /* Skip if not to be dumped */
9123         if (!stinfo->dobj.dump || dataOnly)
9124                 return;
9125
9126         q = createPQExpBuffer();
9127
9128         /*
9129          * Note the lack of a DROP command for the shell type; any required DROP
9130          * is driven off the base type entry, instead.  This interacts with
9131          * _printTocEntry()'s use of the presence of a DROP command to decide
9132          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9133          * the shell type's owner immediately on creation; that should happen only
9134          * after it's filled in, otherwise the backend complains.
9135          */
9136
9137         if (binary_upgrade)
9138                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9139                                                                                    stinfo->baseType->dobj.catId.oid);
9140
9141         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9142                                           fmtId(stinfo->dobj.name));
9143
9144         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9145                                  stinfo->dobj.name,
9146                                  stinfo->dobj.namespace->dobj.name,
9147                                  NULL,
9148                                  stinfo->baseType->rolname, false,
9149                                  "SHELL TYPE", SECTION_PRE_DATA,
9150                                  q->data, "", NULL,
9151                                  NULL, 0,
9152                                  NULL, NULL);
9153
9154         destroyPQExpBuffer(q);
9155 }
9156
9157 /*
9158  * Determine whether we want to dump definitions for procedural languages.
9159  * Since the languages themselves don't have schemas, we can't rely on
9160  * the normal schema-based selection mechanism.  We choose to dump them
9161  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9162  * the dump flag of the PL's call handler function, but in 8.1 this will
9163  * probably always be false since call handlers are created in pg_catalog.)
9164  *
9165  * For some backwards compatibility with the older behavior, we forcibly
9166  * dump a PL if its handler function (and validator if any) are in a
9167  * dumpable namespace.  That case is not checked here.
9168  *
9169  * Also, if the PL belongs to an extension, we do not use this heuristic.
9170  * That case isn't checked here either.
9171  */
9172 static bool
9173 shouldDumpProcLangs(void)
9174 {
9175         if (!include_everything)
9176                 return false;
9177         /* And they're schema not data */
9178         if (dataOnly)
9179                 return false;
9180         return true;
9181 }
9182
9183 /*
9184  * dumpProcLang
9185  *                writes out to fout the queries to recreate a user-defined
9186  *                procedural language
9187  */
9188 static void
9189 dumpProcLang(Archive *fout, ProcLangInfo *plang)
9190 {
9191         PQExpBuffer defqry;
9192         PQExpBuffer delqry;
9193         PQExpBuffer labelq;
9194         bool            useParams;
9195         char       *qlanname;
9196         char       *lanschema;
9197         FuncInfo   *funcInfo;
9198         FuncInfo   *inlineInfo = NULL;
9199         FuncInfo   *validatorInfo = NULL;
9200
9201         /* Skip if not to be dumped */
9202         if (!plang->dobj.dump || dataOnly)
9203                 return;
9204
9205         /*
9206          * Try to find the support function(s).  It is not an error if we don't
9207          * find them --- if the functions are in the pg_catalog schema, as is
9208          * standard in 8.1 and up, then we won't have loaded them. (In this case
9209          * we will emit a parameterless CREATE LANGUAGE command, which will
9210          * require PL template knowledge in the backend to reload.)
9211          */
9212
9213         funcInfo = findFuncByOid(plang->lanplcallfoid);
9214         if (funcInfo != NULL && !funcInfo->dobj.dump)
9215                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9216
9217         if (OidIsValid(plang->laninline))
9218         {
9219                 inlineInfo = findFuncByOid(plang->laninline);
9220                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9221                         inlineInfo = NULL;
9222         }
9223
9224         if (OidIsValid(plang->lanvalidator))
9225         {
9226                 validatorInfo = findFuncByOid(plang->lanvalidator);
9227                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9228                         validatorInfo = NULL;
9229         }
9230
9231         /*
9232          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9233          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9234          * dump it.
9235          *
9236          * However, for a language that belongs to an extension, we must not use
9237          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9238          * told to (via dobj.dump).  Generally the support functions will belong
9239          * to the same extension and so have the same dump flags ... if they
9240          * don't, this might not work terribly nicely.
9241          */
9242         useParams = (funcInfo != NULL &&
9243                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9244                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9245
9246         if (!plang->dobj.ext_member)
9247         {
9248                 if (!useParams && !shouldDumpProcLangs())
9249                         return;
9250         }
9251
9252         defqry = createPQExpBuffer();
9253         delqry = createPQExpBuffer();
9254         labelq = createPQExpBuffer();
9255
9256         qlanname = pg_strdup(fmtId(plang->dobj.name));
9257
9258         /*
9259          * If dumping a HANDLER clause, treat the language as being in the handler
9260          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9261          * it doesn't really have a schema.
9262          */
9263         if (useParams)
9264                 lanschema = funcInfo->dobj.namespace->dobj.name;
9265         else
9266                 lanschema = NULL;
9267
9268         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9269                                           qlanname);
9270
9271         if (useParams)
9272         {
9273                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9274                                                   plang->lanpltrusted ? "TRUSTED " : "",
9275                                                   qlanname);
9276                 appendPQExpBuffer(defqry, " HANDLER %s",
9277                                                   fmtId(funcInfo->dobj.name));
9278                 if (OidIsValid(plang->laninline))
9279                 {
9280                         appendPQExpBuffer(defqry, " INLINE ");
9281                         /* Cope with possibility that inline is in different schema */
9282                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9283                                 appendPQExpBuffer(defqry, "%s.",
9284                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9285                         appendPQExpBuffer(defqry, "%s",
9286                                                           fmtId(inlineInfo->dobj.name));
9287                 }
9288                 if (OidIsValid(plang->lanvalidator))
9289                 {
9290                         appendPQExpBuffer(defqry, " VALIDATOR ");
9291                         /* Cope with possibility that validator is in different schema */
9292                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9293                                 appendPQExpBuffer(defqry, "%s.",
9294                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9295                         appendPQExpBuffer(defqry, "%s",
9296                                                           fmtId(validatorInfo->dobj.name));
9297                 }
9298         }
9299         else
9300         {
9301                 /*
9302                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9303                  * command will not fail if the language is preinstalled in the target
9304                  * database.  We restrict the use of REPLACE to this case so as to
9305                  * eliminate the risk of replacing a language with incompatible
9306                  * parameter settings: this command will only succeed at all if there
9307                  * is a pg_pltemplate entry, and if there is one, the existing entry
9308                  * must match it too.
9309                  */
9310                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9311                                                   qlanname);
9312         }
9313         appendPQExpBuffer(defqry, ";\n");
9314
9315         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9316
9317         if (binary_upgrade)
9318                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9319
9320         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9321                                  plang->dobj.name,
9322                                  lanschema, NULL, plang->lanowner,
9323                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9324                                  defqry->data, delqry->data, NULL,
9325                                  NULL, 0,
9326                                  NULL, NULL);
9327
9328         /* Dump Proc Lang Comments and Security Labels */
9329         dumpComment(fout, labelq->data,
9330                                 NULL, "",
9331                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9332         dumpSecLabel(fout, labelq->data,
9333                                  NULL, "",
9334                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9335
9336         if (plang->lanpltrusted)
9337                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9338                                 qlanname, NULL, plang->dobj.name,
9339                                 lanschema,
9340                                 plang->lanowner, plang->lanacl);
9341
9342         free(qlanname);
9343
9344         destroyPQExpBuffer(defqry);
9345         destroyPQExpBuffer(delqry);
9346         destroyPQExpBuffer(labelq);
9347 }
9348
9349 /*
9350  * format_function_arguments: generate function name and argument list
9351  *
9352  * This is used when we can rely on pg_get_function_arguments to format
9353  * the argument list.
9354  */
9355 static char *
9356 format_function_arguments(FuncInfo *finfo, char *funcargs)
9357 {
9358         PQExpBufferData fn;
9359
9360         initPQExpBuffer(&fn);
9361         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
9362         return fn.data;
9363 }
9364
9365 /*
9366  * format_function_arguments_old: generate function name and argument list
9367  *
9368  * The argument type names are qualified if needed.  The function name
9369  * is never qualified.
9370  *
9371  * This is used only with pre-8.4 servers, so we aren't expecting to see
9372  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9373  *
9374  * Any or all of allargtypes, argmodes, argnames may be NULL.
9375  */
9376 static char *
9377 format_function_arguments_old(Archive *fout,
9378                                                           FuncInfo *finfo, int nallargs,
9379                                                           char **allargtypes,
9380                                                           char **argmodes,
9381                                                           char **argnames)
9382 {
9383         PQExpBufferData fn;
9384         int                     j;
9385
9386         initPQExpBuffer(&fn);
9387         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9388         for (j = 0; j < nallargs; j++)
9389         {
9390                 Oid                     typid;
9391                 char       *typname;
9392                 const char *argmode;
9393                 const char *argname;
9394
9395                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9396                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9397
9398                 if (argmodes)
9399                 {
9400                         switch (argmodes[j][0])
9401                         {
9402                                 case PROARGMODE_IN:
9403                                         argmode = "";
9404                                         break;
9405                                 case PROARGMODE_OUT:
9406                                         argmode = "OUT ";
9407                                         break;
9408                                 case PROARGMODE_INOUT:
9409                                         argmode = "INOUT ";
9410                                         break;
9411                                 default:
9412                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9413                                         argmode = "";
9414                                         break;
9415                         }
9416                 }
9417                 else
9418                         argmode = "";
9419
9420                 argname = argnames ? argnames[j] : (char *) NULL;
9421                 if (argname && argname[0] == '\0')
9422                         argname = NULL;
9423
9424                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9425                                                   (j > 0) ? ", " : "",
9426                                                   argmode,
9427                                                   argname ? fmtId(argname) : "",
9428                                                   argname ? " " : "",
9429                                                   typname);
9430                 free(typname);
9431         }
9432         appendPQExpBuffer(&fn, ")");
9433         return fn.data;
9434 }
9435
9436 /*
9437  * format_function_signature: generate function name and argument list
9438  *
9439  * This is like format_function_arguments_old except that only a minimal
9440  * list of input argument types is generated; this is sufficient to
9441  * reference the function, but not to define it.
9442  *
9443  * If honor_quotes is false then the function name is never quoted.
9444  * This is appropriate for use in TOC tags, but not in SQL commands.
9445  */
9446 static char *
9447 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9448 {
9449         PQExpBufferData fn;
9450         int                     j;
9451
9452         initPQExpBuffer(&fn);
9453         if (honor_quotes)
9454                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9455         else
9456                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9457         for (j = 0; j < finfo->nargs; j++)
9458         {
9459                 char       *typname;
9460
9461                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9462                                                                            zeroAsOpaque);
9463
9464                 appendPQExpBuffer(&fn, "%s%s",
9465                                                   (j > 0) ? ", " : "",
9466                                                   typname);
9467                 free(typname);
9468         }
9469         appendPQExpBuffer(&fn, ")");
9470         return fn.data;
9471 }
9472
9473
9474 /*
9475  * dumpFunc:
9476  *        dump out one function
9477  */
9478 static void
9479 dumpFunc(Archive *fout, FuncInfo *finfo)
9480 {
9481         PQExpBuffer query;
9482         PQExpBuffer q;
9483         PQExpBuffer delqry;
9484         PQExpBuffer labelq;
9485         PQExpBuffer asPart;
9486         PGresult   *res;
9487         char       *funcsig;            /* identity signature */
9488         char       *funcfullsig;        /* full signature */
9489         char       *funcsig_tag;
9490         char       *proretset;
9491         char       *prosrc;
9492         char       *probin;
9493         char       *funcargs;
9494         char       *funciargs;
9495         char       *funcresult;
9496         char       *proallargtypes;
9497         char       *proargmodes;
9498         char       *proargnames;
9499         char       *proiswindow;
9500         char       *provolatile;
9501         char       *proisstrict;
9502         char       *prosecdef;
9503         char       *proleakproof;
9504         char       *proconfig;
9505         char       *procost;
9506         char       *prorows;
9507         char       *lanname;
9508         char       *rettypename;
9509         int                     nallargs;
9510         char      **allargtypes = NULL;
9511         char      **argmodes = NULL;
9512         char      **argnames = NULL;
9513         char      **configitems = NULL;
9514         int                     nconfigitems = 0;
9515         int                     i;
9516
9517         /* Skip if not to be dumped */
9518         if (!finfo->dobj.dump || dataOnly)
9519                 return;
9520
9521         query = createPQExpBuffer();
9522         q = createPQExpBuffer();
9523         delqry = createPQExpBuffer();
9524         labelq = createPQExpBuffer();
9525         asPart = createPQExpBuffer();
9526
9527         /* Set proper schema search path so type references list correctly */
9528         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
9529
9530         /* Fetch function-specific details */
9531         if (fout->remoteVersion >= 90200)
9532         {
9533                 /*
9534                  * proleakproof was added at v9.2
9535                  */
9536                 appendPQExpBuffer(query,
9537                                                   "SELECT proretset, prosrc, probin, "
9538                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9539                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9540                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9541                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9542                                                   "proleakproof, proconfig, procost, prorows, "
9543                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9544                                                   "FROM pg_catalog.pg_proc "
9545                                                   "WHERE oid = '%u'::pg_catalog.oid",
9546                                                   finfo->dobj.catId.oid);
9547         }
9548         else if (fout->remoteVersion >= 80400)
9549         {
9550                 /*
9551                  * In 8.4 and up we rely on pg_get_function_arguments and
9552                  * pg_get_function_result instead of examining proallargtypes etc.
9553                  */
9554                 appendPQExpBuffer(query,
9555                                                   "SELECT proretset, prosrc, probin, "
9556                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
9557                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
9558                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
9559                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
9560                                                   "false AS proleakproof, "
9561                                                   " proconfig, procost, prorows, "
9562                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9563                                                   "FROM pg_catalog.pg_proc "
9564                                                   "WHERE oid = '%u'::pg_catalog.oid",
9565                                                   finfo->dobj.catId.oid);
9566         }
9567         else if (fout->remoteVersion >= 80300)
9568         {
9569                 appendPQExpBuffer(query,
9570                                                   "SELECT proretset, prosrc, probin, "
9571                                                   "proallargtypes, proargmodes, proargnames, "
9572                                                   "false AS proiswindow, "
9573                                                   "provolatile, proisstrict, prosecdef, "
9574                                                   "false AS proleakproof, "
9575                                                   "proconfig, procost, prorows, "
9576                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9577                                                   "FROM pg_catalog.pg_proc "
9578                                                   "WHERE oid = '%u'::pg_catalog.oid",
9579                                                   finfo->dobj.catId.oid);
9580         }
9581         else if (fout->remoteVersion >= 80100)
9582         {
9583                 appendPQExpBuffer(query,
9584                                                   "SELECT proretset, prosrc, probin, "
9585                                                   "proallargtypes, proargmodes, proargnames, "
9586                                                   "false AS proiswindow, "
9587                                                   "provolatile, proisstrict, prosecdef, "
9588                                                   "false AS proleakproof, "
9589                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9590                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9591                                                   "FROM pg_catalog.pg_proc "
9592                                                   "WHERE oid = '%u'::pg_catalog.oid",
9593                                                   finfo->dobj.catId.oid);
9594         }
9595         else if (fout->remoteVersion >= 80000)
9596         {
9597                 appendPQExpBuffer(query,
9598                                                   "SELECT proretset, prosrc, probin, "
9599                                                   "null AS proallargtypes, "
9600                                                   "null AS proargmodes, "
9601                                                   "proargnames, "
9602                                                   "false AS proiswindow, "
9603                                                   "provolatile, proisstrict, prosecdef, "
9604                                                   "false AS proleakproof, "
9605                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9606                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9607                                                   "FROM pg_catalog.pg_proc "
9608                                                   "WHERE oid = '%u'::pg_catalog.oid",
9609                                                   finfo->dobj.catId.oid);
9610         }
9611         else if (fout->remoteVersion >= 70300)
9612         {
9613                 appendPQExpBuffer(query,
9614                                                   "SELECT proretset, prosrc, probin, "
9615                                                   "null AS proallargtypes, "
9616                                                   "null AS proargmodes, "
9617                                                   "null AS proargnames, "
9618                                                   "false AS proiswindow, "
9619                                                   "provolatile, proisstrict, prosecdef, "
9620                                                   "false AS proleakproof, "
9621                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9622                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
9623                                                   "FROM pg_catalog.pg_proc "
9624                                                   "WHERE oid = '%u'::pg_catalog.oid",
9625                                                   finfo->dobj.catId.oid);
9626         }
9627         else if (fout->remoteVersion >= 70100)
9628         {
9629                 appendPQExpBuffer(query,
9630                                                   "SELECT proretset, prosrc, probin, "
9631                                                   "null AS proallargtypes, "
9632                                                   "null AS proargmodes, "
9633                                                   "null AS proargnames, "
9634                                                   "false AS proiswindow, "
9635                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
9636                                                   "proisstrict, "
9637                                                   "false AS prosecdef, "
9638                                                   "false AS proleakproof, "
9639                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
9640                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9641                                                   "FROM pg_proc "
9642                                                   "WHERE oid = '%u'::oid",
9643                                                   finfo->dobj.catId.oid);
9644         }
9645         else
9646         {
9647                 appendPQExpBuffer(query,
9648                                                   "SELECT proretset, prosrc, probin, "
9649                                                   "null AS proallargtypes, "
9650                                                   "null AS proargmodes, "
9651                                                   "null AS proargnames, "
9652                                                   "false AS proiswindow, "
9653                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
9654                                                   "false AS proisstrict, "
9655                                                   "false AS prosecdef, "
9656                                                   "false AS proleakproof, "
9657                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
9658                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
9659                                                   "FROM pg_proc "
9660                                                   "WHERE oid = '%u'::oid",
9661                                                   finfo->dobj.catId.oid);
9662         }
9663
9664         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9665
9666         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
9667         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
9668         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
9669         if (fout->remoteVersion >= 80400)
9670         {
9671                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
9672                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
9673                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
9674                 proallargtypes = proargmodes = proargnames = NULL;
9675         }
9676         else
9677         {
9678                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
9679                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
9680                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
9681                 funcargs = funciargs = funcresult = NULL;
9682         }
9683         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
9684         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
9685         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
9686         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
9687         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
9688         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
9689         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
9690         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
9691         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
9692
9693         /*
9694          * See backend/commands/functioncmds.c for details of how the 'AS' clause
9695          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
9696          * versions would set it to "-".  There are no known cases in which prosrc
9697          * is unused, so the tests below for "-" are probably useless.
9698          */
9699         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
9700         {
9701                 appendPQExpBuffer(asPart, "AS ");
9702                 appendStringLiteralAH(asPart, probin, fout);
9703                 if (strcmp(prosrc, "-") != 0)
9704                 {
9705                         appendPQExpBuffer(asPart, ", ");
9706
9707                         /*
9708                          * where we have bin, use dollar quoting if allowed and src
9709                          * contains quote or backslash; else use regular quoting.
9710                          */
9711                         if (disable_dollar_quoting ||
9712                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
9713                                 appendStringLiteralAH(asPart, prosrc, fout);
9714                         else
9715                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9716                 }
9717         }
9718         else
9719         {
9720                 if (strcmp(prosrc, "-") != 0)
9721                 {
9722                         appendPQExpBuffer(asPart, "AS ");
9723                         /* with no bin, dollar quote src unconditionally if allowed */
9724                         if (disable_dollar_quoting)
9725                                 appendStringLiteralAH(asPart, prosrc, fout);
9726                         else
9727                                 appendStringLiteralDQ(asPart, prosrc, NULL);
9728                 }
9729         }
9730
9731         nallargs = finfo->nargs;        /* unless we learn different from allargs */
9732
9733         if (proallargtypes && *proallargtypes)
9734         {
9735                 int                     nitems = 0;
9736
9737                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
9738                         nitems < finfo->nargs)
9739                 {
9740                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
9741                         if (allargtypes)
9742                                 free(allargtypes);
9743                         allargtypes = NULL;
9744                 }
9745                 else
9746                         nallargs = nitems;
9747         }
9748
9749         if (proargmodes && *proargmodes)
9750         {
9751                 int                     nitems = 0;
9752
9753                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
9754                         nitems != nallargs)
9755                 {
9756                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
9757                         if (argmodes)
9758                                 free(argmodes);
9759                         argmodes = NULL;
9760                 }
9761         }
9762
9763         if (proargnames && *proargnames)
9764         {
9765                 int                     nitems = 0;
9766
9767                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
9768                         nitems != nallargs)
9769                 {
9770                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
9771                         if (argnames)
9772                                 free(argnames);
9773                         argnames = NULL;
9774                 }
9775         }
9776
9777         if (proconfig && *proconfig)
9778         {
9779                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
9780                 {
9781                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
9782                         if (configitems)
9783                                 free(configitems);
9784                         configitems = NULL;
9785                         nconfigitems = 0;
9786                 }
9787         }
9788
9789         if (funcargs)
9790         {
9791                 /* 8.4 or later; we rely on server-side code for most of the work */
9792                 funcfullsig = format_function_arguments(finfo, funcargs);
9793                 funcsig = format_function_arguments(finfo, funciargs);
9794         }
9795         else
9796         {
9797                 /* pre-8.4, do it ourselves */
9798                 funcsig = format_function_arguments_old(fout,
9799                                                                                                 finfo, nallargs, allargtypes,
9800                                                                                                 argmodes, argnames);
9801                 funcfullsig = funcsig;
9802         }
9803
9804         funcsig_tag = format_function_signature(fout, finfo, false);
9805
9806         /*
9807          * DROP must be fully qualified in case same name appears in pg_catalog
9808          */
9809         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
9810                                           fmtId(finfo->dobj.namespace->dobj.name),
9811                                           funcsig);
9812
9813         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
9814         if (funcresult)
9815                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
9816         else
9817         {
9818                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
9819                                                                                    zeroAsOpaque);
9820                 appendPQExpBuffer(q, "RETURNS %s%s",
9821                                                   (proretset[0] == 't') ? "SETOF " : "",
9822                                                   rettypename);
9823                 free(rettypename);
9824         }
9825
9826         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
9827
9828         if (proiswindow[0] == 't')
9829                 appendPQExpBuffer(q, " WINDOW");
9830
9831         if (provolatile[0] != PROVOLATILE_VOLATILE)
9832         {
9833                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
9834                         appendPQExpBuffer(q, " IMMUTABLE");
9835                 else if (provolatile[0] == PROVOLATILE_STABLE)
9836                         appendPQExpBuffer(q, " STABLE");
9837                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
9838                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
9839                                                   finfo->dobj.name);
9840         }
9841
9842         if (proisstrict[0] == 't')
9843                 appendPQExpBuffer(q, " STRICT");
9844
9845         if (prosecdef[0] == 't')
9846                 appendPQExpBuffer(q, " SECURITY DEFINER");
9847
9848         if (proleakproof[0] == 't')
9849                 appendPQExpBuffer(q, " LEAKPROOF");
9850
9851         /*
9852          * COST and ROWS are emitted only if present and not default, so as not to
9853          * break backwards-compatibility of the dump without need.      Keep this code
9854          * in sync with the defaults in functioncmds.c.
9855          */
9856         if (strcmp(procost, "0") != 0)
9857         {
9858                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
9859                 {
9860                         /* default cost is 1 */
9861                         if (strcmp(procost, "1") != 0)
9862                                 appendPQExpBuffer(q, " COST %s", procost);
9863                 }
9864                 else
9865                 {
9866                         /* default cost is 100 */
9867                         if (strcmp(procost, "100") != 0)
9868                                 appendPQExpBuffer(q, " COST %s", procost);
9869                 }
9870         }
9871         if (proretset[0] == 't' &&
9872                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
9873                 appendPQExpBuffer(q, " ROWS %s", prorows);
9874
9875         for (i = 0; i < nconfigitems; i++)
9876         {
9877                 /* we feel free to scribble on configitems[] here */
9878                 char       *configitem = configitems[i];
9879                 char       *pos;
9880
9881                 pos = strchr(configitem, '=');
9882                 if (pos == NULL)
9883                         continue;
9884                 *pos++ = '\0';
9885                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
9886
9887                 /*
9888                  * Some GUC variable names are 'LIST' type and hence must not be
9889                  * quoted.
9890                  */
9891                 if (pg_strcasecmp(configitem, "DateStyle") == 0
9892                         || pg_strcasecmp(configitem, "search_path") == 0)
9893                         appendPQExpBuffer(q, "%s", pos);
9894                 else
9895                         appendStringLiteralAH(q, pos, fout);
9896         }
9897
9898         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
9899
9900         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
9901
9902         if (binary_upgrade)
9903                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
9904
9905         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
9906                                  funcsig_tag,
9907                                  finfo->dobj.namespace->dobj.name,
9908                                  NULL,
9909                                  finfo->rolname, false,
9910                                  "FUNCTION", SECTION_PRE_DATA,
9911                                  q->data, delqry->data, NULL,
9912                                  NULL, 0,
9913                                  NULL, NULL);
9914
9915         /* Dump Function Comments and Security Labels */
9916         dumpComment(fout, labelq->data,
9917                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
9918                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
9919         dumpSecLabel(fout, labelq->data,
9920                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
9921                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
9922
9923         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
9924                         funcsig, NULL, funcsig_tag,
9925                         finfo->dobj.namespace->dobj.name,
9926                         finfo->rolname, finfo->proacl);
9927
9928         PQclear(res);
9929
9930         destroyPQExpBuffer(query);
9931         destroyPQExpBuffer(q);
9932         destroyPQExpBuffer(delqry);
9933         destroyPQExpBuffer(labelq);
9934         destroyPQExpBuffer(asPart);
9935         free(funcsig);
9936         free(funcsig_tag);
9937         if (allargtypes)
9938                 free(allargtypes);
9939         if (argmodes)
9940                 free(argmodes);
9941         if (argnames)
9942                 free(argnames);
9943         if (configitems)
9944                 free(configitems);
9945 }
9946
9947
9948 /*
9949  * Dump a user-defined cast
9950  */
9951 static void
9952 dumpCast(Archive *fout, CastInfo *cast)
9953 {
9954         PQExpBuffer defqry;
9955         PQExpBuffer delqry;
9956         PQExpBuffer labelq;
9957         FuncInfo   *funcInfo = NULL;
9958
9959         /* Skip if not to be dumped */
9960         if (!cast->dobj.dump || dataOnly)
9961                 return;
9962
9963         /* Cannot dump if we don't have the cast function's info */
9964         if (OidIsValid(cast->castfunc))
9965         {
9966                 funcInfo = findFuncByOid(cast->castfunc);
9967                 if (funcInfo == NULL)
9968                         return;
9969         }
9970
9971         /*
9972          * As per discussion we dump casts if one or more of the underlying
9973          * objects (the conversion function and the two data types) are not
9974          * builtin AND if all of the non-builtin objects are included in the dump.
9975          * Builtin meaning, the namespace name does not start with "pg_".
9976          *
9977          * However, for a cast that belongs to an extension, we must not use this
9978          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
9979          */
9980         if (!cast->dobj.ext_member)
9981         {
9982                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
9983                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
9984
9985                 if (sourceInfo == NULL || targetInfo == NULL)
9986                         return;
9987
9988                 /*
9989                  * Skip this cast if all objects are from pg_
9990                  */
9991                 if ((funcInfo == NULL ||
9992                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
9993                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
9994                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
9995                         return;
9996
9997                 /*
9998                  * Skip cast if function isn't from pg_ and is not to be dumped.
9999                  */
10000                 if (funcInfo &&
10001                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10002                         !funcInfo->dobj.dump)
10003                         return;
10004
10005                 /*
10006                  * Same for the source type
10007                  */
10008                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10009                         !sourceInfo->dobj.dump)
10010                         return;
10011
10012                 /*
10013                  * and the target type.
10014                  */
10015                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10016                         !targetInfo->dobj.dump)
10017                         return;
10018         }
10019
10020         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10021         selectSourceSchema(fout, "pg_catalog");
10022
10023         defqry = createPQExpBuffer();
10024         delqry = createPQExpBuffer();
10025         labelq = createPQExpBuffer();
10026
10027         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10028                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10029                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10030
10031         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10032                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10033                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10034
10035         switch (cast->castmethod)
10036         {
10037                 case COERCION_METHOD_BINARY:
10038                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
10039                         break;
10040                 case COERCION_METHOD_INOUT:
10041                         appendPQExpBuffer(defqry, "WITH INOUT");
10042                         break;
10043                 case COERCION_METHOD_FUNCTION:
10044                         if (funcInfo)
10045                         {
10046                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10047
10048                                 /*
10049                                  * Always qualify the function name, in case it is not in
10050                                  * pg_catalog schema (format_function_signature won't qualify
10051                                  * it).
10052                                  */
10053                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10054                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10055                                 free(fsig);
10056                         }
10057                         else
10058                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10059                         break;
10060                 default:
10061                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10062         }
10063
10064         if (cast->castcontext == 'a')
10065                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
10066         else if (cast->castcontext == 'i')
10067                 appendPQExpBuffer(defqry, " AS IMPLICIT");
10068         appendPQExpBuffer(defqry, ";\n");
10069
10070         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10071                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10072                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10073
10074         if (binary_upgrade)
10075                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10076
10077         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10078                                  labelq->data,
10079                                  "pg_catalog", NULL, "",
10080                                  false, "CAST", SECTION_PRE_DATA,
10081                                  defqry->data, delqry->data, NULL,
10082                                  NULL, 0,
10083                                  NULL, NULL);
10084
10085         /* Dump Cast Comments */
10086         dumpComment(fout, labelq->data,
10087                                 NULL, "",
10088                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10089
10090         destroyPQExpBuffer(defqry);
10091         destroyPQExpBuffer(delqry);
10092         destroyPQExpBuffer(labelq);
10093 }
10094
10095 /*
10096  * dumpOpr
10097  *        write out a single operator definition
10098  */
10099 static void
10100 dumpOpr(Archive *fout, OprInfo *oprinfo)
10101 {
10102         PQExpBuffer query;
10103         PQExpBuffer q;
10104         PQExpBuffer delq;
10105         PQExpBuffer labelq;
10106         PQExpBuffer oprid;
10107         PQExpBuffer details;
10108         const char *name;
10109         PGresult   *res;
10110         int                     i_oprkind;
10111         int                     i_oprcode;
10112         int                     i_oprleft;
10113         int                     i_oprright;
10114         int                     i_oprcom;
10115         int                     i_oprnegate;
10116         int                     i_oprrest;
10117         int                     i_oprjoin;
10118         int                     i_oprcanmerge;
10119         int                     i_oprcanhash;
10120         char       *oprkind;
10121         char       *oprcode;
10122         char       *oprleft;
10123         char       *oprright;
10124         char       *oprcom;
10125         char       *oprnegate;
10126         char       *oprrest;
10127         char       *oprjoin;
10128         char       *oprcanmerge;
10129         char       *oprcanhash;
10130
10131         /* Skip if not to be dumped */
10132         if (!oprinfo->dobj.dump || dataOnly)
10133                 return;
10134
10135         /*
10136          * some operators are invalid because they were the result of user
10137          * defining operators before commutators exist
10138          */
10139         if (!OidIsValid(oprinfo->oprcode))
10140                 return;
10141
10142         query = createPQExpBuffer();
10143         q = createPQExpBuffer();
10144         delq = createPQExpBuffer();
10145         labelq = createPQExpBuffer();
10146         oprid = createPQExpBuffer();
10147         details = createPQExpBuffer();
10148
10149         /* Make sure we are in proper schema so regoperator works correctly */
10150         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10151
10152         if (fout->remoteVersion >= 80300)
10153         {
10154                 appendPQExpBuffer(query, "SELECT oprkind, "
10155                                                   "oprcode::pg_catalog.regprocedure, "
10156                                                   "oprleft::pg_catalog.regtype, "
10157                                                   "oprright::pg_catalog.regtype, "
10158                                                   "oprcom::pg_catalog.regoperator, "
10159                                                   "oprnegate::pg_catalog.regoperator, "
10160                                                   "oprrest::pg_catalog.regprocedure, "
10161                                                   "oprjoin::pg_catalog.regprocedure, "
10162                                                   "oprcanmerge, oprcanhash "
10163                                                   "FROM pg_catalog.pg_operator "
10164                                                   "WHERE oid = '%u'::pg_catalog.oid",
10165                                                   oprinfo->dobj.catId.oid);
10166         }
10167         else if (fout->remoteVersion >= 70300)
10168         {
10169                 appendPQExpBuffer(query, "SELECT oprkind, "
10170                                                   "oprcode::pg_catalog.regprocedure, "
10171                                                   "oprleft::pg_catalog.regtype, "
10172                                                   "oprright::pg_catalog.regtype, "
10173                                                   "oprcom::pg_catalog.regoperator, "
10174                                                   "oprnegate::pg_catalog.regoperator, "
10175                                                   "oprrest::pg_catalog.regprocedure, "
10176                                                   "oprjoin::pg_catalog.regprocedure, "
10177                                                   "(oprlsortop != 0) AS oprcanmerge, "
10178                                                   "oprcanhash "
10179                                                   "FROM pg_catalog.pg_operator "
10180                                                   "WHERE oid = '%u'::pg_catalog.oid",
10181                                                   oprinfo->dobj.catId.oid);
10182         }
10183         else if (fout->remoteVersion >= 70100)
10184         {
10185                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10186                                                   "CASE WHEN oprleft = 0 THEN '-' "
10187                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10188                                                   "CASE WHEN oprright = 0 THEN '-' "
10189                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10190                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10191                                                   "(oprlsortop != 0) AS oprcanmerge, "
10192                                                   "oprcanhash "
10193                                                   "FROM pg_operator "
10194                                                   "WHERE oid = '%u'::oid",
10195                                                   oprinfo->dobj.catId.oid);
10196         }
10197         else
10198         {
10199                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10200                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10201                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10202                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10203                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10204                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10205                                                   "(oprlsortop != 0) AS oprcanmerge, "
10206                                                   "oprcanhash "
10207                                                   "FROM pg_operator "
10208                                                   "WHERE oid = '%u'::oid",
10209                                                   oprinfo->dobj.catId.oid);
10210         }
10211
10212         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10213
10214         i_oprkind = PQfnumber(res, "oprkind");
10215         i_oprcode = PQfnumber(res, "oprcode");
10216         i_oprleft = PQfnumber(res, "oprleft");
10217         i_oprright = PQfnumber(res, "oprright");
10218         i_oprcom = PQfnumber(res, "oprcom");
10219         i_oprnegate = PQfnumber(res, "oprnegate");
10220         i_oprrest = PQfnumber(res, "oprrest");
10221         i_oprjoin = PQfnumber(res, "oprjoin");
10222         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10223         i_oprcanhash = PQfnumber(res, "oprcanhash");
10224
10225         oprkind = PQgetvalue(res, 0, i_oprkind);
10226         oprcode = PQgetvalue(res, 0, i_oprcode);
10227         oprleft = PQgetvalue(res, 0, i_oprleft);
10228         oprright = PQgetvalue(res, 0, i_oprright);
10229         oprcom = PQgetvalue(res, 0, i_oprcom);
10230         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10231         oprrest = PQgetvalue(res, 0, i_oprrest);
10232         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10233         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10234         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10235
10236         appendPQExpBuffer(details, "    PROCEDURE = %s",
10237                                           convertRegProcReference(fout, oprcode));
10238
10239         appendPQExpBuffer(oprid, "%s (",
10240                                           oprinfo->dobj.name);
10241
10242         /*
10243          * right unary means there's a left arg and left unary means there's a
10244          * right arg
10245          */
10246         if (strcmp(oprkind, "r") == 0 ||
10247                 strcmp(oprkind, "b") == 0)
10248         {
10249                 if (fout->remoteVersion >= 70100)
10250                         name = oprleft;
10251                 else
10252                         name = fmtId(oprleft);
10253                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10254                 appendPQExpBuffer(oprid, "%s", name);
10255         }
10256         else
10257                 appendPQExpBuffer(oprid, "NONE");
10258
10259         if (strcmp(oprkind, "l") == 0 ||
10260                 strcmp(oprkind, "b") == 0)
10261         {
10262                 if (fout->remoteVersion >= 70100)
10263                         name = oprright;
10264                 else
10265                         name = fmtId(oprright);
10266                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10267                 appendPQExpBuffer(oprid, ", %s)", name);
10268         }
10269         else
10270                 appendPQExpBuffer(oprid, ", NONE)");
10271
10272         name = convertOperatorReference(fout, oprcom);
10273         if (name)
10274                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
10275
10276         name = convertOperatorReference(fout, oprnegate);
10277         if (name)
10278                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
10279
10280         if (strcmp(oprcanmerge, "t") == 0)
10281                 appendPQExpBuffer(details, ",\n    MERGES");
10282
10283         if (strcmp(oprcanhash, "t") == 0)
10284                 appendPQExpBuffer(details, ",\n    HASHES");
10285
10286         name = convertRegProcReference(fout, oprrest);
10287         if (name)
10288                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
10289
10290         name = convertRegProcReference(fout, oprjoin);
10291         if (name)
10292                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
10293
10294         /*
10295          * DROP must be fully qualified in case same name appears in pg_catalog
10296          */
10297         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10298                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10299                                           oprid->data);
10300
10301         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10302                                           oprinfo->dobj.name, details->data);
10303
10304         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10305
10306         if (binary_upgrade)
10307                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10308
10309         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10310                                  oprinfo->dobj.name,
10311                                  oprinfo->dobj.namespace->dobj.name,
10312                                  NULL,
10313                                  oprinfo->rolname,
10314                                  false, "OPERATOR", SECTION_PRE_DATA,
10315                                  q->data, delq->data, NULL,
10316                                  NULL, 0,
10317                                  NULL, NULL);
10318
10319         /* Dump Operator Comments */
10320         dumpComment(fout, labelq->data,
10321                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10322                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10323
10324         PQclear(res);
10325
10326         destroyPQExpBuffer(query);
10327         destroyPQExpBuffer(q);
10328         destroyPQExpBuffer(delq);
10329         destroyPQExpBuffer(labelq);
10330         destroyPQExpBuffer(oprid);
10331         destroyPQExpBuffer(details);
10332 }
10333
10334 /*
10335  * Convert a function reference obtained from pg_operator
10336  *
10337  * Returns what to print, or NULL if function references is InvalidOid
10338  *
10339  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10340  * argument-types part.  In prior versions, the input is a REGPROC display.
10341  */
10342 static const char *
10343 convertRegProcReference(Archive *fout, const char *proc)
10344 {
10345         /* In all cases "-" means a null reference */
10346         if (strcmp(proc, "-") == 0)
10347                 return NULL;
10348
10349         if (fout->remoteVersion >= 70300)
10350         {
10351                 char       *name;
10352                 char       *paren;
10353                 bool            inquote;
10354
10355                 name = pg_strdup(proc);
10356                 /* find non-double-quoted left paren */
10357                 inquote = false;
10358                 for (paren = name; *paren; paren++)
10359                 {
10360                         if (*paren == '(' && !inquote)
10361                         {
10362                                 *paren = '\0';
10363                                 break;
10364                         }
10365                         if (*paren == '"')
10366                                 inquote = !inquote;
10367                 }
10368                 return name;
10369         }
10370
10371         /* REGPROC before 7.3 does not quote its result */
10372         return fmtId(proc);
10373 }
10374
10375 /*
10376  * Convert an operator cross-reference obtained from pg_operator
10377  *
10378  * Returns what to print, or NULL to print nothing
10379  *
10380  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10381  * argument-types part, and add OPERATOR() decoration if the name is
10382  * schema-qualified.  In older versions, the input is just a numeric OID,
10383  * which we search our operator list for.
10384  */
10385 static const char *
10386 convertOperatorReference(Archive *fout, const char *opr)
10387 {
10388         OprInfo    *oprInfo;
10389
10390         /* In all cases "0" means a null reference */
10391         if (strcmp(opr, "0") == 0)
10392                 return NULL;
10393
10394         if (fout->remoteVersion >= 70300)
10395         {
10396                 char       *name;
10397                 char       *oname;
10398                 char       *ptr;
10399                 bool            inquote;
10400                 bool            sawdot;
10401
10402                 name = pg_strdup(opr);
10403                 /* find non-double-quoted left paren, and check for non-quoted dot */
10404                 inquote = false;
10405                 sawdot = false;
10406                 for (ptr = name; *ptr; ptr++)
10407                 {
10408                         if (*ptr == '"')
10409                                 inquote = !inquote;
10410                         else if (*ptr == '.' && !inquote)
10411                                 sawdot = true;
10412                         else if (*ptr == '(' && !inquote)
10413                         {
10414                                 *ptr = '\0';
10415                                 break;
10416                         }
10417                 }
10418                 /* If not schema-qualified, don't need to add OPERATOR() */
10419                 if (!sawdot)
10420                         return name;
10421                 oname = pg_malloc(strlen(name) + 11);
10422                 sprintf(oname, "OPERATOR(%s)", name);
10423                 free(name);
10424                 return oname;
10425         }
10426
10427         oprInfo = findOprByOid(atooid(opr));
10428         if (oprInfo == NULL)
10429         {
10430                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10431                                   opr);
10432                 return NULL;
10433         }
10434         return oprInfo->dobj.name;
10435 }
10436
10437 /*
10438  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10439  *
10440  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10441  * argument lists of these functions are predetermined.  Note that the
10442  * caller should ensure we are in the proper schema, because the results
10443  * are search path dependent!
10444  */
10445 static const char *
10446 convertTSFunction(Archive *fout, Oid funcOid)
10447 {
10448         char       *result;
10449         char            query[128];
10450         PGresult   *res;
10451
10452         snprintf(query, sizeof(query),
10453                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10454         res = ExecuteSqlQueryForSingleRow(fout, query);
10455
10456         result = pg_strdup(PQgetvalue(res, 0, 0));
10457
10458         PQclear(res);
10459
10460         return result;
10461 }
10462
10463
10464 /*
10465  * dumpOpclass
10466  *        write out a single operator class definition
10467  */
10468 static void
10469 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
10470 {
10471         PQExpBuffer query;
10472         PQExpBuffer q;
10473         PQExpBuffer delq;
10474         PQExpBuffer labelq;
10475         PGresult   *res;
10476         int                     ntups;
10477         int                     i_opcintype;
10478         int                     i_opckeytype;
10479         int                     i_opcdefault;
10480         int                     i_opcfamily;
10481         int                     i_opcfamilyname;
10482         int                     i_opcfamilynsp;
10483         int                     i_amname;
10484         int                     i_amopstrategy;
10485         int                     i_amopreqcheck;
10486         int                     i_amopopr;
10487         int                     i_sortfamily;
10488         int                     i_sortfamilynsp;
10489         int                     i_amprocnum;
10490         int                     i_amproc;
10491         int                     i_amproclefttype;
10492         int                     i_amprocrighttype;
10493         char       *opcintype;
10494         char       *opckeytype;
10495         char       *opcdefault;
10496         char       *opcfamily;
10497         char       *opcfamilyname;
10498         char       *opcfamilynsp;
10499         char       *amname;
10500         char       *amopstrategy;
10501         char       *amopreqcheck;
10502         char       *amopopr;
10503         char       *sortfamily;
10504         char       *sortfamilynsp;
10505         char       *amprocnum;
10506         char       *amproc;
10507         char       *amproclefttype;
10508         char       *amprocrighttype;
10509         bool            needComma;
10510         int                     i;
10511
10512         /* Skip if not to be dumped */
10513         if (!opcinfo->dobj.dump || dataOnly)
10514                 return;
10515
10516         /*
10517          * XXX currently we do not implement dumping of operator classes from
10518          * pre-7.3 databases.  This could be done but it seems not worth the
10519          * trouble.
10520          */
10521         if (fout->remoteVersion < 70300)
10522                 return;
10523
10524         query = createPQExpBuffer();
10525         q = createPQExpBuffer();
10526         delq = createPQExpBuffer();
10527         labelq = createPQExpBuffer();
10528
10529         /* Make sure we are in proper schema so regoperator works correctly */
10530         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
10531
10532         /* Get additional fields from the pg_opclass row */
10533         if (fout->remoteVersion >= 80300)
10534         {
10535                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10536                                                   "opckeytype::pg_catalog.regtype, "
10537                                                   "opcdefault, opcfamily, "
10538                                                   "opfname AS opcfamilyname, "
10539                                                   "nspname AS opcfamilynsp, "
10540                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
10541                                                   "FROM pg_catalog.pg_opclass c "
10542                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
10543                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10544                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
10545                                                   opcinfo->dobj.catId.oid);
10546         }
10547         else
10548         {
10549                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
10550                                                   "opckeytype::pg_catalog.regtype, "
10551                                                   "opcdefault, NULL AS opcfamily, "
10552                                                   "NULL AS opcfamilyname, "
10553                                                   "NULL AS opcfamilynsp, "
10554                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
10555                                                   "FROM pg_catalog.pg_opclass "
10556                                                   "WHERE oid = '%u'::pg_catalog.oid",
10557                                                   opcinfo->dobj.catId.oid);
10558         }
10559
10560         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10561
10562         i_opcintype = PQfnumber(res, "opcintype");
10563         i_opckeytype = PQfnumber(res, "opckeytype");
10564         i_opcdefault = PQfnumber(res, "opcdefault");
10565         i_opcfamily = PQfnumber(res, "opcfamily");
10566         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
10567         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
10568         i_amname = PQfnumber(res, "amname");
10569
10570         opcintype = PQgetvalue(res, 0, i_opcintype);
10571         opckeytype = PQgetvalue(res, 0, i_opckeytype);
10572         opcdefault = PQgetvalue(res, 0, i_opcdefault);
10573         /* opcfamily will still be needed after we PQclear res */
10574         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
10575         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
10576         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
10577         /* amname will still be needed after we PQclear res */
10578         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
10579
10580         /*
10581          * DROP must be fully qualified in case same name appears in pg_catalog
10582          */
10583         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
10584                                           fmtId(opcinfo->dobj.namespace->dobj.name));
10585         appendPQExpBuffer(delq, ".%s",
10586                                           fmtId(opcinfo->dobj.name));
10587         appendPQExpBuffer(delq, " USING %s;\n",
10588                                           fmtId(amname));
10589
10590         /* Build the fixed portion of the CREATE command */
10591         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
10592                                           fmtId(opcinfo->dobj.name));
10593         if (strcmp(opcdefault, "t") == 0)
10594                 appendPQExpBuffer(q, "DEFAULT ");
10595         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
10596                                           opcintype,
10597                                           fmtId(amname));
10598         if (strlen(opcfamilyname) > 0 &&
10599                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
10600                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
10601         {
10602                 appendPQExpBuffer(q, " FAMILY ");
10603                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10604                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
10605                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
10606         }
10607         appendPQExpBuffer(q, " AS\n    ");
10608
10609         needComma = false;
10610
10611         if (strcmp(opckeytype, "-") != 0)
10612         {
10613                 appendPQExpBuffer(q, "STORAGE %s",
10614                                                   opckeytype);
10615                 needComma = true;
10616         }
10617
10618         PQclear(res);
10619
10620         /*
10621          * Now fetch and print the OPERATOR entries (pg_amop rows).
10622          *
10623          * Print only those opfamily members that are tied to the opclass by
10624          * pg_depend entries.
10625          *
10626          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10627          * older server's opclass in which it is used.  This is to avoid
10628          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10629          * older server and then reload into that old version.  This can go away
10630          * once 8.3 is so old as to not be of interest to anyone.
10631          */
10632         resetPQExpBuffer(query);
10633
10634         if (fout->remoteVersion >= 90100)
10635         {
10636                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10637                                                   "amopopr::pg_catalog.regoperator, "
10638                                                   "opfname AS sortfamily, "
10639                                                   "nspname AS sortfamilynsp "
10640                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10641                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10642                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10643                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10644                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10645                                                   "AND refobjid = '%u'::pg_catalog.oid "
10646                                                   "AND amopfamily = '%s'::pg_catalog.oid "
10647                                                   "ORDER BY amopstrategy",
10648                                                   opcinfo->dobj.catId.oid,
10649                                                   opcfamily);
10650         }
10651         else if (fout->remoteVersion >= 80400)
10652         {
10653                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10654                                                   "amopopr::pg_catalog.regoperator, "
10655                                                   "NULL AS sortfamily, "
10656                                                   "NULL AS sortfamilynsp "
10657                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10658                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10659                                                   "AND refobjid = '%u'::pg_catalog.oid "
10660                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10661                                                   "AND objid = ao.oid "
10662                                                   "ORDER BY amopstrategy",
10663                                                   opcinfo->dobj.catId.oid);
10664         }
10665         else if (fout->remoteVersion >= 80300)
10666         {
10667                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10668                                                   "amopopr::pg_catalog.regoperator, "
10669                                                   "NULL AS sortfamily, "
10670                                                   "NULL AS sortfamilynsp "
10671                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10672                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10673                                                   "AND refobjid = '%u'::pg_catalog.oid "
10674                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10675                                                   "AND objid = ao.oid "
10676                                                   "ORDER BY amopstrategy",
10677                                                   opcinfo->dobj.catId.oid);
10678         }
10679         else
10680         {
10681                 /*
10682                  * Here, we print all entries since there are no opfamilies and hence
10683                  * no loose operators to worry about.
10684                  */
10685                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10686                                                   "amopopr::pg_catalog.regoperator, "
10687                                                   "NULL AS sortfamily, "
10688                                                   "NULL AS sortfamilynsp "
10689                                                   "FROM pg_catalog.pg_amop "
10690                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10691                                                   "ORDER BY amopstrategy",
10692                                                   opcinfo->dobj.catId.oid);
10693         }
10694
10695         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10696
10697         ntups = PQntuples(res);
10698
10699         i_amopstrategy = PQfnumber(res, "amopstrategy");
10700         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
10701         i_amopopr = PQfnumber(res, "amopopr");
10702         i_sortfamily = PQfnumber(res, "sortfamily");
10703         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
10704
10705         for (i = 0; i < ntups; i++)
10706         {
10707                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
10708                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
10709                 amopopr = PQgetvalue(res, i, i_amopopr);
10710                 sortfamily = PQgetvalue(res, i, i_sortfamily);
10711                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
10712
10713                 if (needComma)
10714                         appendPQExpBuffer(q, " ,\n    ");
10715
10716                 appendPQExpBuffer(q, "OPERATOR %s %s",
10717                                                   amopstrategy, amopopr);
10718
10719                 if (strlen(sortfamily) > 0)
10720                 {
10721                         appendPQExpBuffer(q, " FOR ORDER BY ");
10722                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
10723                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
10724                         appendPQExpBuffer(q, "%s", fmtId(sortfamily));
10725                 }
10726
10727                 if (strcmp(amopreqcheck, "t") == 0)
10728                         appendPQExpBuffer(q, " RECHECK");
10729
10730                 needComma = true;
10731         }
10732
10733         PQclear(res);
10734
10735         /*
10736          * Now fetch and print the FUNCTION entries (pg_amproc rows).
10737          *
10738          * Print only those opfamily members that are tied to the opclass by
10739          * pg_depend entries.
10740          *
10741          * We print the amproclefttype/amprocrighttype even though in most cases
10742          * the backend could deduce the right values, because of the corner case
10743          * of a btree sort support function for a cross-type comparison.  That's
10744          * only allowed in 9.2 and later, but for simplicity print them in all
10745          * versions that have the columns.
10746          */
10747         resetPQExpBuffer(query);
10748
10749         if (fout->remoteVersion >= 80300)
10750         {
10751                 appendPQExpBuffer(query, "SELECT amprocnum, "
10752                                                   "amproc::pg_catalog.regprocedure, "
10753                                                   "amproclefttype::pg_catalog.regtype, "
10754                                                   "amprocrighttype::pg_catalog.regtype "
10755                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10756                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10757                                                   "AND refobjid = '%u'::pg_catalog.oid "
10758                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10759                                                   "AND objid = ap.oid "
10760                                                   "ORDER BY amprocnum",
10761                                                   opcinfo->dobj.catId.oid);
10762         }
10763         else
10764         {
10765                 appendPQExpBuffer(query, "SELECT amprocnum, "
10766                                                   "amproc::pg_catalog.regprocedure, "
10767                                                   "'' AS amproclefttype, "
10768                                                   "'' AS amprocrighttype "
10769                                                   "FROM pg_catalog.pg_amproc "
10770                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
10771                                                   "ORDER BY amprocnum",
10772                                                   opcinfo->dobj.catId.oid);
10773         }
10774
10775         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10776
10777         ntups = PQntuples(res);
10778
10779         i_amprocnum = PQfnumber(res, "amprocnum");
10780         i_amproc = PQfnumber(res, "amproc");
10781         i_amproclefttype = PQfnumber(res, "amproclefttype");
10782         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
10783
10784         for (i = 0; i < ntups; i++)
10785         {
10786                 amprocnum = PQgetvalue(res, i, i_amprocnum);
10787                 amproc = PQgetvalue(res, i, i_amproc);
10788                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
10789                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
10790
10791                 if (needComma)
10792                         appendPQExpBuffer(q, " ,\n    ");
10793
10794                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
10795
10796                 if (*amproclefttype && *amprocrighttype)
10797                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
10798
10799                 appendPQExpBuffer(q, " %s", amproc);
10800
10801                 needComma = true;
10802         }
10803
10804         PQclear(res);
10805
10806         appendPQExpBuffer(q, ";\n");
10807
10808         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
10809                                           fmtId(opcinfo->dobj.name));
10810         appendPQExpBuffer(labelq, " USING %s",
10811                                           fmtId(amname));
10812
10813         if (binary_upgrade)
10814                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
10815
10816         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
10817                                  opcinfo->dobj.name,
10818                                  opcinfo->dobj.namespace->dobj.name,
10819                                  NULL,
10820                                  opcinfo->rolname,
10821                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
10822                                  q->data, delq->data, NULL,
10823                                  NULL, 0,
10824                                  NULL, NULL);
10825
10826         /* Dump Operator Class Comments */
10827         dumpComment(fout, labelq->data,
10828                                 NULL, opcinfo->rolname,
10829                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
10830
10831         free(amname);
10832         destroyPQExpBuffer(query);
10833         destroyPQExpBuffer(q);
10834         destroyPQExpBuffer(delq);
10835         destroyPQExpBuffer(labelq);
10836 }
10837
10838 /*
10839  * dumpOpfamily
10840  *        write out a single operator family definition
10841  *
10842  * Note: this also dumps any "loose" operator members that aren't bound to a
10843  * specific opclass within the opfamily.
10844  */
10845 static void
10846 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
10847 {
10848         PQExpBuffer query;
10849         PQExpBuffer q;
10850         PQExpBuffer delq;
10851         PQExpBuffer labelq;
10852         PGresult   *res;
10853         PGresult   *res_ops;
10854         PGresult   *res_procs;
10855         int                     ntups;
10856         int                     i_amname;
10857         int                     i_amopstrategy;
10858         int                     i_amopreqcheck;
10859         int                     i_amopopr;
10860         int                     i_sortfamily;
10861         int                     i_sortfamilynsp;
10862         int                     i_amprocnum;
10863         int                     i_amproc;
10864         int                     i_amproclefttype;
10865         int                     i_amprocrighttype;
10866         char       *amname;
10867         char       *amopstrategy;
10868         char       *amopreqcheck;
10869         char       *amopopr;
10870         char       *sortfamily;
10871         char       *sortfamilynsp;
10872         char       *amprocnum;
10873         char       *amproc;
10874         char       *amproclefttype;
10875         char       *amprocrighttype;
10876         bool            needComma;
10877         int                     i;
10878
10879         /* Skip if not to be dumped */
10880         if (!opfinfo->dobj.dump || dataOnly)
10881                 return;
10882
10883         /*
10884          * We want to dump the opfamily only if (1) it contains "loose" operators
10885          * or functions, or (2) it contains an opclass with a different name or
10886          * owner.  Otherwise it's sufficient to let it be created during creation
10887          * of the contained opclass, and not dumping it improves portability of
10888          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
10889          * that first.
10890          */
10891
10892         query = createPQExpBuffer();
10893         q = createPQExpBuffer();
10894         delq = createPQExpBuffer();
10895         labelq = createPQExpBuffer();
10896
10897         /* Make sure we are in proper schema so regoperator works correctly */
10898         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
10899
10900         /*
10901          * Fetch only those opfamily members that are tied directly to the
10902          * opfamily by pg_depend entries.
10903          *
10904          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
10905          * older server's opclass in which it is used.  This is to avoid
10906          * hard-to-detect breakage if a newer pg_dump is used to dump from an
10907          * older server and then reload into that old version.  This can go away
10908          * once 8.3 is so old as to not be of interest to anyone.
10909          */
10910         if (fout->remoteVersion >= 90100)
10911         {
10912                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10913                                                   "amopopr::pg_catalog.regoperator, "
10914                                                   "opfname AS sortfamily, "
10915                                                   "nspname AS sortfamilynsp "
10916                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
10917                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
10918                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
10919                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
10920                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10921                                                   "AND refobjid = '%u'::pg_catalog.oid "
10922                                                   "AND amopfamily = '%u'::pg_catalog.oid "
10923                                                   "ORDER BY amopstrategy",
10924                                                   opfinfo->dobj.catId.oid,
10925                                                   opfinfo->dobj.catId.oid);
10926         }
10927         else if (fout->remoteVersion >= 80400)
10928         {
10929                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
10930                                                   "amopopr::pg_catalog.regoperator, "
10931                                                   "NULL AS sortfamily, "
10932                                                   "NULL AS sortfamilynsp "
10933                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10934                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10935                                                   "AND refobjid = '%u'::pg_catalog.oid "
10936                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10937                                                   "AND objid = ao.oid "
10938                                                   "ORDER BY amopstrategy",
10939                                                   opfinfo->dobj.catId.oid);
10940         }
10941         else
10942         {
10943                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
10944                                                   "amopopr::pg_catalog.regoperator, "
10945                                                   "NULL AS sortfamily, "
10946                                                   "NULL AS sortfamilynsp "
10947                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
10948                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10949                                                   "AND refobjid = '%u'::pg_catalog.oid "
10950                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
10951                                                   "AND objid = ao.oid "
10952                                                   "ORDER BY amopstrategy",
10953                                                   opfinfo->dobj.catId.oid);
10954         }
10955
10956         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10957
10958         resetPQExpBuffer(query);
10959
10960         appendPQExpBuffer(query, "SELECT amprocnum, "
10961                                           "amproc::pg_catalog.regprocedure, "
10962                                           "amproclefttype::pg_catalog.regtype, "
10963                                           "amprocrighttype::pg_catalog.regtype "
10964                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
10965                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10966                                           "AND refobjid = '%u'::pg_catalog.oid "
10967                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
10968                                           "AND objid = ap.oid "
10969                                           "ORDER BY amprocnum",
10970                                           opfinfo->dobj.catId.oid);
10971
10972         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10973
10974         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
10975         {
10976                 /* No loose members, so check contained opclasses */
10977                 resetPQExpBuffer(query);
10978
10979                 appendPQExpBuffer(query, "SELECT 1 "
10980                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
10981                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
10982                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
10983                                                   "AND refobjid = f.oid "
10984                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
10985                                                   "AND objid = c.oid "
10986                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
10987                                                   "LIMIT 1",
10988                                                   opfinfo->dobj.catId.oid);
10989
10990                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10991
10992                 if (PQntuples(res) == 0)
10993                 {
10994                         /* no need to dump it, so bail out */
10995                         PQclear(res);
10996                         PQclear(res_ops);
10997                         PQclear(res_procs);
10998                         destroyPQExpBuffer(query);
10999                         destroyPQExpBuffer(q);
11000                         destroyPQExpBuffer(delq);
11001                         destroyPQExpBuffer(labelq);
11002                         return;
11003                 }
11004
11005                 PQclear(res);
11006         }
11007
11008         /* Get additional fields from the pg_opfamily row */
11009         resetPQExpBuffer(query);
11010
11011         appendPQExpBuffer(query, "SELECT "
11012          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11013                                           "FROM pg_catalog.pg_opfamily "
11014                                           "WHERE oid = '%u'::pg_catalog.oid",
11015                                           opfinfo->dobj.catId.oid);
11016
11017         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11018
11019         i_amname = PQfnumber(res, "amname");
11020
11021         /* amname will still be needed after we PQclear res */
11022         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11023
11024         /*
11025          * DROP must be fully qualified in case same name appears in pg_catalog
11026          */
11027         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11028                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11029         appendPQExpBuffer(delq, ".%s",
11030                                           fmtId(opfinfo->dobj.name));
11031         appendPQExpBuffer(delq, " USING %s;\n",
11032                                           fmtId(amname));
11033
11034         /* Build the fixed portion of the CREATE command */
11035         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11036                                           fmtId(opfinfo->dobj.name));
11037         appendPQExpBuffer(q, " USING %s;\n",
11038                                           fmtId(amname));
11039
11040         PQclear(res);
11041
11042         /* Do we need an ALTER to add loose members? */
11043         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11044         {
11045                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11046                                                   fmtId(opfinfo->dobj.name));
11047                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11048                                                   fmtId(amname));
11049
11050                 needComma = false;
11051
11052                 /*
11053                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11054                  */
11055                 ntups = PQntuples(res_ops);
11056
11057                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11058                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11059                 i_amopopr = PQfnumber(res_ops, "amopopr");
11060                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11061                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11062
11063                 for (i = 0; i < ntups; i++)
11064                 {
11065                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11066                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11067                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11068                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11069                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11070
11071                         if (needComma)
11072                                 appendPQExpBuffer(q, " ,\n    ");
11073
11074                         appendPQExpBuffer(q, "OPERATOR %s %s",
11075                                                           amopstrategy, amopopr);
11076
11077                         if (strlen(sortfamily) > 0)
11078                         {
11079                                 appendPQExpBuffer(q, " FOR ORDER BY ");
11080                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11081                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11082                                 appendPQExpBuffer(q, "%s", fmtId(sortfamily));
11083                         }
11084
11085                         if (strcmp(amopreqcheck, "t") == 0)
11086                                 appendPQExpBuffer(q, " RECHECK");
11087
11088                         needComma = true;
11089                 }
11090
11091                 /*
11092                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11093                  */
11094                 ntups = PQntuples(res_procs);
11095
11096                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11097                 i_amproc = PQfnumber(res_procs, "amproc");
11098                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11099                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11100
11101                 for (i = 0; i < ntups; i++)
11102                 {
11103                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11104                         amproc = PQgetvalue(res_procs, i, i_amproc);
11105                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11106                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11107
11108                         if (needComma)
11109                                 appendPQExpBuffer(q, " ,\n    ");
11110
11111                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11112                                                           amprocnum, amproclefttype, amprocrighttype,
11113                                                           amproc);
11114
11115                         needComma = true;
11116                 }
11117
11118                 appendPQExpBuffer(q, ";\n");
11119         }
11120
11121         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11122                                           fmtId(opfinfo->dobj.name));
11123         appendPQExpBuffer(labelq, " USING %s",
11124                                           fmtId(amname));
11125
11126         if (binary_upgrade)
11127                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11128
11129         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11130                                  opfinfo->dobj.name,
11131                                  opfinfo->dobj.namespace->dobj.name,
11132                                  NULL,
11133                                  opfinfo->rolname,
11134                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11135                                  q->data, delq->data, NULL,
11136                                  NULL, 0,
11137                                  NULL, NULL);
11138
11139         /* Dump Operator Family Comments */
11140         dumpComment(fout, labelq->data,
11141                                 NULL, opfinfo->rolname,
11142                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11143
11144         free(amname);
11145         PQclear(res_ops);
11146         PQclear(res_procs);
11147         destroyPQExpBuffer(query);
11148         destroyPQExpBuffer(q);
11149         destroyPQExpBuffer(delq);
11150         destroyPQExpBuffer(labelq);
11151 }
11152
11153 /*
11154  * dumpCollation
11155  *        write out a single collation definition
11156  */
11157 static void
11158 dumpCollation(Archive *fout, CollInfo *collinfo)
11159 {
11160         PQExpBuffer query;
11161         PQExpBuffer q;
11162         PQExpBuffer delq;
11163         PQExpBuffer labelq;
11164         PGresult   *res;
11165         int                     i_collcollate;
11166         int                     i_collctype;
11167         const char *collcollate;
11168         const char *collctype;
11169
11170         /* Skip if not to be dumped */
11171         if (!collinfo->dobj.dump || dataOnly)
11172                 return;
11173
11174         query = createPQExpBuffer();
11175         q = createPQExpBuffer();
11176         delq = createPQExpBuffer();
11177         labelq = createPQExpBuffer();
11178
11179         /* Make sure we are in proper schema */
11180         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11181
11182         /* Get conversion-specific details */
11183         appendPQExpBuffer(query, "SELECT "
11184                                           "collcollate, "
11185                                           "collctype "
11186                                           "FROM pg_catalog.pg_collation c "
11187                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11188                                           collinfo->dobj.catId.oid);
11189
11190         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11191
11192         i_collcollate = PQfnumber(res, "collcollate");
11193         i_collctype = PQfnumber(res, "collctype");
11194
11195         collcollate = PQgetvalue(res, 0, i_collcollate);
11196         collctype = PQgetvalue(res, 0, i_collctype);
11197
11198         /*
11199          * DROP must be fully qualified in case same name appears in pg_catalog
11200          */
11201         appendPQExpBuffer(delq, "DROP COLLATION %s",
11202                                           fmtId(collinfo->dobj.namespace->dobj.name));
11203         appendPQExpBuffer(delq, ".%s;\n",
11204                                           fmtId(collinfo->dobj.name));
11205
11206         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11207                                           fmtId(collinfo->dobj.name));
11208         appendStringLiteralAH(q, collcollate, fout);
11209         appendPQExpBuffer(q, ", lc_ctype = ");
11210         appendStringLiteralAH(q, collctype, fout);
11211         appendPQExpBuffer(q, ");\n");
11212
11213         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11214
11215         if (binary_upgrade)
11216                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11217
11218         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11219                                  collinfo->dobj.name,
11220                                  collinfo->dobj.namespace->dobj.name,
11221                                  NULL,
11222                                  collinfo->rolname,
11223                                  false, "COLLATION", SECTION_PRE_DATA,
11224                                  q->data, delq->data, NULL,
11225                                  NULL, 0,
11226                                  NULL, NULL);
11227
11228         /* Dump Collation Comments */
11229         dumpComment(fout, labelq->data,
11230                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11231                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11232
11233         PQclear(res);
11234
11235         destroyPQExpBuffer(query);
11236         destroyPQExpBuffer(q);
11237         destroyPQExpBuffer(delq);
11238         destroyPQExpBuffer(labelq);
11239 }
11240
11241 /*
11242  * dumpConversion
11243  *        write out a single conversion definition
11244  */
11245 static void
11246 dumpConversion(Archive *fout, ConvInfo *convinfo)
11247 {
11248         PQExpBuffer query;
11249         PQExpBuffer q;
11250         PQExpBuffer delq;
11251         PQExpBuffer labelq;
11252         PGresult   *res;
11253         int                     i_conforencoding;
11254         int                     i_contoencoding;
11255         int                     i_conproc;
11256         int                     i_condefault;
11257         const char *conforencoding;
11258         const char *contoencoding;
11259         const char *conproc;
11260         bool            condefault;
11261
11262         /* Skip if not to be dumped */
11263         if (!convinfo->dobj.dump || dataOnly)
11264                 return;
11265
11266         query = createPQExpBuffer();
11267         q = createPQExpBuffer();
11268         delq = createPQExpBuffer();
11269         labelq = createPQExpBuffer();
11270
11271         /* Make sure we are in proper schema */
11272         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11273
11274         /* Get conversion-specific details */
11275         appendPQExpBuffer(query, "SELECT "
11276                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11277                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11278                                           "conproc, condefault "
11279                                           "FROM pg_catalog.pg_conversion c "
11280                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11281                                           convinfo->dobj.catId.oid);
11282
11283         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11284
11285         i_conforencoding = PQfnumber(res, "conforencoding");
11286         i_contoencoding = PQfnumber(res, "contoencoding");
11287         i_conproc = PQfnumber(res, "conproc");
11288         i_condefault = PQfnumber(res, "condefault");
11289
11290         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11291         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11292         conproc = PQgetvalue(res, 0, i_conproc);
11293         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11294
11295         /*
11296          * DROP must be fully qualified in case same name appears in pg_catalog
11297          */
11298         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11299                                           fmtId(convinfo->dobj.namespace->dobj.name));
11300         appendPQExpBuffer(delq, ".%s;\n",
11301                                           fmtId(convinfo->dobj.name));
11302
11303         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11304                                           (condefault) ? "DEFAULT " : "",
11305                                           fmtId(convinfo->dobj.name));
11306         appendStringLiteralAH(q, conforencoding, fout);
11307         appendPQExpBuffer(q, " TO ");
11308         appendStringLiteralAH(q, contoencoding, fout);
11309         /* regproc is automatically quoted in 7.3 and above */
11310         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11311
11312         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11313
11314         if (binary_upgrade)
11315                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11316
11317         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11318                                  convinfo->dobj.name,
11319                                  convinfo->dobj.namespace->dobj.name,
11320                                  NULL,
11321                                  convinfo->rolname,
11322                                  false, "CONVERSION", SECTION_PRE_DATA,
11323                                  q->data, delq->data, NULL,
11324                                  NULL, 0,
11325                                  NULL, NULL);
11326
11327         /* Dump Conversion Comments */
11328         dumpComment(fout, labelq->data,
11329                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11330                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11331
11332         PQclear(res);
11333
11334         destroyPQExpBuffer(query);
11335         destroyPQExpBuffer(q);
11336         destroyPQExpBuffer(delq);
11337         destroyPQExpBuffer(labelq);
11338 }
11339
11340 /*
11341  * format_aggregate_signature: generate aggregate name and argument list
11342  *
11343  * The argument type names are qualified if needed.  The aggregate name
11344  * is never qualified.
11345  */
11346 static char *
11347 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11348 {
11349         PQExpBufferData buf;
11350         int                     j;
11351
11352         initPQExpBuffer(&buf);
11353         if (honor_quotes)
11354                 appendPQExpBuffer(&buf, "%s",
11355                                                   fmtId(agginfo->aggfn.dobj.name));
11356         else
11357                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
11358
11359         if (agginfo->aggfn.nargs == 0)
11360                 appendPQExpBuffer(&buf, "(*)");
11361         else
11362         {
11363                 appendPQExpBuffer(&buf, "(");
11364                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11365                 {
11366                         char       *typname;
11367
11368                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11369                                                                                    zeroAsOpaque);
11370
11371                         appendPQExpBuffer(&buf, "%s%s",
11372                                                           (j > 0) ? ", " : "",
11373                                                           typname);
11374                         free(typname);
11375                 }
11376                 appendPQExpBuffer(&buf, ")");
11377         }
11378         return buf.data;
11379 }
11380
11381 /*
11382  * dumpAgg
11383  *        write out a single aggregate definition
11384  */
11385 static void
11386 dumpAgg(Archive *fout, AggInfo *agginfo)
11387 {
11388         PQExpBuffer query;
11389         PQExpBuffer q;
11390         PQExpBuffer delq;
11391         PQExpBuffer labelq;
11392         PQExpBuffer details;
11393         char       *aggsig;
11394         char       *aggsig_tag;
11395         PGresult   *res;
11396         int                     i_aggtransfn;
11397         int                     i_aggfinalfn;
11398         int                     i_aggsortop;
11399         int                     i_aggtranstype;
11400         int                     i_agginitval;
11401         int                     i_convertok;
11402         const char *aggtransfn;
11403         const char *aggfinalfn;
11404         const char *aggsortop;
11405         const char *aggtranstype;
11406         const char *agginitval;
11407         bool            convertok;
11408
11409         /* Skip if not to be dumped */
11410         if (!agginfo->aggfn.dobj.dump || dataOnly)
11411                 return;
11412
11413         query = createPQExpBuffer();
11414         q = createPQExpBuffer();
11415         delq = createPQExpBuffer();
11416         labelq = createPQExpBuffer();
11417         details = createPQExpBuffer();
11418
11419         /* Make sure we are in proper schema */
11420         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11421
11422         /* Get aggregate-specific details */
11423         if (fout->remoteVersion >= 80100)
11424         {
11425                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11426                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11427                                                   "aggsortop::pg_catalog.regoperator, "
11428                                                   "agginitval, "
11429                                                   "'t'::boolean AS convertok "
11430                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11431                                                   "WHERE a.aggfnoid = p.oid "
11432                                                   "AND p.oid = '%u'::pg_catalog.oid",
11433                                                   agginfo->aggfn.dobj.catId.oid);
11434         }
11435         else if (fout->remoteVersion >= 70300)
11436         {
11437                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11438                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11439                                                   "0 AS aggsortop, "
11440                                                   "agginitval, "
11441                                                   "'t'::boolean AS convertok "
11442                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11443                                                   "WHERE a.aggfnoid = p.oid "
11444                                                   "AND p.oid = '%u'::pg_catalog.oid",
11445                                                   agginfo->aggfn.dobj.catId.oid);
11446         }
11447         else if (fout->remoteVersion >= 70100)
11448         {
11449                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
11450                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
11451                                                   "0 AS aggsortop, "
11452                                                   "agginitval, "
11453                                                   "'t'::boolean AS convertok "
11454                                                   "FROM pg_aggregate "
11455                                                   "WHERE oid = '%u'::oid",
11456                                                   agginfo->aggfn.dobj.catId.oid);
11457         }
11458         else
11459         {
11460                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
11461                                                   "aggfinalfn, "
11462                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
11463                                                   "0 AS aggsortop, "
11464                                                   "agginitval1 AS agginitval, "
11465                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
11466                                                   "FROM pg_aggregate "
11467                                                   "WHERE oid = '%u'::oid",
11468                                                   agginfo->aggfn.dobj.catId.oid);
11469         }
11470
11471         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11472
11473         i_aggtransfn = PQfnumber(res, "aggtransfn");
11474         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
11475         i_aggsortop = PQfnumber(res, "aggsortop");
11476         i_aggtranstype = PQfnumber(res, "aggtranstype");
11477         i_agginitval = PQfnumber(res, "agginitval");
11478         i_convertok = PQfnumber(res, "convertok");
11479
11480         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
11481         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
11482         aggsortop = PQgetvalue(res, 0, i_aggsortop);
11483         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
11484         agginitval = PQgetvalue(res, 0, i_agginitval);
11485         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
11486
11487         aggsig = format_aggregate_signature(agginfo, fout, true);
11488         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
11489
11490         if (!convertok)
11491         {
11492                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
11493                                   aggsig);
11494                 return;
11495         }
11496
11497         if (fout->remoteVersion >= 70300)
11498         {
11499                 /* If using 7.3's regproc or regtype, data is already quoted */
11500                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11501                                                   aggtransfn,
11502                                                   aggtranstype);
11503         }
11504         else if (fout->remoteVersion >= 70100)
11505         {
11506                 /* format_type quotes, regproc does not */
11507                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
11508                                                   fmtId(aggtransfn),
11509                                                   aggtranstype);
11510         }
11511         else
11512         {
11513                 /* need quotes all around */
11514                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
11515                                                   fmtId(aggtransfn));
11516                 appendPQExpBuffer(details, "    STYPE = %s",
11517                                                   fmtId(aggtranstype));
11518         }
11519
11520         if (!PQgetisnull(res, 0, i_agginitval))
11521         {
11522                 appendPQExpBuffer(details, ",\n    INITCOND = ");
11523                 appendStringLiteralAH(details, agginitval, fout);
11524         }
11525
11526         if (strcmp(aggfinalfn, "-") != 0)
11527         {
11528                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
11529                                                   aggfinalfn);
11530         }
11531
11532         aggsortop = convertOperatorReference(fout, aggsortop);
11533         if (aggsortop)
11534         {
11535                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
11536                                                   aggsortop);
11537         }
11538
11539         /*
11540          * DROP must be fully qualified in case same name appears in pg_catalog
11541          */
11542         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
11543                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
11544                                           aggsig);
11545
11546         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
11547                                           aggsig, details->data);
11548
11549         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
11550
11551         if (binary_upgrade)
11552                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
11553
11554         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11555                                  aggsig_tag,
11556                                  agginfo->aggfn.dobj.namespace->dobj.name,
11557                                  NULL,
11558                                  agginfo->aggfn.rolname,
11559                                  false, "AGGREGATE", SECTION_PRE_DATA,
11560                                  q->data, delq->data, NULL,
11561                                  NULL, 0,
11562                                  NULL, NULL);
11563
11564         /* Dump Aggregate Comments */
11565         dumpComment(fout, labelq->data,
11566                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11567                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11568         dumpSecLabel(fout, labelq->data,
11569                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
11570                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
11571
11572         /*
11573          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
11574          * command look like a function's GRANT; in particular this affects the
11575          * syntax for zero-argument aggregates.
11576          */
11577         free(aggsig);
11578         free(aggsig_tag);
11579
11580         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
11581         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
11582
11583         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
11584                         "FUNCTION",
11585                         aggsig, NULL, aggsig_tag,
11586                         agginfo->aggfn.dobj.namespace->dobj.name,
11587                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
11588
11589         free(aggsig);
11590         free(aggsig_tag);
11591
11592         PQclear(res);
11593
11594         destroyPQExpBuffer(query);
11595         destroyPQExpBuffer(q);
11596         destroyPQExpBuffer(delq);
11597         destroyPQExpBuffer(labelq);
11598         destroyPQExpBuffer(details);
11599 }
11600
11601 /*
11602  * dumpTSParser
11603  *        write out a single text search parser
11604  */
11605 static void
11606 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
11607 {
11608         PQExpBuffer q;
11609         PQExpBuffer delq;
11610         PQExpBuffer labelq;
11611
11612         /* Skip if not to be dumped */
11613         if (!prsinfo->dobj.dump || dataOnly)
11614                 return;
11615
11616         q = createPQExpBuffer();
11617         delq = createPQExpBuffer();
11618         labelq = createPQExpBuffer();
11619
11620         /* Make sure we are in proper schema */
11621         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
11622
11623         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
11624                                           fmtId(prsinfo->dobj.name));
11625
11626         appendPQExpBuffer(q, "    START = %s,\n",
11627                                           convertTSFunction(fout, prsinfo->prsstart));
11628         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
11629                                           convertTSFunction(fout, prsinfo->prstoken));
11630         appendPQExpBuffer(q, "    END = %s,\n",
11631                                           convertTSFunction(fout, prsinfo->prsend));
11632         if (prsinfo->prsheadline != InvalidOid)
11633                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
11634                                                   convertTSFunction(fout, prsinfo->prsheadline));
11635         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
11636                                           convertTSFunction(fout, prsinfo->prslextype));
11637
11638         /*
11639          * DROP must be fully qualified in case same name appears in pg_catalog
11640          */
11641         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
11642                                           fmtId(prsinfo->dobj.namespace->dobj.name));
11643         appendPQExpBuffer(delq, ".%s;\n",
11644                                           fmtId(prsinfo->dobj.name));
11645
11646         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
11647                                           fmtId(prsinfo->dobj.name));
11648
11649         if (binary_upgrade)
11650                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
11651
11652         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
11653                                  prsinfo->dobj.name,
11654                                  prsinfo->dobj.namespace->dobj.name,
11655                                  NULL,
11656                                  "",
11657                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
11658                                  q->data, delq->data, NULL,
11659                                  NULL, 0,
11660                                  NULL, NULL);
11661
11662         /* Dump Parser Comments */
11663         dumpComment(fout, labelq->data,
11664                                 NULL, "",
11665                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
11666
11667         destroyPQExpBuffer(q);
11668         destroyPQExpBuffer(delq);
11669         destroyPQExpBuffer(labelq);
11670 }
11671
11672 /*
11673  * dumpTSDictionary
11674  *        write out a single text search dictionary
11675  */
11676 static void
11677 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
11678 {
11679         PQExpBuffer q;
11680         PQExpBuffer delq;
11681         PQExpBuffer labelq;
11682         PQExpBuffer query;
11683         PGresult   *res;
11684         char       *nspname;
11685         char       *tmplname;
11686
11687         /* Skip if not to be dumped */
11688         if (!dictinfo->dobj.dump || dataOnly)
11689                 return;
11690
11691         q = createPQExpBuffer();
11692         delq = createPQExpBuffer();
11693         labelq = createPQExpBuffer();
11694         query = createPQExpBuffer();
11695
11696         /* Fetch name and namespace of the dictionary's template */
11697         selectSourceSchema(fout, "pg_catalog");
11698         appendPQExpBuffer(query, "SELECT nspname, tmplname "
11699                                           "FROM pg_ts_template p, pg_namespace n "
11700                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
11701                                           dictinfo->dicttemplate);
11702         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11703         nspname = PQgetvalue(res, 0, 0);
11704         tmplname = PQgetvalue(res, 0, 1);
11705
11706         /* Make sure we are in proper schema */
11707         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
11708
11709         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
11710                                           fmtId(dictinfo->dobj.name));
11711
11712         appendPQExpBuffer(q, "    TEMPLATE = ");
11713         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
11714                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11715         appendPQExpBuffer(q, "%s", fmtId(tmplname));
11716
11717         PQclear(res);
11718
11719         /* the dictinitoption can be dumped straight into the command */
11720         if (dictinfo->dictinitoption)
11721                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
11722
11723         appendPQExpBuffer(q, " );\n");
11724
11725         /*
11726          * DROP must be fully qualified in case same name appears in pg_catalog
11727          */
11728         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
11729                                           fmtId(dictinfo->dobj.namespace->dobj.name));
11730         appendPQExpBuffer(delq, ".%s;\n",
11731                                           fmtId(dictinfo->dobj.name));
11732
11733         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
11734                                           fmtId(dictinfo->dobj.name));
11735
11736         if (binary_upgrade)
11737                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
11738
11739         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
11740                                  dictinfo->dobj.name,
11741                                  dictinfo->dobj.namespace->dobj.name,
11742                                  NULL,
11743                                  dictinfo->rolname,
11744                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
11745                                  q->data, delq->data, NULL,
11746                                  NULL, 0,
11747                                  NULL, NULL);
11748
11749         /* Dump Dictionary Comments */
11750         dumpComment(fout, labelq->data,
11751                                 NULL, dictinfo->rolname,
11752                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
11753
11754         destroyPQExpBuffer(q);
11755         destroyPQExpBuffer(delq);
11756         destroyPQExpBuffer(labelq);
11757         destroyPQExpBuffer(query);
11758 }
11759
11760 /*
11761  * dumpTSTemplate
11762  *        write out a single text search template
11763  */
11764 static void
11765 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
11766 {
11767         PQExpBuffer q;
11768         PQExpBuffer delq;
11769         PQExpBuffer labelq;
11770
11771         /* Skip if not to be dumped */
11772         if (!tmplinfo->dobj.dump || dataOnly)
11773                 return;
11774
11775         q = createPQExpBuffer();
11776         delq = createPQExpBuffer();
11777         labelq = createPQExpBuffer();
11778
11779         /* Make sure we are in proper schema */
11780         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
11781
11782         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
11783                                           fmtId(tmplinfo->dobj.name));
11784
11785         if (tmplinfo->tmplinit != InvalidOid)
11786                 appendPQExpBuffer(q, "    INIT = %s,\n",
11787                                                   convertTSFunction(fout, tmplinfo->tmplinit));
11788         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
11789                                           convertTSFunction(fout, tmplinfo->tmpllexize));
11790
11791         /*
11792          * DROP must be fully qualified in case same name appears in pg_catalog
11793          */
11794         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
11795                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
11796         appendPQExpBuffer(delq, ".%s;\n",
11797                                           fmtId(tmplinfo->dobj.name));
11798
11799         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
11800                                           fmtId(tmplinfo->dobj.name));
11801
11802         if (binary_upgrade)
11803                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
11804
11805         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
11806                                  tmplinfo->dobj.name,
11807                                  tmplinfo->dobj.namespace->dobj.name,
11808                                  NULL,
11809                                  "",
11810                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
11811                                  q->data, delq->data, NULL,
11812                                  NULL, 0,
11813                                  NULL, NULL);
11814
11815         /* Dump Template Comments */
11816         dumpComment(fout, labelq->data,
11817                                 NULL, "",
11818                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
11819
11820         destroyPQExpBuffer(q);
11821         destroyPQExpBuffer(delq);
11822         destroyPQExpBuffer(labelq);
11823 }
11824
11825 /*
11826  * dumpTSConfig
11827  *        write out a single text search configuration
11828  */
11829 static void
11830 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
11831 {
11832         PQExpBuffer q;
11833         PQExpBuffer delq;
11834         PQExpBuffer labelq;
11835         PQExpBuffer query;
11836         PGresult   *res;
11837         char       *nspname;
11838         char       *prsname;
11839         int                     ntups,
11840                                 i;
11841         int                     i_tokenname;
11842         int                     i_dictname;
11843
11844         /* Skip if not to be dumped */
11845         if (!cfginfo->dobj.dump || dataOnly)
11846                 return;
11847
11848         q = createPQExpBuffer();
11849         delq = createPQExpBuffer();
11850         labelq = createPQExpBuffer();
11851         query = createPQExpBuffer();
11852
11853         /* Fetch name and namespace of the config's parser */
11854         selectSourceSchema(fout, "pg_catalog");
11855         appendPQExpBuffer(query, "SELECT nspname, prsname "
11856                                           "FROM pg_ts_parser p, pg_namespace n "
11857                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
11858                                           cfginfo->cfgparser);
11859         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11860         nspname = PQgetvalue(res, 0, 0);
11861         prsname = PQgetvalue(res, 0, 1);
11862
11863         /* Make sure we are in proper schema */
11864         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
11865
11866         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
11867                                           fmtId(cfginfo->dobj.name));
11868
11869         appendPQExpBuffer(q, "    PARSER = ");
11870         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
11871                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
11872         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
11873
11874         PQclear(res);
11875
11876         resetPQExpBuffer(query);
11877         appendPQExpBuffer(query,
11878                                           "SELECT \n"
11879                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
11880                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
11881                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
11882                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
11883                                           "WHERE m.mapcfg = '%u' \n"
11884                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
11885                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
11886
11887         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11888         ntups = PQntuples(res);
11889
11890         i_tokenname = PQfnumber(res, "tokenname");
11891         i_dictname = PQfnumber(res, "dictname");
11892
11893         for (i = 0; i < ntups; i++)
11894         {
11895                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
11896                 char       *dictname = PQgetvalue(res, i, i_dictname);
11897
11898                 if (i == 0 ||
11899                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
11900                 {
11901                         /* starting a new token type, so start a new command */
11902                         if (i > 0)
11903                                 appendPQExpBuffer(q, ";\n");
11904                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
11905                                                           fmtId(cfginfo->dobj.name));
11906                         /* tokenname needs quoting, dictname does NOT */
11907                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
11908                                                           fmtId(tokenname), dictname);
11909                 }
11910                 else
11911                         appendPQExpBuffer(q, ", %s", dictname);
11912         }
11913
11914         if (ntups > 0)
11915                 appendPQExpBuffer(q, ";\n");
11916
11917         PQclear(res);
11918
11919         /*
11920          * DROP must be fully qualified in case same name appears in pg_catalog
11921          */
11922         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
11923                                           fmtId(cfginfo->dobj.namespace->dobj.name));
11924         appendPQExpBuffer(delq, ".%s;\n",
11925                                           fmtId(cfginfo->dobj.name));
11926
11927         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
11928                                           fmtId(cfginfo->dobj.name));
11929
11930         if (binary_upgrade)
11931                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
11932
11933         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
11934                                  cfginfo->dobj.name,
11935                                  cfginfo->dobj.namespace->dobj.name,
11936                                  NULL,
11937                                  cfginfo->rolname,
11938                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
11939                                  q->data, delq->data, NULL,
11940                                  NULL, 0,
11941                                  NULL, NULL);
11942
11943         /* Dump Configuration Comments */
11944         dumpComment(fout, labelq->data,
11945                                 NULL, cfginfo->rolname,
11946                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
11947
11948         destroyPQExpBuffer(q);
11949         destroyPQExpBuffer(delq);
11950         destroyPQExpBuffer(labelq);
11951         destroyPQExpBuffer(query);
11952 }
11953
11954 /*
11955  * dumpForeignDataWrapper
11956  *        write out a single foreign-data wrapper definition
11957  */
11958 static void
11959 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
11960 {
11961         PQExpBuffer q;
11962         PQExpBuffer delq;
11963         PQExpBuffer labelq;
11964         char       *qfdwname;
11965
11966         /* Skip if not to be dumped */
11967         if (!fdwinfo->dobj.dump || dataOnly)
11968                 return;
11969
11970         /*
11971          * FDWs that belong to an extension are dumped based on their "dump"
11972          * field. Otherwise omit them if we are only dumping some specific object.
11973          */
11974         if (!fdwinfo->dobj.ext_member)
11975                 if (!include_everything)
11976                         return;
11977
11978         q = createPQExpBuffer();
11979         delq = createPQExpBuffer();
11980         labelq = createPQExpBuffer();
11981
11982         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
11983
11984         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
11985                                           qfdwname);
11986
11987         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
11988                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
11989
11990         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
11991                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
11992
11993         if (strlen(fdwinfo->fdwoptions) > 0)
11994                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
11995
11996         appendPQExpBuffer(q, ";\n");
11997
11998         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
11999                                           qfdwname);
12000
12001         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12002                                           qfdwname);
12003
12004         if (binary_upgrade)
12005                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12006
12007         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12008                                  fdwinfo->dobj.name,
12009                                  NULL,
12010                                  NULL,
12011                                  fdwinfo->rolname,
12012                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12013                                  q->data, delq->data, NULL,
12014                                  NULL, 0,
12015                                  NULL, NULL);
12016
12017         /* Handle the ACL */
12018         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12019                         "FOREIGN DATA WRAPPER",
12020                         qfdwname, NULL, fdwinfo->dobj.name,
12021                         NULL, fdwinfo->rolname,
12022                         fdwinfo->fdwacl);
12023
12024         /* Dump Foreign Data Wrapper Comments */
12025         dumpComment(fout, labelq->data,
12026                                 NULL, fdwinfo->rolname,
12027                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12028
12029         free(qfdwname);
12030
12031         destroyPQExpBuffer(q);
12032         destroyPQExpBuffer(delq);
12033         destroyPQExpBuffer(labelq);
12034 }
12035
12036 /*
12037  * dumpForeignServer
12038  *        write out a foreign server definition
12039  */
12040 static void
12041 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
12042 {
12043         PQExpBuffer q;
12044         PQExpBuffer delq;
12045         PQExpBuffer labelq;
12046         PQExpBuffer query;
12047         PGresult   *res;
12048         char       *qsrvname;
12049         char       *fdwname;
12050
12051         /* Skip if not to be dumped */
12052         if (!srvinfo->dobj.dump || dataOnly || !include_everything)
12053                 return;
12054
12055         q = createPQExpBuffer();
12056         delq = createPQExpBuffer();
12057         labelq = createPQExpBuffer();
12058         query = createPQExpBuffer();
12059
12060         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12061
12062         /* look up the foreign-data wrapper */
12063         selectSourceSchema(fout, "pg_catalog");
12064         appendPQExpBuffer(query, "SELECT fdwname "
12065                                           "FROM pg_foreign_data_wrapper w "
12066                                           "WHERE w.oid = '%u'",
12067                                           srvinfo->srvfdw);
12068         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12069         fdwname = PQgetvalue(res, 0, 0);
12070
12071         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12072         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12073         {
12074                 appendPQExpBuffer(q, " TYPE ");
12075                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12076         }
12077         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12078         {
12079                 appendPQExpBuffer(q, " VERSION ");
12080                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12081         }
12082
12083         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
12084         appendPQExpBuffer(q, "%s", fmtId(fdwname));
12085
12086         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12087                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12088
12089         appendPQExpBuffer(q, ";\n");
12090
12091         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12092                                           qsrvname);
12093
12094         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12095
12096         if (binary_upgrade)
12097                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12098
12099         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12100                                  srvinfo->dobj.name,
12101                                  NULL,
12102                                  NULL,
12103                                  srvinfo->rolname,
12104                                  false, "SERVER", SECTION_PRE_DATA,
12105                                  q->data, delq->data, NULL,
12106                                  NULL, 0,
12107                                  NULL, NULL);
12108
12109         /* Handle the ACL */
12110         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12111                         "FOREIGN SERVER",
12112                         qsrvname, NULL, srvinfo->dobj.name,
12113                         NULL, srvinfo->rolname,
12114                         srvinfo->srvacl);
12115
12116         /* Dump user mappings */
12117         dumpUserMappings(fout,
12118                                          srvinfo->dobj.name, NULL,
12119                                          srvinfo->rolname,
12120                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12121
12122         /* Dump Foreign Server Comments */
12123         dumpComment(fout, labelq->data,
12124                                 NULL, srvinfo->rolname,
12125                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12126
12127         free(qsrvname);
12128
12129         destroyPQExpBuffer(q);
12130         destroyPQExpBuffer(delq);
12131         destroyPQExpBuffer(labelq);
12132 }
12133
12134 /*
12135  * dumpUserMappings
12136  *
12137  * This routine is used to dump any user mappings associated with the
12138  * server handed to this routine. Should be called after ArchiveEntry()
12139  * for the server.
12140  */
12141 static void
12142 dumpUserMappings(Archive *fout,
12143                                  const char *servername, const char *namespace,
12144                                  const char *owner,
12145                                  CatalogId catalogId, DumpId dumpId)
12146 {
12147         PQExpBuffer q;
12148         PQExpBuffer delq;
12149         PQExpBuffer query;
12150         PQExpBuffer tag;
12151         PGresult   *res;
12152         int                     ntups;
12153         int                     i_usename;
12154         int                     i_umoptions;
12155         int                     i;
12156
12157         q = createPQExpBuffer();
12158         tag = createPQExpBuffer();
12159         delq = createPQExpBuffer();
12160         query = createPQExpBuffer();
12161
12162         /*
12163          * We read from the publicly accessible view pg_user_mappings, so as not
12164          * to fail if run by a non-superuser.  Note that the view will show
12165          * umoptions as null if the user hasn't got privileges for the associated
12166          * server; this means that pg_dump will dump such a mapping, but with no
12167          * OPTIONS clause.      A possible alternative is to skip such mappings
12168          * altogether, but it's not clear that that's an improvement.
12169          */
12170         selectSourceSchema(fout, "pg_catalog");
12171
12172         appendPQExpBuffer(query,
12173                                           "SELECT usename, "
12174                                           "array_to_string(ARRAY("
12175                                           "SELECT quote_ident(option_name) || ' ' || "
12176                                           "quote_literal(option_value) "
12177                                           "FROM pg_options_to_table(umoptions) "
12178                                           "ORDER BY option_name"
12179                                           "), E',\n    ') AS umoptions "
12180                                           "FROM pg_user_mappings "
12181                                           "WHERE srvid = '%u' "
12182                                           "ORDER BY usename",
12183                                           catalogId.oid);
12184
12185         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12186
12187         ntups = PQntuples(res);
12188         i_usename = PQfnumber(res, "usename");
12189         i_umoptions = PQfnumber(res, "umoptions");
12190
12191         for (i = 0; i < ntups; i++)
12192         {
12193                 char       *usename;
12194                 char       *umoptions;
12195
12196                 usename = PQgetvalue(res, i, i_usename);
12197                 umoptions = PQgetvalue(res, i, i_umoptions);
12198
12199                 resetPQExpBuffer(q);
12200                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12201                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12202
12203                 if (umoptions && strlen(umoptions) > 0)
12204                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12205
12206                 appendPQExpBuffer(q, ";\n");
12207
12208                 resetPQExpBuffer(delq);
12209                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12210                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12211
12212                 resetPQExpBuffer(tag);
12213                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12214                                                   usename, servername);
12215
12216                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12217                                          tag->data,
12218                                          namespace,
12219                                          NULL,
12220                                          owner, false,
12221                                          "USER MAPPING", SECTION_PRE_DATA,
12222                                          q->data, delq->data, NULL,
12223                                          &dumpId, 1,
12224                                          NULL, NULL);
12225         }
12226
12227         PQclear(res);
12228
12229         destroyPQExpBuffer(query);
12230         destroyPQExpBuffer(delq);
12231         destroyPQExpBuffer(q);
12232 }
12233
12234 /*
12235  * Write out default privileges information
12236  */
12237 static void
12238 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
12239 {
12240         PQExpBuffer q;
12241         PQExpBuffer tag;
12242         const char *type;
12243
12244         /* Skip if not to be dumped */
12245         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
12246                 return;
12247
12248         q = createPQExpBuffer();
12249         tag = createPQExpBuffer();
12250
12251         switch (daclinfo->defaclobjtype)
12252         {
12253                 case DEFACLOBJ_RELATION:
12254                         type = "TABLES";
12255                         break;
12256                 case DEFACLOBJ_SEQUENCE:
12257                         type = "SEQUENCES";
12258                         break;
12259                 case DEFACLOBJ_FUNCTION:
12260                         type = "FUNCTIONS";
12261                         break;
12262                 case DEFACLOBJ_TYPE:
12263                         type = "TYPES";
12264                         break;
12265                 default:
12266                         /* shouldn't get here */
12267                         exit_horribly(NULL,
12268                                           "unrecognized object type in default privileges: %d\n",
12269                                                   (int) daclinfo->defaclobjtype);
12270                         type = "";                      /* keep compiler quiet */
12271         }
12272
12273         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12274
12275         /* build the actual command(s) for this tuple */
12276         if (!buildDefaultACLCommands(type,
12277                                                                  daclinfo->dobj.namespace != NULL ?
12278                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12279                                                                  daclinfo->defaclacl,
12280                                                                  daclinfo->defaclrole,
12281                                                                  fout->remoteVersion,
12282                                                                  q))
12283                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12284                                           daclinfo->defaclacl);
12285
12286         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12287                                  tag->data,
12288            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12289                                  NULL,
12290                                  daclinfo->defaclrole,
12291                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12292                                  q->data, "", NULL,
12293                                  NULL, 0,
12294                                  NULL, NULL);
12295
12296         destroyPQExpBuffer(tag);
12297         destroyPQExpBuffer(q);
12298 }
12299
12300 /*----------
12301  * Write out grant/revoke information
12302  *
12303  * 'objCatId' is the catalog ID of the underlying object.
12304  * 'objDumpId' is the dump ID of the underlying object.
12305  * 'type' must be one of
12306  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12307  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12308  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12309  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12310  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12311  * 'nspname' is the namespace the object is in (NULL if none).
12312  * 'owner' is the owner, NULL if there is no owner (for languages).
12313  * 'acls' is the string read out of the fooacl system catalog field;
12314  *              it will be parsed here.
12315  *----------
12316  */
12317 static void
12318 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
12319                 const char *type, const char *name, const char *subname,
12320                 const char *tag, const char *nspname, const char *owner,
12321                 const char *acls)
12322 {
12323         PQExpBuffer sql;
12324
12325         /* Do nothing if ACL dump is not enabled */
12326         if (aclsSkip)
12327                 return;
12328
12329         /* --data-only skips ACLs *except* BLOB ACLs */
12330         if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
12331                 return;
12332
12333         sql = createPQExpBuffer();
12334
12335         if (!buildACLCommands(name, subname, type, acls, owner,
12336                                                   "", fout->remoteVersion, sql))
12337                 exit_horribly(NULL,
12338                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
12339                                           acls, name, type);
12340
12341         if (sql->len > 0)
12342                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12343                                          tag, nspname,
12344                                          NULL,
12345                                          owner ? owner : "",
12346                                          false, "ACL", SECTION_NONE,
12347                                          sql->data, "", NULL,
12348                                          &(objDumpId), 1,
12349                                          NULL, NULL);
12350
12351         destroyPQExpBuffer(sql);
12352 }
12353
12354 /*
12355  * dumpSecLabel
12356  *
12357  * This routine is used to dump any security labels associated with the
12358  * object handed to this routine. The routine takes a constant character
12359  * string for the target part of the security-label command, plus
12360  * the namespace and owner of the object (for labeling the ArchiveEntry),
12361  * plus catalog ID and subid which are the lookup key for pg_seclabel,
12362  * plus the dump ID for the object (for setting a dependency).
12363  * If a matching pg_seclabel entry is found, it is dumped.
12364  *
12365  * Note: although this routine takes a dumpId for dependency purposes,
12366  * that purpose is just to mark the dependency in the emitted dump file
12367  * for possible future use by pg_restore.  We do NOT use it for determining
12368  * ordering of the label in the dump file, because this routine is called
12369  * after dependency sorting occurs.  This routine should be called just after
12370  * calling ArchiveEntry() for the specified object.
12371  */
12372 static void
12373 dumpSecLabel(Archive *fout, const char *target,
12374                          const char *namespace, const char *owner,
12375                          CatalogId catalogId, int subid, DumpId dumpId)
12376 {
12377         SecLabelItem *labels;
12378         int                     nlabels;
12379         int                     i;
12380         PQExpBuffer query;
12381
12382         /* do nothing, if --no-security-labels is supplied */
12383         if (no_security_labels)
12384                 return;
12385
12386         /* Comments are schema not data ... except blob comments are data */
12387         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
12388         {
12389                 if (dataOnly)
12390                         return;
12391         }
12392         else
12393         {
12394                 if (schemaOnly)
12395                         return;
12396         }
12397
12398         /* Search for security labels associated with catalogId, using table */
12399         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
12400
12401         query = createPQExpBuffer();
12402
12403         for (i = 0; i < nlabels; i++)
12404         {
12405                 /*
12406                  * Ignore label entries for which the subid doesn't match.
12407                  */
12408                 if (labels[i].objsubid != subid)
12409                         continue;
12410
12411                 appendPQExpBuffer(query,
12412                                                   "SECURITY LABEL FOR %s ON %s IS ",
12413                                                   fmtId(labels[i].provider), target);
12414                 appendStringLiteralAH(query, labels[i].label, fout);
12415                 appendPQExpBuffer(query, ";\n");
12416         }
12417
12418         if (query->len > 0)
12419         {
12420                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12421                                          target, namespace, NULL, owner,
12422                                          false, "SECURITY LABEL", SECTION_NONE,
12423                                          query->data, "", NULL,
12424                                          &(dumpId), 1,
12425                                          NULL, NULL);
12426         }
12427         destroyPQExpBuffer(query);
12428 }
12429
12430 /*
12431  * dumpTableSecLabel
12432  *
12433  * As above, but dump security label for both the specified table (or view)
12434  * and its columns.
12435  */
12436 static void
12437 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
12438 {
12439         SecLabelItem *labels;
12440         int                     nlabels;
12441         int                     i;
12442         PQExpBuffer query;
12443         PQExpBuffer target;
12444
12445         /* do nothing, if --no-security-labels is supplied */
12446         if (no_security_labels)
12447                 return;
12448
12449         /* SecLabel are SCHEMA not data */
12450         if (dataOnly)
12451                 return;
12452
12453         /* Search for comments associated with relation, using table */
12454         nlabels = findSecLabels(fout,
12455                                                         tbinfo->dobj.catId.tableoid,
12456                                                         tbinfo->dobj.catId.oid,
12457                                                         &labels);
12458
12459         /* If security labels exist, build SECURITY LABEL statements */
12460         if (nlabels <= 0)
12461                 return;
12462
12463         query = createPQExpBuffer();
12464         target = createPQExpBuffer();
12465
12466         for (i = 0; i < nlabels; i++)
12467         {
12468                 const char *colname;
12469                 const char *provider = labels[i].provider;
12470                 const char *label = labels[i].label;
12471                 int                     objsubid = labels[i].objsubid;
12472
12473                 resetPQExpBuffer(target);
12474                 if (objsubid == 0)
12475                 {
12476                         appendPQExpBuffer(target, "%s %s", reltypename,
12477                                                           fmtId(tbinfo->dobj.name));
12478                 }
12479                 else
12480                 {
12481                         colname = getAttrName(objsubid, tbinfo);
12482                         /* first fmtId result must be consumed before calling it again */
12483                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
12484                         appendPQExpBuffer(target, ".%s", fmtId(colname));
12485                 }
12486                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
12487                                                   fmtId(provider), target->data);
12488                 appendStringLiteralAH(query, label, fout);
12489                 appendPQExpBuffer(query, ";\n");
12490         }
12491         if (query->len > 0)
12492         {
12493                 resetPQExpBuffer(target);
12494                 appendPQExpBuffer(target, "%s %s", reltypename,
12495                                                   fmtId(tbinfo->dobj.name));
12496                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12497                                          target->data,
12498                                          tbinfo->dobj.namespace->dobj.name,
12499                                          NULL, tbinfo->rolname,
12500                                          false, "SECURITY LABEL", SECTION_NONE,
12501                                          query->data, "", NULL,
12502                                          &(tbinfo->dobj.dumpId), 1,
12503                                          NULL, NULL);
12504         }
12505         destroyPQExpBuffer(query);
12506         destroyPQExpBuffer(target);
12507 }
12508
12509 /*
12510  * findSecLabels
12511  *
12512  * Find the security label(s), if any, associated with the given object.
12513  * All the objsubid values associated with the given classoid/objoid are
12514  * found with one search.
12515  */
12516 static int
12517 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
12518 {
12519         /* static storage for table of security labels */
12520         static SecLabelItem *labels = NULL;
12521         static int      nlabels = -1;
12522
12523         SecLabelItem *middle = NULL;
12524         SecLabelItem *low;
12525         SecLabelItem *high;
12526         int                     nmatch;
12527
12528         /* Get security labels if we didn't already */
12529         if (nlabels < 0)
12530                 nlabels = collectSecLabels(fout, &labels);
12531
12532         if (nlabels <= 0)                       /* no labels, so no match is possible */
12533         {
12534                 *items = NULL;
12535                 return 0;
12536         }
12537
12538         /*
12539          * Do binary search to find some item matching the object.
12540          */
12541         low = &labels[0];
12542         high = &labels[nlabels - 1];
12543         while (low <= high)
12544         {
12545                 middle = low + (high - low) / 2;
12546
12547                 if (classoid < middle->classoid)
12548                         high = middle - 1;
12549                 else if (classoid > middle->classoid)
12550                         low = middle + 1;
12551                 else if (objoid < middle->objoid)
12552                         high = middle - 1;
12553                 else if (objoid > middle->objoid)
12554                         low = middle + 1;
12555                 else
12556                         break;                          /* found a match */
12557         }
12558
12559         if (low > high)                         /* no matches */
12560         {
12561                 *items = NULL;
12562                 return 0;
12563         }
12564
12565         /*
12566          * Now determine how many items match the object.  The search loop
12567          * invariant still holds: only items between low and high inclusive could
12568          * match.
12569          */
12570         nmatch = 1;
12571         while (middle > low)
12572         {
12573                 if (classoid != middle[-1].classoid ||
12574                         objoid != middle[-1].objoid)
12575                         break;
12576                 middle--;
12577                 nmatch++;
12578         }
12579
12580         *items = middle;
12581
12582         middle += nmatch;
12583         while (middle <= high)
12584         {
12585                 if (classoid != middle->classoid ||
12586                         objoid != middle->objoid)
12587                         break;
12588                 middle++;
12589                 nmatch++;
12590         }
12591
12592         return nmatch;
12593 }
12594
12595 /*
12596  * collectSecLabels
12597  *
12598  * Construct a table of all security labels available for database objects.
12599  * It's much faster to pull them all at once.
12600  *
12601  * The table is sorted by classoid/objid/objsubid for speed in lookup.
12602  */
12603 static int
12604 collectSecLabels(Archive *fout, SecLabelItem **items)
12605 {
12606         PGresult   *res;
12607         PQExpBuffer query;
12608         int                     i_label;
12609         int                     i_provider;
12610         int                     i_classoid;
12611         int                     i_objoid;
12612         int                     i_objsubid;
12613         int                     ntups;
12614         int                     i;
12615         SecLabelItem *labels;
12616
12617         query = createPQExpBuffer();
12618
12619         appendPQExpBuffer(query,
12620                                           "SELECT label, provider, classoid, objoid, objsubid "
12621                                           "FROM pg_catalog.pg_seclabel "
12622                                           "ORDER BY classoid, objoid, objsubid");
12623
12624         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12625
12626         /* Construct lookup table containing OIDs in numeric form */
12627         i_label = PQfnumber(res, "label");
12628         i_provider = PQfnumber(res, "provider");
12629         i_classoid = PQfnumber(res, "classoid");
12630         i_objoid = PQfnumber(res, "objoid");
12631         i_objsubid = PQfnumber(res, "objsubid");
12632
12633         ntups = PQntuples(res);
12634
12635         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
12636
12637         for (i = 0; i < ntups; i++)
12638         {
12639                 labels[i].label = PQgetvalue(res, i, i_label);
12640                 labels[i].provider = PQgetvalue(res, i, i_provider);
12641                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
12642                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
12643                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
12644         }
12645
12646         /* Do NOT free the PGresult since we are keeping pointers into it */
12647         destroyPQExpBuffer(query);
12648
12649         *items = labels;
12650         return ntups;
12651 }
12652
12653 /*
12654  * dumpTable
12655  *        write out to fout the declarations (not data) of a user-defined table
12656  */
12657 static void
12658 dumpTable(Archive *fout, TableInfo *tbinfo)
12659 {
12660         if (tbinfo->dobj.dump && !dataOnly)
12661         {
12662                 char       *namecopy;
12663
12664                 if (tbinfo->relkind == RELKIND_SEQUENCE)
12665                         dumpSequence(fout, tbinfo);
12666                 else
12667                         dumpTableSchema(fout, tbinfo);
12668
12669                 /* Handle the ACL here */
12670                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
12671                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
12672                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
12673                                 "TABLE",
12674                                 namecopy, NULL, tbinfo->dobj.name,
12675                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12676                                 tbinfo->relacl);
12677
12678                 /*
12679                  * Handle column ACLs, if any.  Note: we pull these with a separate
12680                  * query rather than trying to fetch them during getTableAttrs, so
12681                  * that we won't miss ACLs on system columns.
12682                  */
12683                 if (fout->remoteVersion >= 80400)
12684                 {
12685                         PQExpBuffer query = createPQExpBuffer();
12686                         PGresult   *res;
12687                         int                     i;
12688
12689                         appendPQExpBuffer(query,
12690                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
12691                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
12692                                                           "ORDER BY attnum",
12693                                                           tbinfo->dobj.catId.oid);
12694                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12695
12696                         for (i = 0; i < PQntuples(res); i++)
12697                         {
12698                                 char       *attname = PQgetvalue(res, i, 0);
12699                                 char       *attacl = PQgetvalue(res, i, 1);
12700                                 char       *attnamecopy;
12701                                 char       *acltag;
12702
12703                                 attnamecopy = pg_strdup(fmtId(attname));
12704                                 acltag = pg_malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
12705                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
12706                                 /* Column's GRANT type is always TABLE */
12707                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
12708                                                 namecopy, attnamecopy, acltag,
12709                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
12710                                                 attacl);
12711                                 free(attnamecopy);
12712                                 free(acltag);
12713                         }
12714                         PQclear(res);
12715                         destroyPQExpBuffer(query);
12716                 }
12717
12718                 free(namecopy);
12719         }
12720 }
12721
12722 /*
12723  * Create the AS clause for a view or materialized view. The semicolon is
12724  * stripped because a materialized view must add a WITH NO DATA clause.
12725  *
12726  * This returns a new buffer which must be freed by the caller.
12727  */
12728 static PQExpBuffer
12729 createViewAsClause(Archive *fout, TableInfo *tbinfo)
12730 {
12731         PQExpBuffer query = createPQExpBuffer();
12732         PQExpBuffer result = createPQExpBuffer();
12733         PGresult   *res;
12734         int                     len;
12735
12736         /* Fetch the view definition */
12737         if (fout->remoteVersion >= 70300)
12738         {
12739                 /* Beginning in 7.3, viewname is not unique; rely on OID */
12740                 appendPQExpBuffer(query,
12741                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
12742                                                   tbinfo->dobj.catId.oid);
12743         }
12744         else
12745         {
12746                 appendPQExpBuffer(query, "SELECT definition AS viewdef "
12747                                                   "FROM pg_views WHERE viewname = ");
12748                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
12749                 appendPQExpBuffer(query, ";");
12750         }
12751
12752         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12753
12754         if (PQntuples(res) != 1)
12755         {
12756                 if (PQntuples(res) < 1)
12757                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
12758                                                   tbinfo->dobj.name);
12759                 else
12760                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
12761                                                   tbinfo->dobj.name);
12762         }
12763
12764         len = PQgetlength(res, 0, 0);
12765
12766         if (len == 0)
12767                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
12768                                           tbinfo->dobj.name);
12769
12770         /* Strip off the trailing semicolon so that other things may follow. */
12771         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
12772         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
12773
12774         PQclear(res);
12775         destroyPQExpBuffer(query);
12776
12777         return result;
12778 }
12779
12780 /*
12781  * dumpTableSchema
12782  *        write the declaration (not data) of one user-defined table or view
12783  */
12784 static void
12785 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
12786 {
12787         PQExpBuffer q = createPQExpBuffer();
12788         PQExpBuffer delq = createPQExpBuffer();
12789         PQExpBuffer labelq = createPQExpBuffer();
12790         int                     numParents;
12791         TableInfo **parents;
12792         int                     actual_atts;    /* number of attrs in this CREATE statement */
12793         const char *reltypename;
12794         char       *storage;
12795         char       *srvname;
12796         char       *ftoptions;
12797         int                     j,
12798                                 k;
12799
12800         /* Make sure we are in proper schema */
12801         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
12802
12803         if (binary_upgrade)
12804                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
12805                                                                                                 tbinfo->dobj.catId.oid);
12806
12807         /* Is it a table or a view? */
12808         if (tbinfo->relkind == RELKIND_VIEW)
12809         {
12810                 PQExpBuffer result;
12811
12812                 reltypename = "VIEW";
12813
12814                 /*
12815                  * DROP must be fully qualified in case same name appears in
12816                  * pg_catalog
12817                  */
12818                 appendPQExpBuffer(delq, "DROP VIEW %s.",
12819                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12820                 appendPQExpBuffer(delq, "%s;\n",
12821                                                   fmtId(tbinfo->dobj.name));
12822
12823                 if (binary_upgrade)
12824                         binary_upgrade_set_pg_class_oids(fout, q,
12825                                                                                          tbinfo->dobj.catId.oid, false);
12826
12827                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
12828                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
12829                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
12830                 result = createViewAsClause(fout, tbinfo);
12831                 appendPQExpBuffer(q, " AS\n%s;\n", result->data);
12832                 destroyPQExpBuffer(result);
12833
12834                 appendPQExpBuffer(labelq, "VIEW %s",
12835                                                   fmtId(tbinfo->dobj.name));
12836         }
12837         else
12838         {
12839                 switch (tbinfo->relkind)
12840                 {
12841                         case (RELKIND_FOREIGN_TABLE):
12842                                 {
12843                                         PQExpBuffer query = createPQExpBuffer();
12844                                         PGresult   *res;
12845                                         int                     i_srvname;
12846                                         int                     i_ftoptions;
12847
12848                                         reltypename = "FOREIGN TABLE";
12849
12850                                         /* retrieve name of foreign server and generic options */
12851                                         appendPQExpBuffer(query,
12852                                                                           "SELECT fs.srvname, "
12853                                                                           "pg_catalog.array_to_string(ARRAY("
12854                                                          "SELECT pg_catalog.quote_ident(option_name) || "
12855                                                          "' ' || pg_catalog.quote_literal(option_value) "
12856                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
12857                                                                           "ORDER BY option_name"
12858                                                                           "), E',\n    ') AS ftoptions "
12859                                                                           "FROM pg_catalog.pg_foreign_table ft "
12860                                                                           "JOIN pg_catalog.pg_foreign_server fs "
12861                                                                           "ON (fs.oid = ft.ftserver) "
12862                                                                           "WHERE ft.ftrelid = '%u'",
12863                                                                           tbinfo->dobj.catId.oid);
12864                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12865                                         i_srvname = PQfnumber(res, "srvname");
12866                                         i_ftoptions = PQfnumber(res, "ftoptions");
12867                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
12868                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
12869                                         PQclear(res);
12870                                         destroyPQExpBuffer(query);
12871                                         break;
12872                                 }
12873                         case (RELKIND_MATVIEW):
12874                                 reltypename = "MATERIALIZED VIEW";
12875                                 srvname = NULL;
12876                                 ftoptions = NULL;
12877                                 break;
12878                         default:
12879                                 reltypename = "TABLE";
12880                                 srvname = NULL;
12881                                 ftoptions = NULL;
12882                 }
12883
12884                 numParents = tbinfo->numParents;
12885                 parents = tbinfo->parents;
12886
12887                 /*
12888                  * DROP must be fully qualified in case same name appears in
12889                  * pg_catalog
12890                  */
12891                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
12892                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
12893                 appendPQExpBuffer(delq, "%s;\n",
12894                                                   fmtId(tbinfo->dobj.name));
12895
12896                 appendPQExpBuffer(labelq, "%s %s", reltypename,
12897                                                   fmtId(tbinfo->dobj.name));
12898
12899                 if (binary_upgrade)
12900                         binary_upgrade_set_pg_class_oids(fout, q,
12901                                                                                          tbinfo->dobj.catId.oid, false);
12902
12903                 appendPQExpBuffer(q, "CREATE %s%s %s",
12904                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
12905                                                   "UNLOGGED " : "",
12906                                                   reltypename,
12907                                                   fmtId(tbinfo->dobj.name));
12908
12909                 /*
12910                  * Attach to type, if reloftype; except in case of a binary upgrade,
12911                  * we dump the table normally and attach it to the type afterward.
12912                  */
12913                 if (tbinfo->reloftype && !binary_upgrade)
12914                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
12915
12916                 if (tbinfo->relkind != RELKIND_MATVIEW)
12917                 {
12918                         /* Dump the attributes */
12919                         actual_atts = 0;
12920                         for (j = 0; j < tbinfo->numatts; j++)
12921                         {
12922                                 /*
12923                                  * Normally, dump if it's locally defined in this table, and
12924                                  * not dropped.  But for binary upgrade, we'll dump all the
12925                                  * columns, and then fix up the dropped and nonlocal cases
12926                                  * below.
12927                                  */
12928                                 if (shouldPrintColumn(tbinfo, j))
12929                                 {
12930                                         /*
12931                                          * Default value --- suppress if to be printed separately.
12932                                          */
12933                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
12934                                                                                          !tbinfo->attrdefs[j]->separate);
12935
12936                                         /*
12937                                          * Not Null constraint --- suppress if inherited, except
12938                                          * in binary-upgrade case where that won't work.
12939                                          */
12940                                         bool            has_notnull = (tbinfo->notnull[j] &&
12941                                                                                            (!tbinfo->inhNotNull[j] ||
12942                                                                                                 binary_upgrade));
12943
12944                                         /* Skip column if fully defined by reloftype */
12945                                         if (tbinfo->reloftype &&
12946                                                 !has_default && !has_notnull && !binary_upgrade)
12947                                                 continue;
12948
12949                                         /* Format properly if not first attr */
12950                                         if (actual_atts == 0)
12951                                                 appendPQExpBuffer(q, " (");
12952                                         else
12953                                                 appendPQExpBuffer(q, ",");
12954                                         appendPQExpBuffer(q, "\n    ");
12955                                         actual_atts++;
12956
12957                                         /* Attribute name */
12958                                         appendPQExpBuffer(q, "%s",
12959                                                                           fmtId(tbinfo->attnames[j]));
12960
12961                                         if (tbinfo->attisdropped[j])
12962                                         {
12963                                                 /*
12964                                                  * ALTER TABLE DROP COLUMN clears
12965                                                  * pg_attribute.atttypid, so we will not have gotten a
12966                                                  * valid type name; insert INTEGER as a stopgap. We'll
12967                                                  * clean things up later.
12968                                                  */
12969                                                 appendPQExpBuffer(q, " INTEGER /* dummy */");
12970                                                 /* Skip all the rest, too */
12971                                                 continue;
12972                                         }
12973
12974                                         /* Attribute type */
12975                                         if (tbinfo->reloftype && !binary_upgrade)
12976                                         {
12977                                                 appendPQExpBuffer(q, " WITH OPTIONS");
12978                                         }
12979                                         else if (fout->remoteVersion >= 70100)
12980                                         {
12981                                                 appendPQExpBuffer(q, " %s",
12982                                                                                   tbinfo->atttypnames[j]);
12983                                         }
12984                                         else
12985                                         {
12986                                                 /* If no format_type, fake it */
12987                                                 appendPQExpBuffer(q, " %s",
12988                                                                                   myFormatType(tbinfo->atttypnames[j],
12989                                                                                                            tbinfo->atttypmod[j]));
12990                                         }
12991
12992                                         /* Add collation if not default for the type */
12993                                         if (OidIsValid(tbinfo->attcollation[j]))
12994                                         {
12995                                                 CollInfo   *coll;
12996
12997                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
12998                                                 if (coll)
12999                                                 {
13000                                                         /* always schema-qualify, don't try to be smart */
13001                                                         appendPQExpBuffer(q, " COLLATE %s.",
13002                                                                          fmtId(coll->dobj.namespace->dobj.name));
13003                                                         appendPQExpBuffer(q, "%s",
13004                                                                                           fmtId(coll->dobj.name));
13005                                                 }
13006                                         }
13007
13008                                         if (has_default)
13009                                                 appendPQExpBuffer(q, " DEFAULT %s",
13010                                                                                   tbinfo->attrdefs[j]->adef_expr);
13011
13012                                         if (has_notnull)
13013                                                 appendPQExpBuffer(q, " NOT NULL");
13014                                 }
13015                         }
13016
13017                         /*
13018                          * Add non-inherited CHECK constraints, if any.
13019                          */
13020                         for (j = 0; j < tbinfo->ncheck; j++)
13021                         {
13022                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13023
13024                                 if (constr->separate || !constr->conislocal)
13025                                         continue;
13026
13027                                 if (actual_atts == 0)
13028                                         appendPQExpBuffer(q, " (\n    ");
13029                                 else
13030                                         appendPQExpBuffer(q, ",\n    ");
13031
13032                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13033                                                                   fmtId(constr->dobj.name));
13034                                 appendPQExpBuffer(q, "%s", constr->condef);
13035
13036                                 actual_atts++;
13037                         }
13038
13039                         if (actual_atts)
13040                                 appendPQExpBuffer(q, "\n)");
13041                         else if (!(tbinfo->reloftype && !binary_upgrade))
13042                         {
13043                                 /*
13044                                  * We must have a parenthesized attribute list, even though
13045                                  * empty, when not using the OF TYPE syntax.
13046                                  */
13047                                 appendPQExpBuffer(q, " (\n)");
13048                         }
13049
13050                         if (numParents > 0 && !binary_upgrade)
13051                         {
13052                                 appendPQExpBuffer(q, "\nINHERITS (");
13053                                 for (k = 0; k < numParents; k++)
13054                                 {
13055                                         TableInfo  *parentRel = parents[k];
13056
13057                                         if (k > 0)
13058                                                 appendPQExpBuffer(q, ", ");
13059                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13060                                                 appendPQExpBuffer(q, "%s.",
13061                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13062                                         appendPQExpBuffer(q, "%s",
13063                                                                           fmtId(parentRel->dobj.name));
13064                                 }
13065                                 appendPQExpBuffer(q, ")");
13066                         }
13067
13068                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13069                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13070                 }
13071
13072                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13073                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13074                 {
13075                         bool            addcomma = false;
13076
13077                         appendPQExpBuffer(q, "\nWITH (");
13078                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13079                         {
13080                                 addcomma = true;
13081                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
13082                         }
13083                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13084                         {
13085                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13086                                                                   tbinfo->toast_reloptions);
13087                         }
13088                         appendPQExpBuffer(q, ")");
13089                 }
13090
13091                 /* Dump generic options if any */
13092                 if (ftoptions && ftoptions[0])
13093                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13094
13095                 /*
13096                  * For materialized views, create the AS clause just like a view.
13097                  */
13098                 if (tbinfo->relkind == RELKIND_MATVIEW)
13099                 {
13100                         PQExpBuffer result;
13101
13102                         result = createViewAsClause(fout, tbinfo);
13103                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13104                                                           result->data);
13105                         destroyPQExpBuffer(result);
13106                 }
13107                 else
13108                         appendPQExpBuffer(q, ";\n");
13109
13110                 /*
13111                  * To create binary-compatible heap files, we have to ensure the same
13112                  * physical column order, including dropped columns, as in the
13113                  * original.  Therefore, we create dropped columns above and drop them
13114                  * here, also updating their attlen/attalign values so that the
13115                  * dropped column can be skipped properly.      (We do not bother with
13116                  * restoring the original attbyval setting.)  Also, inheritance
13117                  * relationships are set up by doing ALTER INHERIT rather than using
13118                  * an INHERITS clause --- the latter would possibly mess up the column
13119                  * order.  That also means we have to take care about setting
13120                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13121                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13122                  */
13123                 if (binary_upgrade && tbinfo->relkind == RELKIND_RELATION)
13124                 {
13125                         for (j = 0; j < tbinfo->numatts; j++)
13126                         {
13127                                 if (tbinfo->attisdropped[j])
13128                                 {
13129                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
13130                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13131                                                                           "SET attlen = %d, "
13132                                                                           "attalign = '%c', attbyval = false\n"
13133                                                                           "WHERE attname = ",
13134                                                                           tbinfo->attlen[j],
13135                                                                           tbinfo->attalign[j]);
13136                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13137                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13138                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13139                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13140
13141                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13142                                                                           fmtId(tbinfo->dobj.name));
13143                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13144                                                                           fmtId(tbinfo->attnames[j]));
13145                                 }
13146                                 else if (!tbinfo->attislocal[j])
13147                                 {
13148                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
13149                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13150                                                                           "SET attislocal = false\n"
13151                                                                           "WHERE attname = ");
13152                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13153                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
13154                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13155                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13156                                 }
13157                         }
13158
13159                         for (k = 0; k < tbinfo->ncheck; k++)
13160                         {
13161                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13162
13163                                 if (constr->separate || constr->conislocal)
13164                                         continue;
13165
13166                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13167                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13168                                                                   fmtId(tbinfo->dobj.name));
13169                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13170                                                                   fmtId(constr->dobj.name));
13171                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13172                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
13173                                                                   "SET conislocal = false\n"
13174                                                                   "WHERE contype = 'c' AND conname = ");
13175                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13176                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
13177                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13178                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13179                         }
13180
13181                         if (numParents > 0)
13182                         {
13183                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13184                                 for (k = 0; k < numParents; k++)
13185                                 {
13186                                         TableInfo  *parentRel = parents[k];
13187
13188                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13189                                                                           fmtId(tbinfo->dobj.name));
13190                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13191                                                 appendPQExpBuffer(q, "%s.",
13192                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13193                                         appendPQExpBuffer(q, "%s;\n",
13194                                                                           fmtId(parentRel->dobj.name));
13195                                 }
13196                         }
13197
13198                         if (tbinfo->reloftype)
13199                         {
13200                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13201                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13202                                                                   fmtId(tbinfo->dobj.name),
13203                                                                   tbinfo->reloftype);
13204                         }
13205
13206                         appendPQExpBuffer(q, "\n-- For binary upgrade, set heap's relfrozenxid\n");
13207                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13208                                                           "SET relfrozenxid = '%u'\n"
13209                                                           "WHERE oid = ",
13210                                                           tbinfo->frozenxid);
13211                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13212                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
13213
13214                         if (tbinfo->toast_oid)
13215                         {
13216                                 /* We preserve the toast oids, so we can use it during restore */
13217                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set toast's relfrozenxid\n");
13218                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13219                                                                   "SET relfrozenxid = '%u'\n"
13220                                                                   "WHERE oid = '%u';\n",
13221                                                                   tbinfo->toast_frozenxid, tbinfo->toast_oid);
13222                         }
13223                 }
13224
13225                 /*
13226                  * Dump additional per-column properties that we can't handle in the
13227                  * main CREATE TABLE command.
13228                  */
13229                 for (j = 0; j < tbinfo->numatts; j++)
13230                 {
13231                         /* None of this applies to dropped columns */
13232                         if (tbinfo->attisdropped[j])
13233                                 continue;
13234
13235                         /*
13236                          * If we didn't dump the column definition explicitly above, and
13237                          * it is NOT NULL and did not inherit that property from a parent,
13238                          * we have to mark it separately.
13239                          */
13240                         if (!shouldPrintColumn(tbinfo, j) &&
13241                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13242                         {
13243                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13244                                                                   fmtId(tbinfo->dobj.name));
13245                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13246                                                                   fmtId(tbinfo->attnames[j]));
13247                         }
13248
13249                         /*
13250                          * Dump per-column statistics information. We only issue an ALTER
13251                          * TABLE statement if the attstattarget entry for this column is
13252                          * non-negative (i.e. it's not the default value)
13253                          */
13254                         if (tbinfo->attstattarget[j] >= 0)
13255                         {
13256                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13257                                                                   fmtId(tbinfo->dobj.name));
13258                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13259                                                                   fmtId(tbinfo->attnames[j]));
13260                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13261                                                                   tbinfo->attstattarget[j]);
13262                         }
13263
13264                         /*
13265                          * Dump per-column storage information.  The statement is only
13266                          * dumped if the storage has been changed from the type's default.
13267                          */
13268                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13269                         {
13270                                 switch (tbinfo->attstorage[j])
13271                                 {
13272                                         case 'p':
13273                                                 storage = "PLAIN";
13274                                                 break;
13275                                         case 'e':
13276                                                 storage = "EXTERNAL";
13277                                                 break;
13278                                         case 'm':
13279                                                 storage = "MAIN";
13280                                                 break;
13281                                         case 'x':
13282                                                 storage = "EXTENDED";
13283                                                 break;
13284                                         default:
13285                                                 storage = NULL;
13286                                 }
13287
13288                                 /*
13289                                  * Only dump the statement if it's a storage type we recognize
13290                                  */
13291                                 if (storage != NULL)
13292                                 {
13293                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13294                                                                           fmtId(tbinfo->dobj.name));
13295                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
13296                                                                           fmtId(tbinfo->attnames[j]));
13297                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
13298                                                                           storage);
13299                                 }
13300                         }
13301
13302                         /*
13303                          * Dump per-column attributes.
13304                          */
13305                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
13306                         {
13307                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13308                                                                   fmtId(tbinfo->dobj.name));
13309                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13310                                                                   fmtId(tbinfo->attnames[j]));
13311                                 appendPQExpBuffer(q, "SET (%s);\n",
13312                                                                   tbinfo->attoptions[j]);
13313                         }
13314
13315                         /*
13316                          * Dump per-column fdw options.
13317                          */
13318                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
13319                                 tbinfo->attfdwoptions[j] &&
13320                                 tbinfo->attfdwoptions[j][0] != '\0')
13321                         {
13322                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13323                                                                   fmtId(tbinfo->dobj.name));
13324                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13325                                                                   fmtId(tbinfo->attnames[j]));
13326                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
13327                                                                   tbinfo->attfdwoptions[j]);
13328                         }
13329                 }
13330         }
13331
13332         if (binary_upgrade)
13333                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
13334
13335         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13336                                  tbinfo->dobj.name,
13337                                  tbinfo->dobj.namespace->dobj.name,
13338                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
13339                                  tbinfo->rolname,
13340                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
13341                                  reltypename, SECTION_PRE_DATA,
13342                                  q->data, delq->data, NULL,
13343                                  NULL, 0,
13344                                  NULL, NULL);
13345
13346
13347         /* Dump Table Comments */
13348         dumpTableComment(fout, tbinfo, reltypename);
13349
13350         /* Dump Table Security Labels */
13351         dumpTableSecLabel(fout, tbinfo, reltypename);
13352
13353         /* Dump comments on inlined table constraints */
13354         for (j = 0; j < tbinfo->ncheck; j++)
13355         {
13356                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13357
13358                 if (constr->separate || !constr->conislocal)
13359                         continue;
13360
13361                 dumpTableConstraintComment(fout, constr);
13362         }
13363
13364         destroyPQExpBuffer(q);
13365         destroyPQExpBuffer(delq);
13366         destroyPQExpBuffer(labelq);
13367 }
13368
13369 /*
13370  * dumpAttrDef --- dump an attribute's default-value declaration
13371  */
13372 static void
13373 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
13374 {
13375         TableInfo  *tbinfo = adinfo->adtable;
13376         int                     adnum = adinfo->adnum;
13377         PQExpBuffer q;
13378         PQExpBuffer delq;
13379
13380         /* Skip if table definition not to be dumped */
13381         if (!tbinfo->dobj.dump || dataOnly)
13382                 return;
13383
13384         /* Skip if not "separate"; it was dumped in the table's definition */
13385         if (!adinfo->separate)
13386                 return;
13387
13388         q = createPQExpBuffer();
13389         delq = createPQExpBuffer();
13390
13391         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13392                                           fmtId(tbinfo->dobj.name));
13393         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
13394                                           fmtId(tbinfo->attnames[adnum - 1]),
13395                                           adinfo->adef_expr);
13396
13397         /*
13398          * DROP must be fully qualified in case same name appears in pg_catalog
13399          */
13400         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13401                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13402         appendPQExpBuffer(delq, "%s ",
13403                                           fmtId(tbinfo->dobj.name));
13404         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
13405                                           fmtId(tbinfo->attnames[adnum - 1]));
13406
13407         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
13408                                  tbinfo->attnames[adnum - 1],
13409                                  tbinfo->dobj.namespace->dobj.name,
13410                                  NULL,
13411                                  tbinfo->rolname,
13412                                  false, "DEFAULT", SECTION_PRE_DATA,
13413                                  q->data, delq->data, NULL,
13414                                  NULL, 0,
13415                                  NULL, NULL);
13416
13417         destroyPQExpBuffer(q);
13418         destroyPQExpBuffer(delq);
13419 }
13420
13421 /*
13422  * getAttrName: extract the correct name for an attribute
13423  *
13424  * The array tblInfo->attnames[] only provides names of user attributes;
13425  * if a system attribute number is supplied, we have to fake it.
13426  * We also do a little bit of bounds checking for safety's sake.
13427  */
13428 static const char *
13429 getAttrName(int attrnum, TableInfo *tblInfo)
13430 {
13431         if (attrnum > 0 && attrnum <= tblInfo->numatts)
13432                 return tblInfo->attnames[attrnum - 1];
13433         switch (attrnum)
13434         {
13435                 case SelfItemPointerAttributeNumber:
13436                         return "ctid";
13437                 case ObjectIdAttributeNumber:
13438                         return "oid";
13439                 case MinTransactionIdAttributeNumber:
13440                         return "xmin";
13441                 case MinCommandIdAttributeNumber:
13442                         return "cmin";
13443                 case MaxTransactionIdAttributeNumber:
13444                         return "xmax";
13445                 case MaxCommandIdAttributeNumber:
13446                         return "cmax";
13447                 case TableOidAttributeNumber:
13448                         return "tableoid";
13449         }
13450         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
13451                                   attrnum, tblInfo->dobj.name);
13452         return NULL;                            /* keep compiler quiet */
13453 }
13454
13455 /*
13456  * dumpIndex
13457  *        write out to fout a user-defined index
13458  */
13459 static void
13460 dumpIndex(Archive *fout, IndxInfo *indxinfo)
13461 {
13462         TableInfo  *tbinfo = indxinfo->indextable;
13463         PQExpBuffer q;
13464         PQExpBuffer delq;
13465         PQExpBuffer labelq;
13466
13467         if (dataOnly)
13468                 return;
13469
13470         q = createPQExpBuffer();
13471         delq = createPQExpBuffer();
13472         labelq = createPQExpBuffer();
13473
13474         appendPQExpBuffer(labelq, "INDEX %s",
13475                                           fmtId(indxinfo->dobj.name));
13476
13477         /*
13478          * If there's an associated constraint, don't dump the index per se, but
13479          * do dump any comment for it.  (This is safe because dependency ordering
13480          * will have ensured the constraint is emitted first.)
13481          */
13482         if (indxinfo->indexconstraint == 0)
13483         {
13484                 if (binary_upgrade)
13485                         binary_upgrade_set_pg_class_oids(fout, q,
13486                                                                                          indxinfo->dobj.catId.oid, true);
13487
13488                 /* Plain secondary index */
13489                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
13490
13491                 /* If the index is clustered, we need to record that. */
13492                 if (indxinfo->indisclustered)
13493                 {
13494                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13495                                                           fmtId(tbinfo->dobj.name));
13496                         appendPQExpBuffer(q, " ON %s;\n",
13497                                                           fmtId(indxinfo->dobj.name));
13498                 }
13499
13500                 /*
13501                  * DROP must be fully qualified in case same name appears in
13502                  * pg_catalog
13503                  */
13504                 appendPQExpBuffer(delq, "DROP INDEX %s.",
13505                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13506                 appendPQExpBuffer(delq, "%s;\n",
13507                                                   fmtId(indxinfo->dobj.name));
13508
13509                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
13510                                          indxinfo->dobj.name,
13511                                          tbinfo->dobj.namespace->dobj.name,
13512                                          indxinfo->tablespace,
13513                                          tbinfo->rolname, false,
13514                                          "INDEX", SECTION_POST_DATA,
13515                                          q->data, delq->data, NULL,
13516                                          NULL, 0,
13517                                          NULL, NULL);
13518         }
13519
13520         /* Dump Index Comments */
13521         dumpComment(fout, labelq->data,
13522                                 tbinfo->dobj.namespace->dobj.name,
13523                                 tbinfo->rolname,
13524                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
13525
13526         destroyPQExpBuffer(q);
13527         destroyPQExpBuffer(delq);
13528         destroyPQExpBuffer(labelq);
13529 }
13530
13531 /*
13532  * dumpConstraint
13533  *        write out to fout a user-defined constraint
13534  */
13535 static void
13536 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
13537 {
13538         TableInfo  *tbinfo = coninfo->contable;
13539         PQExpBuffer q;
13540         PQExpBuffer delq;
13541
13542         /* Skip if not to be dumped */
13543         if (!coninfo->dobj.dump || dataOnly)
13544                 return;
13545
13546         q = createPQExpBuffer();
13547         delq = createPQExpBuffer();
13548
13549         if (coninfo->contype == 'p' ||
13550                 coninfo->contype == 'u' ||
13551                 coninfo->contype == 'x')
13552         {
13553                 /* Index-related constraint */
13554                 IndxInfo   *indxinfo;
13555                 int                     k;
13556
13557                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
13558
13559                 if (indxinfo == NULL)
13560                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
13561                                                   coninfo->dobj.name);
13562
13563                 if (binary_upgrade)
13564                         binary_upgrade_set_pg_class_oids(fout, q,
13565                                                                                          indxinfo->dobj.catId.oid, true);
13566
13567                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13568                                                   fmtId(tbinfo->dobj.name));
13569                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
13570                                                   fmtId(coninfo->dobj.name));
13571
13572                 if (coninfo->condef)
13573                 {
13574                         /* pg_get_constraintdef should have provided everything */
13575                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
13576                 }
13577                 else
13578                 {
13579                         appendPQExpBuffer(q, "%s (",
13580                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
13581                         for (k = 0; k < indxinfo->indnkeys; k++)
13582                         {
13583                                 int                     indkey = (int) indxinfo->indkeys[k];
13584                                 const char *attname;
13585
13586                                 if (indkey == InvalidAttrNumber)
13587                                         break;
13588                                 attname = getAttrName(indkey, tbinfo);
13589
13590                                 appendPQExpBuffer(q, "%s%s",
13591                                                                   (k == 0) ? "" : ", ",
13592                                                                   fmtId(attname));
13593                         }
13594
13595                         appendPQExpBuffer(q, ")");
13596
13597                         if (indxinfo->options && strlen(indxinfo->options) > 0)
13598                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
13599
13600                         if (coninfo->condeferrable)
13601                         {
13602                                 appendPQExpBuffer(q, " DEFERRABLE");
13603                                 if (coninfo->condeferred)
13604                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
13605                         }
13606
13607                         appendPQExpBuffer(q, ";\n");
13608                 }
13609
13610                 /* If the index is clustered, we need to record that. */
13611                 if (indxinfo->indisclustered)
13612                 {
13613                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
13614                                                           fmtId(tbinfo->dobj.name));
13615                         appendPQExpBuffer(q, " ON %s;\n",
13616                                                           fmtId(indxinfo->dobj.name));
13617                 }
13618
13619                 /*
13620                  * DROP must be fully qualified in case same name appears in
13621                  * pg_catalog
13622                  */
13623                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13624                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13625                 appendPQExpBuffer(delq, "%s ",
13626                                                   fmtId(tbinfo->dobj.name));
13627                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13628                                                   fmtId(coninfo->dobj.name));
13629
13630                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13631                                          coninfo->dobj.name,
13632                                          tbinfo->dobj.namespace->dobj.name,
13633                                          indxinfo->tablespace,
13634                                          tbinfo->rolname, false,
13635                                          "CONSTRAINT", SECTION_POST_DATA,
13636                                          q->data, delq->data, NULL,
13637                                          NULL, 0,
13638                                          NULL, NULL);
13639         }
13640         else if (coninfo->contype == 'f')
13641         {
13642                 /*
13643                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
13644                  * current table data is not processed
13645                  */
13646                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
13647                                                   fmtId(tbinfo->dobj.name));
13648                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13649                                                   fmtId(coninfo->dobj.name),
13650                                                   coninfo->condef);
13651
13652                 /*
13653                  * DROP must be fully qualified in case same name appears in
13654                  * pg_catalog
13655                  */
13656                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
13657                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13658                 appendPQExpBuffer(delq, "%s ",
13659                                                   fmtId(tbinfo->dobj.name));
13660                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13661                                                   fmtId(coninfo->dobj.name));
13662
13663                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13664                                          coninfo->dobj.name,
13665                                          tbinfo->dobj.namespace->dobj.name,
13666                                          NULL,
13667                                          tbinfo->rolname, false,
13668                                          "FK CONSTRAINT", SECTION_POST_DATA,
13669                                          q->data, delq->data, NULL,
13670                                          NULL, 0,
13671                                          NULL, NULL);
13672         }
13673         else if (coninfo->contype == 'c' && tbinfo)
13674         {
13675                 /* CHECK constraint on a table */
13676
13677                 /* Ignore if not to be dumped separately */
13678                 if (coninfo->separate)
13679                 {
13680                         /* not ONLY since we want it to propagate to children */
13681                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
13682                                                           fmtId(tbinfo->dobj.name));
13683                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13684                                                           fmtId(coninfo->dobj.name),
13685                                                           coninfo->condef);
13686
13687                         /*
13688                          * DROP must be fully qualified in case same name appears in
13689                          * pg_catalog
13690                          */
13691                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
13692                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13693                         appendPQExpBuffer(delq, "%s ",
13694                                                           fmtId(tbinfo->dobj.name));
13695                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13696                                                           fmtId(coninfo->dobj.name));
13697
13698                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13699                                                  coninfo->dobj.name,
13700                                                  tbinfo->dobj.namespace->dobj.name,
13701                                                  NULL,
13702                                                  tbinfo->rolname, false,
13703                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13704                                                  q->data, delq->data, NULL,
13705                                                  NULL, 0,
13706                                                  NULL, NULL);
13707                 }
13708         }
13709         else if (coninfo->contype == 'c' && tbinfo == NULL)
13710         {
13711                 /* CHECK constraint on a domain */
13712                 TypeInfo   *tyinfo = coninfo->condomain;
13713
13714                 /* Ignore if not to be dumped separately */
13715                 if (coninfo->separate)
13716                 {
13717                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
13718                                                           fmtId(tyinfo->dobj.name));
13719                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
13720                                                           fmtId(coninfo->dobj.name),
13721                                                           coninfo->condef);
13722
13723                         /*
13724                          * DROP must be fully qualified in case same name appears in
13725                          * pg_catalog
13726                          */
13727                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
13728                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
13729                         appendPQExpBuffer(delq, "%s ",
13730                                                           fmtId(tyinfo->dobj.name));
13731                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
13732                                                           fmtId(coninfo->dobj.name));
13733
13734                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
13735                                                  coninfo->dobj.name,
13736                                                  tyinfo->dobj.namespace->dobj.name,
13737                                                  NULL,
13738                                                  tyinfo->rolname, false,
13739                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
13740                                                  q->data, delq->data, NULL,
13741                                                  NULL, 0,
13742                                                  NULL, NULL);
13743                 }
13744         }
13745         else
13746         {
13747                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
13748                                           coninfo->contype);
13749         }
13750
13751         /* Dump Constraint Comments --- only works for table constraints */
13752         if (tbinfo && coninfo->separate)
13753                 dumpTableConstraintComment(fout, coninfo);
13754
13755         destroyPQExpBuffer(q);
13756         destroyPQExpBuffer(delq);
13757 }
13758
13759 /*
13760  * dumpTableConstraintComment --- dump a constraint's comment if any
13761  *
13762  * This is split out because we need the function in two different places
13763  * depending on whether the constraint is dumped as part of CREATE TABLE
13764  * or as a separate ALTER command.
13765  */
13766 static void
13767 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
13768 {
13769         TableInfo  *tbinfo = coninfo->contable;
13770         PQExpBuffer labelq = createPQExpBuffer();
13771
13772         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
13773                                           fmtId(coninfo->dobj.name));
13774         appendPQExpBuffer(labelq, "ON %s",
13775                                           fmtId(tbinfo->dobj.name));
13776         dumpComment(fout, labelq->data,
13777                                 tbinfo->dobj.namespace->dobj.name,
13778                                 tbinfo->rolname,
13779                                 coninfo->dobj.catId, 0,
13780                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
13781
13782         destroyPQExpBuffer(labelq);
13783 }
13784
13785 /*
13786  * findLastBuiltInOid -
13787  * find the last built in oid
13788  *
13789  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
13790  * pg_database entry for the current database
13791  */
13792 static Oid
13793 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
13794 {
13795         PGresult   *res;
13796         Oid                     last_oid;
13797         PQExpBuffer query = createPQExpBuffer();
13798
13799         resetPQExpBuffer(query);
13800         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
13801         appendStringLiteralAH(query, dbname, fout);
13802
13803         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13804         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
13805         PQclear(res);
13806         destroyPQExpBuffer(query);
13807         return last_oid;
13808 }
13809
13810 /*
13811  * findLastBuiltInOid -
13812  * find the last built in oid
13813  *
13814  * For 7.0, we do this by assuming that the last thing that initdb does is to
13815  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
13816  * initdb won't be changing anymore, it'll do.
13817  */
13818 static Oid
13819 findLastBuiltinOid_V70(Archive *fout)
13820 {
13821         PGresult   *res;
13822         int                     last_oid;
13823
13824         res = ExecuteSqlQueryForSingleRow(fout,
13825                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
13826         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
13827         PQclear(res);
13828         return last_oid;
13829 }
13830
13831 /*
13832  * dumpSequence
13833  *        write the declaration (not data) of one user-defined sequence
13834  */
13835 static void
13836 dumpSequence(Archive *fout, TableInfo *tbinfo)
13837 {
13838         PGresult   *res;
13839         char       *startv,
13840                            *incby,
13841                            *maxv = NULL,
13842                            *minv = NULL,
13843                            *cache;
13844         char            bufm[100],
13845                                 bufx[100];
13846         bool            cycled;
13847         PQExpBuffer query = createPQExpBuffer();
13848         PQExpBuffer delqry = createPQExpBuffer();
13849         PQExpBuffer labelq = createPQExpBuffer();
13850
13851         /* Make sure we are in proper schema */
13852         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13853
13854         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
13855         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
13856
13857         if (fout->remoteVersion >= 80400)
13858         {
13859                 appendPQExpBuffer(query,
13860                                                   "SELECT sequence_name, "
13861                                                   "start_value, increment_by, "
13862                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13863                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13864                                                   "     ELSE max_value "
13865                                                   "END AS max_value, "
13866                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13867                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13868                                                   "     ELSE min_value "
13869                                                   "END AS min_value, "
13870                                                   "cache_value, is_cycled FROM %s",
13871                                                   bufx, bufm,
13872                                                   fmtId(tbinfo->dobj.name));
13873         }
13874         else
13875         {
13876                 appendPQExpBuffer(query,
13877                                                   "SELECT sequence_name, "
13878                                                   "0 AS start_value, increment_by, "
13879                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
13880                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
13881                                                   "     ELSE max_value "
13882                                                   "END AS max_value, "
13883                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
13884                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
13885                                                   "     ELSE min_value "
13886                                                   "END AS min_value, "
13887                                                   "cache_value, is_cycled FROM %s",
13888                                                   bufx, bufm,
13889                                                   fmtId(tbinfo->dobj.name));
13890         }
13891
13892         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13893
13894         if (PQntuples(res) != 1)
13895         {
13896                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
13897                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
13898                                                                  PQntuples(res)),
13899                                   tbinfo->dobj.name, PQntuples(res));
13900                 exit_nicely(1);
13901         }
13902
13903         /* Disable this check: it fails if sequence has been renamed */
13904 #ifdef NOT_USED
13905         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
13906         {
13907                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
13908                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
13909                 exit_nicely(1);
13910         }
13911 #endif
13912
13913         startv = PQgetvalue(res, 0, 1);
13914         incby = PQgetvalue(res, 0, 2);
13915         if (!PQgetisnull(res, 0, 3))
13916                 maxv = PQgetvalue(res, 0, 3);
13917         if (!PQgetisnull(res, 0, 4))
13918                 minv = PQgetvalue(res, 0, 4);
13919         cache = PQgetvalue(res, 0, 5);
13920         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
13921
13922         /*
13923          * DROP must be fully qualified in case same name appears in pg_catalog
13924          */
13925         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
13926                                           fmtId(tbinfo->dobj.namespace->dobj.name));
13927         appendPQExpBuffer(delqry, "%s;\n",
13928                                           fmtId(tbinfo->dobj.name));
13929
13930         resetPQExpBuffer(query);
13931
13932         if (binary_upgrade)
13933         {
13934                 binary_upgrade_set_pg_class_oids(fout, query,
13935                                                                                  tbinfo->dobj.catId.oid, false);
13936                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
13937                                                                                                 tbinfo->dobj.catId.oid);
13938         }
13939
13940         appendPQExpBuffer(query,
13941                                           "CREATE SEQUENCE %s\n",
13942                                           fmtId(tbinfo->dobj.name));
13943
13944         if (fout->remoteVersion >= 80400)
13945                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
13946
13947         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
13948
13949         if (minv)
13950                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
13951         else
13952                 appendPQExpBuffer(query, "    NO MINVALUE\n");
13953
13954         if (maxv)
13955                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
13956         else
13957                 appendPQExpBuffer(query, "    NO MAXVALUE\n");
13958
13959         appendPQExpBuffer(query,
13960                                           "    CACHE %s%s",
13961                                           cache, (cycled ? "\n    CYCLE" : ""));
13962
13963         appendPQExpBuffer(query, ";\n");
13964
13965         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
13966
13967         /* binary_upgrade:      no need to clear TOAST table oid */
13968
13969         if (binary_upgrade)
13970                 binary_upgrade_extension_member(query, &tbinfo->dobj,
13971                                                                                 labelq->data);
13972
13973         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13974                                  tbinfo->dobj.name,
13975                                  tbinfo->dobj.namespace->dobj.name,
13976                                  NULL,
13977                                  tbinfo->rolname,
13978                                  false, "SEQUENCE", SECTION_PRE_DATA,
13979                                  query->data, delqry->data, NULL,
13980                                  NULL, 0,
13981                                  NULL, NULL);
13982
13983         /*
13984          * If the sequence is owned by a table column, emit the ALTER for it as a
13985          * separate TOC entry immediately following the sequence's own entry. It's
13986          * OK to do this rather than using full sorting logic, because the
13987          * dependency that tells us it's owned will have forced the table to be
13988          * created first.  We can't just include the ALTER in the TOC entry
13989          * because it will fail if we haven't reassigned the sequence owner to
13990          * match the table's owner.
13991          *
13992          * We need not schema-qualify the table reference because both sequence
13993          * and table must be in the same schema.
13994          */
13995         if (OidIsValid(tbinfo->owning_tab))
13996         {
13997                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
13998
13999                 if (owning_tab && owning_tab->dobj.dump)
14000                 {
14001                         resetPQExpBuffer(query);
14002                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14003                                                           fmtId(tbinfo->dobj.name));
14004                         appendPQExpBuffer(query, " OWNED BY %s",
14005                                                           fmtId(owning_tab->dobj.name));
14006                         appendPQExpBuffer(query, ".%s;\n",
14007                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14008
14009                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14010                                                  tbinfo->dobj.name,
14011                                                  tbinfo->dobj.namespace->dobj.name,
14012                                                  NULL,
14013                                                  tbinfo->rolname,
14014                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14015                                                  query->data, "", NULL,
14016                                                  &(tbinfo->dobj.dumpId), 1,
14017                                                  NULL, NULL);
14018                 }
14019         }
14020
14021         /* Dump Sequence Comments and Security Labels */
14022         dumpComment(fout, labelq->data,
14023                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14024                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14025         dumpSecLabel(fout, labelq->data,
14026                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14027                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14028
14029         PQclear(res);
14030
14031         destroyPQExpBuffer(query);
14032         destroyPQExpBuffer(delqry);
14033         destroyPQExpBuffer(labelq);
14034 }
14035
14036 /*
14037  * dumpSequenceData
14038  *        write the data of one user-defined sequence
14039  */
14040 static void
14041 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14042 {
14043         TableInfo  *tbinfo = tdinfo->tdtable;
14044         PGresult   *res;
14045         char       *last;
14046         bool            called;
14047         PQExpBuffer query = createPQExpBuffer();
14048
14049         /* Make sure we are in proper schema */
14050         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14051
14052         appendPQExpBuffer(query,
14053                                           "SELECT last_value, is_called FROM %s",
14054                                           fmtId(tbinfo->dobj.name));
14055
14056         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14057
14058         if (PQntuples(res) != 1)
14059         {
14060                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14061                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14062                                                                  PQntuples(res)),
14063                                   tbinfo->dobj.name, PQntuples(res));
14064                 exit_nicely(1);
14065         }
14066
14067         last = PQgetvalue(res, 0, 0);
14068         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14069
14070         resetPQExpBuffer(query);
14071         appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
14072         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14073         appendPQExpBuffer(query, ", %s, %s);\n",
14074                                           last, (called ? "true" : "false"));
14075
14076         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14077                                  tbinfo->dobj.name,
14078                                  tbinfo->dobj.namespace->dobj.name,
14079                                  NULL,
14080                                  tbinfo->rolname,
14081                                  false, "SEQUENCE SET", SECTION_DATA,
14082                                  query->data, "", NULL,
14083                                  &(tbinfo->dobj.dumpId), 1,
14084                                  NULL, NULL);
14085
14086         PQclear(res);
14087
14088         destroyPQExpBuffer(query);
14089 }
14090
14091 static void
14092 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
14093 {
14094         TableInfo  *tbinfo = tginfo->tgtable;
14095         PQExpBuffer query;
14096         PQExpBuffer delqry;
14097         PQExpBuffer labelq;
14098         char       *tgargs;
14099         size_t          lentgargs;
14100         const char *p;
14101         int                     findx;
14102
14103         if (dataOnly)
14104                 return;
14105
14106         query = createPQExpBuffer();
14107         delqry = createPQExpBuffer();
14108         labelq = createPQExpBuffer();
14109
14110         /*
14111          * DROP must be fully qualified in case same name appears in pg_catalog
14112          */
14113         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14114                                           fmtId(tginfo->dobj.name));
14115         appendPQExpBuffer(delqry, "ON %s.",
14116                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14117         appendPQExpBuffer(delqry, "%s;\n",
14118                                           fmtId(tbinfo->dobj.name));
14119
14120         if (tginfo->tgdef)
14121         {
14122                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14123         }
14124         else
14125         {
14126                 if (tginfo->tgisconstraint)
14127                 {
14128                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
14129                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14130                 }
14131                 else
14132                 {
14133                         appendPQExpBuffer(query, "CREATE TRIGGER ");
14134                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14135                 }
14136                 appendPQExpBuffer(query, "\n    ");
14137
14138                 /* Trigger type */
14139                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14140                         appendPQExpBuffer(query, "BEFORE");
14141                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14142                         appendPQExpBuffer(query, "AFTER");
14143                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14144                         appendPQExpBuffer(query, "INSTEAD OF");
14145                 else
14146                 {
14147                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14148                         exit_nicely(1);
14149                 }
14150
14151                 findx = 0;
14152                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14153                 {
14154                         appendPQExpBuffer(query, " INSERT");
14155                         findx++;
14156                 }
14157                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14158                 {
14159                         if (findx > 0)
14160                                 appendPQExpBuffer(query, " OR DELETE");
14161                         else
14162                                 appendPQExpBuffer(query, " DELETE");
14163                         findx++;
14164                 }
14165                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14166                 {
14167                         if (findx > 0)
14168                                 appendPQExpBuffer(query, " OR UPDATE");
14169                         else
14170                                 appendPQExpBuffer(query, " UPDATE");
14171                         findx++;
14172                 }
14173                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14174                 {
14175                         if (findx > 0)
14176                                 appendPQExpBuffer(query, " OR TRUNCATE");
14177                         else
14178                                 appendPQExpBuffer(query, " TRUNCATE");
14179                         findx++;
14180                 }
14181                 appendPQExpBuffer(query, " ON %s\n",
14182                                                   fmtId(tbinfo->dobj.name));
14183
14184                 if (tginfo->tgisconstraint)
14185                 {
14186                         if (OidIsValid(tginfo->tgconstrrelid))
14187                         {
14188                                 /* If we are using regclass, name is already quoted */
14189                                 if (fout->remoteVersion >= 70300)
14190                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14191                                                                           tginfo->tgconstrrelname);
14192                                 else
14193                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14194                                                                           fmtId(tginfo->tgconstrrelname));
14195                         }
14196                         if (!tginfo->tgdeferrable)
14197                                 appendPQExpBuffer(query, "NOT ");
14198                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
14199                         if (tginfo->tginitdeferred)
14200                                 appendPQExpBuffer(query, "DEFERRED\n");
14201                         else
14202                                 appendPQExpBuffer(query, "IMMEDIATE\n");
14203                 }
14204
14205                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14206                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
14207                 else
14208                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
14209
14210                 /* In 7.3, result of regproc is already quoted */
14211                 if (fout->remoteVersion >= 70300)
14212                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14213                                                           tginfo->tgfname);
14214                 else
14215                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14216                                                           fmtId(tginfo->tgfname));
14217
14218                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14219                                                                                   &lentgargs);
14220                 p = tgargs;
14221                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14222                 {
14223                         /* find the embedded null that terminates this trigger argument */
14224                         size_t          tlen = strlen(p);
14225
14226                         if (p + tlen >= tgargs + lentgargs)
14227                         {
14228                                 /* hm, not found before end of bytea value... */
14229                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14230                                                   tginfo->tgargs,
14231                                                   tginfo->dobj.name,
14232                                                   tbinfo->dobj.name);
14233                                 exit_nicely(1);
14234                         }
14235
14236                         if (findx > 0)
14237                                 appendPQExpBuffer(query, ", ");
14238                         appendStringLiteralAH(query, p, fout);
14239                         p += tlen + 1;
14240                 }
14241                 free(tgargs);
14242                 appendPQExpBuffer(query, ");\n");
14243         }
14244
14245         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
14246         {
14247                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
14248                                                   fmtId(tbinfo->dobj.name));
14249                 switch (tginfo->tgenabled)
14250                 {
14251                         case 'D':
14252                         case 'f':
14253                                 appendPQExpBuffer(query, "DISABLE");
14254                                 break;
14255                         case 'A':
14256                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14257                                 break;
14258                         case 'R':
14259                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14260                                 break;
14261                         default:
14262                                 appendPQExpBuffer(query, "ENABLE");
14263                                 break;
14264                 }
14265                 appendPQExpBuffer(query, " TRIGGER %s;\n",
14266                                                   fmtId(tginfo->dobj.name));
14267         }
14268
14269         appendPQExpBuffer(labelq, "TRIGGER %s ",
14270                                           fmtId(tginfo->dobj.name));
14271         appendPQExpBuffer(labelq, "ON %s",
14272                                           fmtId(tbinfo->dobj.name));
14273
14274         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
14275                                  tginfo->dobj.name,
14276                                  tbinfo->dobj.namespace->dobj.name,
14277                                  NULL,
14278                                  tbinfo->rolname, false,
14279                                  "TRIGGER", SECTION_POST_DATA,
14280                                  query->data, delqry->data, NULL,
14281                                  NULL, 0,
14282                                  NULL, NULL);
14283
14284         dumpComment(fout, labelq->data,
14285                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14286                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
14287
14288         destroyPQExpBuffer(query);
14289         destroyPQExpBuffer(delqry);
14290         destroyPQExpBuffer(labelq);
14291 }
14292
14293 static void
14294 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
14295 {
14296         PQExpBuffer query;
14297         PQExpBuffer labelq;
14298
14299         query = createPQExpBuffer();
14300         labelq = createPQExpBuffer();
14301
14302         appendPQExpBuffer(query, "CREATE EVENT TRIGGER ");
14303         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
14304         appendPQExpBuffer(query, " ON ");
14305         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
14306         appendPQExpBufferStr(query, " ");
14307
14308         if (strcmp("", evtinfo->evttags) != 0)
14309         {
14310                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
14311                 appendPQExpBufferStr(query, evtinfo->evttags);
14312                 appendPQExpBufferStr(query, ") ");
14313         }
14314
14315         appendPQExpBuffer(query, "\n   EXECUTE PROCEDURE ");
14316         appendPQExpBufferStr(query, evtinfo->evtfname);
14317         appendPQExpBuffer(query, "();\n");
14318
14319         if (evtinfo->evtenabled != 'O')
14320         {
14321                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
14322                                                   fmtId(evtinfo->dobj.name));
14323                 switch (evtinfo->evtenabled)
14324                 {
14325                         case 'D':
14326                                 appendPQExpBuffer(query, "DISABLE");
14327                                 break;
14328                         case 'A':
14329                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
14330                                 break;
14331                         case 'R':
14332                                 appendPQExpBuffer(query, "ENABLE REPLICA");
14333                                 break;
14334                         default:
14335                                 appendPQExpBuffer(query, "ENABLE");
14336                                 break;
14337                 }
14338                 appendPQExpBuffer(query, ";\n");
14339         }
14340         appendPQExpBuffer(labelq, "EVENT TRIGGER %s ",
14341                                           fmtId(evtinfo->dobj.name));
14342
14343         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
14344                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
14345                                  "EVENT TRIGGER", SECTION_POST_DATA,
14346                                  query->data, "", NULL, NULL, 0, NULL, NULL);
14347
14348         dumpComment(fout, labelq->data,
14349                                 NULL, NULL,
14350                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
14351
14352         destroyPQExpBuffer(query);
14353         destroyPQExpBuffer(labelq);
14354 }
14355
14356 /*
14357  * dumpRule
14358  *              Dump a rule
14359  */
14360 static void
14361 dumpRule(Archive *fout, RuleInfo *rinfo)
14362 {
14363         TableInfo  *tbinfo = rinfo->ruletable;
14364         PQExpBuffer query;
14365         PQExpBuffer cmd;
14366         PQExpBuffer delcmd;
14367         PQExpBuffer labelq;
14368         PGresult   *res;
14369
14370         /* Skip if not to be dumped */
14371         if (!rinfo->dobj.dump || dataOnly)
14372                 return;
14373
14374         /*
14375          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
14376          * we do not want to dump it as a separate object.
14377          */
14378         if (!rinfo->separate)
14379                 return;
14380
14381         /*
14382          * Make sure we are in proper schema.
14383          */
14384         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14385
14386         query = createPQExpBuffer();
14387         cmd = createPQExpBuffer();
14388         delcmd = createPQExpBuffer();
14389         labelq = createPQExpBuffer();
14390
14391         if (fout->remoteVersion >= 70300)
14392         {
14393                 appendPQExpBuffer(query,
14394                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
14395                                                   rinfo->dobj.catId.oid);
14396         }
14397         else
14398         {
14399                 /* Rule name was unique before 7.3 ... */
14400                 appendPQExpBuffer(query,
14401                                                   "SELECT pg_get_ruledef('%s') AS definition",
14402                                                   rinfo->dobj.name);
14403         }
14404
14405         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14406
14407         if (PQntuples(res) != 1)
14408         {
14409                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
14410                                   rinfo->dobj.name, tbinfo->dobj.name);
14411                 exit_nicely(1);
14412         }
14413
14414         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
14415
14416         /*
14417          * Add the command to alter the rules replication firing semantics if it
14418          * differs from the default.
14419          */
14420         if (rinfo->ev_enabled != 'O')
14421         {
14422                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
14423                 switch (rinfo->ev_enabled)
14424                 {
14425                         case 'A':
14426                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
14427                                                                   fmtId(rinfo->dobj.name));
14428                                 break;
14429                         case 'R':
14430                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
14431                                                                   fmtId(rinfo->dobj.name));
14432                                 break;
14433                         case 'D':
14434                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
14435                                                                   fmtId(rinfo->dobj.name));
14436                                 break;
14437                 }
14438         }
14439
14440         /*
14441          * Apply view's reloptions when its ON SELECT rule is separate.
14442          */
14443         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
14444         {
14445                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
14446                                                   fmtId(tbinfo->dobj.name),
14447                                                   rinfo->reloptions);
14448         }
14449
14450         /*
14451          * DROP must be fully qualified in case same name appears in pg_catalog
14452          */
14453         appendPQExpBuffer(delcmd, "DROP RULE %s ",
14454                                           fmtId(rinfo->dobj.name));
14455         appendPQExpBuffer(delcmd, "ON %s.",
14456                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14457         appendPQExpBuffer(delcmd, "%s;\n",
14458                                           fmtId(tbinfo->dobj.name));
14459
14460         appendPQExpBuffer(labelq, "RULE %s",
14461                                           fmtId(rinfo->dobj.name));
14462         appendPQExpBuffer(labelq, " ON %s",
14463                                           fmtId(tbinfo->dobj.name));
14464
14465         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
14466                                  rinfo->dobj.name,
14467                                  tbinfo->dobj.namespace->dobj.name,
14468                                  NULL,
14469                                  tbinfo->rolname, false,
14470                                  "RULE", SECTION_POST_DATA,
14471                                  cmd->data, delcmd->data, NULL,
14472                                  NULL, 0,
14473                                  NULL, NULL);
14474
14475         /* Dump rule comments */
14476         dumpComment(fout, labelq->data,
14477                                 tbinfo->dobj.namespace->dobj.name,
14478                                 tbinfo->rolname,
14479                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
14480
14481         PQclear(res);
14482
14483         destroyPQExpBuffer(query);
14484         destroyPQExpBuffer(cmd);
14485         destroyPQExpBuffer(delcmd);
14486         destroyPQExpBuffer(labelq);
14487 }
14488
14489 /*
14490  * getExtensionMembership --- obtain extension membership data
14491  */
14492 void
14493 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
14494                                            int numExtensions)
14495 {
14496         PQExpBuffer query;
14497         PGresult   *res;
14498         int                     ntups,
14499                                 i;
14500         int                     i_classid,
14501                                 i_objid,
14502                                 i_refclassid,
14503                                 i_refobjid;
14504         DumpableObject *dobj,
14505                            *refdobj;
14506
14507         /* Nothing to do if no extensions */
14508         if (numExtensions == 0)
14509                 return;
14510
14511         /* Make sure we are in proper schema */
14512         selectSourceSchema(fout, "pg_catalog");
14513
14514         query = createPQExpBuffer();
14515
14516         /* refclassid constraint is redundant but may speed the search */
14517         appendPQExpBuffer(query, "SELECT "
14518                                           "classid, objid, refclassid, refobjid "
14519                                           "FROM pg_depend "
14520                                           "WHERE refclassid = 'pg_extension'::regclass "
14521                                           "AND deptype = 'e' "
14522                                           "ORDER BY 3,4");
14523
14524         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14525
14526         ntups = PQntuples(res);
14527
14528         i_classid = PQfnumber(res, "classid");
14529         i_objid = PQfnumber(res, "objid");
14530         i_refclassid = PQfnumber(res, "refclassid");
14531         i_refobjid = PQfnumber(res, "refobjid");
14532
14533         /*
14534          * Since we ordered the SELECT by referenced ID, we can expect that
14535          * multiple entries for the same extension will appear together; this
14536          * saves on searches.
14537          */
14538         refdobj = NULL;
14539
14540         for (i = 0; i < ntups; i++)
14541         {
14542                 CatalogId       objId;
14543                 CatalogId       refobjId;
14544
14545                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14546                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14547                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14548                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14549
14550                 if (refdobj == NULL ||
14551                         refdobj->catId.tableoid != refobjId.tableoid ||
14552                         refdobj->catId.oid != refobjId.oid)
14553                         refdobj = findObjectByCatalogId(refobjId);
14554
14555                 /*
14556                  * Failure to find objects mentioned in pg_depend is not unexpected,
14557                  * since for example we don't collect info about TOAST tables.
14558                  */
14559                 if (refdobj == NULL)
14560                 {
14561 #ifdef NOT_USED
14562                         fprintf(stderr, "no referenced object %u %u\n",
14563                                         refobjId.tableoid, refobjId.oid);
14564 #endif
14565                         continue;
14566                 }
14567
14568                 dobj = findObjectByCatalogId(objId);
14569
14570                 if (dobj == NULL)
14571                 {
14572 #ifdef NOT_USED
14573                         fprintf(stderr, "no referencing object %u %u\n",
14574                                         objId.tableoid, objId.oid);
14575 #endif
14576                         continue;
14577                 }
14578
14579                 /* Record dependency so that getDependencies needn't repeat this */
14580                 addObjectDependency(dobj, refdobj->dumpId);
14581
14582                 dobj->ext_member = true;
14583
14584                 /*
14585                  * Normally, mark the member object as not to be dumped.  But in
14586                  * binary upgrades, we still dump the members individually, since the
14587                  * idea is to exactly reproduce the database contents rather than
14588                  * replace the extension contents with something different.
14589                  */
14590                 if (!binary_upgrade)
14591                         dobj->dump = false;
14592                 else
14593                         dobj->dump = refdobj->dump;
14594         }
14595
14596         PQclear(res);
14597
14598         /*
14599          * Now identify extension configuration tables and create TableDataInfo
14600          * objects for them, ensuring their data will be dumped even though the
14601          * tables themselves won't be.
14602          *
14603          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
14604          * user data in a configuration table is treated like schema data. This
14605          * seems appropriate since system data in a config table would get
14606          * reloaded by CREATE EXTENSION.
14607          */
14608         for (i = 0; i < numExtensions; i++)
14609         {
14610                 ExtensionInfo *curext = &(extinfo[i]);
14611                 char       *extconfig = curext->extconfig;
14612                 char       *extcondition = curext->extcondition;
14613                 char      **extconfigarray = NULL;
14614                 char      **extconditionarray = NULL;
14615                 int                     nconfigitems;
14616                 int                     nconditionitems;
14617
14618                 /* Tables of not-to-be-dumped extensions shouldn't be dumped */
14619                 if (!curext->dobj.dump)
14620                         continue;
14621
14622                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
14623                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
14624                         nconfigitems == nconditionitems)
14625                 {
14626                         int                     j;
14627
14628                         for (j = 0; j < nconfigitems; j++)
14629                         {
14630                                 TableInfo  *configtbl;
14631
14632                                 configtbl = findTableByOid(atooid(extconfigarray[j]));
14633                                 if (configtbl == NULL)
14634                                         continue;
14635
14636                                 /*
14637                                  * Note: config tables are dumped without OIDs regardless of
14638                                  * the --oids setting.  This is because row filtering
14639                                  * conditions aren't compatible with dumping OIDs.
14640                                  */
14641                                 makeTableDataInfo(configtbl, false);
14642                                 if (configtbl->dataObj != NULL)
14643                                 {
14644                                         if (strlen(extconditionarray[j]) > 0)
14645                                                 configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
14646                                 }
14647                         }
14648                 }
14649                 if (extconfigarray)
14650                         free(extconfigarray);
14651                 if (extconditionarray)
14652                         free(extconditionarray);
14653         }
14654
14655         destroyPQExpBuffer(query);
14656 }
14657
14658 /*
14659  * getDependencies --- obtain available dependency data
14660  */
14661 static void
14662 getDependencies(Archive *fout)
14663 {
14664         PQExpBuffer query;
14665         PGresult   *res;
14666         int                     ntups,
14667                                 i;
14668         int                     i_classid,
14669                                 i_objid,
14670                                 i_refclassid,
14671                                 i_refobjid,
14672                                 i_deptype;
14673         DumpableObject *dobj,
14674                            *refdobj;
14675
14676         /* No dependency info available before 7.3 */
14677         if (fout->remoteVersion < 70300)
14678                 return;
14679
14680         if (g_verbose)
14681                 write_msg(NULL, "reading dependency data\n");
14682
14683         /* Make sure we are in proper schema */
14684         selectSourceSchema(fout, "pg_catalog");
14685
14686         query = createPQExpBuffer();
14687
14688         /*
14689          * PIN dependencies aren't interesting, and EXTENSION dependencies were
14690          * already processed by getExtensionMembership.
14691          */
14692         appendPQExpBuffer(query, "SELECT "
14693                                           "classid, objid, refclassid, refobjid, deptype "
14694                                           "FROM pg_depend "
14695                                           "WHERE deptype != 'p' AND deptype != 'e' "
14696                                           "ORDER BY 1,2");
14697
14698         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14699
14700         ntups = PQntuples(res);
14701
14702         i_classid = PQfnumber(res, "classid");
14703         i_objid = PQfnumber(res, "objid");
14704         i_refclassid = PQfnumber(res, "refclassid");
14705         i_refobjid = PQfnumber(res, "refobjid");
14706         i_deptype = PQfnumber(res, "deptype");
14707
14708         /*
14709          * Since we ordered the SELECT by referencing ID, we can expect that
14710          * multiple entries for the same object will appear together; this saves
14711          * on searches.
14712          */
14713         dobj = NULL;
14714
14715         for (i = 0; i < ntups; i++)
14716         {
14717                 CatalogId       objId;
14718                 CatalogId       refobjId;
14719                 char            deptype;
14720
14721                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
14722                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
14723                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
14724                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
14725                 deptype = *(PQgetvalue(res, i, i_deptype));
14726
14727                 if (dobj == NULL ||
14728                         dobj->catId.tableoid != objId.tableoid ||
14729                         dobj->catId.oid != objId.oid)
14730                         dobj = findObjectByCatalogId(objId);
14731
14732                 /*
14733                  * Failure to find objects mentioned in pg_depend is not unexpected,
14734                  * since for example we don't collect info about TOAST tables.
14735                  */
14736                 if (dobj == NULL)
14737                 {
14738 #ifdef NOT_USED
14739                         fprintf(stderr, "no referencing object %u %u\n",
14740                                         objId.tableoid, objId.oid);
14741 #endif
14742                         continue;
14743                 }
14744
14745                 refdobj = findObjectByCatalogId(refobjId);
14746
14747                 if (refdobj == NULL)
14748                 {
14749 #ifdef NOT_USED
14750                         fprintf(stderr, "no referenced object %u %u\n",
14751                                         refobjId.tableoid, refobjId.oid);
14752 #endif
14753                         continue;
14754                 }
14755
14756                 /*
14757                  * Ordinarily, table rowtypes have implicit dependencies on their
14758                  * tables.      However, for a composite type the implicit dependency goes
14759                  * the other way in pg_depend; which is the right thing for DROP but
14760                  * it doesn't produce the dependency ordering we need. So in that one
14761                  * case, we reverse the direction of the dependency.
14762                  */
14763                 if (deptype == 'i' &&
14764                         dobj->objType == DO_TABLE &&
14765                         refdobj->objType == DO_TYPE)
14766                         addObjectDependency(refdobj, dobj->dumpId);
14767                 else
14768                         /* normal case */
14769                         addObjectDependency(dobj, refdobj->dumpId);
14770         }
14771
14772         PQclear(res);
14773
14774         destroyPQExpBuffer(query);
14775 }
14776
14777
14778 /*
14779  * createBoundaryObjects - create dummy DumpableObjects to represent
14780  * dump section boundaries.
14781  */
14782 static DumpableObject *
14783 createBoundaryObjects(void)
14784 {
14785         DumpableObject *dobjs;
14786
14787         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
14788
14789         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
14790         dobjs[0].catId = nilCatalogId;
14791         AssignDumpId(dobjs + 0);
14792         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
14793
14794         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
14795         dobjs[1].catId = nilCatalogId;
14796         AssignDumpId(dobjs + 1);
14797         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
14798
14799         return dobjs;
14800 }
14801
14802 /*
14803  * addBoundaryDependencies - add dependencies as needed to enforce the dump
14804  * section boundaries.
14805  */
14806 static void
14807 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
14808                                                 DumpableObject *boundaryObjs)
14809 {
14810         DumpableObject *preDataBound = boundaryObjs + 0;
14811         DumpableObject *postDataBound = boundaryObjs + 1;
14812         int                     i;
14813
14814         for (i = 0; i < numObjs; i++)
14815         {
14816                 DumpableObject *dobj = dobjs[i];
14817
14818                 /*
14819                  * The classification of object types here must match the SECTION_xxx
14820                  * values assigned during subsequent ArchiveEntry calls!
14821                  */
14822                 switch (dobj->objType)
14823                 {
14824                         case DO_NAMESPACE:
14825                         case DO_EXTENSION:
14826                         case DO_TYPE:
14827                         case DO_SHELL_TYPE:
14828                         case DO_FUNC:
14829                         case DO_AGG:
14830                         case DO_OPERATOR:
14831                         case DO_OPCLASS:
14832                         case DO_OPFAMILY:
14833                         case DO_COLLATION:
14834                         case DO_CONVERSION:
14835                         case DO_TABLE:
14836                         case DO_ATTRDEF:
14837                         case DO_PROCLANG:
14838                         case DO_CAST:
14839                         case DO_DUMMY_TYPE:
14840                         case DO_TSPARSER:
14841                         case DO_TSDICT:
14842                         case DO_TSTEMPLATE:
14843                         case DO_TSCONFIG:
14844                         case DO_FDW:
14845                         case DO_FOREIGN_SERVER:
14846                         case DO_BLOB:
14847                                 /* Pre-data objects: must come before the pre-data boundary */
14848                                 addObjectDependency(preDataBound, dobj->dumpId);
14849                                 break;
14850                         case DO_TABLE_DATA:
14851                         case DO_BLOB_DATA:
14852                                 /* Data objects: must come between the boundaries */
14853                                 addObjectDependency(dobj, preDataBound->dumpId);
14854                                 addObjectDependency(postDataBound, dobj->dumpId);
14855                                 break;
14856                         case DO_INDEX:
14857                         case DO_REFRESH_MATVIEW:
14858                         case DO_TRIGGER:
14859                         case DO_EVENT_TRIGGER:
14860                         case DO_DEFAULT_ACL:
14861                                 /* Post-data objects: must come after the post-data boundary */
14862                                 addObjectDependency(dobj, postDataBound->dumpId);
14863                                 break;
14864                         case DO_RULE:
14865                                 /* Rules are post-data, but only if dumped separately */
14866                                 if (((RuleInfo *) dobj)->separate)
14867                                         addObjectDependency(dobj, postDataBound->dumpId);
14868                                 break;
14869                         case DO_CONSTRAINT:
14870                         case DO_FK_CONSTRAINT:
14871                                 /* Constraints are post-data, but only if dumped separately */
14872                                 if (((ConstraintInfo *) dobj)->separate)
14873                                         addObjectDependency(dobj, postDataBound->dumpId);
14874                                 break;
14875                         case DO_PRE_DATA_BOUNDARY:
14876                                 /* nothing to do */
14877                                 break;
14878                         case DO_POST_DATA_BOUNDARY:
14879                                 /* must come after the pre-data boundary */
14880                                 addObjectDependency(dobj, preDataBound->dumpId);
14881                                 break;
14882                 }
14883         }
14884 }
14885
14886
14887 /*
14888  * BuildArchiveDependencies - create dependency data for archive TOC entries
14889  *
14890  * The raw dependency data obtained by getDependencies() is not terribly
14891  * useful in an archive dump, because in many cases there are dependency
14892  * chains linking through objects that don't appear explicitly in the dump.
14893  * For example, a view will depend on its _RETURN rule while the _RETURN rule
14894  * will depend on other objects --- but the rule will not appear as a separate
14895  * object in the dump.  We need to adjust the view's dependencies to include
14896  * whatever the rule depends on that is included in the dump.
14897  *
14898  * Just to make things more complicated, there are also "special" dependencies
14899  * such as the dependency of a TABLE DATA item on its TABLE, which we must
14900  * not rearrange because pg_restore knows that TABLE DATA only depends on
14901  * its table.  In these cases we must leave the dependencies strictly as-is
14902  * even if they refer to not-to-be-dumped objects.
14903  *
14904  * To handle this, the convention is that "special" dependencies are created
14905  * during ArchiveEntry calls, and an archive TOC item that has any such
14906  * entries will not be touched here.  Otherwise, we recursively search the
14907  * DumpableObject data structures to build the correct dependencies for each
14908  * archive TOC item.
14909  */
14910 static void
14911 BuildArchiveDependencies(Archive *fout)
14912 {
14913         ArchiveHandle *AH = (ArchiveHandle *) fout;
14914         TocEntry   *te;
14915
14916         /* Scan all TOC entries in the archive */
14917         for (te = AH->toc->next; te != AH->toc; te = te->next)
14918         {
14919                 DumpableObject *dobj;
14920                 DumpId     *dependencies;
14921                 int                     nDeps;
14922                 int                     allocDeps;
14923
14924                 /* No need to process entries that will not be dumped */
14925                 if (te->reqs == 0)
14926                         continue;
14927                 /* Ignore entries that already have "special" dependencies */
14928                 if (te->nDeps > 0)
14929                         continue;
14930                 /* Otherwise, look up the item's original DumpableObject, if any */
14931                 dobj = findObjectByDumpId(te->dumpId);
14932                 if (dobj == NULL)
14933                         continue;
14934                 /* No work if it has no dependencies */
14935                 if (dobj->nDeps <= 0)
14936                         continue;
14937                 /* Set up work array */
14938                 allocDeps = 64;
14939                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
14940                 nDeps = 0;
14941                 /* Recursively find all dumpable dependencies */
14942                 findDumpableDependencies(AH, dobj,
14943                                                                  &dependencies, &nDeps, &allocDeps);
14944                 /* And save 'em ... */
14945                 if (nDeps > 0)
14946                 {
14947                         dependencies = (DumpId *) pg_realloc(dependencies,
14948                                                                                                  nDeps * sizeof(DumpId));
14949                         te->dependencies = dependencies;
14950                         te->nDeps = nDeps;
14951                 }
14952                 else
14953                         free(dependencies);
14954         }
14955 }
14956
14957 /* Recursive search subroutine for BuildArchiveDependencies */
14958 static void
14959 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
14960                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
14961 {
14962         int                     i;
14963
14964         /*
14965          * Ignore section boundary objects: if we search through them, we'll
14966          * report lots of bogus dependencies.
14967          */
14968         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
14969                 dobj->objType == DO_POST_DATA_BOUNDARY)
14970                 return;
14971
14972         for (i = 0; i < dobj->nDeps; i++)
14973         {
14974                 DumpId          depid = dobj->dependencies[i];
14975
14976                 if (TocIDRequired(AH, depid) != 0)
14977                 {
14978                         /* Object will be dumped, so just reference it as a dependency */
14979                         if (*nDeps >= *allocDeps)
14980                         {
14981                                 *allocDeps *= 2;
14982                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
14983                                                                                                 *allocDeps * sizeof(DumpId));
14984                         }
14985                         (*dependencies)[*nDeps] = depid;
14986                         (*nDeps)++;
14987                 }
14988                 else
14989                 {
14990                         /*
14991                          * Object will not be dumped, so recursively consider its deps. We
14992                          * rely on the assumption that sortDumpableObjects already broke
14993                          * any dependency loops, else we might recurse infinitely.
14994                          */
14995                         DumpableObject *otherdobj = findObjectByDumpId(depid);
14996
14997                         if (otherdobj)
14998                                 findDumpableDependencies(AH, otherdobj,
14999                                                                                  dependencies, nDeps, allocDeps);
15000                 }
15001         }
15002 }
15003
15004
15005 /*
15006  * selectSourceSchema - make the specified schema the active search path
15007  * in the source database.
15008  *
15009  * NB: pg_catalog is explicitly searched after the specified schema;
15010  * so user names are only qualified if they are cross-schema references,
15011  * and system names are only qualified if they conflict with a user name
15012  * in the current schema.
15013  *
15014  * Whenever the selected schema is not pg_catalog, be careful to qualify
15015  * references to system catalogs and types in our emitted commands!
15016  *
15017  * This function is called only from selectSourceSchemaOnAH and
15018  * selectSourceSchema.
15019  */
15020 static void
15021 selectSourceSchema(Archive *fout, const char *schemaName)
15022 {
15023         PQExpBuffer query;
15024
15025         /* This is checked by the callers already */
15026         Assert(schemaName != NULL && *schemaName != '\0');
15027
15028         /* Not relevant if fetching from pre-7.3 DB */
15029         if (fout->remoteVersion < 70300)
15030                 return;
15031
15032         query = createPQExpBuffer();
15033         appendPQExpBuffer(query, "SET search_path = %s",
15034                                           fmtId(schemaName));
15035         if (strcmp(schemaName, "pg_catalog") != 0)
15036                 appendPQExpBuffer(query, ", pg_catalog");
15037
15038         ExecuteSqlStatement(fout, query->data);
15039
15040         destroyPQExpBuffer(query);
15041 }
15042
15043 /*
15044  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15045  * given type name.
15046  *
15047  * NB: in 7.3 and up the result may depend on the currently-selected
15048  * schema; this is why we don't try to cache the names.
15049  */
15050 static char *
15051 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15052 {
15053         char       *result;
15054         PQExpBuffer query;
15055         PGresult   *res;
15056
15057         if (oid == 0)
15058         {
15059                 if ((opts & zeroAsOpaque) != 0)
15060                         return pg_strdup(g_opaque_type);
15061                 else if ((opts & zeroAsAny) != 0)
15062                         return pg_strdup("'any'");
15063                 else if ((opts & zeroAsStar) != 0)
15064                         return pg_strdup("*");
15065                 else if ((opts & zeroAsNone) != 0)
15066                         return pg_strdup("NONE");
15067         }
15068
15069         query = createPQExpBuffer();
15070         if (fout->remoteVersion >= 70300)
15071         {
15072                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15073                                                   oid);
15074         }
15075         else if (fout->remoteVersion >= 70100)
15076         {
15077                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15078                                                   oid);
15079         }
15080         else
15081         {
15082                 appendPQExpBuffer(query, "SELECT typname "
15083                                                   "FROM pg_type "
15084                                                   "WHERE oid = '%u'::oid",
15085                                                   oid);
15086         }
15087
15088         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15089
15090         if (fout->remoteVersion >= 70100)
15091         {
15092                 /* already quoted */
15093                 result = pg_strdup(PQgetvalue(res, 0, 0));
15094         }
15095         else
15096         {
15097                 /* may need to quote it */
15098                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15099         }
15100
15101         PQclear(res);
15102         destroyPQExpBuffer(query);
15103
15104         return result;
15105 }
15106
15107 /*
15108  * myFormatType --- local implementation of format_type for use with 7.0.
15109  */
15110 static char *
15111 myFormatType(const char *typname, int32 typmod)
15112 {
15113         char       *result;
15114         bool            isarray = false;
15115         PQExpBuffer buf = createPQExpBuffer();
15116
15117         /* Handle array types */
15118         if (typname[0] == '_')
15119         {
15120                 isarray = true;
15121                 typname++;
15122         }
15123
15124         /* Show lengths on bpchar and varchar */
15125         if (strcmp(typname, "bpchar") == 0)
15126         {
15127                 int                     len = (typmod - VARHDRSZ);
15128
15129                 appendPQExpBuffer(buf, "character");
15130                 if (len > 1)
15131                         appendPQExpBuffer(buf, "(%d)",
15132                                                           typmod - VARHDRSZ);
15133         }
15134         else if (strcmp(typname, "varchar") == 0)
15135         {
15136                 appendPQExpBuffer(buf, "character varying");
15137                 if (typmod != -1)
15138                         appendPQExpBuffer(buf, "(%d)",
15139                                                           typmod - VARHDRSZ);
15140         }
15141         else if (strcmp(typname, "numeric") == 0)
15142         {
15143                 appendPQExpBuffer(buf, "numeric");
15144                 if (typmod != -1)
15145                 {
15146                         int32           tmp_typmod;
15147                         int                     precision;
15148                         int                     scale;
15149
15150                         tmp_typmod = typmod - VARHDRSZ;
15151                         precision = (tmp_typmod >> 16) & 0xffff;
15152                         scale = tmp_typmod & 0xffff;
15153                         appendPQExpBuffer(buf, "(%d,%d)",
15154                                                           precision, scale);
15155                 }
15156         }
15157
15158         /*
15159          * char is an internal single-byte data type; Let's make sure we force it
15160          * through with quotes. - thomas 1998-12-13
15161          */
15162         else if (strcmp(typname, "char") == 0)
15163                 appendPQExpBuffer(buf, "\"char\"");
15164         else
15165                 appendPQExpBuffer(buf, "%s", fmtId(typname));
15166
15167         /* Append array qualifier for array types */
15168         if (isarray)
15169                 appendPQExpBuffer(buf, "[]");
15170
15171         result = pg_strdup(buf->data);
15172         destroyPQExpBuffer(buf);
15173
15174         return result;
15175 }
15176
15177 /*
15178  * Return a column list clause for the given relation.
15179  *
15180  * Special case: if there are no undropped columns in the relation, return
15181  * "", not an invalid "()" column list.
15182  */
15183 static const char *
15184 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15185 {
15186         int                     numatts = ti->numatts;
15187         char      **attnames = ti->attnames;
15188         bool       *attisdropped = ti->attisdropped;
15189         bool            needComma;
15190         int                     i;
15191
15192         appendPQExpBuffer(buffer, "(");
15193         needComma = false;
15194         for (i = 0; i < numatts; i++)
15195         {
15196                 if (attisdropped[i])
15197                         continue;
15198                 if (needComma)
15199                         appendPQExpBuffer(buffer, ", ");
15200                 appendPQExpBuffer(buffer, "%s", fmtId(attnames[i]));
15201                 needComma = true;
15202         }
15203
15204         if (!needComma)
15205                 return "";                              /* no undropped columns */
15206
15207         appendPQExpBuffer(buffer, ")");
15208         return buffer->data;
15209 }
15210
15211 /*
15212  * Execute an SQL query and verify that we got exactly one row back.
15213  */
15214 static PGresult *
15215 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
15216 {
15217         PGresult   *res;
15218         int                     ntups;
15219
15220         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
15221
15222         /* Expecting a single result only */
15223         ntups = PQntuples(res);
15224         if (ntups != 1)
15225                 exit_horribly(NULL,
15226                                           ngettext("query returned %d row instead of one: %s\n",
15227                                                            "query returned %d rows instead of one: %s\n",
15228                                                            ntups),
15229                                           ntups, query);
15230
15231         return res;
15232 }