]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Move some pg_dump function around.
[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 "pg_backup_utils.h"
63 #include "dumputils.h"
64 #include "parallel.h"
65
66 extern char *optarg;
67 extern int      optind,
68                         opterr;
69
70
71 typedef struct
72 {
73         const char *descr;                      /* comment for an object */
74         Oid                     classoid;               /* object class (catalog OID) */
75         Oid                     objoid;                 /* object OID */
76         int                     objsubid;               /* subobject (table column #) */
77 } CommentItem;
78
79 typedef struct
80 {
81         const char *provider;           /* label provider of this security label */
82         const char *label;                      /* security label for an object */
83         Oid                     classoid;               /* object class (catalog OID) */
84         Oid                     objoid;                 /* object OID */
85         int                     objsubid;               /* subobject (table column #) */
86 } SecLabelItem;
87
88 /* global decls */
89 bool            g_verbose;                      /* User wants verbose narration of our
90                                                                  * activities. */
91
92 /* various user-settable parameters */
93 bool            schemaOnly;
94 bool            dataOnly;
95 int                     dumpSections;           /* bitmask of chosen sections */
96 bool            aclsSkip;
97 const char *lockWaitTimeout;
98
99 /* subquery used to convert user ID (eg, datdba) to user name */
100 static const char *username_subquery;
101
102 /* obsolete as of 7.3: */
103 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
104
105 /*
106  * Object inclusion/exclusion lists
107  *
108  * The string lists record the patterns given by command-line switches,
109  * which we then convert to lists of OIDs of matching objects.
110  */
111 static SimpleStringList schema_include_patterns = {NULL, NULL};
112 static SimpleOidList schema_include_oids = {NULL, NULL};
113 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
114 static SimpleOidList schema_exclude_oids = {NULL, NULL};
115
116 static SimpleStringList table_include_patterns = {NULL, NULL};
117 static SimpleOidList table_include_oids = {NULL, NULL};
118 static SimpleStringList table_exclude_patterns = {NULL, NULL};
119 static SimpleOidList table_exclude_oids = {NULL, NULL};
120 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
121 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
122
123 /* default, if no "inclusion" switches appear, is to dump everything */
124 static bool include_everything = true;
125
126 char            g_opaque_type[10];      /* name for the opaque type */
127
128 /* placeholders for the delimiters for comments */
129 char            g_comment_start[10];
130 char            g_comment_end[10];
131
132 static const CatalogId nilCatalogId = {0, 0};
133
134 /* flags for various command-line long options */
135 static int      binary_upgrade = 0;
136 static int      disable_dollar_quoting = 0;
137 static int      dump_inserts = 0;
138 static int      column_inserts = 0;
139 static int      no_security_labels = 0;
140 static int      no_synchronized_snapshots = 0;
141 static int      no_unlogged_table_data = 0;
142 static int      serializable_deferrable = 0;
143
144
145 static void help(const char *progname);
146 static void setup_connection(Archive *AH, const char *dumpencoding,
147                                  char *use_role);
148 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
149 static void expand_schema_name_patterns(Archive *fout,
150                                                         SimpleStringList *patterns,
151                                                         SimpleOidList *oids);
152 static void expand_table_name_patterns(Archive *fout,
153                                                    SimpleStringList *patterns,
154                                                    SimpleOidList *oids);
155 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
156 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
157 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
158 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
159 static void dumpComment(Archive *fout, const char *target,
160                         const char *namespace, const char *owner,
161                         CatalogId catalogId, int subid, DumpId dumpId);
162 static int findComments(Archive *fout, Oid classoid, Oid objoid,
163                          CommentItem **items);
164 static int      collectComments(Archive *fout, CommentItem **items);
165 static void dumpSecLabel(Archive *fout, const char *target,
166                          const char *namespace, const char *owner,
167                          CatalogId catalogId, int subid, DumpId dumpId);
168 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
169                           SecLabelItem **items);
170 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
171 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
172 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
173 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
174 static void dumpType(Archive *fout, TypeInfo *tyinfo);
175 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
179 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
181 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
182 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
183 static void dumpFunc(Archive *fout, FuncInfo *finfo);
184 static void dumpCast(Archive *fout, CastInfo *cast);
185 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
186 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
187 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
188 static void dumpCollation(Archive *fout, CollInfo *convinfo);
189 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
190 static void dumpRule(Archive *fout, RuleInfo *rinfo);
191 static void dumpAgg(Archive *fout, AggInfo *agginfo);
192 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
193 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
194 static void dumpTable(Archive *fout, TableInfo *tbinfo);
195 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
196 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
197 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
198 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
199 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
200 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
201 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
202 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
203 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
204 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
205 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
206 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
207 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
208 static void dumpUserMappings(Archive *fout,
209                                  const char *servername, const char *namespace,
210                                  const char *owner, CatalogId catalogId, DumpId dumpId);
211 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
212
213 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
214                 const char *type, const char *name, const char *subname,
215                 const char *tag, const char *nspname, const char *owner,
216                 const char *acls);
217
218 static void getDependencies(Archive *fout);
219 static void BuildArchiveDependencies(Archive *fout);
220 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
221                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
222
223 static DumpableObject *createBoundaryObjects(void);
224 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
225                                                 DumpableObject *boundaryObjs);
226
227 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
228 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
229 static void makeTableDataInfo(TableInfo *tbinfo, bool oids);
230 static void buildMatViewRefreshDependencies(Archive *fout);
231 static void getTableDataFKConstraints(void);
232 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
233 static char *format_function_arguments_old(Archive *fout,
234                                                           FuncInfo *finfo, int nallargs,
235                                                           char **allargtypes,
236                                                           char **argmodes,
237                                                           char **argnames);
238 static char *format_function_signature(Archive *fout,
239                                                   FuncInfo *finfo, bool honor_quotes);
240 static const char *convertRegProcReference(Archive *fout,
241                                                 const char *proc);
242 static const char *convertOperatorReference(Archive *fout, const char *opr);
243 static const char *convertTSFunction(Archive *fout, Oid funcOid);
244 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
245 static Oid      findLastBuiltinOid_V70(Archive *fout);
246 static void selectSourceSchema(Archive *fout, const char *schemaName);
247 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
248 static char *myFormatType(const char *typname, int32 typmod);
249 static void getBlobs(Archive *fout);
250 static void dumpBlob(Archive *fout, BlobInfo *binfo);
251 static int      dumpBlobs(Archive *fout, void *arg);
252 static void dumpDatabase(Archive *AH);
253 static void dumpEncoding(Archive *AH);
254 static void dumpStdStrings(Archive *AH);
255 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
256                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
257 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
258                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
259 static void binary_upgrade_set_pg_class_oids(Archive *fout,
260                                                                  PQExpBuffer upgrade_buffer,
261                                                                  Oid pg_class_oid, bool is_index);
262 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
263                                                                 DumpableObject *dobj,
264                                                                 const char *objlabel);
265 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
266 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
267 static char *get_synchronized_snapshot(Archive *fout);
268 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
269 static void setupDumpWorker(Archive *AHX, RestoreOptions *ropt);
270
271
272 int
273 main(int argc, char **argv)
274 {
275         int                     c;
276         const char *filename = NULL;
277         const char *format = "p";
278         const char *dbname = NULL;
279         const char *pghost = NULL;
280         const char *pgport = NULL;
281         const char *username = NULL;
282         const char *dumpencoding = NULL;
283         bool            oids = false;
284         TableInfo  *tblinfo;
285         int                     numTables;
286         DumpableObject **dobjs;
287         int                     numObjs;
288         DumpableObject *boundaryObjs;
289         int                     i;
290         int                     numWorkers = 1;
291         enum trivalue prompt_password = TRI_DEFAULT;
292         int                     compressLevel = -1;
293         int                     plainText = 0;
294         int                     outputClean = 0;
295         int                     outputCreateDB = 0;
296         bool            outputBlobs = false;
297         int                     outputNoOwner = 0;
298         char       *outputSuperuser = NULL;
299         char       *use_role = NULL;
300         int                     optindex;
301         RestoreOptions *ropt;
302         ArchiveFormat archiveFormat = archUnknown;
303         ArchiveMode archiveMode;
304         Archive    *fout;                       /* the script file */
305
306         static int      disable_triggers = 0;
307         static int      outputNoTablespaces = 0;
308         static int      use_setsessauth = 0;
309
310         static struct option long_options[] = {
311                 {"data-only", no_argument, NULL, 'a'},
312                 {"blobs", no_argument, NULL, 'b'},
313                 {"clean", no_argument, NULL, 'c'},
314                 {"create", no_argument, NULL, 'C'},
315                 {"dbname", required_argument, NULL, 'd'},
316                 {"file", required_argument, NULL, 'f'},
317                 {"format", required_argument, NULL, 'F'},
318                 {"host", required_argument, NULL, 'h'},
319                 {"ignore-version", no_argument, NULL, 'i'},
320                 {"jobs", 1, NULL, 'j'},
321                 {"no-reconnect", no_argument, NULL, 'R'},
322                 {"oids", no_argument, NULL, 'o'},
323                 {"no-owner", no_argument, NULL, 'O'},
324                 {"port", required_argument, NULL, 'p'},
325                 {"schema", required_argument, NULL, 'n'},
326                 {"exclude-schema", required_argument, NULL, 'N'},
327                 {"schema-only", no_argument, NULL, 's'},
328                 {"superuser", required_argument, NULL, 'S'},
329                 {"table", required_argument, NULL, 't'},
330                 {"exclude-table", required_argument, NULL, 'T'},
331                 {"no-password", no_argument, NULL, 'w'},
332                 {"password", no_argument, NULL, 'W'},
333                 {"username", required_argument, NULL, 'U'},
334                 {"verbose", no_argument, NULL, 'v'},
335                 {"no-privileges", no_argument, NULL, 'x'},
336                 {"no-acl", no_argument, NULL, 'x'},
337                 {"compress", required_argument, NULL, 'Z'},
338                 {"encoding", required_argument, NULL, 'E'},
339                 {"help", no_argument, NULL, '?'},
340                 {"version", no_argument, NULL, 'V'},
341
342                 /*
343                  * the following options don't have an equivalent short option letter
344                  */
345                 {"attribute-inserts", no_argument, &column_inserts, 1},
346                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
347                 {"column-inserts", no_argument, &column_inserts, 1},
348                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
349                 {"disable-triggers", no_argument, &disable_triggers, 1},
350                 {"exclude-table-data", required_argument, NULL, 4},
351                 {"inserts", no_argument, &dump_inserts, 1},
352                 {"lock-wait-timeout", required_argument, NULL, 2},
353                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
354                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
355                 {"role", required_argument, NULL, 3},
356                 {"section", required_argument, NULL, 5},
357                 {"serializable-deferrable", no_argument, &serializable_deferrable, 1},
358                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
359                 {"no-security-labels", no_argument, &no_security_labels, 1},
360                 {"no-synchronized-snapshots", no_argument, &no_synchronized_snapshots, 1},
361                 {"no-unlogged-table-data", no_argument, &no_unlogged_table_data, 1},
362
363                 {NULL, 0, NULL, 0}
364         };
365
366         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
367
368         /*
369          * Initialize what we need for parallel execution, especially for thread
370          * support on Windows.
371          */
372         init_parallel_dump_utils();
373
374         g_verbose = false;
375
376         strcpy(g_comment_start, "-- ");
377         g_comment_end[0] = '\0';
378         strcpy(g_opaque_type, "opaque");
379
380         dataOnly = schemaOnly = false;
381         dumpSections = DUMP_UNSECTIONED;
382         lockWaitTimeout = NULL;
383
384         progname = get_progname(argv[0]);
385
386         /* Set default options based on progname */
387         if (strcmp(progname, "pg_backup") == 0)
388                 format = "c";
389
390         if (argc > 1)
391         {
392                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
393                 {
394                         help(progname);
395                         exit_nicely(0);
396                 }
397                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
398                 {
399                         puts("pg_dump (PostgreSQL) " PG_VERSION);
400                         exit_nicely(0);
401                 }
402         }
403
404         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:K:n:N:oOp:RsS:t:T:U:vwWxZ:",
405                                                         long_options, &optindex)) != -1)
406         {
407                 switch (c)
408                 {
409                         case 'a':                       /* Dump data only */
410                                 dataOnly = true;
411                                 break;
412
413                         case 'b':                       /* Dump blobs */
414                                 outputBlobs = true;
415                                 break;
416
417                         case 'c':                       /* clean (i.e., drop) schema prior to create */
418                                 outputClean = 1;
419                                 break;
420
421                         case 'C':                       /* Create DB */
422                                 outputCreateDB = 1;
423                                 break;
424
425                         case 'd':                       /* database name */
426                                 dbname = pg_strdup(optarg);
427                                 break;
428
429                         case 'E':                       /* Dump encoding */
430                                 dumpencoding = pg_strdup(optarg);
431                                 break;
432
433                         case 'f':
434                                 filename = pg_strdup(optarg);
435                                 break;
436
437                         case 'F':
438                                 format = pg_strdup(optarg);
439                                 break;
440
441                         case 'h':                       /* server host */
442                                 pghost = pg_strdup(optarg);
443                                 break;
444
445                         case 'i':
446                                 /* ignored, deprecated option */
447                                 break;
448
449                         case 'j':                       /* number of dump jobs */
450                                 numWorkers = atoi(optarg);
451                                 break;
452
453                         case 'n':                       /* include schema(s) */
454                                 simple_string_list_append(&schema_include_patterns, optarg);
455                                 include_everything = false;
456                                 break;
457
458                         case 'N':                       /* exclude schema(s) */
459                                 simple_string_list_append(&schema_exclude_patterns, optarg);
460                                 break;
461
462                         case 'o':                       /* Dump oids */
463                                 oids = true;
464                                 break;
465
466                         case 'O':                       /* Don't reconnect to match owner */
467                                 outputNoOwner = 1;
468                                 break;
469
470                         case 'p':                       /* server port */
471                                 pgport = pg_strdup(optarg);
472                                 break;
473
474                         case 'R':
475                                 /* no-op, still accepted for backwards compatibility */
476                                 break;
477
478                         case 's':                       /* dump schema only */
479                                 schemaOnly = true;
480                                 break;
481
482                         case 'S':                       /* Username for superuser in plain text output */
483                                 outputSuperuser = pg_strdup(optarg);
484                                 break;
485
486                         case 't':                       /* include table(s) */
487                                 simple_string_list_append(&table_include_patterns, optarg);
488                                 include_everything = false;
489                                 break;
490
491                         case 'T':                       /* exclude table(s) */
492                                 simple_string_list_append(&table_exclude_patterns, optarg);
493                                 break;
494
495                         case 'U':
496                                 username = pg_strdup(optarg);
497                                 break;
498
499                         case 'v':                       /* verbose */
500                                 g_verbose = true;
501                                 break;
502
503                         case 'w':
504                                 prompt_password = TRI_NO;
505                                 break;
506
507                         case 'W':
508                                 prompt_password = TRI_YES;
509                                 break;
510
511                         case 'x':                       /* skip ACL dump */
512                                 aclsSkip = true;
513                                 break;
514
515                         case 'Z':                       /* Compression Level */
516                                 compressLevel = atoi(optarg);
517                                 break;
518
519                         case 0:
520                                 /* This covers the long options. */
521                                 break;
522
523                         case 2:                         /* lock-wait-timeout */
524                                 lockWaitTimeout = pg_strdup(optarg);
525                                 break;
526
527                         case 3:                         /* SET ROLE */
528                                 use_role = pg_strdup(optarg);
529                                 break;
530
531                         case 4:                         /* exclude table(s) data */
532                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
533                                 break;
534
535                         case 5:                         /* section */
536                                 set_dump_section(optarg, &dumpSections);
537                                 break;
538
539                         default:
540                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
541                                 exit_nicely(1);
542                 }
543         }
544
545         /*
546          * Non-option argument specifies database name as long as it wasn't
547          * already specified with -d / --dbname
548          */
549         if (optind < argc && dbname == NULL)
550                 dbname = argv[optind++];
551
552         /* Complain if any arguments remain */
553         if (optind < argc)
554         {
555                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
556                                 progname, argv[optind]);
557                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
558                                 progname);
559                 exit_nicely(1);
560         }
561
562         /* --column-inserts implies --inserts */
563         if (column_inserts)
564                 dump_inserts = 1;
565
566         if (dataOnly && schemaOnly)
567                 exit_horribly(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
568
569         if (dataOnly && outputClean)
570                 exit_horribly(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
571
572         if (dump_inserts && oids)
573         {
574                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
575                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
576                 exit_nicely(1);
577         }
578
579         /* Identify archive format to emit */
580         archiveFormat = parseArchiveFormat(format, &archiveMode);
581
582         /* archiveFormat specific setup */
583         if (archiveFormat == archNull)
584                 plainText = 1;
585
586         /* Custom and directory formats are compressed by default, others not */
587         if (compressLevel == -1)
588         {
589                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
590                         compressLevel = Z_DEFAULT_COMPRESSION;
591                 else
592                         compressLevel = 0;
593         }
594
595         /*
596          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
597          * parallel jobs because that's the maximum limit for the
598          * WaitForMultipleObjects() call.
599          */
600         if (numWorkers <= 0
601 #ifdef WIN32
602                 || numWorkers > MAXIMUM_WAIT_OBJECTS
603 #endif
604                 )
605                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
606
607         /* Parallel backup only in the directory archive format so far */
608         if (archiveFormat != archDirectory && numWorkers > 1)
609                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
610
611         /* Open the output file */
612         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
613                                                  setupDumpWorker);
614
615         /* Register the cleanup hook */
616         on_exit_close_archive(fout);
617
618         if (fout == NULL)
619                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
620
621         /* Let the archiver know how noisy to be */
622         fout->verbose = g_verbose;
623
624         /*
625          * We allow the server to be back to 7.0, and up to any minor release of
626          * our own major version.  (See also version check in pg_dumpall.c.)
627          */
628         fout->minRemoteVersion = 70000;
629         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
630
631         fout->numWorkers = numWorkers;
632
633         /*
634          * Open the database using the Archiver, so it knows about it. Errors mean
635          * death.
636          */
637         ConnectDatabase(fout, dbname, pghost, pgport, username, prompt_password);
638         setup_connection(fout, dumpencoding, use_role);
639
640         /*
641          * Disable security label support if server version < v9.1.x (prevents
642          * access to nonexistent pg_seclabel catalog)
643          */
644         if (fout->remoteVersion < 90100)
645                 no_security_labels = 1;
646
647         /*
648          * When running against 9.0 or later, check if we are in recovery mode,
649          * which means we are on a hot standby.
650          */
651         if (fout->remoteVersion >= 90000)
652         {
653                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
654
655                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
656                 {
657                         /*
658                          * On hot standby slaves, never try to dump unlogged table data,
659                          * since it will just throw an error.
660                          */
661                         no_unlogged_table_data = true;
662                 }
663                 PQclear(res);
664         }
665
666         /* Select the appropriate subquery to convert user IDs to names */
667         if (fout->remoteVersion >= 80100)
668                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
669         else if (fout->remoteVersion >= 70300)
670                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
671         else
672                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
673
674         /* check the version for the synchronized snapshots feature */
675         if (numWorkers > 1 && fout->remoteVersion < 90200
676                 && !no_synchronized_snapshots)
677                 exit_horribly(NULL,
678                           "No synchronized snapshots available in this server version.\n"
679                            "Run with --no-synchronized-snapshots instead if you do not\n"
680                                           "need synchronized snapshots.\n");
681
682         /* Find the last built-in OID, if needed */
683         if (fout->remoteVersion < 70300)
684         {
685                 if (fout->remoteVersion >= 70100)
686                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
687                                                                                                   PQdb(GetConnection(fout)));
688                 else
689                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
690                 if (g_verbose)
691                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
692         }
693
694         /* Expand schema selection patterns into OID lists */
695         if (schema_include_patterns.head != NULL)
696         {
697                 expand_schema_name_patterns(fout, &schema_include_patterns,
698                                                                         &schema_include_oids);
699                 if (schema_include_oids.head == NULL)
700                         exit_horribly(NULL, "No matching schemas were found\n");
701         }
702         expand_schema_name_patterns(fout, &schema_exclude_patterns,
703                                                                 &schema_exclude_oids);
704         /* non-matching exclusion patterns aren't an error */
705
706         /* Expand table selection patterns into OID lists */
707         if (table_include_patterns.head != NULL)
708         {
709                 expand_table_name_patterns(fout, &table_include_patterns,
710                                                                    &table_include_oids);
711                 if (table_include_oids.head == NULL)
712                         exit_horribly(NULL, "No matching tables were found\n");
713         }
714         expand_table_name_patterns(fout, &table_exclude_patterns,
715                                                            &table_exclude_oids);
716
717         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
718                                                            &tabledata_exclude_oids);
719
720         /* non-matching exclusion patterns aren't an error */
721
722         /*
723          * Dumping blobs is now default unless we saw an inclusion switch or -s
724          * ... but even if we did see one of these, -b turns it back on.
725          */
726         if (include_everything && !schemaOnly)
727                 outputBlobs = true;
728
729         /*
730          * Now scan the database and create DumpableObject structs for all the
731          * objects we intend to dump.
732          */
733         tblinfo = getSchemaData(fout, &numTables);
734
735         if (fout->remoteVersion < 80400)
736                 guessConstraintInheritance(tblinfo, numTables);
737
738         if (!schemaOnly)
739         {
740                 getTableData(tblinfo, numTables, oids);
741                 buildMatViewRefreshDependencies(fout);
742                 if (dataOnly)
743                         getTableDataFKConstraints();
744         }
745
746         if (outputBlobs)
747                 getBlobs(fout);
748
749         /*
750          * Collect dependency data to assist in ordering the objects.
751          */
752         getDependencies(fout);
753
754         /* Lastly, create dummy objects to represent the section boundaries */
755         boundaryObjs = createBoundaryObjects();
756
757         /* Get pointers to all the known DumpableObjects */
758         getDumpableObjects(&dobjs, &numObjs);
759
760         /*
761          * Add dummy dependencies to enforce the dump section ordering.
762          */
763         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
764
765         /*
766          * Sort the objects into a safe dump order (no forward references).
767          *
768          * In 7.3 or later, we can rely on dependency information to help us
769          * determine a safe order, so the initial sort is mostly for cosmetic
770          * purposes: we sort by name to ensure that logically identical schemas
771          * will dump identically.  Before 7.3 we don't have dependencies and we
772          * use OID ordering as an (unreliable) guide to creation order.
773          */
774         if (fout->remoteVersion >= 70300)
775                 sortDumpableObjectsByTypeName(dobjs, numObjs);
776         else
777                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
778
779         /* If we do a parallel dump, we want the largest tables to go first */
780         if (archiveFormat == archDirectory && numWorkers > 1)
781                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
782
783         sortDumpableObjects(dobjs, numObjs,
784                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
785
786         /*
787          * Create archive TOC entries for all the objects to be dumped, in a safe
788          * order.
789          */
790
791         /* First the special ENCODING and STDSTRINGS entries. */
792         dumpEncoding(fout);
793         dumpStdStrings(fout);
794
795         /* The database item is always next, unless we don't want it at all */
796         if (include_everything && !dataOnly)
797                 dumpDatabase(fout);
798
799         /* Now the rearrangeable objects. */
800         for (i = 0; i < numObjs; i++)
801                 dumpDumpableObject(fout, dobjs[i]);
802
803         /*
804          * Set up options info to ensure we dump what we want.
805          */
806         ropt = NewRestoreOptions();
807         ropt->filename = filename;
808         ropt->dropSchema = outputClean;
809         ropt->dataOnly = dataOnly;
810         ropt->schemaOnly = schemaOnly;
811         ropt->dumpSections = dumpSections;
812         ropt->aclsSkip = aclsSkip;
813         ropt->superuser = outputSuperuser;
814         ropt->createDB = outputCreateDB;
815         ropt->noOwner = outputNoOwner;
816         ropt->noTablespace = outputNoTablespaces;
817         ropt->disable_triggers = disable_triggers;
818         ropt->use_setsessauth = use_setsessauth;
819
820         if (compressLevel == -1)
821                 ropt->compression = 0;
822         else
823                 ropt->compression = compressLevel;
824
825         ropt->suppressDumpWarnings = true;      /* We've already shown them */
826
827         SetArchiveRestoreOptions(fout, ropt);
828
829         /*
830          * The archive's TOC entries are now marked as to which ones will actually
831          * be output, so we can set up their dependency lists properly. This isn't
832          * necessary for plain-text output, though.
833          */
834         if (!plainText)
835                 BuildArchiveDependencies(fout);
836
837         /*
838          * And finally we can do the actual output.
839          *
840          * Note: for non-plain-text output formats, the output file is written
841          * inside CloseArchive().  This is, um, bizarre; but not worth changing
842          * right now.
843          */
844         if (plainText)
845                 RestoreArchive(fout);
846
847         CloseArchive(fout);
848
849         exit_nicely(0);
850 }
851
852
853 static void
854 help(const char *progname)
855 {
856         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
857         printf(_("Usage:\n"));
858         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
859
860         printf(_("\nGeneral options:\n"));
861         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
862         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
863                          "                               plain text (default))\n"));
864         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
865         printf(_("  -v, --verbose                verbose mode\n"));
866         printf(_("  -V, --version                output version information, then exit\n"));
867         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
868         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
869         printf(_("  -?, --help                   show this help, then exit\n"));
870
871         printf(_("\nOptions controlling the output content:\n"));
872         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
873         printf(_("  -b, --blobs                  include large objects in dump\n"));
874         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
875         printf(_("  -C, --create                 include commands to create database in dump\n"));
876         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
877         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
878         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
879         printf(_("  -o, --oids                   include OIDs in dump\n"));
880         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
881                          "                               plain-text format\n"));
882         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
883         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
884         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
885         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
886         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
887         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
888         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
889         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
890         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
891         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
892         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
893         printf(_("  --no-security-labels         do not dump security label assignments\n"));
894         printf(_("  --no-synchronized-snapshots parallel processes should not use synchronized snapshots\n"));
895         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
896         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
897         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
898         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
899         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
900         printf(_("  --use-set-session-authorization\n"
901                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
902                          "                               ALTER OWNER commands to set ownership\n"));
903
904         printf(_("\nConnection options:\n"));
905         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
906         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
907         printf(_("  -p, --port=PORT          database server port number\n"));
908         printf(_("  -U, --username=NAME      connect as specified database user\n"));
909         printf(_("  -w, --no-password        never prompt for password\n"));
910         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
911         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
912
913         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
914                          "variable value is used.\n\n"));
915         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
916 }
917
918 static void
919 setup_connection(Archive *AH, const char *dumpencoding, char *use_role)
920 {
921         PGconn     *conn = GetConnection(AH);
922         const char *std_strings;
923
924         /*
925          * Set the client encoding if requested. If dumpencoding == NULL then
926          * either it hasn't been requested or we're a cloned connection and then
927          * this has already been set in CloneArchive according to the original
928          * connection encoding.
929          */
930         if (dumpencoding)
931         {
932                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
933                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
934                                                   dumpencoding);
935         }
936
937         /*
938          * Get the active encoding and the standard_conforming_strings setting, so
939          * we know how to escape strings.
940          */
941         AH->encoding = PQclientEncoding(conn);
942
943         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
944         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
945
946         /* Set the role if requested */
947         if (!use_role && AH->use_role)
948                 use_role = AH->use_role;
949
950         /* Set the role if requested */
951         if (use_role && AH->remoteVersion >= 80100)
952         {
953                 PQExpBuffer query = createPQExpBuffer();
954
955                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
956                 ExecuteSqlStatement(AH, query->data);
957                 destroyPQExpBuffer(query);
958
959                 /* save this for later use on parallel connections */
960                 if (!AH->use_role)
961                         AH->use_role = strdup(use_role);
962         }
963
964         /* Set the datestyle to ISO to ensure the dump's portability */
965         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
966
967         /* Likewise, avoid using sql_standard intervalstyle */
968         if (AH->remoteVersion >= 80400)
969                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
970
971         /*
972          * If supported, set extra_float_digits so that we can dump float data
973          * exactly (given correctly implemented float I/O code, anyway)
974          */
975         if (AH->remoteVersion >= 90000)
976                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
977         else if (AH->remoteVersion >= 70400)
978                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
979
980         /*
981          * If synchronized scanning is supported, disable it, to prevent
982          * unpredictable changes in row ordering across a dump and reload.
983          */
984         if (AH->remoteVersion >= 80300)
985                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
986
987         /*
988          * Disable timeouts if supported.
989          */
990         if (AH->remoteVersion >= 70300)
991                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
992         if (AH->remoteVersion >= 90300)
993                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
994
995         /*
996          * Quote all identifiers, if requested.
997          */
998         if (quote_all_identifiers && AH->remoteVersion >= 90100)
999                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1000
1001         /*
1002          * Start transaction-snapshot mode transaction to dump consistent data.
1003          */
1004         ExecuteSqlStatement(AH, "BEGIN");
1005         if (AH->remoteVersion >= 90100)
1006         {
1007                 if (serializable_deferrable)
1008                         ExecuteSqlStatement(AH,
1009                                                                 "SET TRANSACTION ISOLATION LEVEL "
1010                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1011                 else
1012                         ExecuteSqlStatement(AH,
1013                                                                 "SET TRANSACTION ISOLATION LEVEL "
1014                                                                 "REPEATABLE READ, READ ONLY");
1015         }
1016         else if (AH->remoteVersion >= 70400)
1017         {
1018                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1019                 ExecuteSqlStatement(AH,
1020                                                         "SET TRANSACTION ISOLATION LEVEL "
1021                                                         "SERIALIZABLE READ ONLY");
1022         }
1023         else
1024                 ExecuteSqlStatement(AH,
1025                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1026
1027
1028
1029         if (AH->numWorkers > 1 && AH->remoteVersion >= 90200 && !no_synchronized_snapshots)
1030         {
1031                 if (AH->sync_snapshot_id)
1032                 {
1033                         PQExpBuffer query = createPQExpBuffer();
1034
1035                         appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1036                         appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1037                         destroyPQExpBuffer(query);
1038                 }
1039                 else
1040                         AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1041         }
1042 }
1043
1044 static void
1045 setupDumpWorker(Archive *AHX, RestoreOptions *ropt)
1046 {
1047         setup_connection(AHX, NULL, NULL);
1048 }
1049
1050 static char *
1051 get_synchronized_snapshot(Archive *fout)
1052 {
1053         char       *query = "SELECT pg_export_snapshot()";
1054         char       *result;
1055         PGresult   *res;
1056
1057         res = ExecuteSqlQueryForSingleRow(fout, query);
1058         result = strdup(PQgetvalue(res, 0, 0));
1059         PQclear(res);
1060
1061         return result;
1062 }
1063
1064 static ArchiveFormat
1065 parseArchiveFormat(const char *format, ArchiveMode *mode)
1066 {
1067         ArchiveFormat archiveFormat;
1068
1069         *mode = archModeWrite;
1070
1071         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1072         {
1073                 /* This is used by pg_dumpall, and is not documented */
1074                 archiveFormat = archNull;
1075                 *mode = archModeAppend;
1076         }
1077         else if (pg_strcasecmp(format, "c") == 0)
1078                 archiveFormat = archCustom;
1079         else if (pg_strcasecmp(format, "custom") == 0)
1080                 archiveFormat = archCustom;
1081         else if (pg_strcasecmp(format, "d") == 0)
1082                 archiveFormat = archDirectory;
1083         else if (pg_strcasecmp(format, "directory") == 0)
1084                 archiveFormat = archDirectory;
1085         else if (pg_strcasecmp(format, "p") == 0)
1086                 archiveFormat = archNull;
1087         else if (pg_strcasecmp(format, "plain") == 0)
1088                 archiveFormat = archNull;
1089         else if (pg_strcasecmp(format, "t") == 0)
1090                 archiveFormat = archTar;
1091         else if (pg_strcasecmp(format, "tar") == 0)
1092                 archiveFormat = archTar;
1093         else
1094                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1095         return archiveFormat;
1096 }
1097
1098 /*
1099  * Find the OIDs of all schemas matching the given list of patterns,
1100  * and append them to the given OID list.
1101  */
1102 static void
1103 expand_schema_name_patterns(Archive *fout,
1104                                                         SimpleStringList *patterns,
1105                                                         SimpleOidList *oids)
1106 {
1107         PQExpBuffer query;
1108         PGresult   *res;
1109         SimpleStringListCell *cell;
1110         int                     i;
1111
1112         if (patterns->head == NULL)
1113                 return;                                 /* nothing to do */
1114
1115         if (fout->remoteVersion < 70300)
1116                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1117
1118         query = createPQExpBuffer();
1119
1120         /*
1121          * We use UNION ALL rather than UNION; this might sometimes result in
1122          * duplicate entries in the OID list, but we don't care.
1123          */
1124
1125         for (cell = patterns->head; cell; cell = cell->next)
1126         {
1127                 if (cell != patterns->head)
1128                         appendPQExpBuffer(query, "UNION ALL\n");
1129                 appendPQExpBuffer(query,
1130                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1131                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1132                                                           false, NULL, "n.nspname", NULL, NULL);
1133         }
1134
1135         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1136
1137         for (i = 0; i < PQntuples(res); i++)
1138         {
1139                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1140         }
1141
1142         PQclear(res);
1143         destroyPQExpBuffer(query);
1144 }
1145
1146 /*
1147  * Find the OIDs of all tables matching the given list of patterns,
1148  * and append them to the given OID list.
1149  */
1150 static void
1151 expand_table_name_patterns(Archive *fout,
1152                                                    SimpleStringList *patterns, SimpleOidList *oids)
1153 {
1154         PQExpBuffer query;
1155         PGresult   *res;
1156         SimpleStringListCell *cell;
1157         int                     i;
1158
1159         if (patterns->head == NULL)
1160                 return;                                 /* nothing to do */
1161
1162         query = createPQExpBuffer();
1163
1164         /*
1165          * We use UNION ALL rather than UNION; this might sometimes result in
1166          * duplicate entries in the OID list, but we don't care.
1167          */
1168
1169         for (cell = patterns->head; cell; cell = cell->next)
1170         {
1171                 if (cell != patterns->head)
1172                         appendPQExpBuffer(query, "UNION ALL\n");
1173                 appendPQExpBuffer(query,
1174                                                   "SELECT c.oid"
1175                                                   "\nFROM pg_catalog.pg_class c"
1176                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1177                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1178                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1179                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1180                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1181                                                           false, "n.nspname", "c.relname", NULL,
1182                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1183         }
1184
1185         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1186
1187         for (i = 0; i < PQntuples(res); i++)
1188         {
1189                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1190         }
1191
1192         PQclear(res);
1193         destroyPQExpBuffer(query);
1194 }
1195
1196 /*
1197  * selectDumpableNamespace: policy-setting subroutine
1198  *              Mark a namespace as to be dumped or not
1199  */
1200 static void
1201 selectDumpableNamespace(NamespaceInfo *nsinfo)
1202 {
1203         /*
1204          * If specific tables are being dumped, do not dump any complete
1205          * namespaces. If specific namespaces are being dumped, dump just those
1206          * namespaces. Otherwise, dump all non-system namespaces.
1207          */
1208         if (table_include_oids.head != NULL)
1209                 nsinfo->dobj.dump = false;
1210         else if (schema_include_oids.head != NULL)
1211                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1212                                                                                                    nsinfo->dobj.catId.oid);
1213         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1214                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1215                 nsinfo->dobj.dump = false;
1216         else
1217                 nsinfo->dobj.dump = true;
1218
1219         /*
1220          * In any case, a namespace can be excluded by an exclusion switch
1221          */
1222         if (nsinfo->dobj.dump &&
1223                 simple_oid_list_member(&schema_exclude_oids,
1224                                                            nsinfo->dobj.catId.oid))
1225                 nsinfo->dobj.dump = false;
1226 }
1227
1228 /*
1229  * selectDumpableTable: policy-setting subroutine
1230  *              Mark a table as to be dumped or not
1231  */
1232 static void
1233 selectDumpableTable(TableInfo *tbinfo)
1234 {
1235         /*
1236          * If specific tables are being dumped, dump just those tables; else, dump
1237          * according to the parent namespace's dump flag.
1238          */
1239         if (table_include_oids.head != NULL)
1240                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1241                                                                                                    tbinfo->dobj.catId.oid);
1242         else
1243                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1244
1245         /*
1246          * In any case, a table can be excluded by an exclusion switch
1247          */
1248         if (tbinfo->dobj.dump &&
1249                 simple_oid_list_member(&table_exclude_oids,
1250                                                            tbinfo->dobj.catId.oid))
1251                 tbinfo->dobj.dump = false;
1252 }
1253
1254 /*
1255  * selectDumpableType: policy-setting subroutine
1256  *              Mark a type as to be dumped or not
1257  *
1258  * If it's a table's rowtype or an autogenerated array type, we also apply a
1259  * special type code to facilitate sorting into the desired order.      (We don't
1260  * want to consider those to be ordinary types because that would bring tables
1261  * up into the datatype part of the dump order.)  We still set the object's
1262  * dump flag; that's not going to cause the dummy type to be dumped, but we
1263  * need it so that casts involving such types will be dumped correctly -- see
1264  * dumpCast.  This means the flag should be set the same as for the underlying
1265  * object (the table or base type).
1266  */
1267 static void
1268 selectDumpableType(TypeInfo *tyinfo)
1269 {
1270         /* skip complex types, except for standalone composite types */
1271         if (OidIsValid(tyinfo->typrelid) &&
1272                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1273         {
1274                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1275
1276                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1277                 if (tytable != NULL)
1278                         tyinfo->dobj.dump = tytable->dobj.dump;
1279                 else
1280                         tyinfo->dobj.dump = false;
1281                 return;
1282         }
1283
1284         /* skip auto-generated array types */
1285         if (tyinfo->isArray)
1286         {
1287                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1288
1289                 /*
1290                  * Fall through to set the dump flag; we assume that the subsequent
1291                  * rules will do the same thing as they would for the array's base
1292                  * type.  (We cannot reliably look up the base type here, since
1293                  * getTypes may not have processed it yet.)
1294                  */
1295         }
1296
1297         /* dump only types in dumpable namespaces */
1298         if (!tyinfo->dobj.namespace->dobj.dump)
1299                 tyinfo->dobj.dump = false;
1300
1301         /* skip undefined placeholder types */
1302         else if (!tyinfo->isDefined)
1303                 tyinfo->dobj.dump = false;
1304
1305         else
1306                 tyinfo->dobj.dump = true;
1307 }
1308
1309 /*
1310  * selectDumpableDefaultACL: policy-setting subroutine
1311  *              Mark a default ACL as to be dumped or not
1312  *
1313  * For per-schema default ACLs, dump if the schema is to be dumped.
1314  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1315  * and aclsSkip are checked separately.
1316  */
1317 static void
1318 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1319 {
1320         if (dinfo->dobj.namespace)
1321                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1322         else
1323                 dinfo->dobj.dump = include_everything;
1324 }
1325
1326 /*
1327  * selectDumpableExtension: policy-setting subroutine
1328  *              Mark an extension as to be dumped or not
1329  *
1330  * Normally, we dump all extensions, or none of them if include_everything
1331  * is false (i.e., a --schema or --table switch was given).  However, in
1332  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1333  * assume those will already be installed in the target database.  We identify
1334  * such extensions by their having OIDs in the range reserved for initdb.
1335  */
1336 static void
1337 selectDumpableExtension(ExtensionInfo *extinfo)
1338 {
1339         if (binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1340                 extinfo->dobj.dump = false;
1341         else
1342                 extinfo->dobj.dump = include_everything;
1343 }
1344
1345 /*
1346  * selectDumpableObject: policy-setting subroutine
1347  *              Mark a generic dumpable object as to be dumped or not
1348  *
1349  * Use this only for object types without a special-case routine above.
1350  */
1351 static void
1352 selectDumpableObject(DumpableObject *dobj)
1353 {
1354         /*
1355          * Default policy is to dump if parent namespace is dumpable, or always
1356          * for non-namespace-associated items.
1357          */
1358         if (dobj->namespace)
1359                 dobj->dump = dobj->namespace->dobj.dump;
1360         else
1361                 dobj->dump = true;
1362 }
1363
1364 /*
1365  *      Dump a table's contents for loading using the COPY command
1366  *      - this routine is called by the Archiver when it wants the table
1367  *        to be dumped.
1368  */
1369
1370 static int
1371 dumpTableData_copy(Archive *fout, void *dcontext)
1372 {
1373         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1374         TableInfo  *tbinfo = tdinfo->tdtable;
1375         const char *classname = tbinfo->dobj.name;
1376         const bool      hasoids = tbinfo->hasoids;
1377         const bool      oids = tdinfo->oids;
1378         PQExpBuffer q = createPQExpBuffer();
1379
1380         /*
1381          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1382          * which uses it already.
1383          */
1384         PQExpBuffer clistBuf = createPQExpBuffer();
1385         PGconn     *conn = GetConnection(fout);
1386         PGresult   *res;
1387         int                     ret;
1388         char       *copybuf;
1389         const char *column_list;
1390
1391         if (g_verbose)
1392                 write_msg(NULL, "dumping contents of table %s\n", classname);
1393
1394         /*
1395          * Make sure we are in proper schema.  We will qualify the table name
1396          * below anyway (in case its name conflicts with a pg_catalog table); but
1397          * this ensures reproducible results in case the table contains regproc,
1398          * regclass, etc columns.
1399          */
1400         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1401
1402         /*
1403          * If possible, specify the column list explicitly so that we have no
1404          * possibility of retrieving data in the wrong column order.  (The default
1405          * column ordering of COPY will not be what we want in certain corner
1406          * cases involving ADD COLUMN and inheritance.)
1407          */
1408         if (fout->remoteVersion >= 70300)
1409                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1410         else
1411                 column_list = "";               /* can't select columns in COPY */
1412
1413         if (oids && hasoids)
1414         {
1415                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1416                                                   fmtQualifiedId(fout->remoteVersion,
1417                                                                                  tbinfo->dobj.namespace->dobj.name,
1418                                                                                  classname),
1419                                                   column_list);
1420         }
1421         else if (tdinfo->filtercond)
1422         {
1423                 /* Note: this syntax is only supported in 8.2 and up */
1424                 appendPQExpBufferStr(q, "COPY (SELECT ");
1425                 /* klugery to get rid of parens in column list */
1426                 if (strlen(column_list) > 2)
1427                 {
1428                         appendPQExpBufferStr(q, column_list + 1);
1429                         q->data[q->len - 1] = ' ';
1430                 }
1431                 else
1432                         appendPQExpBufferStr(q, "* ");
1433                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1434                                                   fmtQualifiedId(fout->remoteVersion,
1435                                                                                  tbinfo->dobj.namespace->dobj.name,
1436                                                                                  classname),
1437                                                   tdinfo->filtercond);
1438         }
1439         else
1440         {
1441                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1442                                                   fmtQualifiedId(fout->remoteVersion,
1443                                                                                  tbinfo->dobj.namespace->dobj.name,
1444                                                                                  classname),
1445                                                   column_list);
1446         }
1447         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1448         PQclear(res);
1449         destroyPQExpBuffer(clistBuf);
1450
1451         for (;;)
1452         {
1453                 ret = PQgetCopyData(conn, &copybuf, 0);
1454
1455                 if (ret < 0)
1456                         break;                          /* done or error */
1457
1458                 if (copybuf)
1459                 {
1460                         WriteData(fout, copybuf, ret);
1461                         PQfreemem(copybuf);
1462                 }
1463
1464                 /* ----------
1465                  * THROTTLE:
1466                  *
1467                  * There was considerable discussion in late July, 2000 regarding
1468                  * slowing down pg_dump when backing up large tables. Users with both
1469                  * slow & fast (multi-processor) machines experienced performance
1470                  * degradation when doing a backup.
1471                  *
1472                  * Initial attempts based on sleeping for a number of ms for each ms
1473                  * of work were deemed too complex, then a simple 'sleep in each loop'
1474                  * implementation was suggested. The latter failed because the loop
1475                  * was too tight. Finally, the following was implemented:
1476                  *
1477                  * If throttle is non-zero, then
1478                  *              See how long since the last sleep.
1479                  *              Work out how long to sleep (based on ratio).
1480                  *              If sleep is more than 100ms, then
1481                  *                      sleep
1482                  *                      reset timer
1483                  *              EndIf
1484                  * EndIf
1485                  *
1486                  * where the throttle value was the number of ms to sleep per ms of
1487                  * work. The calculation was done in each loop.
1488                  *
1489                  * Most of the hard work is done in the backend, and this solution
1490                  * still did not work particularly well: on slow machines, the ratio
1491                  * was 50:1, and on medium paced machines, 1:1, and on fast
1492                  * multi-processor machines, it had little or no effect, for reasons
1493                  * that were unclear.
1494                  *
1495                  * Further discussion ensued, and the proposal was dropped.
1496                  *
1497                  * For those people who want this feature, it can be implemented using
1498                  * gettimeofday in each loop, calculating the time since last sleep,
1499                  * multiplying that by the sleep ratio, then if the result is more
1500                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1501                  * function to sleep for a subsecond period ie.
1502                  *
1503                  * select(0, NULL, NULL, NULL, &tvi);
1504                  *
1505                  * This will return after the interval specified in the structure tvi.
1506                  * Finally, call gettimeofday again to save the 'last sleep time'.
1507                  * ----------
1508                  */
1509         }
1510         archprintf(fout, "\\.\n\n\n");
1511
1512         if (ret == -2)
1513         {
1514                 /* copy data transfer failed */
1515                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1516                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1517                 write_msg(NULL, "The command was: %s\n", q->data);
1518                 exit_nicely(1);
1519         }
1520
1521         /* Check command status and return to normal libpq state */
1522         res = PQgetResult(conn);
1523         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1524         {
1525                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1526                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1527                 write_msg(NULL, "The command was: %s\n", q->data);
1528                 exit_nicely(1);
1529         }
1530         PQclear(res);
1531
1532         destroyPQExpBuffer(q);
1533         return 1;
1534 }
1535
1536 /*
1537  * Dump table data using INSERT commands.
1538  *
1539  * Caution: when we restore from an archive file direct to database, the
1540  * INSERT commands emitted by this function have to be parsed by
1541  * pg_backup_db.c's ExecuteInsertCommands(), which will not handle comments,
1542  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1543  */
1544 static int
1545 dumpTableData_insert(Archive *fout, void *dcontext)
1546 {
1547         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1548         TableInfo  *tbinfo = tdinfo->tdtable;
1549         const char *classname = tbinfo->dobj.name;
1550         PQExpBuffer q = createPQExpBuffer();
1551         PGresult   *res;
1552         int                     tuple;
1553         int                     nfields;
1554         int                     field;
1555
1556         /*
1557          * Make sure we are in proper schema.  We will qualify the table name
1558          * below anyway (in case its name conflicts with a pg_catalog table); but
1559          * this ensures reproducible results in case the table contains regproc,
1560          * regclass, etc columns.
1561          */
1562         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1563
1564         if (fout->remoteVersion >= 70100)
1565         {
1566                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1567                                                   "SELECT * FROM ONLY %s",
1568                                                   fmtQualifiedId(fout->remoteVersion,
1569                                                                                  tbinfo->dobj.namespace->dobj.name,
1570                                                                                  classname));
1571         }
1572         else
1573         {
1574                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1575                                                   "SELECT * FROM %s",
1576                                                   fmtQualifiedId(fout->remoteVersion,
1577                                                                                  tbinfo->dobj.namespace->dobj.name,
1578                                                                                  classname));
1579         }
1580         if (tdinfo->filtercond)
1581                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1582
1583         ExecuteSqlStatement(fout, q->data);
1584
1585         while (1)
1586         {
1587                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1588                                                           PGRES_TUPLES_OK);
1589                 nfields = PQnfields(res);
1590                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1591                 {
1592                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1593                         if (nfields == 0)
1594                         {
1595                                 /* corner case for zero-column table */
1596                                 archprintf(fout, "DEFAULT VALUES;\n");
1597                                 continue;
1598                         }
1599                         if (column_inserts)
1600                         {
1601                                 resetPQExpBuffer(q);
1602                                 appendPQExpBuffer(q, "(");
1603                                 for (field = 0; field < nfields; field++)
1604                                 {
1605                                         if (field > 0)
1606                                                 appendPQExpBuffer(q, ", ");
1607                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1608                                 }
1609                                 appendPQExpBuffer(q, ") ");
1610                                 archputs(q->data, fout);
1611                         }
1612                         archprintf(fout, "VALUES (");
1613                         for (field = 0; field < nfields; field++)
1614                         {
1615                                 if (field > 0)
1616                                         archprintf(fout, ", ");
1617                                 if (PQgetisnull(res, tuple, field))
1618                                 {
1619                                         archprintf(fout, "NULL");
1620                                         continue;
1621                                 }
1622
1623                                 /* XXX This code is partially duplicated in ruleutils.c */
1624                                 switch (PQftype(res, field))
1625                                 {
1626                                         case INT2OID:
1627                                         case INT4OID:
1628                                         case INT8OID:
1629                                         case OIDOID:
1630                                         case FLOAT4OID:
1631                                         case FLOAT8OID:
1632                                         case NUMERICOID:
1633                                                 {
1634                                                         /*
1635                                                          * These types are printed without quotes unless
1636                                                          * they contain values that aren't accepted by the
1637                                                          * scanner unquoted (e.g., 'NaN').      Note that
1638                                                          * strtod() and friends might accept NaN, so we
1639                                                          * can't use that to test.
1640                                                          *
1641                                                          * In reality we only need to defend against
1642                                                          * infinity and NaN, so we need not get too crazy
1643                                                          * about pattern matching here.
1644                                                          */
1645                                                         const char *s = PQgetvalue(res, tuple, field);
1646
1647                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1648                                                                 archprintf(fout, "%s", s);
1649                                                         else
1650                                                                 archprintf(fout, "'%s'", s);
1651                                                 }
1652                                                 break;
1653
1654                                         case BITOID:
1655                                         case VARBITOID:
1656                                                 archprintf(fout, "B'%s'",
1657                                                                    PQgetvalue(res, tuple, field));
1658                                                 break;
1659
1660                                         case BOOLOID:
1661                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1662                                                         archprintf(fout, "true");
1663                                                 else
1664                                                         archprintf(fout, "false");
1665                                                 break;
1666
1667                                         default:
1668                                                 /* All other types are printed as string literals. */
1669                                                 resetPQExpBuffer(q);
1670                                                 appendStringLiteralAH(q,
1671                                                                                           PQgetvalue(res, tuple, field),
1672                                                                                           fout);
1673                                                 archputs(q->data, fout);
1674                                                 break;
1675                                 }
1676                         }
1677                         archprintf(fout, ");\n");
1678                 }
1679
1680                 if (PQntuples(res) <= 0)
1681                 {
1682                         PQclear(res);
1683                         break;
1684                 }
1685                 PQclear(res);
1686         }
1687
1688         archprintf(fout, "\n\n");
1689
1690         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1691
1692         destroyPQExpBuffer(q);
1693         return 1;
1694 }
1695
1696
1697 /*
1698  * dumpTableData -
1699  *        dump the contents of a single table
1700  *
1701  * Actually, this just makes an ArchiveEntry for the table contents.
1702  */
1703 static void
1704 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1705 {
1706         TableInfo  *tbinfo = tdinfo->tdtable;
1707         PQExpBuffer copyBuf = createPQExpBuffer();
1708         PQExpBuffer clistBuf = createPQExpBuffer();
1709         DataDumperPtr dumpFn;
1710         char       *copyStmt;
1711
1712         if (!dump_inserts)
1713         {
1714                 /* Dump/restore using COPY */
1715                 dumpFn = dumpTableData_copy;
1716                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1717                 appendPQExpBuffer(copyBuf, "COPY %s ",
1718                                                   fmtId(tbinfo->dobj.name));
1719                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1720                                                   fmtCopyColumnList(tbinfo, clistBuf),
1721                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1722                 copyStmt = copyBuf->data;
1723         }
1724         else
1725         {
1726                 /* Restore using INSERT */
1727                 dumpFn = dumpTableData_insert;
1728                 copyStmt = NULL;
1729         }
1730
1731         /*
1732          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1733          * dependency on its table as "special" and pass it to ArchiveEntry now.
1734          * See comments for BuildArchiveDependencies.
1735          */
1736         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1737                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1738                                  NULL, tbinfo->rolname,
1739                                  false, "TABLE DATA", SECTION_DATA,
1740                                  "", "", copyStmt,
1741                                  &(tbinfo->dobj.dumpId), 1,
1742                                  dumpFn, tdinfo);
1743
1744         destroyPQExpBuffer(copyBuf);
1745         destroyPQExpBuffer(clistBuf);
1746 }
1747
1748 /*
1749  * refreshMatViewData -
1750  *        load or refresh the contents of a single materialized view
1751  *
1752  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1753  * statement.
1754  */
1755 static void
1756 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1757 {
1758         TableInfo  *tbinfo = tdinfo->tdtable;
1759         PQExpBuffer q;
1760
1761         /* If the materialized view is not flagged as scannable, skip this. */
1762         if (!tbinfo->isscannable)
1763                 return;
1764
1765         q = createPQExpBuffer();
1766
1767         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1768                                           fmtId(tbinfo->dobj.name));
1769
1770         ArchiveEntry(fout,
1771                                  tdinfo->dobj.catId,    /* catalog ID */
1772                                  tdinfo->dobj.dumpId,   /* dump ID */
1773                                  tbinfo->dobj.name,             /* Name */
1774                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1775                                  NULL,                  /* Tablespace */
1776                                  tbinfo->rolname,               /* Owner */
1777                                  false,                 /* with oids */
1778                                  "MATERIALIZED VIEW DATA",              /* Desc */
1779                                  SECTION_POST_DATA,             /* Section */
1780                                  q->data,               /* Create */
1781                                  "",                    /* Del */
1782                                  NULL,                  /* Copy */
1783                                  tdinfo->dobj.dependencies,             /* Deps */
1784                                  tdinfo->dobj.nDeps,    /* # Deps */
1785                                  NULL,                  /* Dumper */
1786                                  NULL);                 /* Dumper Arg */
1787
1788         destroyPQExpBuffer(q);
1789 }
1790
1791 /*
1792  * getTableData -
1793  *        set up dumpable objects representing the contents of tables
1794  */
1795 static void
1796 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1797 {
1798         int                     i;
1799
1800         for (i = 0; i < numTables; i++)
1801         {
1802                 if (tblinfo[i].dobj.dump)
1803                         makeTableDataInfo(&(tblinfo[i]), oids);
1804         }
1805 }
1806
1807 /*
1808  * Make a dumpable object for the data of this specific table
1809  *
1810  * Note: we make a TableDataInfo if and only if we are going to dump the
1811  * table data; the "dump" flag in such objects isn't used.
1812  */
1813 static void
1814 makeTableDataInfo(TableInfo *tbinfo, bool oids)
1815 {
1816         TableDataInfo *tdinfo;
1817
1818         /*
1819          * Nothing to do if we already decided to dump the table.  This will
1820          * happen for "config" tables.
1821          */
1822         if (tbinfo->dataObj != NULL)
1823                 return;
1824
1825         /* Skip VIEWs (no data to dump) */
1826         if (tbinfo->relkind == RELKIND_VIEW)
1827                 return;
1828         /* Skip FOREIGN TABLEs (no data to dump) */
1829         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1830                 return;
1831
1832         /* Don't dump data in unlogged tables, if so requested */
1833         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1834                 no_unlogged_table_data)
1835                 return;
1836
1837         /* Check that the data is not explicitly excluded */
1838         if (simple_oid_list_member(&tabledata_exclude_oids,
1839                                                            tbinfo->dobj.catId.oid))
1840                 return;
1841
1842         /* OK, let's dump it */
1843         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1844
1845         if (tbinfo->relkind == RELKIND_MATVIEW)
1846                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1847         else
1848                 tdinfo->dobj.objType = DO_TABLE_DATA;
1849
1850         /*
1851          * Note: use tableoid 0 so that this object won't be mistaken for
1852          * something that pg_depend entries apply to.
1853          */
1854         tdinfo->dobj.catId.tableoid = 0;
1855         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1856         AssignDumpId(&tdinfo->dobj);
1857         tdinfo->dobj.name = tbinfo->dobj.name;
1858         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1859         tdinfo->tdtable = tbinfo;
1860         tdinfo->oids = oids;
1861         tdinfo->filtercond = NULL;      /* might get set later */
1862         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1863
1864         tbinfo->dataObj = tdinfo;
1865 }
1866
1867 /*
1868  * The refresh for a materialized view must be dependent on the refresh for
1869  * any materialized view that this one is dependent on.
1870  *
1871  * This must be called after all the objects are created, but before they are
1872  * sorted.
1873  */
1874 static void
1875 buildMatViewRefreshDependencies(Archive *fout)
1876 {
1877         PQExpBuffer query;
1878         PGresult   *res;
1879         int                     ntups,
1880                                 i;
1881         int                     i_classid,
1882                                 i_objid,
1883                                 i_refobjid;
1884
1885         /* No Mat Views before 9.3. */
1886         if (fout->remoteVersion < 90300)
1887                 return;
1888
1889         /* Make sure we are in proper schema */
1890         selectSourceSchema(fout, "pg_catalog");
1891
1892         query = createPQExpBuffer();
1893
1894         appendPQExpBuffer(query, "with recursive w as "
1895                                           "( "
1896                                         "select d1.objid, d2.refobjid, c2.relkind as refrelkind "
1897                                           "from pg_depend d1 "
1898                                           "join pg_class c1 on c1.oid = d1.objid "
1899                                           "and c1.relkind = 'm' "
1900                                           "join pg_rewrite r1 on r1.ev_class = d1.objid "
1901                                   "join pg_depend d2 on d2.classid = 'pg_rewrite'::regclass "
1902                                           "and d2.objid = r1.oid "
1903                                           "and d2.refobjid <> d1.objid "
1904                                           "join pg_class c2 on c2.oid = d2.refobjid "
1905                                           "and c2.relkind in ('m','v') "
1906                                           "where d1.classid = 'pg_class'::regclass "
1907                                           "union "
1908                                           "select w.objid, d3.refobjid, c3.relkind "
1909                                           "from w "
1910                                           "join pg_rewrite r3 on r3.ev_class = w.refobjid "
1911                                   "join pg_depend d3 on d3.classid = 'pg_rewrite'::regclass "
1912                                           "and d3.objid = r3.oid "
1913                                           "and d3.refobjid <> w.refobjid "
1914                                           "join pg_class c3 on c3.oid = d3.refobjid "
1915                                           "and c3.relkind in ('m','v') "
1916                                           ") "
1917                           "select 'pg_class'::regclass::oid as classid, objid, refobjid "
1918                                           "from w "
1919                                           "where refrelkind = 'm'");
1920
1921         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1922
1923         ntups = PQntuples(res);
1924
1925         i_classid = PQfnumber(res, "classid");
1926         i_objid = PQfnumber(res, "objid");
1927         i_refobjid = PQfnumber(res, "refobjid");
1928
1929         for (i = 0; i < ntups; i++)
1930         {
1931                 CatalogId       objId;
1932                 CatalogId       refobjId;
1933                 DumpableObject *dobj;
1934                 DumpableObject *refdobj;
1935                 TableInfo  *tbinfo;
1936                 TableInfo  *reftbinfo;
1937
1938                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1939                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1940                 refobjId.tableoid = objId.tableoid;
1941                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1942
1943                 dobj = findObjectByCatalogId(objId);
1944                 if (dobj == NULL)
1945                         continue;
1946
1947                 Assert(dobj->objType == DO_TABLE);
1948                 tbinfo = (TableInfo *) dobj;
1949                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1950                 dobj = (DumpableObject *) tbinfo->dataObj;
1951                 if (dobj == NULL)
1952                         continue;
1953                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
1954
1955                 refdobj = findObjectByCatalogId(refobjId);
1956                 if (refdobj == NULL)
1957                         continue;
1958
1959                 Assert(refdobj->objType == DO_TABLE);
1960                 reftbinfo = (TableInfo *) refdobj;
1961                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
1962                 refdobj = (DumpableObject *) reftbinfo->dataObj;
1963                 if (refdobj == NULL)
1964                         continue;
1965                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
1966
1967                 addObjectDependency(dobj, refdobj->dumpId);
1968
1969                 if (!reftbinfo->isscannable)
1970                         tbinfo->isscannable = false;
1971         }
1972
1973         PQclear(res);
1974
1975         destroyPQExpBuffer(query);
1976 }
1977
1978 /*
1979  * getTableDataFKConstraints -
1980  *        add dump-order dependencies reflecting foreign key constraints
1981  *
1982  * This code is executed only in a data-only dump --- in schema+data dumps
1983  * we handle foreign key issues by not creating the FK constraints until
1984  * after the data is loaded.  In a data-only dump, however, we want to
1985  * order the table data objects in such a way that a table's referenced
1986  * tables are restored first.  (In the presence of circular references or
1987  * self-references this may be impossible; we'll detect and complain about
1988  * that during the dependency sorting step.)
1989  */
1990 static void
1991 getTableDataFKConstraints(void)
1992 {
1993         DumpableObject **dobjs;
1994         int                     numObjs;
1995         int                     i;
1996
1997         /* Search through all the dumpable objects for FK constraints */
1998         getDumpableObjects(&dobjs, &numObjs);
1999         for (i = 0; i < numObjs; i++)
2000         {
2001                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2002                 {
2003                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2004                         TableInfo  *ftable;
2005
2006                         /* Not interesting unless both tables are to be dumped */
2007                         if (cinfo->contable == NULL ||
2008                                 cinfo->contable->dataObj == NULL)
2009                                 continue;
2010                         ftable = findTableByOid(cinfo->confrelid);
2011                         if (ftable == NULL ||
2012                                 ftable->dataObj == NULL)
2013                                 continue;
2014
2015                         /*
2016                          * Okay, make referencing table's TABLE_DATA object depend on the
2017                          * referenced table's TABLE_DATA object.
2018                          */
2019                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2020                                                                 ftable->dataObj->dobj.dumpId);
2021                 }
2022         }
2023         free(dobjs);
2024 }
2025
2026
2027 /*
2028  * guessConstraintInheritance:
2029  *      In pre-8.4 databases, we can't tell for certain which constraints
2030  *      are inherited.  We assume a CHECK constraint is inherited if its name
2031  *      matches the name of any constraint in the parent.  Originally this code
2032  *      tried to compare the expression texts, but that can fail for various
2033  *      reasons --- for example, if the parent and child tables are in different
2034  *      schemas, reverse-listing of function calls may produce different text
2035  *      (schema-qualified or not) depending on search path.
2036  *
2037  *      In 8.4 and up we can rely on the conislocal field to decide which
2038  *      constraints must be dumped; much safer.
2039  *
2040  *      This function assumes all conislocal flags were initialized to TRUE.
2041  *      It clears the flag on anything that seems to be inherited.
2042  */
2043 static void
2044 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2045 {
2046         int                     i,
2047                                 j,
2048                                 k;
2049
2050         for (i = 0; i < numTables; i++)
2051         {
2052                 TableInfo  *tbinfo = &(tblinfo[i]);
2053                 int                     numParents;
2054                 TableInfo **parents;
2055                 TableInfo  *parent;
2056
2057                 /* Sequences and views never have parents */
2058                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2059                         tbinfo->relkind == RELKIND_VIEW)
2060                         continue;
2061
2062                 /* Don't bother computing anything for non-target tables, either */
2063                 if (!tbinfo->dobj.dump)
2064                         continue;
2065
2066                 numParents = tbinfo->numParents;
2067                 parents = tbinfo->parents;
2068
2069                 if (numParents == 0)
2070                         continue;                       /* nothing to see here, move along */
2071
2072                 /* scan for inherited CHECK constraints */
2073                 for (j = 0; j < tbinfo->ncheck; j++)
2074                 {
2075                         ConstraintInfo *constr;
2076
2077                         constr = &(tbinfo->checkexprs[j]);
2078
2079                         for (k = 0; k < numParents; k++)
2080                         {
2081                                 int                     l;
2082
2083                                 parent = parents[k];
2084                                 for (l = 0; l < parent->ncheck; l++)
2085                                 {
2086                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2087
2088                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2089                                         {
2090                                                 constr->conislocal = false;
2091                                                 break;
2092                                         }
2093                                 }
2094                                 if (!constr->conislocal)
2095                                         break;
2096                         }
2097                 }
2098         }
2099 }
2100
2101
2102 /*
2103  * dumpDatabase:
2104  *      dump the database definition
2105  */
2106 static void
2107 dumpDatabase(Archive *fout)
2108 {
2109         PQExpBuffer dbQry = createPQExpBuffer();
2110         PQExpBuffer delQry = createPQExpBuffer();
2111         PQExpBuffer creaQry = createPQExpBuffer();
2112         PGconn     *conn = GetConnection(fout);
2113         PGresult   *res;
2114         int                     i_tableoid,
2115                                 i_oid,
2116                                 i_dba,
2117                                 i_encoding,
2118                                 i_collate,
2119                                 i_ctype,
2120                                 i_frozenxid,
2121                                 i_tablespace;
2122         CatalogId       dbCatId;
2123         DumpId          dbDumpId;
2124         const char *datname,
2125                            *dba,
2126                            *encoding,
2127                            *collate,
2128                            *ctype,
2129                            *tablespace;
2130         uint32          frozenxid;
2131
2132         datname = PQdb(conn);
2133
2134         if (g_verbose)
2135                 write_msg(NULL, "saving database definition\n");
2136
2137         /* Make sure we are in proper schema */
2138         selectSourceSchema(fout, "pg_catalog");
2139
2140         /* Get the database owner and parameters from pg_database */
2141         if (fout->remoteVersion >= 80400)
2142         {
2143                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2144                                                   "(%s datdba) AS dba, "
2145                                                   "pg_encoding_to_char(encoding) AS encoding, "
2146                                                   "datcollate, datctype, datfrozenxid, "
2147                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2148                                           "shobj_description(oid, 'pg_database') AS description "
2149
2150                                                   "FROM pg_database "
2151                                                   "WHERE datname = ",
2152                                                   username_subquery);
2153                 appendStringLiteralAH(dbQry, datname, fout);
2154         }
2155         else if (fout->remoteVersion >= 80200)
2156         {
2157                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2158                                                   "(%s datdba) AS dba, "
2159                                                   "pg_encoding_to_char(encoding) AS encoding, "
2160                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2161                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2162                                           "shobj_description(oid, 'pg_database') AS description "
2163
2164                                                   "FROM pg_database "
2165                                                   "WHERE datname = ",
2166                                                   username_subquery);
2167                 appendStringLiteralAH(dbQry, datname, fout);
2168         }
2169         else if (fout->remoteVersion >= 80000)
2170         {
2171                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2172                                                   "(%s datdba) AS dba, "
2173                                                   "pg_encoding_to_char(encoding) AS encoding, "
2174                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
2175                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2176                                                   "FROM pg_database "
2177                                                   "WHERE datname = ",
2178                                                   username_subquery);
2179                 appendStringLiteralAH(dbQry, datname, fout);
2180         }
2181         else if (fout->remoteVersion >= 70100)
2182         {
2183                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2184                                                   "(%s datdba) AS dba, "
2185                                                   "pg_encoding_to_char(encoding) AS encoding, "
2186                                                   "NULL AS datcollate, NULL AS datctype, "
2187                                                   "0 AS datfrozenxid, "
2188                                                   "NULL AS tablespace "
2189                                                   "FROM pg_database "
2190                                                   "WHERE datname = ",
2191                                                   username_subquery);
2192                 appendStringLiteralAH(dbQry, datname, fout);
2193         }
2194         else
2195         {
2196                 appendPQExpBuffer(dbQry, "SELECT "
2197                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2198                                                   "oid, "
2199                                                   "(%s datdba) AS dba, "
2200                                                   "pg_encoding_to_char(encoding) AS encoding, "
2201                                                   "NULL AS datcollate, NULL AS datctype, "
2202                                                   "0 AS datfrozenxid, "
2203                                                   "NULL AS tablespace "
2204                                                   "FROM pg_database "
2205                                                   "WHERE datname = ",
2206                                                   username_subquery);
2207                 appendStringLiteralAH(dbQry, datname, fout);
2208         }
2209
2210         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2211
2212         i_tableoid = PQfnumber(res, "tableoid");
2213         i_oid = PQfnumber(res, "oid");
2214         i_dba = PQfnumber(res, "dba");
2215         i_encoding = PQfnumber(res, "encoding");
2216         i_collate = PQfnumber(res, "datcollate");
2217         i_ctype = PQfnumber(res, "datctype");
2218         i_frozenxid = PQfnumber(res, "datfrozenxid");
2219         i_tablespace = PQfnumber(res, "tablespace");
2220
2221         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2222         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2223         dba = PQgetvalue(res, 0, i_dba);
2224         encoding = PQgetvalue(res, 0, i_encoding);
2225         collate = PQgetvalue(res, 0, i_collate);
2226         ctype = PQgetvalue(res, 0, i_ctype);
2227         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2228         tablespace = PQgetvalue(res, 0, i_tablespace);
2229
2230         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2231                                           fmtId(datname));
2232         if (strlen(encoding) > 0)
2233         {
2234                 appendPQExpBuffer(creaQry, " ENCODING = ");
2235                 appendStringLiteralAH(creaQry, encoding, fout);
2236         }
2237         if (strlen(collate) > 0)
2238         {
2239                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
2240                 appendStringLiteralAH(creaQry, collate, fout);
2241         }
2242         if (strlen(ctype) > 0)
2243         {
2244                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
2245                 appendStringLiteralAH(creaQry, ctype, fout);
2246         }
2247         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2248                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2249                                                   fmtId(tablespace));
2250         appendPQExpBuffer(creaQry, ";\n");
2251
2252         if (binary_upgrade)
2253         {
2254                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
2255                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2256                                                   "SET datfrozenxid = '%u'\n"
2257                                                   "WHERE        datname = ",
2258                                                   frozenxid);
2259                 appendStringLiteralAH(creaQry, datname, fout);
2260                 appendPQExpBuffer(creaQry, ";\n");
2261
2262         }
2263
2264         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2265                                           fmtId(datname));
2266
2267         dbDumpId = createDumpId();
2268
2269         ArchiveEntry(fout,
2270                                  dbCatId,               /* catalog ID */
2271                                  dbDumpId,              /* dump ID */
2272                                  datname,               /* Name */
2273                                  NULL,                  /* Namespace */
2274                                  NULL,                  /* Tablespace */
2275                                  dba,                   /* Owner */
2276                                  false,                 /* with oids */
2277                                  "DATABASE",    /* Desc */
2278                                  SECTION_PRE_DATA,              /* Section */
2279                                  creaQry->data, /* Create */
2280                                  delQry->data,  /* Del */
2281                                  NULL,                  /* Copy */
2282                                  NULL,                  /* Deps */
2283                                  0,                             /* # Deps */
2284                                  NULL,                  /* Dumper */
2285                                  NULL);                 /* Dumper Arg */
2286
2287         /*
2288          * pg_largeobject and pg_largeobject_metadata come from the old system
2289          * intact, so set their relfrozenxids.
2290          */
2291         if (binary_upgrade)
2292         {
2293                 PGresult   *lo_res;
2294                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2295                 PQExpBuffer loOutQry = createPQExpBuffer();
2296                 int                     i_relfrozenxid;
2297
2298                 /*
2299                  * pg_largeobject
2300                  */
2301                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2302                                                   "FROM pg_catalog.pg_class\n"
2303                                                   "WHERE oid = %u;\n",
2304                                                   LargeObjectRelationId);
2305
2306                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2307
2308                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2309
2310                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject.relfrozenxid\n");
2311                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2312                                                   "SET relfrozenxid = '%u'\n"
2313                                                   "WHERE oid = %u;\n",
2314                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2315                                                   LargeObjectRelationId);
2316                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2317                                          "pg_largeobject", NULL, NULL, "",
2318                                          false, "pg_largeobject", SECTION_PRE_DATA,
2319                                          loOutQry->data, "", NULL,
2320                                          NULL, 0,
2321                                          NULL, NULL);
2322
2323                 PQclear(lo_res);
2324
2325                 /*
2326                  * pg_largeobject_metadata
2327                  */
2328                 if (fout->remoteVersion >= 90000)
2329                 {
2330                         resetPQExpBuffer(loFrozenQry);
2331                         resetPQExpBuffer(loOutQry);
2332
2333                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
2334                                                           "FROM pg_catalog.pg_class\n"
2335                                                           "WHERE oid = %u;\n",
2336                                                           LargeObjectMetadataRelationId);
2337
2338                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2339
2340                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2341
2342                         appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata.relfrozenxid\n");
2343                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2344                                                           "SET relfrozenxid = '%u'\n"
2345                                                           "WHERE oid = %u;\n",
2346                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2347                                                           LargeObjectMetadataRelationId);
2348                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2349                                                  "pg_largeobject_metadata", NULL, NULL, "",
2350                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2351                                                  loOutQry->data, "", NULL,
2352                                                  NULL, 0,
2353                                                  NULL, NULL);
2354
2355                         PQclear(lo_res);
2356                 }
2357
2358                 destroyPQExpBuffer(loFrozenQry);
2359                 destroyPQExpBuffer(loOutQry);
2360         }
2361
2362         /* Dump DB comment if any */
2363         if (fout->remoteVersion >= 80200)
2364         {
2365                 /*
2366                  * 8.2 keeps comments on shared objects in a shared table, so we
2367                  * cannot use the dumpComment used for other database objects.
2368                  */
2369                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2370
2371                 if (comment && strlen(comment))
2372                 {
2373                         resetPQExpBuffer(dbQry);
2374
2375                         /*
2376                          * Generates warning when loaded into a differently-named
2377                          * database.
2378                          */
2379                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2380                         appendStringLiteralAH(dbQry, comment, fout);
2381                         appendPQExpBuffer(dbQry, ";\n");
2382
2383                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2384                                                  dba, false, "COMMENT", SECTION_NONE,
2385                                                  dbQry->data, "", NULL,
2386                                                  &dbDumpId, 1, NULL, NULL);
2387                 }
2388         }
2389         else
2390         {
2391                 resetPQExpBuffer(dbQry);
2392                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2393                 dumpComment(fout, dbQry->data, NULL, "",
2394                                         dbCatId, 0, dbDumpId);
2395         }
2396
2397         PQclear(res);
2398
2399         /* Dump shared security label. */
2400         if (!no_security_labels && fout->remoteVersion >= 90200)
2401         {
2402                 PQExpBuffer seclabelQry = createPQExpBuffer();
2403
2404                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2405                 res = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2406                 resetPQExpBuffer(seclabelQry);
2407                 emitShSecLabels(conn, res, seclabelQry, "DATABASE", datname);
2408                 if (strlen(seclabelQry->data))
2409                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2410                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2411                                                  seclabelQry->data, "", NULL,
2412                                                  &dbDumpId, 1, NULL, NULL);
2413                 destroyPQExpBuffer(seclabelQry);
2414         }
2415
2416         destroyPQExpBuffer(dbQry);
2417         destroyPQExpBuffer(delQry);
2418         destroyPQExpBuffer(creaQry);
2419 }
2420
2421
2422 /*
2423  * dumpEncoding: put the correct encoding into the archive
2424  */
2425 static void
2426 dumpEncoding(Archive *AH)
2427 {
2428         const char *encname = pg_encoding_to_char(AH->encoding);
2429         PQExpBuffer qry = createPQExpBuffer();
2430
2431         if (g_verbose)
2432                 write_msg(NULL, "saving encoding = %s\n", encname);
2433
2434         appendPQExpBuffer(qry, "SET client_encoding = ");
2435         appendStringLiteralAH(qry, encname, AH);
2436         appendPQExpBuffer(qry, ";\n");
2437
2438         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2439                                  "ENCODING", NULL, NULL, "",
2440                                  false, "ENCODING", SECTION_PRE_DATA,
2441                                  qry->data, "", NULL,
2442                                  NULL, 0,
2443                                  NULL, NULL);
2444
2445         destroyPQExpBuffer(qry);
2446 }
2447
2448
2449 /*
2450  * dumpStdStrings: put the correct escape string behavior into the archive
2451  */
2452 static void
2453 dumpStdStrings(Archive *AH)
2454 {
2455         const char *stdstrings = AH->std_strings ? "on" : "off";
2456         PQExpBuffer qry = createPQExpBuffer();
2457
2458         if (g_verbose)
2459                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2460                                   stdstrings);
2461
2462         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2463                                           stdstrings);
2464
2465         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2466                                  "STDSTRINGS", NULL, NULL, "",
2467                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2468                                  qry->data, "", NULL,
2469                                  NULL, 0,
2470                                  NULL, NULL);
2471
2472         destroyPQExpBuffer(qry);
2473 }
2474
2475
2476 /*
2477  * getBlobs:
2478  *      Collect schema-level data about large objects
2479  */
2480 static void
2481 getBlobs(Archive *fout)
2482 {
2483         PQExpBuffer blobQry = createPQExpBuffer();
2484         BlobInfo   *binfo;
2485         DumpableObject *bdata;
2486         PGresult   *res;
2487         int                     ntups;
2488         int                     i;
2489
2490         /* Verbose message */
2491         if (g_verbose)
2492                 write_msg(NULL, "reading large objects\n");
2493
2494         /* Make sure we are in proper schema */
2495         selectSourceSchema(fout, "pg_catalog");
2496
2497         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2498         if (fout->remoteVersion >= 90000)
2499                 appendPQExpBuffer(blobQry,
2500                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2501                                                   " FROM pg_largeobject_metadata",
2502                                                   username_subquery);
2503         else if (fout->remoteVersion >= 70100)
2504                 appendPQExpBuffer(blobQry,
2505                                                   "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2506                                                   " FROM pg_largeobject");
2507         else
2508                 appendPQExpBuffer(blobQry,
2509                                                   "SELECT oid, NULL::oid, NULL::oid"
2510                                                   " FROM pg_class WHERE relkind = 'l'");
2511
2512         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2513
2514         ntups = PQntuples(res);
2515         if (ntups > 0)
2516         {
2517                 /*
2518                  * Each large object has its own BLOB archive entry.
2519                  */
2520                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2521
2522                 for (i = 0; i < ntups; i++)
2523                 {
2524                         binfo[i].dobj.objType = DO_BLOB;
2525                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2526                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2527                         AssignDumpId(&binfo[i].dobj);
2528
2529                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2530                         if (!PQgetisnull(res, i, 1))
2531                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2532                         else
2533                                 binfo[i].rolname = "";
2534                         if (!PQgetisnull(res, i, 2))
2535                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2536                         else
2537                                 binfo[i].blobacl = NULL;
2538                 }
2539
2540                 /*
2541                  * If we have any large objects, a "BLOBS" archive entry is needed.
2542                  * This is just a placeholder for sorting; it carries no data now.
2543                  */
2544                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2545                 bdata->objType = DO_BLOB_DATA;
2546                 bdata->catId = nilCatalogId;
2547                 AssignDumpId(bdata);
2548                 bdata->name = pg_strdup("BLOBS");
2549         }
2550
2551         PQclear(res);
2552         destroyPQExpBuffer(blobQry);
2553 }
2554
2555 /*
2556  * dumpBlob
2557  *
2558  * dump the definition (metadata) of the given large object
2559  */
2560 static void
2561 dumpBlob(Archive *fout, BlobInfo *binfo)
2562 {
2563         PQExpBuffer cquery = createPQExpBuffer();
2564         PQExpBuffer dquery = createPQExpBuffer();
2565
2566         appendPQExpBuffer(cquery,
2567                                           "SELECT pg_catalog.lo_create('%s');\n",
2568                                           binfo->dobj.name);
2569
2570         appendPQExpBuffer(dquery,
2571                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2572                                           binfo->dobj.name);
2573
2574         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2575                                  binfo->dobj.name,
2576                                  NULL, NULL,
2577                                  binfo->rolname, false,
2578                                  "BLOB", SECTION_PRE_DATA,
2579                                  cquery->data, dquery->data, NULL,
2580                                  NULL, 0,
2581                                  NULL, NULL);
2582
2583         /* set up tag for comment and/or ACL */
2584         resetPQExpBuffer(cquery);
2585         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2586
2587         /* Dump comment if any */
2588         dumpComment(fout, cquery->data,
2589                                 NULL, binfo->rolname,
2590                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2591
2592         /* Dump security label if any */
2593         dumpSecLabel(fout, cquery->data,
2594                                  NULL, binfo->rolname,
2595                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2596
2597         /* Dump ACL if any */
2598         if (binfo->blobacl)
2599                 dumpACL(fout, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2600                                 binfo->dobj.name, NULL, cquery->data,
2601                                 NULL, binfo->rolname, binfo->blobacl);
2602
2603         destroyPQExpBuffer(cquery);
2604         destroyPQExpBuffer(dquery);
2605 }
2606
2607 /*
2608  * dumpBlobs:
2609  *      dump the data contents of all large objects
2610  */
2611 static int
2612 dumpBlobs(Archive *fout, void *arg)
2613 {
2614         const char *blobQry;
2615         const char *blobFetchQry;
2616         PGconn     *conn = GetConnection(fout);
2617         PGresult   *res;
2618         char            buf[LOBBUFSIZE];
2619         int                     ntups;
2620         int                     i;
2621         int                     cnt;
2622
2623         if (g_verbose)
2624                 write_msg(NULL, "saving large objects\n");
2625
2626         /* Make sure we are in proper schema */
2627         selectSourceSchema(fout, "pg_catalog");
2628
2629         /*
2630          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2631          * the already-in-memory dumpable objects instead...
2632          */
2633         if (fout->remoteVersion >= 90000)
2634                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2635         else if (fout->remoteVersion >= 70100)
2636                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2637         else
2638                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2639
2640         ExecuteSqlStatement(fout, blobQry);
2641
2642         /* Command to fetch from cursor */
2643         blobFetchQry = "FETCH 1000 IN bloboid";
2644
2645         do
2646         {
2647                 /* Do a fetch */
2648                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2649
2650                 /* Process the tuples, if any */
2651                 ntups = PQntuples(res);
2652                 for (i = 0; i < ntups; i++)
2653                 {
2654                         Oid                     blobOid;
2655                         int                     loFd;
2656
2657                         blobOid = atooid(PQgetvalue(res, i, 0));
2658                         /* Open the BLOB */
2659                         loFd = lo_open(conn, blobOid, INV_READ);
2660                         if (loFd == -1)
2661                                 exit_horribly(NULL, "could not open large object %u: %s",
2662                                                           blobOid, PQerrorMessage(conn));
2663
2664                         StartBlob(fout, blobOid);
2665
2666                         /* Now read it in chunks, sending data to archive */
2667                         do
2668                         {
2669                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2670                                 if (cnt < 0)
2671                                         exit_horribly(NULL, "error reading large object %u: %s",
2672                                                                   blobOid, PQerrorMessage(conn));
2673
2674                                 WriteData(fout, buf, cnt);
2675                         } while (cnt > 0);
2676
2677                         lo_close(conn, loFd);
2678
2679                         EndBlob(fout, blobOid);
2680                 }
2681
2682                 PQclear(res);
2683         } while (ntups > 0);
2684
2685         return 1;
2686 }
2687
2688 static void
2689 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
2690                                                                                  PQExpBuffer upgrade_buffer,
2691                                                                                  Oid pg_type_oid)
2692 {
2693         PQExpBuffer upgrade_query = createPQExpBuffer();
2694         PGresult   *upgrade_res;
2695         Oid                     pg_type_array_oid;
2696
2697         appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
2698         appendPQExpBuffer(upgrade_buffer,
2699          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2700                                           pg_type_oid);
2701
2702         /* we only support old >= 8.3 for binary upgrades */
2703         appendPQExpBuffer(upgrade_query,
2704                                           "SELECT typarray "
2705                                           "FROM pg_catalog.pg_type "
2706                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
2707                                           pg_type_oid);
2708
2709         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2710
2711         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
2712
2713         if (OidIsValid(pg_type_array_oid))
2714         {
2715                 appendPQExpBuffer(upgrade_buffer,
2716                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
2717                 appendPQExpBuffer(upgrade_buffer,
2718                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2719                                                   pg_type_array_oid);
2720         }
2721
2722         PQclear(upgrade_res);
2723         destroyPQExpBuffer(upgrade_query);
2724 }
2725
2726 static bool
2727 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
2728                                                                                 PQExpBuffer upgrade_buffer,
2729                                                                                 Oid pg_rel_oid)
2730 {
2731         PQExpBuffer upgrade_query = createPQExpBuffer();
2732         PGresult   *upgrade_res;
2733         Oid                     pg_type_oid;
2734         bool            toast_set = false;
2735
2736         /* we only support old >= 8.3 for binary upgrades */
2737         appendPQExpBuffer(upgrade_query,
2738                                           "SELECT c.reltype AS crel, t.reltype AS trel "
2739                                           "FROM pg_catalog.pg_class c "
2740                                           "LEFT JOIN pg_catalog.pg_class t ON "
2741                                           "  (c.reltoastrelid = t.oid) "
2742                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2743                                           pg_rel_oid);
2744
2745         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2746
2747         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
2748
2749         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
2750                                                                                          pg_type_oid);
2751
2752         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
2753         {
2754                 /* Toast tables do not have pg_type array rows */
2755                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
2756                                                                                         PQfnumber(upgrade_res, "trel")));
2757
2758                 appendPQExpBuffer(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
2759                 appendPQExpBuffer(upgrade_buffer,
2760                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
2761                                                   pg_type_toast_oid);
2762
2763                 toast_set = true;
2764         }
2765
2766         PQclear(upgrade_res);
2767         destroyPQExpBuffer(upgrade_query);
2768
2769         return toast_set;
2770 }
2771
2772 static void
2773 binary_upgrade_set_pg_class_oids(Archive *fout,
2774                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
2775                                                                  bool is_index)
2776 {
2777         PQExpBuffer upgrade_query = createPQExpBuffer();
2778         PGresult   *upgrade_res;
2779         Oid                     pg_class_reltoastrelid;
2780         Oid                     pg_class_reltoastidxid;
2781
2782         appendPQExpBuffer(upgrade_query,
2783                                           "SELECT c.reltoastrelid, t.reltoastidxid "
2784                                           "FROM pg_catalog.pg_class c LEFT JOIN "
2785                                           "pg_catalog.pg_class t ON (c.reltoastrelid = t.oid) "
2786                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
2787                                           pg_class_oid);
2788
2789         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
2790
2791         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
2792         pg_class_reltoastidxid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastidxid")));
2793
2794         appendPQExpBuffer(upgrade_buffer,
2795                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
2796
2797         if (!is_index)
2798         {
2799                 appendPQExpBuffer(upgrade_buffer,
2800                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
2801                                                   pg_class_oid);
2802                 /* only tables have toast tables, not indexes */
2803                 if (OidIsValid(pg_class_reltoastrelid))
2804                 {
2805                         /*
2806                          * One complexity is that the table definition might not require
2807                          * the creation of a TOAST table, and the TOAST table might have
2808                          * been created long after table creation, when the table was
2809                          * loaded with wide data.  By setting the TOAST oid we force
2810                          * creation of the TOAST heap and TOAST index by the backend so we
2811                          * can cleanly copy the files during binary upgrade.
2812                          */
2813
2814                         appendPQExpBuffer(upgrade_buffer,
2815                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
2816                                                           pg_class_reltoastrelid);
2817
2818                         /* every toast table has an index */
2819                         appendPQExpBuffer(upgrade_buffer,
2820                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2821                                                           pg_class_reltoastidxid);
2822                 }
2823         }
2824         else
2825                 appendPQExpBuffer(upgrade_buffer,
2826                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
2827                                                   pg_class_oid);
2828
2829         appendPQExpBuffer(upgrade_buffer, "\n");
2830
2831         PQclear(upgrade_res);
2832         destroyPQExpBuffer(upgrade_query);
2833 }
2834
2835 /*
2836  * If the DumpableObject is a member of an extension, add a suitable
2837  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
2838  */
2839 static void
2840 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
2841                                                                 DumpableObject *dobj,
2842                                                                 const char *objlabel)
2843 {
2844         DumpableObject *extobj = NULL;
2845         int                     i;
2846
2847         if (!dobj->ext_member)
2848                 return;
2849
2850         /*
2851          * Find the parent extension.  We could avoid this search if we wanted to
2852          * add a link field to DumpableObject, but the space costs of that would
2853          * be considerable.  We assume that member objects could only have a
2854          * direct dependency on their own extension, not any others.
2855          */
2856         for (i = 0; i < dobj->nDeps; i++)
2857         {
2858                 extobj = findObjectByDumpId(dobj->dependencies[i]);
2859                 if (extobj && extobj->objType == DO_EXTENSION)
2860                         break;
2861                 extobj = NULL;
2862         }
2863         if (extobj == NULL)
2864                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
2865
2866         appendPQExpBuffer(upgrade_buffer,
2867           "\n-- For binary upgrade, handle extension membership the hard way\n");
2868         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
2869                                           fmtId(extobj->name),
2870                                           objlabel);
2871 }
2872
2873 /*
2874  * getNamespaces:
2875  *        read all namespaces in the system catalogs and return them in the
2876  * NamespaceInfo* structure
2877  *
2878  *      numNamespaces is set to the number of namespaces read in
2879  */
2880 NamespaceInfo *
2881 getNamespaces(Archive *fout, int *numNamespaces)
2882 {
2883         PGresult   *res;
2884         int                     ntups;
2885         int                     i;
2886         PQExpBuffer query;
2887         NamespaceInfo *nsinfo;
2888         int                     i_tableoid;
2889         int                     i_oid;
2890         int                     i_nspname;
2891         int                     i_rolname;
2892         int                     i_nspacl;
2893
2894         /*
2895          * Before 7.3, there are no real namespaces; create two dummy entries, one
2896          * for user stuff and one for system stuff.
2897          */
2898         if (fout->remoteVersion < 70300)
2899         {
2900                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
2901
2902                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2903                 nsinfo[0].dobj.catId.tableoid = 0;
2904                 nsinfo[0].dobj.catId.oid = 0;
2905                 AssignDumpId(&nsinfo[0].dobj);
2906                 nsinfo[0].dobj.name = pg_strdup("public");
2907                 nsinfo[0].rolname = pg_strdup("");
2908                 nsinfo[0].nspacl = pg_strdup("");
2909
2910                 selectDumpableNamespace(&nsinfo[0]);
2911
2912                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2913                 nsinfo[1].dobj.catId.tableoid = 0;
2914                 nsinfo[1].dobj.catId.oid = 1;
2915                 AssignDumpId(&nsinfo[1].dobj);
2916                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
2917                 nsinfo[1].rolname = pg_strdup("");
2918                 nsinfo[1].nspacl = pg_strdup("");
2919
2920                 selectDumpableNamespace(&nsinfo[1]);
2921
2922                 *numNamespaces = 2;
2923
2924                 return nsinfo;
2925         }
2926
2927         query = createPQExpBuffer();
2928
2929         /* Make sure we are in proper schema */
2930         selectSourceSchema(fout, "pg_catalog");
2931
2932         /*
2933          * we fetch all namespaces including system ones, so that every object we
2934          * read in can be linked to a containing namespace.
2935          */
2936         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2937                                           "(%s nspowner) AS rolname, "
2938                                           "nspacl FROM pg_namespace",
2939                                           username_subquery);
2940
2941         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2942
2943         ntups = PQntuples(res);
2944
2945         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
2946
2947         i_tableoid = PQfnumber(res, "tableoid");
2948         i_oid = PQfnumber(res, "oid");
2949         i_nspname = PQfnumber(res, "nspname");
2950         i_rolname = PQfnumber(res, "rolname");
2951         i_nspacl = PQfnumber(res, "nspacl");
2952
2953         for (i = 0; i < ntups; i++)
2954         {
2955                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2956                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2957                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2958                 AssignDumpId(&nsinfo[i].dobj);
2959                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
2960                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
2961                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
2962
2963                 /* Decide whether to dump this namespace */
2964                 selectDumpableNamespace(&nsinfo[i]);
2965
2966                 if (strlen(nsinfo[i].rolname) == 0)
2967                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2968                                           nsinfo[i].dobj.name);
2969         }
2970
2971         PQclear(res);
2972         destroyPQExpBuffer(query);
2973
2974         *numNamespaces = ntups;
2975
2976         return nsinfo;
2977 }
2978
2979 /*
2980  * findNamespace:
2981  *              given a namespace OID and an object OID, look up the info read by
2982  *              getNamespaces
2983  *
2984  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2985  * a system object or not.      In 7.3 and later there is no guessing, and we
2986  * don't use objoid at all.
2987  */
2988 static NamespaceInfo *
2989 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
2990 {
2991         NamespaceInfo *nsinfo;
2992
2993         if (fout->remoteVersion >= 70300)
2994         {
2995                 nsinfo = findNamespaceByOid(nsoid);
2996         }
2997         else
2998         {
2999                 /* This code depends on the dummy objects set up by getNamespaces. */
3000                 Oid                     i;
3001
3002                 if (objoid > g_last_builtin_oid)
3003                         i = 0;                          /* user object */
3004                 else
3005                         i = 1;                          /* system object */
3006                 nsinfo = findNamespaceByOid(i);
3007         }
3008
3009         if (nsinfo == NULL)
3010                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3011
3012         return nsinfo;
3013 }
3014
3015 /*
3016  * getExtensions:
3017  *        read all extensions in the system catalogs and return them in the
3018  * ExtensionInfo* structure
3019  *
3020  *      numExtensions is set to the number of extensions read in
3021  */
3022 ExtensionInfo *
3023 getExtensions(Archive *fout, int *numExtensions)
3024 {
3025         PGresult   *res;
3026         int                     ntups;
3027         int                     i;
3028         PQExpBuffer query;
3029         ExtensionInfo *extinfo;
3030         int                     i_tableoid;
3031         int                     i_oid;
3032         int                     i_extname;
3033         int                     i_nspname;
3034         int                     i_extrelocatable;
3035         int                     i_extversion;
3036         int                     i_extconfig;
3037         int                     i_extcondition;
3038
3039         /*
3040          * Before 9.1, there are no extensions.
3041          */
3042         if (fout->remoteVersion < 90100)
3043         {
3044                 *numExtensions = 0;
3045                 return NULL;
3046         }
3047
3048         query = createPQExpBuffer();
3049
3050         /* Make sure we are in proper schema */
3051         selectSourceSchema(fout, "pg_catalog");
3052
3053         appendPQExpBuffer(query, "SELECT x.tableoid, x.oid, "
3054                                           "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3055                                           "FROM pg_extension x "
3056                                           "JOIN pg_namespace n ON n.oid = x.extnamespace");
3057
3058         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3059
3060         ntups = PQntuples(res);
3061
3062         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3063
3064         i_tableoid = PQfnumber(res, "tableoid");
3065         i_oid = PQfnumber(res, "oid");
3066         i_extname = PQfnumber(res, "extname");
3067         i_nspname = PQfnumber(res, "nspname");
3068         i_extrelocatable = PQfnumber(res, "extrelocatable");
3069         i_extversion = PQfnumber(res, "extversion");
3070         i_extconfig = PQfnumber(res, "extconfig");
3071         i_extcondition = PQfnumber(res, "extcondition");
3072
3073         for (i = 0; i < ntups; i++)
3074         {
3075                 extinfo[i].dobj.objType = DO_EXTENSION;
3076                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3077                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3078                 AssignDumpId(&extinfo[i].dobj);
3079                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3080                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3081                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3082                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3083                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3084                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3085
3086                 /* Decide whether we want to dump it */
3087                 selectDumpableExtension(&(extinfo[i]));
3088         }
3089
3090         PQclear(res);
3091         destroyPQExpBuffer(query);
3092
3093         *numExtensions = ntups;
3094
3095         return extinfo;
3096 }
3097
3098 /*
3099  * getTypes:
3100  *        read all types in the system catalogs and return them in the
3101  * TypeInfo* structure
3102  *
3103  *      numTypes is set to the number of types read in
3104  *
3105  * NB: this must run after getFuncs() because we assume we can do
3106  * findFuncByOid().
3107  */
3108 TypeInfo *
3109 getTypes(Archive *fout, int *numTypes)
3110 {
3111         PGresult   *res;
3112         int                     ntups;
3113         int                     i;
3114         PQExpBuffer query = createPQExpBuffer();
3115         TypeInfo   *tyinfo;
3116         ShellTypeInfo *stinfo;
3117         int                     i_tableoid;
3118         int                     i_oid;
3119         int                     i_typname;
3120         int                     i_typnamespace;
3121         int                     i_typacl;
3122         int                     i_rolname;
3123         int                     i_typinput;
3124         int                     i_typoutput;
3125         int                     i_typelem;
3126         int                     i_typrelid;
3127         int                     i_typrelkind;
3128         int                     i_typtype;
3129         int                     i_typisdefined;
3130         int                     i_isarray;
3131
3132         /*
3133          * we include even the built-in types because those may be used as array
3134          * elements by user-defined types
3135          *
3136          * we filter out the built-in types when we dump out the types
3137          *
3138          * same approach for undefined (shell) types and array types
3139          *
3140          * Note: as of 8.3 we can reliably detect whether a type is an
3141          * auto-generated array type by checking the element type's typarray.
3142          * (Before that the test is capable of generating false positives.) We
3143          * still check for name beginning with '_', though, so as to avoid the
3144          * cost of the subselect probe for all standard types.  This would have to
3145          * be revisited if the backend ever allows renaming of array types.
3146          */
3147
3148         /* Make sure we are in proper schema */
3149         selectSourceSchema(fout, "pg_catalog");
3150
3151         if (fout->remoteVersion >= 90200)
3152         {
3153                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3154                                                   "typnamespace, typacl, "
3155                                                   "(%s typowner) AS rolname, "
3156                                                   "typinput::oid AS typinput, "
3157                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3158                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3159                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3160                                                   "typtype, typisdefined, "
3161                                                   "typname[0] = '_' AND typelem != 0 AND "
3162                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3163                                                   "FROM pg_type",
3164                                                   username_subquery);
3165         }
3166         else if (fout->remoteVersion >= 80300)
3167         {
3168                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3169                                                   "typnamespace, '{=U}' AS typacl, "
3170                                                   "(%s typowner) AS rolname, "
3171                                                   "typinput::oid AS typinput, "
3172                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3173                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3174                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3175                                                   "typtype, typisdefined, "
3176                                                   "typname[0] = '_' AND typelem != 0 AND "
3177                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3178                                                   "FROM pg_type",
3179                                                   username_subquery);
3180         }
3181         else if (fout->remoteVersion >= 70300)
3182         {
3183                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3184                                                   "typnamespace, '{=U}' AS typacl, "
3185                                                   "(%s typowner) AS rolname, "
3186                                                   "typinput::oid AS typinput, "
3187                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3188                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3189                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3190                                                   "typtype, typisdefined, "
3191                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3192                                                   "FROM pg_type",
3193                                                   username_subquery);
3194         }
3195         else if (fout->remoteVersion >= 70100)
3196         {
3197                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3198                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3199                                                   "(%s typowner) AS rolname, "
3200                                                   "typinput::oid AS typinput, "
3201                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3202                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3203                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3204                                                   "typtype, typisdefined, "
3205                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3206                                                   "FROM pg_type",
3207                                                   username_subquery);
3208         }
3209         else
3210         {
3211                 appendPQExpBuffer(query, "SELECT "
3212                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3213                                                   "oid, typname, "
3214                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3215                                                   "(%s typowner) AS rolname, "
3216                                                   "typinput::oid AS typinput, "
3217                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3218                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3219                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3220                                                   "typtype, typisdefined, "
3221                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3222                                                   "FROM pg_type",
3223                                                   username_subquery);
3224         }
3225
3226         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3227
3228         ntups = PQntuples(res);
3229
3230         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3231
3232         i_tableoid = PQfnumber(res, "tableoid");
3233         i_oid = PQfnumber(res, "oid");
3234         i_typname = PQfnumber(res, "typname");
3235         i_typnamespace = PQfnumber(res, "typnamespace");
3236         i_typacl = PQfnumber(res, "typacl");
3237         i_rolname = PQfnumber(res, "rolname");
3238         i_typinput = PQfnumber(res, "typinput");
3239         i_typoutput = PQfnumber(res, "typoutput");
3240         i_typelem = PQfnumber(res, "typelem");
3241         i_typrelid = PQfnumber(res, "typrelid");
3242         i_typrelkind = PQfnumber(res, "typrelkind");
3243         i_typtype = PQfnumber(res, "typtype");
3244         i_typisdefined = PQfnumber(res, "typisdefined");
3245         i_isarray = PQfnumber(res, "isarray");
3246
3247         for (i = 0; i < ntups; i++)
3248         {
3249                 tyinfo[i].dobj.objType = DO_TYPE;
3250                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3251                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3252                 AssignDumpId(&tyinfo[i].dobj);
3253                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3254                 tyinfo[i].dobj.namespace =
3255                         findNamespace(fout,
3256                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3257                                                   tyinfo[i].dobj.catId.oid);
3258                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3259                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3260                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3261                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3262                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3263                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3264                 tyinfo[i].shellType = NULL;
3265
3266                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3267                         tyinfo[i].isDefined = true;
3268                 else
3269                         tyinfo[i].isDefined = false;
3270
3271                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3272                         tyinfo[i].isArray = true;
3273                 else
3274                         tyinfo[i].isArray = false;
3275
3276                 /* Decide whether we want to dump it */
3277                 selectDumpableType(&tyinfo[i]);
3278
3279                 /*
3280                  * If it's a domain, fetch info about its constraints, if any
3281                  */
3282                 tyinfo[i].nDomChecks = 0;
3283                 tyinfo[i].domChecks = NULL;
3284                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3285                         getDomainConstraints(fout, &(tyinfo[i]));
3286
3287                 /*
3288                  * If it's a base type, make a DumpableObject representing a shell
3289                  * definition of the type.      We will need to dump that ahead of the I/O
3290                  * functions for the type.      Similarly, range types need a shell
3291                  * definition in case they have a canonicalize function.
3292                  *
3293                  * Note: the shell type doesn't have a catId.  You might think it
3294                  * should copy the base type's catId, but then it might capture the
3295                  * pg_depend entries for the type, which we don't want.
3296                  */
3297                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3298                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3299                 {
3300                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3301                         stinfo->dobj.objType = DO_SHELL_TYPE;
3302                         stinfo->dobj.catId = nilCatalogId;
3303                         AssignDumpId(&stinfo->dobj);
3304                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3305                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3306                         stinfo->baseType = &(tyinfo[i]);
3307                         tyinfo[i].shellType = stinfo;
3308
3309                         /*
3310                          * Initially mark the shell type as not to be dumped.  We'll only
3311                          * dump it if the I/O or canonicalize functions need to be dumped;
3312                          * this is taken care of while sorting dependencies.
3313                          */
3314                         stinfo->dobj.dump = false;
3315
3316                         /*
3317                          * However, if dumping from pre-7.3, there will be no dependency
3318                          * info so we have to fake it here.  We only need to worry about
3319                          * typinput and typoutput since the other functions only exist
3320                          * post-7.3.
3321                          */
3322                         if (fout->remoteVersion < 70300)
3323                         {
3324                                 Oid                     typinput;
3325                                 Oid                     typoutput;
3326                                 FuncInfo   *funcInfo;
3327
3328                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3329                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3330
3331                                 funcInfo = findFuncByOid(typinput);
3332                                 if (funcInfo && funcInfo->dobj.dump)
3333                                 {
3334                                         /* base type depends on function */
3335                                         addObjectDependency(&tyinfo[i].dobj,
3336                                                                                 funcInfo->dobj.dumpId);
3337                                         /* function depends on shell type */
3338                                         addObjectDependency(&funcInfo->dobj,
3339                                                                                 stinfo->dobj.dumpId);
3340                                         /* mark shell type as to be dumped */
3341                                         stinfo->dobj.dump = true;
3342                                 }
3343
3344                                 funcInfo = findFuncByOid(typoutput);
3345                                 if (funcInfo && funcInfo->dobj.dump)
3346                                 {
3347                                         /* base type depends on function */
3348                                         addObjectDependency(&tyinfo[i].dobj,
3349                                                                                 funcInfo->dobj.dumpId);
3350                                         /* function depends on shell type */
3351                                         addObjectDependency(&funcInfo->dobj,
3352                                                                                 stinfo->dobj.dumpId);
3353                                         /* mark shell type as to be dumped */
3354                                         stinfo->dobj.dump = true;
3355                                 }
3356                         }
3357                 }
3358
3359                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3360                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3361                                           tyinfo[i].dobj.name);
3362         }
3363
3364         *numTypes = ntups;
3365
3366         PQclear(res);
3367
3368         destroyPQExpBuffer(query);
3369
3370         return tyinfo;
3371 }
3372
3373 /*
3374  * getOperators:
3375  *        read all operators in the system catalogs and return them in the
3376  * OprInfo* structure
3377  *
3378  *      numOprs is set to the number of operators read in
3379  */
3380 OprInfo *
3381 getOperators(Archive *fout, int *numOprs)
3382 {
3383         PGresult   *res;
3384         int                     ntups;
3385         int                     i;
3386         PQExpBuffer query = createPQExpBuffer();
3387         OprInfo    *oprinfo;
3388         int                     i_tableoid;
3389         int                     i_oid;
3390         int                     i_oprname;
3391         int                     i_oprnamespace;
3392         int                     i_rolname;
3393         int                     i_oprkind;
3394         int                     i_oprcode;
3395
3396         /*
3397          * find all operators, including builtin operators; we filter out
3398          * system-defined operators at dump-out time.
3399          */
3400
3401         /* Make sure we are in proper schema */
3402         selectSourceSchema(fout, "pg_catalog");
3403
3404         if (fout->remoteVersion >= 70300)
3405         {
3406                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3407                                                   "oprnamespace, "
3408                                                   "(%s oprowner) AS rolname, "
3409                                                   "oprkind, "
3410                                                   "oprcode::oid AS oprcode "
3411                                                   "FROM pg_operator",
3412                                                   username_subquery);
3413         }
3414         else if (fout->remoteVersion >= 70100)
3415         {
3416                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3417                                                   "0::oid AS oprnamespace, "
3418                                                   "(%s oprowner) AS rolname, "
3419                                                   "oprkind, "
3420                                                   "oprcode::oid AS oprcode "
3421                                                   "FROM pg_operator",
3422                                                   username_subquery);
3423         }
3424         else
3425         {
3426                 appendPQExpBuffer(query, "SELECT "
3427                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3428                                                   "oid, oprname, "
3429                                                   "0::oid AS oprnamespace, "
3430                                                   "(%s oprowner) AS rolname, "
3431                                                   "oprkind, "
3432                                                   "oprcode::oid AS oprcode "
3433                                                   "FROM pg_operator",
3434                                                   username_subquery);
3435         }
3436
3437         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3438
3439         ntups = PQntuples(res);
3440         *numOprs = ntups;
3441
3442         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3443
3444         i_tableoid = PQfnumber(res, "tableoid");
3445         i_oid = PQfnumber(res, "oid");
3446         i_oprname = PQfnumber(res, "oprname");
3447         i_oprnamespace = PQfnumber(res, "oprnamespace");
3448         i_rolname = PQfnumber(res, "rolname");
3449         i_oprkind = PQfnumber(res, "oprkind");
3450         i_oprcode = PQfnumber(res, "oprcode");
3451
3452         for (i = 0; i < ntups; i++)
3453         {
3454                 oprinfo[i].dobj.objType = DO_OPERATOR;
3455                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3456                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3457                 AssignDumpId(&oprinfo[i].dobj);
3458                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3459                 oprinfo[i].dobj.namespace =
3460                         findNamespace(fout,
3461                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3462                                                   oprinfo[i].dobj.catId.oid);
3463                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3464                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3465                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3466
3467                 /* Decide whether we want to dump it */
3468                 selectDumpableObject(&(oprinfo[i].dobj));
3469
3470                 if (strlen(oprinfo[i].rolname) == 0)
3471                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3472                                           oprinfo[i].dobj.name);
3473         }
3474
3475         PQclear(res);
3476
3477         destroyPQExpBuffer(query);
3478
3479         return oprinfo;
3480 }
3481
3482 /*
3483  * getCollations:
3484  *        read all collations in the system catalogs and return them in the
3485  * CollInfo* structure
3486  *
3487  *      numCollations is set to the number of collations read in
3488  */
3489 CollInfo *
3490 getCollations(Archive *fout, int *numCollations)
3491 {
3492         PGresult   *res;
3493         int                     ntups;
3494         int                     i;
3495         PQExpBuffer query;
3496         CollInfo   *collinfo;
3497         int                     i_tableoid;
3498         int                     i_oid;
3499         int                     i_collname;
3500         int                     i_collnamespace;
3501         int                     i_rolname;
3502
3503         /* Collations didn't exist pre-9.1 */
3504         if (fout->remoteVersion < 90100)
3505         {
3506                 *numCollations = 0;
3507                 return NULL;
3508         }
3509
3510         query = createPQExpBuffer();
3511
3512         /*
3513          * find all collations, including builtin collations; we filter out
3514          * system-defined collations at dump-out time.
3515          */
3516
3517         /* Make sure we are in proper schema */
3518         selectSourceSchema(fout, "pg_catalog");
3519
3520         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3521                                           "collnamespace, "
3522                                           "(%s collowner) AS rolname "
3523                                           "FROM pg_collation",
3524                                           username_subquery);
3525
3526         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3527
3528         ntups = PQntuples(res);
3529         *numCollations = ntups;
3530
3531         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3532
3533         i_tableoid = PQfnumber(res, "tableoid");
3534         i_oid = PQfnumber(res, "oid");
3535         i_collname = PQfnumber(res, "collname");
3536         i_collnamespace = PQfnumber(res, "collnamespace");
3537         i_rolname = PQfnumber(res, "rolname");
3538
3539         for (i = 0; i < ntups; i++)
3540         {
3541                 collinfo[i].dobj.objType = DO_COLLATION;
3542                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3543                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3544                 AssignDumpId(&collinfo[i].dobj);
3545                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3546                 collinfo[i].dobj.namespace =
3547                         findNamespace(fout,
3548                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3549                                                   collinfo[i].dobj.catId.oid);
3550                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3551
3552                 /* Decide whether we want to dump it */
3553                 selectDumpableObject(&(collinfo[i].dobj));
3554         }
3555
3556         PQclear(res);
3557
3558         destroyPQExpBuffer(query);
3559
3560         return collinfo;
3561 }
3562
3563 /*
3564  * getConversions:
3565  *        read all conversions in the system catalogs and return them in the
3566  * ConvInfo* structure
3567  *
3568  *      numConversions is set to the number of conversions read in
3569  */
3570 ConvInfo *
3571 getConversions(Archive *fout, int *numConversions)
3572 {
3573         PGresult   *res;
3574         int                     ntups;
3575         int                     i;
3576         PQExpBuffer query = createPQExpBuffer();
3577         ConvInfo   *convinfo;
3578         int                     i_tableoid;
3579         int                     i_oid;
3580         int                     i_conname;
3581         int                     i_connamespace;
3582         int                     i_rolname;
3583
3584         /* Conversions didn't exist pre-7.3 */
3585         if (fout->remoteVersion < 70300)
3586         {
3587                 *numConversions = 0;
3588                 return NULL;
3589         }
3590
3591         /*
3592          * find all conversions, including builtin conversions; we filter out
3593          * system-defined conversions at dump-out time.
3594          */
3595
3596         /* Make sure we are in proper schema */
3597         selectSourceSchema(fout, "pg_catalog");
3598
3599         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3600                                           "connamespace, "
3601                                           "(%s conowner) AS rolname "
3602                                           "FROM pg_conversion",
3603                                           username_subquery);
3604
3605         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3606
3607         ntups = PQntuples(res);
3608         *numConversions = ntups;
3609
3610         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3611
3612         i_tableoid = PQfnumber(res, "tableoid");
3613         i_oid = PQfnumber(res, "oid");
3614         i_conname = PQfnumber(res, "conname");
3615         i_connamespace = PQfnumber(res, "connamespace");
3616         i_rolname = PQfnumber(res, "rolname");
3617
3618         for (i = 0; i < ntups; i++)
3619         {
3620                 convinfo[i].dobj.objType = DO_CONVERSION;
3621                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3622                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3623                 AssignDumpId(&convinfo[i].dobj);
3624                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3625                 convinfo[i].dobj.namespace =
3626                         findNamespace(fout,
3627                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3628                                                   convinfo[i].dobj.catId.oid);
3629                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3630
3631                 /* Decide whether we want to dump it */
3632                 selectDumpableObject(&(convinfo[i].dobj));
3633         }
3634
3635         PQclear(res);
3636
3637         destroyPQExpBuffer(query);
3638
3639         return convinfo;
3640 }
3641
3642 /*
3643  * getOpclasses:
3644  *        read all opclasses in the system catalogs and return them in the
3645  * OpclassInfo* structure
3646  *
3647  *      numOpclasses is set to the number of opclasses read in
3648  */
3649 OpclassInfo *
3650 getOpclasses(Archive *fout, int *numOpclasses)
3651 {
3652         PGresult   *res;
3653         int                     ntups;
3654         int                     i;
3655         PQExpBuffer query = createPQExpBuffer();
3656         OpclassInfo *opcinfo;
3657         int                     i_tableoid;
3658         int                     i_oid;
3659         int                     i_opcname;
3660         int                     i_opcnamespace;
3661         int                     i_rolname;
3662
3663         /*
3664          * find all opclasses, including builtin opclasses; we filter out
3665          * system-defined opclasses at dump-out time.
3666          */
3667
3668         /* Make sure we are in proper schema */
3669         selectSourceSchema(fout, "pg_catalog");
3670
3671         if (fout->remoteVersion >= 70300)
3672         {
3673                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3674                                                   "opcnamespace, "
3675                                                   "(%s opcowner) AS rolname "
3676                                                   "FROM pg_opclass",
3677                                                   username_subquery);
3678         }
3679         else if (fout->remoteVersion >= 70100)
3680         {
3681                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
3682                                                   "0::oid AS opcnamespace, "
3683                                                   "''::name AS rolname "
3684                                                   "FROM pg_opclass");
3685         }
3686         else
3687         {
3688                 appendPQExpBuffer(query, "SELECT "
3689                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
3690                                                   "oid, opcname, "
3691                                                   "0::oid AS opcnamespace, "
3692                                                   "''::name AS rolname "
3693                                                   "FROM pg_opclass");
3694         }
3695
3696         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3697
3698         ntups = PQntuples(res);
3699         *numOpclasses = ntups;
3700
3701         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
3702
3703         i_tableoid = PQfnumber(res, "tableoid");
3704         i_oid = PQfnumber(res, "oid");
3705         i_opcname = PQfnumber(res, "opcname");
3706         i_opcnamespace = PQfnumber(res, "opcnamespace");
3707         i_rolname = PQfnumber(res, "rolname");
3708
3709         for (i = 0; i < ntups; i++)
3710         {
3711                 opcinfo[i].dobj.objType = DO_OPCLASS;
3712                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3713                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3714                 AssignDumpId(&opcinfo[i].dobj);
3715                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
3716                 opcinfo[i].dobj.namespace =
3717                         findNamespace(fout,
3718                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
3719                                                   opcinfo[i].dobj.catId.oid);
3720                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3721
3722                 /* Decide whether we want to dump it */
3723                 selectDumpableObject(&(opcinfo[i].dobj));
3724
3725                 if (fout->remoteVersion >= 70300)
3726                 {
3727                         if (strlen(opcinfo[i].rolname) == 0)
3728                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
3729                                                   opcinfo[i].dobj.name);
3730                 }
3731         }
3732
3733         PQclear(res);
3734
3735         destroyPQExpBuffer(query);
3736
3737         return opcinfo;
3738 }
3739
3740 /*
3741  * getOpfamilies:
3742  *        read all opfamilies in the system catalogs and return them in the
3743  * OpfamilyInfo* structure
3744  *
3745  *      numOpfamilies is set to the number of opfamilies read in
3746  */
3747 OpfamilyInfo *
3748 getOpfamilies(Archive *fout, int *numOpfamilies)
3749 {
3750         PGresult   *res;
3751         int                     ntups;
3752         int                     i;
3753         PQExpBuffer query;
3754         OpfamilyInfo *opfinfo;
3755         int                     i_tableoid;
3756         int                     i_oid;
3757         int                     i_opfname;
3758         int                     i_opfnamespace;
3759         int                     i_rolname;
3760
3761         /* Before 8.3, there is no separate concept of opfamilies */
3762         if (fout->remoteVersion < 80300)
3763         {
3764                 *numOpfamilies = 0;
3765                 return NULL;
3766         }
3767
3768         query = createPQExpBuffer();
3769
3770         /*
3771          * find all opfamilies, including builtin opfamilies; we filter out
3772          * system-defined opfamilies at dump-out time.
3773          */
3774
3775         /* Make sure we are in proper schema */
3776         selectSourceSchema(fout, "pg_catalog");
3777
3778         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
3779                                           "opfnamespace, "
3780                                           "(%s opfowner) AS rolname "
3781                                           "FROM pg_opfamily",
3782                                           username_subquery);
3783
3784         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3785
3786         ntups = PQntuples(res);
3787         *numOpfamilies = ntups;
3788
3789         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
3790
3791         i_tableoid = PQfnumber(res, "tableoid");
3792         i_oid = PQfnumber(res, "oid");
3793         i_opfname = PQfnumber(res, "opfname");
3794         i_opfnamespace = PQfnumber(res, "opfnamespace");
3795         i_rolname = PQfnumber(res, "rolname");
3796
3797         for (i = 0; i < ntups; i++)
3798         {
3799                 opfinfo[i].dobj.objType = DO_OPFAMILY;
3800                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3801                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3802                 AssignDumpId(&opfinfo[i].dobj);
3803                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
3804                 opfinfo[i].dobj.namespace =
3805                         findNamespace(fout,
3806                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
3807                                                   opfinfo[i].dobj.catId.oid);
3808                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3809
3810                 /* Decide whether we want to dump it */
3811                 selectDumpableObject(&(opfinfo[i].dobj));
3812
3813                 if (fout->remoteVersion >= 70300)
3814                 {
3815                         if (strlen(opfinfo[i].rolname) == 0)
3816                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
3817                                                   opfinfo[i].dobj.name);
3818                 }
3819         }
3820
3821         PQclear(res);
3822
3823         destroyPQExpBuffer(query);
3824
3825         return opfinfo;
3826 }
3827
3828 /*
3829  * getAggregates:
3830  *        read all the user-defined aggregates in the system catalogs and
3831  * return them in the AggInfo* structure
3832  *
3833  * numAggs is set to the number of aggregates read in
3834  */
3835 AggInfo *
3836 getAggregates(Archive *fout, int *numAggs)
3837 {
3838         PGresult   *res;
3839         int                     ntups;
3840         int                     i;
3841         PQExpBuffer query = createPQExpBuffer();
3842         AggInfo    *agginfo;
3843         int                     i_tableoid;
3844         int                     i_oid;
3845         int                     i_aggname;
3846         int                     i_aggnamespace;
3847         int                     i_pronargs;
3848         int                     i_proargtypes;
3849         int                     i_rolname;
3850         int                     i_aggacl;
3851         int                     i_proiargs;
3852
3853         /* Make sure we are in proper schema */
3854         selectSourceSchema(fout, "pg_catalog");
3855
3856         /*
3857          * Find all user-defined aggregates.  See comment in getFuncs() for the
3858          * rationale behind the filtering logic.
3859          */
3860
3861         if (fout->remoteVersion >= 80400)
3862         {
3863                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3864                                                   "pronamespace AS aggnamespace, "
3865                                                   "pronargs, proargtypes, "
3866                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
3867                                                   "(%s proowner) AS rolname, "
3868                                                   "proacl AS aggacl "
3869                                                   "FROM pg_proc p "
3870                                                   "WHERE proisagg AND ("
3871                                                   "pronamespace != "
3872                                                   "(SELECT oid FROM pg_namespace "
3873                                                   "WHERE nspname = 'pg_catalog')",
3874                                                   username_subquery);
3875                 if (binary_upgrade && fout->remoteVersion >= 90100)
3876                         appendPQExpBuffer(query,
3877                                                           " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
3878                                                           "classid = 'pg_proc'::regclass AND "
3879                                                           "objid = p.oid AND "
3880                                                           "refclassid = 'pg_extension'::regclass AND "
3881                                                           "deptype = 'e')");
3882                 appendPQExpBuffer(query, ")");
3883         }
3884         else if (fout->remoteVersion >= 80200)
3885         {
3886                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3887                                                   "pronamespace AS aggnamespace, "
3888                                                   "pronargs, proargtypes, "
3889                                                   "NULL::text AS proiargs,"
3890                                                   "(%s proowner) AS rolname, "
3891                                                   "proacl AS aggacl "
3892                                                   "FROM pg_proc p "
3893                                                   "WHERE proisagg AND ("
3894                                                   "pronamespace != "
3895                                                   "(SELECT oid FROM pg_namespace "
3896                                                   "WHERE nspname = 'pg_catalog'))",
3897                                                   username_subquery);
3898         }
3899         else if (fout->remoteVersion >= 70300)
3900         {
3901                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
3902                                                   "pronamespace AS aggnamespace, "
3903                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
3904                                                   "proargtypes, "
3905                                                   "NULL::text AS proiargs, "
3906                                                   "(%s proowner) AS rolname, "
3907                                                   "proacl AS aggacl "
3908                                                   "FROM pg_proc "
3909                                                   "WHERE proisagg "
3910                                                   "AND pronamespace != "
3911                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
3912                                                   username_subquery);
3913         }
3914         else if (fout->remoteVersion >= 70100)
3915         {
3916                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3917                                                   "0::oid AS aggnamespace, "
3918                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3919                                                   "aggbasetype AS proargtypes, "
3920                                                   "NULL::text AS proiargs, "
3921                                                   "(%s aggowner) AS rolname, "
3922                                                   "'{=X}' AS aggacl "
3923                                                   "FROM pg_aggregate "
3924                                                   "where oid > '%u'::oid",
3925                                                   username_subquery,
3926                                                   g_last_builtin_oid);
3927         }
3928         else
3929         {
3930                 appendPQExpBuffer(query, "SELECT "
3931                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3932                                                   "oid, aggname, "
3933                                                   "0::oid AS aggnamespace, "
3934                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3935                                                   "aggbasetype AS proargtypes, "
3936                                                   "NULL::text AS proiargs, "
3937                                                   "(%s aggowner) AS rolname, "
3938                                                   "'{=X}' AS aggacl "
3939                                                   "FROM pg_aggregate "
3940                                                   "where oid > '%u'::oid",
3941                                                   username_subquery,
3942                                                   g_last_builtin_oid);
3943         }
3944
3945         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3946
3947         ntups = PQntuples(res);
3948         *numAggs = ntups;
3949
3950         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
3951
3952         i_tableoid = PQfnumber(res, "tableoid");
3953         i_oid = PQfnumber(res, "oid");
3954         i_aggname = PQfnumber(res, "aggname");
3955         i_aggnamespace = PQfnumber(res, "aggnamespace");
3956         i_pronargs = PQfnumber(res, "pronargs");
3957         i_proargtypes = PQfnumber(res, "proargtypes");
3958         i_rolname = PQfnumber(res, "rolname");
3959         i_aggacl = PQfnumber(res, "aggacl");
3960         i_proiargs = PQfnumber(res, "proiargs");
3961
3962         for (i = 0; i < ntups; i++)
3963         {
3964                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3965                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3966                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3967                 AssignDumpId(&agginfo[i].aggfn.dobj);
3968                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
3969                 agginfo[i].aggfn.dobj.namespace =
3970                         findNamespace(fout,
3971                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
3972                                                   agginfo[i].aggfn.dobj.catId.oid);
3973                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3974                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3975                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3976                                           agginfo[i].aggfn.dobj.name);
3977                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3978                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3979                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
3980                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
3981                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3982                 if (agginfo[i].aggfn.nargs == 0)
3983                         agginfo[i].aggfn.argtypes = NULL;
3984                 else
3985                 {
3986                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3987                         if (fout->remoteVersion >= 70300)
3988                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3989                                                           agginfo[i].aggfn.argtypes,
3990                                                           agginfo[i].aggfn.nargs);
3991                         else
3992                                 /* it's just aggbasetype */
3993                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3994                 }
3995
3996                 /* Decide whether we want to dump it */
3997                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3998         }
3999
4000         PQclear(res);
4001
4002         destroyPQExpBuffer(query);
4003
4004         return agginfo;
4005 }
4006
4007 /*
4008  * getFuncs:
4009  *        read all the user-defined functions in the system catalogs and
4010  * return them in the FuncInfo* structure
4011  *
4012  * numFuncs is set to the number of functions read in
4013  */
4014 FuncInfo *
4015 getFuncs(Archive *fout, int *numFuncs)
4016 {
4017         PGresult   *res;
4018         int                     ntups;
4019         int                     i;
4020         PQExpBuffer query = createPQExpBuffer();
4021         FuncInfo   *finfo;
4022         int                     i_tableoid;
4023         int                     i_oid;
4024         int                     i_proname;
4025         int                     i_pronamespace;
4026         int                     i_rolname;
4027         int                     i_prolang;
4028         int                     i_pronargs;
4029         int                     i_proargtypes;
4030         int                     i_prorettype;
4031         int                     i_proacl;
4032         int                     i_proiargs;
4033
4034         /* Make sure we are in proper schema */
4035         selectSourceSchema(fout, "pg_catalog");
4036
4037         /*
4038          * Find all user-defined functions.  Normally we can exclude functions in
4039          * pg_catalog, which is worth doing since there are several thousand of
4040          * 'em.  However, there are some extensions that create functions in
4041          * pg_catalog.  In normal dumps we can still ignore those --- but in
4042          * binary-upgrade mode, we must dump the member objects of the extension,
4043          * so be sure to fetch any such functions.
4044          *
4045          * Also, in 9.2 and up, exclude functions that are internally dependent on
4046          * something else, since presumably those will be created as a result of
4047          * creating the something else.  This currently only acts to suppress
4048          * constructor functions for range types.  Note that this is OK only
4049          * because the constructors don't have any dependencies the range type
4050          * doesn't have; otherwise we might not get creation ordering correct.
4051          */
4052
4053         if (fout->remoteVersion >= 80400)
4054         {
4055                 appendPQExpBuffer(query,
4056                                                   "SELECT tableoid, oid, proname, prolang, "
4057                                                   "pronargs, proargtypes, prorettype, proacl, "
4058                                                   "pronamespace, "
4059                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4060                                                   "(%s proowner) AS rolname "
4061                                                   "FROM pg_proc p "
4062                                                   "WHERE NOT proisagg AND ("
4063                                                   "pronamespace != "
4064                                                   "(SELECT oid FROM pg_namespace "
4065                                                   "WHERE nspname = 'pg_catalog')",
4066                                                   username_subquery);
4067                 if (fout->remoteVersion >= 90200)
4068                         appendPQExpBuffer(query,
4069                                                           "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4070                                                           "WHERE classid = 'pg_proc'::regclass AND "
4071                                                           "objid = p.oid AND deptype = 'i')");
4072                 if (binary_upgrade && fout->remoteVersion >= 90100)
4073                         appendPQExpBuffer(query,
4074                                                           "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4075                                                           "classid = 'pg_proc'::regclass AND "
4076                                                           "objid = p.oid AND "
4077                                                           "refclassid = 'pg_extension'::regclass AND "
4078                                                           "deptype = 'e')");
4079                 appendPQExpBuffer(query, ")");
4080         }
4081         else if (fout->remoteVersion >= 70300)
4082         {
4083                 appendPQExpBuffer(query,
4084                                                   "SELECT tableoid, oid, proname, prolang, "
4085                                                   "pronargs, proargtypes, prorettype, proacl, "
4086                                                   "pronamespace, "
4087                                                   "NULL::text AS proiargs,"
4088                                                   "(%s proowner) AS rolname "
4089                                                   "FROM pg_proc p "
4090                                                   "WHERE NOT proisagg AND ("
4091                                                   "pronamespace != "
4092                                                   "(SELECT oid FROM pg_namespace "
4093                                                   "WHERE nspname = 'pg_catalog'))",
4094                                                   username_subquery);
4095         }
4096         else if (fout->remoteVersion >= 70100)
4097         {
4098                 appendPQExpBuffer(query,
4099                                                   "SELECT tableoid, oid, proname, prolang, "
4100                                                   "pronargs, proargtypes, prorettype, "
4101                                                   "'{=X}' AS proacl, "
4102                                                   "0::oid AS pronamespace, "
4103                                                   "NULL::text AS proiargs,"
4104                                                   "(%s proowner) AS rolname "
4105                                                   "FROM pg_proc "
4106                                                   "WHERE pg_proc.oid > '%u'::oid",
4107                                                   username_subquery,
4108                                                   g_last_builtin_oid);
4109         }
4110         else
4111         {
4112                 appendPQExpBuffer(query,
4113                                                   "SELECT "
4114                                                   "(SELECT oid FROM pg_class "
4115                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4116                                                   "oid, proname, prolang, "
4117                                                   "pronargs, proargtypes, prorettype, "
4118                                                   "'{=X}' AS proacl, "
4119                                                   "0::oid AS pronamespace, "
4120                                                   "NULL::text AS proiargs,"
4121                                                   "(%s proowner) AS rolname "
4122                                                   "FROM pg_proc "
4123                                                   "where pg_proc.oid > '%u'::oid",
4124                                                   username_subquery,
4125                                                   g_last_builtin_oid);
4126         }
4127
4128         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4129
4130         ntups = PQntuples(res);
4131
4132         *numFuncs = ntups;
4133
4134         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4135
4136         i_tableoid = PQfnumber(res, "tableoid");
4137         i_oid = PQfnumber(res, "oid");
4138         i_proname = PQfnumber(res, "proname");
4139         i_pronamespace = PQfnumber(res, "pronamespace");
4140         i_rolname = PQfnumber(res, "rolname");
4141         i_prolang = PQfnumber(res, "prolang");
4142         i_pronargs = PQfnumber(res, "pronargs");
4143         i_proargtypes = PQfnumber(res, "proargtypes");
4144         i_prorettype = PQfnumber(res, "prorettype");
4145         i_proacl = PQfnumber(res, "proacl");
4146         i_proiargs = PQfnumber(res, "proiargs");
4147
4148         for (i = 0; i < ntups; i++)
4149         {
4150                 finfo[i].dobj.objType = DO_FUNC;
4151                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4152                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4153                 AssignDumpId(&finfo[i].dobj);
4154                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4155                 finfo[i].dobj.namespace =
4156                         findNamespace(fout,
4157                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4158                                                   finfo[i].dobj.catId.oid);
4159                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4160                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4161                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4162                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4163                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4164                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4165                 if (finfo[i].nargs == 0)
4166                         finfo[i].argtypes = NULL;
4167                 else
4168                 {
4169                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4170                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4171                                                   finfo[i].argtypes, finfo[i].nargs);
4172                 }
4173
4174                 /* Decide whether we want to dump it */
4175                 selectDumpableObject(&(finfo[i].dobj));
4176
4177                 if (strlen(finfo[i].rolname) == 0)
4178                         write_msg(NULL,
4179                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4180                                           finfo[i].dobj.name);
4181         }
4182
4183         PQclear(res);
4184
4185         destroyPQExpBuffer(query);
4186
4187         return finfo;
4188 }
4189
4190 /*
4191  * getTables
4192  *        read all the user-defined tables (no indexes, no catalogs)
4193  * in the system catalogs return them in the TableInfo* structure
4194  *
4195  * numTables is set to the number of tables read in
4196  */
4197 TableInfo *
4198 getTables(Archive *fout, int *numTables)
4199 {
4200         PGresult   *res;
4201         int                     ntups;
4202         int                     i;
4203         PQExpBuffer query = createPQExpBuffer();
4204         TableInfo  *tblinfo;
4205         int                     i_reltableoid;
4206         int                     i_reloid;
4207         int                     i_relname;
4208         int                     i_relnamespace;
4209         int                     i_relkind;
4210         int                     i_relacl;
4211         int                     i_rolname;
4212         int                     i_relchecks;
4213         int                     i_relhastriggers;
4214         int                     i_relhasindex;
4215         int                     i_relhasrules;
4216         int                     i_relhasoids;
4217         int                     i_relfrozenxid;
4218         int                     i_toastoid;
4219         int                     i_toastfrozenxid;
4220         int                     i_relpersistence;
4221         int                     i_isscannable;
4222         int                     i_owning_tab;
4223         int                     i_owning_col;
4224         int                     i_reltablespace;
4225         int                     i_reloptions;
4226         int                     i_toastreloptions;
4227         int                     i_reloftype;
4228         int                     i_relpages;
4229
4230         /* Make sure we are in proper schema */
4231         selectSourceSchema(fout, "pg_catalog");
4232
4233         /*
4234          * Find all the tables and table-like objects.
4235          *
4236          * We include system catalogs, so that we can work if a user table is
4237          * defined to inherit from a system catalog (pretty weird, but...)
4238          *
4239          * We ignore relations that are not ordinary tables, sequences, views,
4240          * materialized views, composite types, or foreign tables.
4241          *
4242          * Composite-type table entries won't be dumped as such, but we have to
4243          * make a DumpableObject for them so that we can track dependencies of the
4244          * composite type (pg_depend entries for columns of the composite type
4245          * link to the pg_class entry not the pg_type entry).
4246          *
4247          * Note: in this phase we should collect only a minimal amount of
4248          * information about each table, basically just enough to decide if it is
4249          * interesting. We must fetch all tables in this phase because otherwise
4250          * we cannot correctly identify inherited columns, owned sequences, etc.
4251          */
4252
4253         if (fout->remoteVersion >= 90300)
4254         {
4255                 /*
4256                  * Left join to pick up dependency info linking sequences to their
4257                  * owning column, if any (note this dependency is AUTO as of 8.2)
4258                  */
4259                 appendPQExpBuffer(query,
4260                                                   "SELECT c.tableoid, c.oid, c.relname, "
4261                                                   "c.relacl, c.relkind, c.relnamespace, "
4262                                                   "(%s c.relowner) AS rolname, "
4263                                                   "c.relchecks, c.relhastriggers, "
4264                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4265                                                   "c.relfrozenxid, tc.oid AS toid, "
4266                                                   "tc.relfrozenxid AS tfrozenxid, "
4267                  "c.relpersistence, pg_relation_is_scannable(c.oid) as isscannable, "
4268                                                   "c.relpages, "
4269                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4270                                                   "d.refobjid AS owning_tab, "
4271                                                   "d.refobjsubid AS owning_col, "
4272                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4273                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4274                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4275                                                   "FROM pg_class c "
4276                                                   "LEFT JOIN pg_depend d ON "
4277                                                   "(c.relkind = '%c' AND "
4278                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4279                                                   "d.objsubid = 0 AND "
4280                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4281                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4282                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4283                                                   "ORDER BY c.oid",
4284                                                   username_subquery,
4285                                                   RELKIND_SEQUENCE,
4286                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4287                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4288                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4289         }
4290         else if (fout->remoteVersion >= 90100)
4291         {
4292                 /*
4293                  * Left join to pick up dependency info linking sequences to their
4294                  * owning column, if any (note this dependency is AUTO as of 8.2)
4295                  */
4296                 appendPQExpBuffer(query,
4297                                                   "SELECT c.tableoid, c.oid, c.relname, "
4298                                                   "c.relacl, c.relkind, c.relnamespace, "
4299                                                   "(%s c.relowner) AS rolname, "
4300                                                   "c.relchecks, c.relhastriggers, "
4301                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4302                                                   "c.relfrozenxid, tc.oid AS toid, "
4303                                                   "tc.relfrozenxid AS tfrozenxid, "
4304                                                   "c.relpersistence, 't'::bool as isscannable, "
4305                                                   "c.relpages, "
4306                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4307                                                   "d.refobjid AS owning_tab, "
4308                                                   "d.refobjsubid AS owning_col, "
4309                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4310                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4311                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4312                                                   "FROM pg_class c "
4313                                                   "LEFT JOIN pg_depend d ON "
4314                                                   "(c.relkind = '%c' AND "
4315                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4316                                                   "d.objsubid = 0 AND "
4317                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4318                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4319                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4320                                                   "ORDER BY c.oid",
4321                                                   username_subquery,
4322                                                   RELKIND_SEQUENCE,
4323                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4324                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4325                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4326         }
4327         else if (fout->remoteVersion >= 90000)
4328         {
4329                 /*
4330                  * Left join to pick up dependency info linking sequences to their
4331                  * owning column, if any (note this dependency is AUTO as of 8.2)
4332                  */
4333                 appendPQExpBuffer(query,
4334                                                   "SELECT c.tableoid, c.oid, c.relname, "
4335                                                   "c.relacl, c.relkind, c.relnamespace, "
4336                                                   "(%s c.relowner) AS rolname, "
4337                                                   "c.relchecks, c.relhastriggers, "
4338                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4339                                                   "c.relfrozenxid, tc.oid AS toid, "
4340                                                   "tc.relfrozenxid AS tfrozenxid, "
4341                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4342                                                   "c.relpages, "
4343                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4344                                                   "d.refobjid AS owning_tab, "
4345                                                   "d.refobjsubid AS owning_col, "
4346                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4347                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4348                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4349                                                   "FROM pg_class c "
4350                                                   "LEFT JOIN pg_depend d ON "
4351                                                   "(c.relkind = '%c' AND "
4352                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4353                                                   "d.objsubid = 0 AND "
4354                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4355                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4356                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4357                                                   "ORDER BY c.oid",
4358                                                   username_subquery,
4359                                                   RELKIND_SEQUENCE,
4360                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4361                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4362         }
4363         else if (fout->remoteVersion >= 80400)
4364         {
4365                 /*
4366                  * Left join to pick up dependency info linking sequences to their
4367                  * owning column, if any (note this dependency is AUTO as of 8.2)
4368                  */
4369                 appendPQExpBuffer(query,
4370                                                   "SELECT c.tableoid, c.oid, c.relname, "
4371                                                   "c.relacl, c.relkind, c.relnamespace, "
4372                                                   "(%s c.relowner) AS rolname, "
4373                                                   "c.relchecks, c.relhastriggers, "
4374                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4375                                                   "c.relfrozenxid, tc.oid AS toid, "
4376                                                   "tc.relfrozenxid AS tfrozenxid, "
4377                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4378                                                   "c.relpages, "
4379                                                   "NULL AS reloftype, "
4380                                                   "d.refobjid AS owning_tab, "
4381                                                   "d.refobjsubid AS owning_col, "
4382                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4383                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4384                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4385                                                   "FROM pg_class c "
4386                                                   "LEFT JOIN pg_depend d ON "
4387                                                   "(c.relkind = '%c' AND "
4388                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4389                                                   "d.objsubid = 0 AND "
4390                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4391                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4392                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4393                                                   "ORDER BY c.oid",
4394                                                   username_subquery,
4395                                                   RELKIND_SEQUENCE,
4396                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4397                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4398         }
4399         else if (fout->remoteVersion >= 80200)
4400         {
4401                 /*
4402                  * Left join to pick up dependency info linking sequences to their
4403                  * owning column, if any (note this dependency is AUTO as of 8.2)
4404                  */
4405                 appendPQExpBuffer(query,
4406                                                   "SELECT c.tableoid, c.oid, c.relname, "
4407                                                   "c.relacl, c.relkind, c.relnamespace, "
4408                                                   "(%s c.relowner) AS rolname, "
4409                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4410                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4411                                                   "c.relfrozenxid, tc.oid AS toid, "
4412                                                   "tc.relfrozenxid AS tfrozenxid, "
4413                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4414                                                   "c.relpages, "
4415                                                   "NULL AS reloftype, "
4416                                                   "d.refobjid AS owning_tab, "
4417                                                   "d.refobjsubid AS owning_col, "
4418                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4419                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4420                                                   "NULL AS toast_reloptions "
4421                                                   "FROM pg_class c "
4422                                                   "LEFT JOIN pg_depend d ON "
4423                                                   "(c.relkind = '%c' AND "
4424                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4425                                                   "d.objsubid = 0 AND "
4426                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4427                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4428                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4429                                                   "ORDER BY c.oid",
4430                                                   username_subquery,
4431                                                   RELKIND_SEQUENCE,
4432                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4433                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4434         }
4435         else if (fout->remoteVersion >= 80000)
4436         {
4437                 /*
4438                  * Left join to pick up dependency info linking sequences to their
4439                  * owning column, if any
4440                  */
4441                 appendPQExpBuffer(query,
4442                                                   "SELECT c.tableoid, c.oid, relname, "
4443                                                   "relacl, relkind, relnamespace, "
4444                                                   "(%s relowner) AS rolname, "
4445                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4446                                                   "relhasindex, relhasrules, relhasoids, "
4447                                                   "0 AS relfrozenxid, "
4448                                                   "0 AS toid, "
4449                                                   "0 AS tfrozenxid, "
4450                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4451                                                   "relpages, "
4452                                                   "NULL AS reloftype, "
4453                                                   "d.refobjid AS owning_tab, "
4454                                                   "d.refobjsubid AS owning_col, "
4455                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4456                                                   "NULL AS reloptions, "
4457                                                   "NULL AS toast_reloptions "
4458                                                   "FROM pg_class c "
4459                                                   "LEFT JOIN pg_depend d ON "
4460                                                   "(c.relkind = '%c' AND "
4461                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4462                                                   "d.objsubid = 0 AND "
4463                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4464                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4465                                                   "ORDER BY c.oid",
4466                                                   username_subquery,
4467                                                   RELKIND_SEQUENCE,
4468                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4469                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4470         }
4471         else if (fout->remoteVersion >= 70300)
4472         {
4473                 /*
4474                  * Left join to pick up dependency info linking sequences to their
4475                  * owning column, if any
4476                  */
4477                 appendPQExpBuffer(query,
4478                                                   "SELECT c.tableoid, c.oid, relname, "
4479                                                   "relacl, relkind, relnamespace, "
4480                                                   "(%s relowner) AS rolname, "
4481                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4482                                                   "relhasindex, relhasrules, relhasoids, "
4483                                                   "0 AS relfrozenxid, "
4484                                                   "0 AS toid, "
4485                                                   "0 AS tfrozenxid, "
4486                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4487                                                   "relpages, "
4488                                                   "NULL AS reloftype, "
4489                                                   "d.refobjid AS owning_tab, "
4490                                                   "d.refobjsubid AS owning_col, "
4491                                                   "NULL AS reltablespace, "
4492                                                   "NULL AS reloptions, "
4493                                                   "NULL AS toast_reloptions "
4494                                                   "FROM pg_class c "
4495                                                   "LEFT JOIN pg_depend d ON "
4496                                                   "(c.relkind = '%c' AND "
4497                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4498                                                   "d.objsubid = 0 AND "
4499                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4500                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4501                                                   "ORDER BY c.oid",
4502                                                   username_subquery,
4503                                                   RELKIND_SEQUENCE,
4504                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4505                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4506         }
4507         else if (fout->remoteVersion >= 70200)
4508         {
4509                 appendPQExpBuffer(query,
4510                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4511                                                   "0::oid AS relnamespace, "
4512                                                   "(%s relowner) AS rolname, "
4513                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4514                                                   "relhasindex, relhasrules, relhasoids, "
4515                                                   "0 AS relfrozenxid, "
4516                                                   "0 AS toid, "
4517                                                   "0 AS tfrozenxid, "
4518                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4519                                                   "relpages, "
4520                                                   "NULL AS reloftype, "
4521                                                   "NULL::oid AS owning_tab, "
4522                                                   "NULL::int4 AS owning_col, "
4523                                                   "NULL AS reltablespace, "
4524                                                   "NULL AS reloptions, "
4525                                                   "NULL AS toast_reloptions "
4526                                                   "FROM pg_class "
4527                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4528                                                   "ORDER BY oid",
4529                                                   username_subquery,
4530                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4531         }
4532         else if (fout->remoteVersion >= 70100)
4533         {
4534                 /* all tables have oids in 7.1 */
4535                 appendPQExpBuffer(query,
4536                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4537                                                   "0::oid AS relnamespace, "
4538                                                   "(%s relowner) AS rolname, "
4539                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4540                                                   "relhasindex, relhasrules, "
4541                                                   "'t'::bool AS relhasoids, "
4542                                                   "0 AS relfrozenxid, "
4543                                                   "0 AS toid, "
4544                                                   "0 AS tfrozenxid, "
4545                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4546                                                   "relpages, "
4547                                                   "NULL AS reloftype, "
4548                                                   "NULL::oid AS owning_tab, "
4549                                                   "NULL::int4 AS owning_col, "
4550                                                   "NULL AS reltablespace, "
4551                                                   "NULL AS reloptions, "
4552                                                   "NULL AS toast_reloptions "
4553                                                   "FROM pg_class "
4554                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4555                                                   "ORDER BY oid",
4556                                                   username_subquery,
4557                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4558         }
4559         else
4560         {
4561                 /*
4562                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4563                  * have a view by looking for a rule in pg_rewrite.
4564                  */
4565                 appendPQExpBuffer(query,
4566                                                   "SELECT "
4567                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4568                                                   "oid, relname, relacl, "
4569                                                   "CASE WHEN relhasrules and relkind = 'r' "
4570                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
4571                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
4572                                                   "THEN '%c'::\"char\" "
4573                                                   "ELSE relkind END AS relkind,"
4574                                                   "0::oid AS relnamespace, "
4575                                                   "(%s relowner) AS rolname, "
4576                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4577                                                   "relhasindex, relhasrules, "
4578                                                   "'t'::bool AS relhasoids, "
4579                                                   "0 as relfrozenxid, "
4580                                                   "0 AS toid, "
4581                                                   "0 AS tfrozenxid, "
4582                                                   "'p' AS relpersistence, 't'::bool as isscannable, "
4583                                                   "0 AS relpages, "
4584                                                   "NULL AS reloftype, "
4585                                                   "NULL::oid AS owning_tab, "
4586                                                   "NULL::int4 AS owning_col, "
4587                                                   "NULL AS reltablespace, "
4588                                                   "NULL AS reloptions, "
4589                                                   "NULL AS toast_reloptions "
4590                                                   "FROM pg_class c "
4591                                                   "WHERE relkind IN ('%c', '%c') "
4592                                                   "ORDER BY oid",
4593                                                   RELKIND_VIEW,
4594                                                   username_subquery,
4595                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
4596         }
4597
4598         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4599
4600         ntups = PQntuples(res);
4601
4602         *numTables = ntups;
4603
4604         /*
4605          * Extract data from result and lock dumpable tables.  We do the locking
4606          * before anything else, to minimize the window wherein a table could
4607          * disappear under us.
4608          *
4609          * Note that we have to save info about all tables here, even when dumping
4610          * only one, because we don't yet know which tables might be inheritance
4611          * ancestors of the target table.
4612          */
4613         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
4614
4615         i_reltableoid = PQfnumber(res, "tableoid");
4616         i_reloid = PQfnumber(res, "oid");
4617         i_relname = PQfnumber(res, "relname");
4618         i_relnamespace = PQfnumber(res, "relnamespace");
4619         i_relacl = PQfnumber(res, "relacl");
4620         i_relkind = PQfnumber(res, "relkind");
4621         i_rolname = PQfnumber(res, "rolname");
4622         i_relchecks = PQfnumber(res, "relchecks");
4623         i_relhastriggers = PQfnumber(res, "relhastriggers");
4624         i_relhasindex = PQfnumber(res, "relhasindex");
4625         i_relhasrules = PQfnumber(res, "relhasrules");
4626         i_relhasoids = PQfnumber(res, "relhasoids");
4627         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
4628         i_toastoid = PQfnumber(res, "toid");
4629         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
4630         i_relpersistence = PQfnumber(res, "relpersistence");
4631         i_isscannable = PQfnumber(res, "isscannable");
4632         i_relpages = PQfnumber(res, "relpages");
4633         i_owning_tab = PQfnumber(res, "owning_tab");
4634         i_owning_col = PQfnumber(res, "owning_col");
4635         i_reltablespace = PQfnumber(res, "reltablespace");
4636         i_reloptions = PQfnumber(res, "reloptions");
4637         i_toastreloptions = PQfnumber(res, "toast_reloptions");
4638         i_reloftype = PQfnumber(res, "reloftype");
4639
4640         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4641         {
4642                 /*
4643                  * Arrange to fail instead of waiting forever for a table lock.
4644                  *
4645                  * NB: this coding assumes that the only queries issued within the
4646                  * following loop are LOCK TABLEs; else the timeout may be undesirably
4647                  * applied to other things too.
4648                  */
4649                 resetPQExpBuffer(query);
4650                 appendPQExpBuffer(query, "SET statement_timeout = ");
4651                 appendStringLiteralConn(query, lockWaitTimeout, GetConnection(fout));
4652                 ExecuteSqlStatement(fout, query->data);
4653         }
4654
4655         for (i = 0; i < ntups; i++)
4656         {
4657                 tblinfo[i].dobj.objType = DO_TABLE;
4658                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
4659                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
4660                 AssignDumpId(&tblinfo[i].dobj);
4661                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
4662                 tblinfo[i].dobj.namespace =
4663                         findNamespace(fout,
4664                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
4665                                                   tblinfo[i].dobj.catId.oid);
4666                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4667                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
4668                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
4669                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
4670                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
4671                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
4672                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
4673                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
4674                 tblinfo[i].isscannable = (strcmp(PQgetvalue(res, i, i_isscannable), "t") == 0);
4675                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
4676                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
4677                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
4678                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
4679                 if (PQgetisnull(res, i, i_reloftype))
4680                         tblinfo[i].reloftype = NULL;
4681                 else
4682                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
4683                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
4684                 if (PQgetisnull(res, i, i_owning_tab))
4685                 {
4686                         tblinfo[i].owning_tab = InvalidOid;
4687                         tblinfo[i].owning_col = 0;
4688                 }
4689                 else
4690                 {
4691                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
4692                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
4693                 }
4694                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
4695                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
4696                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
4697
4698                 /* other fields were zeroed above */
4699
4700                 /*
4701                  * Decide whether we want to dump this table.
4702                  */
4703                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
4704                         tblinfo[i].dobj.dump = false;
4705                 else
4706                         selectDumpableTable(&tblinfo[i]);
4707                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
4708
4709                 /*
4710                  * Read-lock target tables to make sure they aren't DROPPED or altered
4711                  * in schema before we get around to dumping them.
4712                  *
4713                  * Note that we don't explicitly lock parents of the target tables; we
4714                  * assume our lock on the child is enough to prevent schema
4715                  * alterations to parent tables.
4716                  *
4717                  * NOTE: it'd be kinda nice to lock other relations too, not only
4718                  * plain tables, but the backend doesn't presently allow that.
4719                  */
4720                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
4721                 {
4722                         resetPQExpBuffer(query);
4723                         appendPQExpBuffer(query,
4724                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
4725                                                           fmtQualifiedId(fout->remoteVersion,
4726                                                                                 tblinfo[i].dobj.namespace->dobj.name,
4727                                                                                          tblinfo[i].dobj.name));
4728                         ExecuteSqlStatement(fout, query->data);
4729                 }
4730
4731                 /* Emit notice if join for owner failed */
4732                 if (strlen(tblinfo[i].rolname) == 0)
4733                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
4734                                           tblinfo[i].dobj.name);
4735         }
4736
4737         if (lockWaitTimeout && fout->remoteVersion >= 70300)
4738         {
4739                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
4740         }
4741
4742         PQclear(res);
4743
4744         destroyPQExpBuffer(query);
4745
4746         return tblinfo;
4747 }
4748
4749 /*
4750  * getOwnedSeqs
4751  *        identify owned sequences and mark them as dumpable if owning table is
4752  *
4753  * We used to do this in getTables(), but it's better to do it after the
4754  * index used by findTableByOid() has been set up.
4755  */
4756 void
4757 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
4758 {
4759         int                     i;
4760
4761         /*
4762          * Force sequences that are "owned" by table columns to be dumped whenever
4763          * their owning table is being dumped.
4764          */
4765         for (i = 0; i < numTables; i++)
4766         {
4767                 TableInfo  *seqinfo = &tblinfo[i];
4768                 TableInfo  *owning_tab;
4769
4770                 if (!OidIsValid(seqinfo->owning_tab))
4771                         continue;                       /* not an owned sequence */
4772                 if (seqinfo->dobj.dump)
4773                         continue;                       /* no need to search */
4774                 owning_tab = findTableByOid(seqinfo->owning_tab);
4775                 if (owning_tab && owning_tab->dobj.dump)
4776                 {
4777                         seqinfo->interesting = true;
4778                         seqinfo->dobj.dump = true;
4779                 }
4780         }
4781 }
4782
4783 /*
4784  * getInherits
4785  *        read all the inheritance information
4786  * from the system catalogs return them in the InhInfo* structure
4787  *
4788  * numInherits is set to the number of pairs read in
4789  */
4790 InhInfo *
4791 getInherits(Archive *fout, int *numInherits)
4792 {
4793         PGresult   *res;
4794         int                     ntups;
4795         int                     i;
4796         PQExpBuffer query = createPQExpBuffer();
4797         InhInfo    *inhinfo;
4798
4799         int                     i_inhrelid;
4800         int                     i_inhparent;
4801
4802         /* Make sure we are in proper schema */
4803         selectSourceSchema(fout, "pg_catalog");
4804
4805         /* find all the inheritance information */
4806
4807         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
4808
4809         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4810
4811         ntups = PQntuples(res);
4812
4813         *numInherits = ntups;
4814
4815         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
4816
4817         i_inhrelid = PQfnumber(res, "inhrelid");
4818         i_inhparent = PQfnumber(res, "inhparent");
4819
4820         for (i = 0; i < ntups; i++)
4821         {
4822                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
4823                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
4824         }
4825
4826         PQclear(res);
4827
4828         destroyPQExpBuffer(query);
4829
4830         return inhinfo;
4831 }
4832
4833 /*
4834  * getIndexes
4835  *        get information about every index on a dumpable table
4836  *
4837  * Note: index data is not returned directly to the caller, but it
4838  * does get entered into the DumpableObject tables.
4839  */
4840 void
4841 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
4842 {
4843         int                     i,
4844                                 j;
4845         PQExpBuffer query = createPQExpBuffer();
4846         PGresult   *res;
4847         IndxInfo   *indxinfo;
4848         ConstraintInfo *constrinfo;
4849         int                     i_tableoid,
4850                                 i_oid,
4851                                 i_indexname,
4852                                 i_indexdef,
4853                                 i_indnkeys,
4854                                 i_indkey,
4855                                 i_indisclustered,
4856                                 i_contype,
4857                                 i_conname,
4858                                 i_condeferrable,
4859                                 i_condeferred,
4860                                 i_contableoid,
4861                                 i_conoid,
4862                                 i_condef,
4863                                 i_tablespace,
4864                                 i_options,
4865                                 i_relpages;
4866         int                     ntups;
4867
4868         for (i = 0; i < numTables; i++)
4869         {
4870                 TableInfo  *tbinfo = &tblinfo[i];
4871
4872                 /* Only plain tables and materialized views have indexes. */
4873                 if (tbinfo->relkind != RELKIND_RELATION &&
4874                         tbinfo->relkind != RELKIND_MATVIEW)
4875                         continue;
4876                 if (!tbinfo->hasindex)
4877                         continue;
4878
4879                 /* Ignore indexes of tables not to be dumped */
4880                 if (!tbinfo->dobj.dump)
4881                         continue;
4882
4883                 if (g_verbose)
4884                         write_msg(NULL, "reading indexes for table \"%s\"\n",
4885                                           tbinfo->dobj.name);
4886
4887                 /* Make sure we are in proper schema so indexdef is right */
4888                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
4889
4890                 /*
4891                  * The point of the messy-looking outer join is to find a constraint
4892                  * that is related by an internal dependency link to the index. If we
4893                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
4894                  * assume an index won't have more than one internal dependency.
4895                  *
4896                  * As of 9.0 we don't need to look at pg_depend but can check for a
4897                  * match to pg_constraint.conindid.  The check on conrelid is
4898                  * redundant but useful because that column is indexed while conindid
4899                  * is not.
4900                  */
4901                 resetPQExpBuffer(query);
4902                 if (fout->remoteVersion >= 90000)
4903                 {
4904                         appendPQExpBuffer(query,
4905                                                           "SELECT t.tableoid, t.oid, "
4906                                                           "t.relname AS indexname, "
4907                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4908                                                           "t.relnatts AS indnkeys, "
4909                                                           "i.indkey, i.indisclustered, "
4910                                                           "t.relpages, "
4911                                                           "c.contype, c.conname, "
4912                                                           "c.condeferrable, c.condeferred, "
4913                                                           "c.tableoid AS contableoid, "
4914                                                           "c.oid AS conoid, "
4915                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
4916                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4917                                                         "array_to_string(t.reloptions, ', ') AS options "
4918                                                           "FROM pg_catalog.pg_index i "
4919                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4920                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4921                                                           "ON (i.indrelid = c.conrelid AND "
4922                                                           "i.indexrelid = c.conindid AND "
4923                                                           "c.contype IN ('p','u','x')) "
4924                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4925                                                           "AND i.indisvalid "
4926                                                           "ORDER BY indexname",
4927                                                           tbinfo->dobj.catId.oid);
4928                 }
4929                 else if (fout->remoteVersion >= 80200)
4930                 {
4931                         appendPQExpBuffer(query,
4932                                                           "SELECT t.tableoid, t.oid, "
4933                                                           "t.relname AS indexname, "
4934                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
4935                                                           "t.relnatts AS indnkeys, "
4936                                                           "i.indkey, i.indisclustered, "
4937                                                           "t.relpages, "
4938                                                           "c.contype, c.conname, "
4939                                                           "c.condeferrable, c.condeferred, "
4940                                                           "c.tableoid AS contableoid, "
4941                                                           "c.oid AS conoid, "
4942                                                           "null AS condef, "
4943                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
4944                                                         "array_to_string(t.reloptions, ', ') AS options "
4945                                                           "FROM pg_catalog.pg_index i "
4946                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
4947                                                           "LEFT JOIN pg_catalog.pg_depend d "
4948                                                           "ON (d.classid = t.tableoid "
4949                                                           "AND d.objid = t.oid "
4950                                                           "AND d.deptype = 'i') "
4951                                                           "LEFT JOIN pg_catalog.pg_constraint c "
4952                                                           "ON (d.refclassid = c.tableoid "
4953                                                           "AND d.refobjid = c.oid) "
4954                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
4955                                                           "AND i.indisvalid "
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 }