]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Fix use of already freed memory when dumping a database's security label.
[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-2015, 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 look at
18  *      the currently committed state.  So it is possible to get 'cache
19  *      lookup failed' error if someone performs DDL changes while a dump is
20  *      happening. The window for this sort of thing is from the acquisition
21  *      of the transaction snapshot to getSchemaData() (when pg_dump acquires
22  *      AccessShareLock on every table it intends to dump). It isn't very large,
23  *      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 #include "postgres_fe.h"
33
34 #include <unistd.h>
35 #include <ctype.h>
36 #ifdef ENABLE_NLS
37 #include <locale.h>
38 #endif
39 #ifdef HAVE_TERMIOS_H
40 #include <termios.h>
41 #endif
42
43 #include "getopt_long.h"
44
45 #include "access/attnum.h"
46 #include "access/sysattr.h"
47 #include "access/transam.h"
48 #include "catalog/pg_cast.h"
49 #include "catalog/pg_class.h"
50 #include "catalog/pg_default_acl.h"
51 #include "catalog/pg_largeobject.h"
52 #include "catalog/pg_largeobject_metadata.h"
53 #include "catalog/pg_proc.h"
54 #include "catalog/pg_trigger.h"
55 #include "catalog/pg_type.h"
56 #include "libpq/libpq-fs.h"
57
58 #include "dumputils.h"
59 #include "parallel.h"
60 #include "pg_backup_db.h"
61 #include "pg_backup_utils.h"
62 #include "pg_dump.h"
63
64
65 typedef struct
66 {
67         const char *descr;                      /* comment for an object */
68         Oid                     classoid;               /* object class (catalog OID) */
69         Oid                     objoid;                 /* object OID */
70         int                     objsubid;               /* subobject (table column #) */
71 } CommentItem;
72
73 typedef struct
74 {
75         const char *provider;           /* label provider of this security label */
76         const char *label;                      /* security label for an object */
77         Oid                     classoid;               /* object class (catalog OID) */
78         Oid                     objoid;                 /* object OID */
79         int                     objsubid;               /* subobject (table column #) */
80 } SecLabelItem;
81
82 typedef enum OidOptions
83 {
84         zeroAsOpaque = 1,
85         zeroAsAny = 2,
86         zeroAsStar = 4,
87         zeroAsNone = 8
88 } OidOptions;
89
90 /* global decls */
91 bool            g_verbose;                      /* User wants verbose narration of our
92                                                                  * activities. */
93
94 /* subquery used to convert user ID (eg, datdba) to user name */
95 static const char *username_subquery;
96
97 /* obsolete as of 7.3: */
98 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
99
100 /*
101  * Object inclusion/exclusion lists
102  *
103  * The string lists record the patterns given by command-line switches,
104  * which we then convert to lists of OIDs of matching objects.
105  */
106 static SimpleStringList schema_include_patterns = {NULL, NULL};
107 static SimpleOidList schema_include_oids = {NULL, NULL};
108 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
109 static SimpleOidList schema_exclude_oids = {NULL, NULL};
110
111 static SimpleStringList table_include_patterns = {NULL, NULL};
112 static SimpleOidList table_include_oids = {NULL, NULL};
113 static SimpleStringList table_exclude_patterns = {NULL, NULL};
114 static SimpleOidList table_exclude_oids = {NULL, NULL};
115 static SimpleStringList tabledata_exclude_patterns = {NULL, NULL};
116 static SimpleOidList tabledata_exclude_oids = {NULL, NULL};
117
118
119 char            g_opaque_type[10];      /* name for the opaque type */
120
121 /* placeholders for the delimiters for comments */
122 char            g_comment_start[10];
123 char            g_comment_end[10];
124
125 static const CatalogId nilCatalogId = {0, 0};
126
127 static void help(const char *progname);
128 static void setup_connection(Archive *AH, DumpOptions *dopt,
129                                 const char *dumpencoding, const char *dumpsnapshot,
130                                 char *use_role);
131 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
132 static void expand_schema_name_patterns(Archive *fout,
133                                                         SimpleStringList *patterns,
134                                                         SimpleOidList *oids);
135 static void expand_table_name_patterns(Archive *fout,
136                                                    SimpleStringList *patterns,
137                                                    SimpleOidList *oids);
138 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid, Oid objoid);
139 static void dumpTableData(Archive *fout, DumpOptions *dopt, TableDataInfo *tdinfo);
140 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
141 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
142 static void dumpComment(Archive *fout, DumpOptions *dopt, const char *target,
143                         const char *namespace, const char *owner,
144                         CatalogId catalogId, int subid, DumpId dumpId);
145 static int findComments(Archive *fout, Oid classoid, Oid objoid,
146                          CommentItem **items);
147 static int      collectComments(Archive *fout, CommentItem **items);
148 static void dumpSecLabel(Archive *fout, DumpOptions *dopt, const char *target,
149                          const char *namespace, const char *owner,
150                          CatalogId catalogId, int subid, DumpId dumpId);
151 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
152                           SecLabelItem **items);
153 static int      collectSecLabels(Archive *fout, SecLabelItem **items);
154 static void dumpDumpableObject(Archive *fout, DumpOptions *dopt, DumpableObject *dobj);
155 static void dumpNamespace(Archive *fout, DumpOptions *dopt, NamespaceInfo *nspinfo);
156 static void dumpExtension(Archive *fout, DumpOptions *dopt, ExtensionInfo *extinfo);
157 static void dumpType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
158 static void dumpBaseType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
159 static void dumpEnumType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
160 static void dumpRangeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
161 static void dumpDomain(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
162 static void dumpCompositeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo);
163 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
164 static void dumpShellType(Archive *fout, DumpOptions *dopt, ShellTypeInfo *stinfo);
165 static void dumpProcLang(Archive *fout, DumpOptions *dopt, ProcLangInfo *plang);
166 static void dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo);
167 static void dumpCast(Archive *fout, DumpOptions *dopt, CastInfo *cast);
168 static void dumpOpr(Archive *fout, DumpOptions *dopt, OprInfo *oprinfo);
169 static void dumpOpclass(Archive *fout, DumpOptions *dopt, OpclassInfo *opcinfo);
170 static void dumpOpfamily(Archive *fout, DumpOptions *dopt, OpfamilyInfo *opfinfo);
171 static void dumpCollation(Archive *fout, DumpOptions *dopt, CollInfo *convinfo);
172 static void dumpConversion(Archive *fout, DumpOptions *dopt, ConvInfo *convinfo);
173 static void dumpRule(Archive *fout, DumpOptions *dopt, RuleInfo *rinfo);
174 static void dumpAgg(Archive *fout, DumpOptions *dopt, AggInfo *agginfo);
175 static void dumpTrigger(Archive *fout, DumpOptions *dopt, TriggerInfo *tginfo);
176 static void dumpEventTrigger(Archive *fout, DumpOptions *dopt, EventTriggerInfo *evtinfo);
177 static void dumpTable(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo);
178 static void dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo);
179 static void dumpAttrDef(Archive *fout, DumpOptions *dopt, AttrDefInfo *adinfo);
180 static void dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo);
181 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
182 static void dumpIndex(Archive *fout, DumpOptions *dopt, IndxInfo *indxinfo);
183 static void dumpConstraint(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo);
184 static void dumpTableConstraintComment(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo);
185 static void dumpTSParser(Archive *fout, DumpOptions *dopt, TSParserInfo *prsinfo);
186 static void dumpTSDictionary(Archive *fout, DumpOptions *dopt, TSDictInfo *dictinfo);
187 static void dumpTSTemplate(Archive *fout, DumpOptions *dopt, TSTemplateInfo *tmplinfo);
188 static void dumpTSConfig(Archive *fout, DumpOptions *dopt, TSConfigInfo *cfginfo);
189 static void dumpForeignDataWrapper(Archive *fout, DumpOptions *dopt, FdwInfo *fdwinfo);
190 static void dumpForeignServer(Archive *fout, DumpOptions *dopt, ForeignServerInfo *srvinfo);
191 static void dumpUserMappings(Archive *fout,
192                                  const char *servername, const char *namespace,
193                                  const char *owner, CatalogId catalogId, DumpId dumpId);
194 static void dumpDefaultACL(Archive *fout, DumpOptions *dopt, DefaultACLInfo *daclinfo);
195
196 static void dumpACL(Archive *fout, DumpOptions *dopt, CatalogId objCatId, DumpId objDumpId,
197                 const char *type, const char *name, const char *subname,
198                 const char *tag, const char *nspname, const char *owner,
199                 const char *acls);
200
201 static void getDependencies(Archive *fout);
202 static void BuildArchiveDependencies(Archive *fout);
203 static void findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
204                                                  DumpId **dependencies, int *nDeps, int *allocDeps);
205
206 static DumpableObject *createBoundaryObjects(void);
207 static void addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
208                                                 DumpableObject *boundaryObjs);
209
210 static void getDomainConstraints(Archive *fout, TypeInfo *tyinfo);
211 static void getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids);
212 static void makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids);
213 static void buildMatViewRefreshDependencies(Archive *fout);
214 static void getTableDataFKConstraints(void);
215 static char *format_function_arguments(FuncInfo *finfo, char *funcargs,
216                                                   bool is_agg);
217 static char *format_function_arguments_old(Archive *fout,
218                                                           FuncInfo *finfo, int nallargs,
219                                                           char **allargtypes,
220                                                           char **argmodes,
221                                                           char **argnames);
222 static char *format_function_signature(Archive *fout,
223                                                   FuncInfo *finfo, bool honor_quotes);
224 static char *convertRegProcReference(Archive *fout,
225                                                 const char *proc);
226 static char *convertOperatorReference(Archive *fout, const char *opr);
227 static const char *convertTSFunction(Archive *fout, Oid funcOid);
228 static Oid      findLastBuiltinOid_V71(Archive *fout, const char *);
229 static Oid      findLastBuiltinOid_V70(Archive *fout);
230 static void selectSourceSchema(Archive *fout, const char *schemaName);
231 static char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
232 static char *myFormatType(const char *typname, int32 typmod);
233 static void getBlobs(Archive *fout);
234 static void dumpBlob(Archive *fout, DumpOptions *dopt, BlobInfo *binfo);
235 static int      dumpBlobs(Archive *fout, DumpOptions *dopt, void *arg);
236 static void dumpPolicy(Archive *fout, DumpOptions *dopt, PolicyInfo *polinfo);
237 static void dumpDatabase(Archive *AH, DumpOptions *dopt);
238 static void dumpEncoding(Archive *AH);
239 static void dumpStdStrings(Archive *AH);
240 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
241                                                                 PQExpBuffer upgrade_buffer, Oid pg_type_oid);
242 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
243                                                                  PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
244 static void binary_upgrade_set_pg_class_oids(Archive *fout,
245                                                                  PQExpBuffer upgrade_buffer,
246                                                                  Oid pg_class_oid, bool is_index);
247 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
248                                                                 DumpableObject *dobj,
249                                                                 const char *objlabel);
250 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
251 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
252 static char *get_synchronized_snapshot(Archive *fout);
253 static PGresult *ExecuteSqlQueryForSingleRow(Archive *fout, char *query);
254 static void setupDumpWorker(Archive *AHX, DumpOptions *dopt, RestoreOptions *ropt);
255
256
257 int
258 main(int argc, char **argv)
259 {
260         int                     c;
261         const char *filename = NULL;
262         const char *format = "p";
263         TableInfo  *tblinfo;
264         int                     numTables;
265         DumpableObject **dobjs;
266         int                     numObjs;
267         DumpableObject *boundaryObjs;
268         int                     i;
269         int                     optindex;
270         RestoreOptions *ropt;
271         Archive    *fout;                       /* the script file */
272         const char *dumpencoding = NULL;
273         const char *dumpsnapshot = NULL;
274         char       *use_role = NULL;
275         int                     numWorkers = 1;
276         trivalue        prompt_password = TRI_DEFAULT;
277         int                     compressLevel = -1;
278         int                     plainText = 0;
279         ArchiveFormat archiveFormat = archUnknown;
280         ArchiveMode archiveMode;
281
282         static DumpOptions dopt;
283
284         static struct option long_options[] = {
285                 {"data-only", no_argument, NULL, 'a'},
286                 {"blobs", no_argument, NULL, 'b'},
287                 {"clean", no_argument, NULL, 'c'},
288                 {"create", no_argument, NULL, 'C'},
289                 {"dbname", required_argument, NULL, 'd'},
290                 {"file", required_argument, NULL, 'f'},
291                 {"format", required_argument, NULL, 'F'},
292                 {"host", required_argument, NULL, 'h'},
293                 {"ignore-version", no_argument, NULL, 'i'},
294                 {"jobs", 1, NULL, 'j'},
295                 {"no-reconnect", no_argument, NULL, 'R'},
296                 {"oids", no_argument, NULL, 'o'},
297                 {"no-owner", no_argument, NULL, 'O'},
298                 {"port", required_argument, NULL, 'p'},
299                 {"schema", required_argument, NULL, 'n'},
300                 {"exclude-schema", required_argument, NULL, 'N'},
301                 {"schema-only", no_argument, NULL, 's'},
302                 {"superuser", required_argument, NULL, 'S'},
303                 {"table", required_argument, NULL, 't'},
304                 {"exclude-table", required_argument, NULL, 'T'},
305                 {"no-password", no_argument, NULL, 'w'},
306                 {"password", no_argument, NULL, 'W'},
307                 {"username", required_argument, NULL, 'U'},
308                 {"verbose", no_argument, NULL, 'v'},
309                 {"no-privileges", no_argument, NULL, 'x'},
310                 {"no-acl", no_argument, NULL, 'x'},
311                 {"compress", required_argument, NULL, 'Z'},
312                 {"encoding", required_argument, NULL, 'E'},
313                 {"help", no_argument, NULL, '?'},
314                 {"version", no_argument, NULL, 'V'},
315
316                 /*
317                  * the following options don't have an equivalent short option letter
318                  */
319                 {"attribute-inserts", no_argument, &dopt.column_inserts, 1},
320                 {"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
321                 {"column-inserts", no_argument, &dopt.column_inserts, 1},
322                 {"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
323                 {"disable-triggers", no_argument, &dopt.disable_triggers, 1},
324                 {"enable-row-security", no_argument, &dopt.enable_row_security, 1},
325                 {"exclude-table-data", required_argument, NULL, 4},
326                 {"if-exists", no_argument, &dopt.if_exists, 1},
327                 {"inserts", no_argument, &dopt.dump_inserts, 1},
328                 {"lock-wait-timeout", required_argument, NULL, 2},
329                 {"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
330                 {"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
331                 {"role", required_argument, NULL, 3},
332                 {"section", required_argument, NULL, 5},
333                 {"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
334                 {"snapshot", required_argument, NULL, 6},
335                 {"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
336                 {"no-security-labels", no_argument, &dopt.no_security_labels, 1},
337                 {"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
338                 {"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
339
340                 {NULL, 0, NULL, 0}
341         };
342
343         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
344
345         /*
346          * Initialize what we need for parallel execution, especially for thread
347          * support on Windows.
348          */
349         init_parallel_dump_utils();
350
351         g_verbose = false;
352
353         strcpy(g_comment_start, "-- ");
354         g_comment_end[0] = '\0';
355         strcpy(g_opaque_type, "opaque");
356
357         progname = get_progname(argv[0]);
358
359         /* Set default options based on progname */
360         if (strcmp(progname, "pg_backup") == 0)
361                 format = "c";
362
363         if (argc > 1)
364         {
365                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
366                 {
367                         help(progname);
368                         exit_nicely(0);
369                 }
370                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
371                 {
372                         puts("pg_dump (PostgreSQL) " PG_VERSION);
373                         exit_nicely(0);
374                 }
375         }
376
377         InitDumpOptions(&dopt);
378
379         while ((c = getopt_long(argc, argv, "abcCd:E:f:F:h:ij:n:N:oOp:RsS:t:T:U:vwWxZ:",
380                                                         long_options, &optindex)) != -1)
381         {
382                 switch (c)
383                 {
384                         case 'a':                       /* Dump data only */
385                                 dopt.dataOnly = true;
386                                 break;
387
388                         case 'b':                       /* Dump blobs */
389                                 dopt.outputBlobs = true;
390                                 break;
391
392                         case 'c':                       /* clean (i.e., drop) schema prior to create */
393                                 dopt.outputClean = 1;
394                                 break;
395
396                         case 'C':                       /* Create DB */
397                                 dopt.outputCreateDB = 1;
398                                 break;
399
400                         case 'd':                       /* database name */
401                                 dopt.dbname = pg_strdup(optarg);
402                                 break;
403
404                         case 'E':                       /* Dump encoding */
405                                 dumpencoding = pg_strdup(optarg);
406                                 break;
407
408                         case 'f':
409                                 filename = pg_strdup(optarg);
410                                 break;
411
412                         case 'F':
413                                 format = pg_strdup(optarg);
414                                 break;
415
416                         case 'h':                       /* server host */
417                                 dopt.pghost = pg_strdup(optarg);
418                                 break;
419
420                         case 'i':
421                                 /* ignored, deprecated option */
422                                 break;
423
424                         case 'j':                       /* number of dump jobs */
425                                 numWorkers = atoi(optarg);
426                                 break;
427
428                         case 'n':                       /* include schema(s) */
429                                 simple_string_list_append(&schema_include_patterns, optarg);
430                                 dopt.include_everything = false;
431                                 break;
432
433                         case 'N':                       /* exclude schema(s) */
434                                 simple_string_list_append(&schema_exclude_patterns, optarg);
435                                 break;
436
437                         case 'o':                       /* Dump oids */
438                                 dopt.oids = true;
439                                 break;
440
441                         case 'O':                       /* Don't reconnect to match owner */
442                                 dopt.outputNoOwner = 1;
443                                 break;
444
445                         case 'p':                       /* server port */
446                                 dopt.pgport = pg_strdup(optarg);
447                                 break;
448
449                         case 'R':
450                                 /* no-op, still accepted for backwards compatibility */
451                                 break;
452
453                         case 's':                       /* dump schema only */
454                                 dopt.schemaOnly = true;
455                                 break;
456
457                         case 'S':                       /* Username for superuser in plain text output */
458                                 dopt.outputSuperuser = pg_strdup(optarg);
459                                 break;
460
461                         case 't':                       /* include table(s) */
462                                 simple_string_list_append(&table_include_patterns, optarg);
463                                 dopt.include_everything = false;
464                                 break;
465
466                         case 'T':                       /* exclude table(s) */
467                                 simple_string_list_append(&table_exclude_patterns, optarg);
468                                 break;
469
470                         case 'U':
471                                 dopt.username = pg_strdup(optarg);
472                                 break;
473
474                         case 'v':                       /* verbose */
475                                 g_verbose = true;
476                                 break;
477
478                         case 'w':
479                                 prompt_password = TRI_NO;
480                                 break;
481
482                         case 'W':
483                                 prompt_password = TRI_YES;
484                                 break;
485
486                         case 'x':                       /* skip ACL dump */
487                                 dopt.aclsSkip = true;
488                                 break;
489
490                         case 'Z':                       /* Compression Level */
491                                 compressLevel = atoi(optarg);
492                                 break;
493
494                         case 0:
495                                 /* This covers the long options. */
496                                 break;
497
498                         case 2:                         /* lock-wait-timeout */
499                                 dopt.lockWaitTimeout = pg_strdup(optarg);
500                                 break;
501
502                         case 3:                         /* SET ROLE */
503                                 use_role = pg_strdup(optarg);
504                                 break;
505
506                         case 4:                         /* exclude table(s) data */
507                                 simple_string_list_append(&tabledata_exclude_patterns, optarg);
508                                 break;
509
510                         case 5:                         /* section */
511                                 set_dump_section(optarg, &dopt.dumpSections);
512                                 break;
513
514                         case 6:                         /* snapshot */
515                                 dumpsnapshot = pg_strdup(optarg);
516                                 break;
517
518                         default:
519                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
520                                 exit_nicely(1);
521                 }
522         }
523
524         /*
525          * Non-option argument specifies database name as long as it wasn't
526          * already specified with -d / --dbname
527          */
528         if (optind < argc && dopt.dbname == NULL)
529                 dopt.dbname = argv[optind++];
530
531         /* Complain if any arguments remain */
532         if (optind < argc)
533         {
534                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
535                                 progname, argv[optind]);
536                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
537                                 progname);
538                 exit_nicely(1);
539         }
540
541         /* --column-inserts implies --inserts */
542         if (dopt.column_inserts)
543                 dopt.dump_inserts = 1;
544
545         if (dopt.dataOnly && dopt.schemaOnly)
546         {
547                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
548                 exit_nicely(1);
549         }
550
551         if (dopt.dataOnly && dopt.outputClean)
552         {
553                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
554                 exit_nicely(1);
555         }
556
557         if (dopt.dump_inserts && dopt.oids)
558         {
559                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
560                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
561                 exit_nicely(1);
562         }
563
564         if (dopt.if_exists && !dopt.outputClean)
565                 exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
566
567         /* Identify archive format to emit */
568         archiveFormat = parseArchiveFormat(format, &archiveMode);
569
570         /* archiveFormat specific setup */
571         if (archiveFormat == archNull)
572                 plainText = 1;
573
574         /* Custom and directory formats are compressed by default, others not */
575         if (compressLevel == -1)
576         {
577                 if (archiveFormat == archCustom || archiveFormat == archDirectory)
578                         compressLevel = Z_DEFAULT_COMPRESSION;
579                 else
580                         compressLevel = 0;
581         }
582
583         /*
584          * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
585          * parallel jobs because that's the maximum limit for the
586          * WaitForMultipleObjects() call.
587          */
588         if (numWorkers <= 0
589 #ifdef WIN32
590                 || numWorkers > MAXIMUM_WAIT_OBJECTS
591 #endif
592                 )
593                 exit_horribly(NULL, "%s: invalid number of parallel jobs\n", progname);
594
595         /* Parallel backup only in the directory archive format so far */
596         if (archiveFormat != archDirectory && numWorkers > 1)
597                 exit_horribly(NULL, "parallel backup only supported by the directory format\n");
598
599         /* Open the output file */
600         fout = CreateArchive(filename, archiveFormat, compressLevel, archiveMode,
601                                                  setupDumpWorker);
602
603         /* Register the cleanup hook */
604         on_exit_close_archive(fout);
605
606         if (fout == NULL)
607                 exit_horribly(NULL, "could not open output file \"%s\" for writing\n", filename);
608
609         /* Let the archiver know how noisy to be */
610         fout->verbose = g_verbose;
611
612         /*
613          * We allow the server to be back to 7.0, and up to any minor release of
614          * our own major version.  (See also version check in pg_dumpall.c.)
615          */
616         fout->minRemoteVersion = 70000;
617         fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
618
619         fout->numWorkers = numWorkers;
620
621         /*
622          * Open the database using the Archiver, so it knows about it. Errors mean
623          * death.
624          */
625         ConnectDatabase(fout, dopt.dbname, dopt.pghost, dopt.pgport, dopt.username, prompt_password);
626         setup_connection(fout, &dopt, dumpencoding, dumpsnapshot, use_role);
627
628         /*
629          * Disable security label support if server version < v9.1.x (prevents
630          * access to nonexistent pg_seclabel catalog)
631          */
632         if (fout->remoteVersion < 90100)
633                 dopt.no_security_labels = 1;
634
635         /*
636          * When running against 9.0 or later, check if we are in recovery mode,
637          * which means we are on a hot standby.
638          */
639         if (fout->remoteVersion >= 90000)
640         {
641                 PGresult   *res = ExecuteSqlQueryForSingleRow(fout, "SELECT pg_catalog.pg_is_in_recovery()");
642
643                 if (strcmp(PQgetvalue(res, 0, 0), "t") == 0)
644                 {
645                         /*
646                          * On hot standby slaves, never try to dump unlogged table data,
647                          * since it will just throw an error.
648                          */
649                         dopt.no_unlogged_table_data = true;
650                 }
651                 PQclear(res);
652         }
653
654         /* Select the appropriate subquery to convert user IDs to names */
655         if (fout->remoteVersion >= 80100)
656                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
657         else if (fout->remoteVersion >= 70300)
658                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
659         else
660                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
661
662         /* check the version for the synchronized snapshots feature */
663         if (numWorkers > 1 && fout->remoteVersion < 90200
664                 && !dopt.no_synchronized_snapshots)
665                 exit_horribly(NULL,
666                  "Synchronized snapshots are not supported by this server version.\n"
667                   "Run with --no-synchronized-snapshots instead if you do not need\n"
668                                           "synchronized snapshots.\n");
669
670         /* check the version when a snapshot is explicitly specified by user */
671         if (dumpsnapshot && fout->remoteVersion < 90200)
672                 exit_horribly(NULL,
673                         "Exported snapshots are not supported by this server version.\n");
674
675         /* Find the last built-in OID, if needed */
676         if (fout->remoteVersion < 70300)
677         {
678                 if (fout->remoteVersion >= 70100)
679                         g_last_builtin_oid = findLastBuiltinOid_V71(fout,
680                                                                                                   PQdb(GetConnection(fout)));
681                 else
682                         g_last_builtin_oid = findLastBuiltinOid_V70(fout);
683                 if (g_verbose)
684                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
685         }
686
687         /* Expand schema selection patterns into OID lists */
688         if (schema_include_patterns.head != NULL)
689         {
690                 expand_schema_name_patterns(fout, &schema_include_patterns,
691                                                                         &schema_include_oids);
692                 if (schema_include_oids.head == NULL)
693                         exit_horribly(NULL, "No matching schemas were found\n");
694         }
695         expand_schema_name_patterns(fout, &schema_exclude_patterns,
696                                                                 &schema_exclude_oids);
697         /* non-matching exclusion patterns aren't an error */
698
699         /* Expand table selection patterns into OID lists */
700         if (table_include_patterns.head != NULL)
701         {
702                 expand_table_name_patterns(fout, &table_include_patterns,
703                                                                    &table_include_oids);
704                 if (table_include_oids.head == NULL)
705                         exit_horribly(NULL, "No matching tables were found\n");
706         }
707         expand_table_name_patterns(fout, &table_exclude_patterns,
708                                                            &table_exclude_oids);
709
710         expand_table_name_patterns(fout, &tabledata_exclude_patterns,
711                                                            &tabledata_exclude_oids);
712
713         /* non-matching exclusion patterns aren't an error */
714
715         /*
716          * Dumping blobs is now default unless we saw an inclusion switch or -s
717          * ... but even if we did see one of these, -b turns it back on.
718          */
719         if (dopt.include_everything && !dopt.schemaOnly)
720                 dopt.outputBlobs = true;
721
722         /*
723          * Now scan the database and create DumpableObject structs for all the
724          * objects we intend to dump.
725          */
726         tblinfo = getSchemaData(fout, &dopt, &numTables);
727
728         if (fout->remoteVersion < 80400)
729                 guessConstraintInheritance(tblinfo, numTables);
730
731         if (!dopt.schemaOnly)
732         {
733                 getTableData(&dopt, tblinfo, numTables, dopt.oids);
734                 buildMatViewRefreshDependencies(fout);
735                 if (dopt.dataOnly)
736                         getTableDataFKConstraints();
737         }
738
739         if (dopt.outputBlobs)
740                 getBlobs(fout);
741
742         /*
743          * Collect dependency data to assist in ordering the objects.
744          */
745         getDependencies(fout);
746
747         /* Lastly, create dummy objects to represent the section boundaries */
748         boundaryObjs = createBoundaryObjects();
749
750         /* Get pointers to all the known DumpableObjects */
751         getDumpableObjects(&dobjs, &numObjs);
752
753         /*
754          * Add dummy dependencies to enforce the dump section ordering.
755          */
756         addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
757
758         /*
759          * Sort the objects into a safe dump order (no forward references).
760          *
761          * In 7.3 or later, we can rely on dependency information to help us
762          * determine a safe order, so the initial sort is mostly for cosmetic
763          * purposes: we sort by name to ensure that logically identical schemas
764          * will dump identically.  Before 7.3 we don't have dependencies and we
765          * use OID ordering as an (unreliable) guide to creation order.
766          */
767         if (fout->remoteVersion >= 70300)
768                 sortDumpableObjectsByTypeName(dobjs, numObjs);
769         else
770                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
771
772         /* If we do a parallel dump, we want the largest tables to go first */
773         if (archiveFormat == archDirectory && numWorkers > 1)
774                 sortDataAndIndexObjectsBySize(dobjs, numObjs);
775
776         sortDumpableObjects(dobjs, numObjs,
777                                                 boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
778
779         /*
780          * Create archive TOC entries for all the objects to be dumped, in a safe
781          * order.
782          */
783
784         /* First the special ENCODING and STDSTRINGS entries. */
785         dumpEncoding(fout);
786         dumpStdStrings(fout);
787
788         /* The database item is always next, unless we don't want it at all */
789         if (dopt.include_everything && !dopt.dataOnly)
790                 dumpDatabase(fout, &dopt);
791
792         /* Now the rearrangeable objects. */
793         for (i = 0; i < numObjs; i++)
794                 dumpDumpableObject(fout, &dopt, dobjs[i]);
795
796         /*
797          * Set up options info to ensure we dump what we want.
798          */
799         ropt = NewRestoreOptions();
800         ropt->filename = filename;
801
802         /* if you change this list, see dumpOptionsFromRestoreOptions */
803         ropt->dropSchema = dopt.outputClean;
804         ropt->dataOnly = dopt.dataOnly;
805         ropt->schemaOnly = dopt.schemaOnly;
806         ropt->if_exists = dopt.if_exists;
807         ropt->column_inserts = dopt.column_inserts;
808         ropt->dumpSections = dopt.dumpSections;
809         ropt->aclsSkip = dopt.aclsSkip;
810         ropt->superuser = dopt.outputSuperuser;
811         ropt->createDB = dopt.outputCreateDB;
812         ropt->noOwner = dopt.outputNoOwner;
813         ropt->noTablespace = dopt.outputNoTablespaces;
814         ropt->disable_triggers = dopt.disable_triggers;
815         ropt->use_setsessauth = dopt.use_setsessauth;
816         ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
817         ropt->dump_inserts = dopt.dump_inserts;
818         ropt->no_security_labels = dopt.no_security_labels;
819         ropt->lockWaitTimeout = dopt.lockWaitTimeout;
820         ropt->include_everything = dopt.include_everything;
821         ropt->enable_row_security = dopt.enable_row_security;
822
823         if (compressLevel == -1)
824                 ropt->compression = 0;
825         else
826                 ropt->compression = compressLevel;
827
828         ropt->suppressDumpWarnings = true;      /* We've already shown them */
829
830         SetArchiveRestoreOptions(fout, ropt);
831
832         /*
833          * The archive's TOC entries are now marked as to which ones will actually
834          * be output, so we can set up their dependency lists properly. This isn't
835          * necessary for plain-text output, though.
836          */
837         if (!plainText)
838                 BuildArchiveDependencies(fout);
839
840         /*
841          * And finally we can do the actual output.
842          *
843          * Note: for non-plain-text output formats, the output file is written
844          * inside CloseArchive().  This is, um, bizarre; but not worth changing
845          * right now.
846          */
847         if (plainText)
848                 RestoreArchive(fout);
849
850         CloseArchive(fout, &dopt);
851
852         exit_nicely(0);
853 }
854
855
856 static void
857 help(const char *progname)
858 {
859         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
860         printf(_("Usage:\n"));
861         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
862
863         printf(_("\nGeneral options:\n"));
864         printf(_("  -f, --file=FILENAME          output file or directory name\n"));
865         printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
866                          "                               plain text (default))\n"));
867         printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
868         printf(_("  -v, --verbose                verbose mode\n"));
869         printf(_("  -V, --version                output version information, then exit\n"));
870         printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
871         printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
872         printf(_("  -?, --help                   show this help, then exit\n"));
873
874         printf(_("\nOptions controlling the output content:\n"));
875         printf(_("  -a, --data-only              dump only the data, not the schema\n"));
876         printf(_("  -b, --blobs                  include large objects in dump\n"));
877         printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
878         printf(_("  -C, --create                 include commands to create database in dump\n"));
879         printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
880         printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
881         printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
882         printf(_("  -o, --oids                   include OIDs in dump\n"));
883         printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
884                          "                               plain-text format\n"));
885         printf(_("  -s, --schema-only            dump only the schema, no data\n"));
886         printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
887         printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
888         printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
889         printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
890         printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
891         printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
892         printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
893         printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
894         printf(_("  --enable-row-security        enable row level security\n"));
895         printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
896         printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
897         printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
898         printf(_("  --no-security-labels         do not dump security label assignments\n"));
899         printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
900         printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
901         printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
902         printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
903         printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
904         printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
905         printf(_("  --snapshot=SNAPSHOT          use given synchronous snapshot for the dump\n"));
906         printf(_("  --use-set-session-authorization\n"
907                          "                               use SET SESSION AUTHORIZATION commands instead of\n"
908                          "                               ALTER OWNER commands to set ownership\n"));
909
910         printf(_("\nConnection options:\n"));
911         printf(_("  -d, --dbname=DBNAME      database to dump\n"));
912         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
913         printf(_("  -p, --port=PORT          database server port number\n"));
914         printf(_("  -U, --username=NAME      connect as specified database user\n"));
915         printf(_("  -w, --no-password        never prompt for password\n"));
916         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
917         printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
918
919         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
920                          "variable value is used.\n\n"));
921         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
922 }
923
924 static void
925 setup_connection(Archive *AH, DumpOptions *dopt, const char *dumpencoding,
926                                  const char *dumpsnapshot, char *use_role)
927 {
928         PGconn     *conn = GetConnection(AH);
929         const char *std_strings;
930
931         /*
932          * Set the client encoding if requested. If dumpencoding == NULL then
933          * either it hasn't been requested or we're a cloned connection and then
934          * this has already been set in CloneArchive according to the original
935          * connection encoding.
936          */
937         if (dumpencoding)
938         {
939                 if (PQsetClientEncoding(conn, dumpencoding) < 0)
940                         exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
941                                                   dumpencoding);
942         }
943
944         /*
945          * Get the active encoding and the standard_conforming_strings setting, so
946          * we know how to escape strings.
947          */
948         AH->encoding = PQclientEncoding(conn);
949
950         std_strings = PQparameterStatus(conn, "standard_conforming_strings");
951         AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
952
953         /* Set the role if requested */
954         if (!use_role && AH->use_role)
955                 use_role = AH->use_role;
956
957         /* Set the role if requested */
958         if (use_role && AH->remoteVersion >= 80100)
959         {
960                 PQExpBuffer query = createPQExpBuffer();
961
962                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
963                 ExecuteSqlStatement(AH, query->data);
964                 destroyPQExpBuffer(query);
965
966                 /* save this for later use on parallel connections */
967                 if (!AH->use_role)
968                         AH->use_role = strdup(use_role);
969         }
970
971         /* Set the datestyle to ISO to ensure the dump's portability */
972         ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
973
974         /* Likewise, avoid using sql_standard intervalstyle */
975         if (AH->remoteVersion >= 80400)
976                 ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
977
978         /*
979          * If supported, set extra_float_digits so that we can dump float data
980          * exactly (given correctly implemented float I/O code, anyway)
981          */
982         if (AH->remoteVersion >= 90000)
983                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
984         else if (AH->remoteVersion >= 70400)
985                 ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
986
987         /*
988          * If synchronized scanning is supported, disable it, to prevent
989          * unpredictable changes in row ordering across a dump and reload.
990          */
991         if (AH->remoteVersion >= 80300)
992                 ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
993
994         /*
995          * Disable timeouts if supported.
996          */
997         if (AH->remoteVersion >= 70300)
998                 ExecuteSqlStatement(AH, "SET statement_timeout = 0");
999         if (AH->remoteVersion >= 90300)
1000                 ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1001
1002         /*
1003          * Quote all identifiers, if requested.
1004          */
1005         if (quote_all_identifiers && AH->remoteVersion >= 90100)
1006                 ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1007
1008         /*
1009          * Start transaction-snapshot mode transaction to dump consistent data.
1010          */
1011         ExecuteSqlStatement(AH, "BEGIN");
1012         if (AH->remoteVersion >= 90100)
1013         {
1014                 if (dopt->serializable_deferrable)
1015                         ExecuteSqlStatement(AH,
1016                                                                 "SET TRANSACTION ISOLATION LEVEL "
1017                                                                 "SERIALIZABLE, READ ONLY, DEFERRABLE");
1018                 else
1019                         ExecuteSqlStatement(AH,
1020                                                                 "SET TRANSACTION ISOLATION LEVEL "
1021                                                                 "REPEATABLE READ, READ ONLY");
1022         }
1023         else if (AH->remoteVersion >= 70400)
1024         {
1025                 /* note: comma was not accepted in SET TRANSACTION before 8.0 */
1026                 ExecuteSqlStatement(AH,
1027                                                         "SET TRANSACTION ISOLATION LEVEL "
1028                                                         "SERIALIZABLE READ ONLY");
1029         }
1030         else
1031                 ExecuteSqlStatement(AH,
1032                                                         "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
1033
1034         /*
1035          * define an export snapshot, either chosen by user or needed for
1036          * parallel dump.
1037          */
1038         if (dumpsnapshot)
1039                 AH->sync_snapshot_id = strdup(dumpsnapshot);
1040
1041         if (AH->sync_snapshot_id)
1042         {
1043                 PQExpBuffer query = createPQExpBuffer();
1044                 appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1045                 appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1046                 ExecuteSqlStatement(AH, query->data);
1047                 destroyPQExpBuffer(query);
1048         }
1049         else if (AH->numWorkers > 1 &&
1050                          AH->remoteVersion >= 90200 &&
1051                          !dopt->no_synchronized_snapshots)
1052                 AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1053
1054         if (AH->remoteVersion >= 90500)
1055         {
1056                 if (dopt->enable_row_security)
1057                         ExecuteSqlStatement(AH, "SET row_security TO ON");
1058                 else
1059                         ExecuteSqlStatement(AH, "SET row_security TO OFF");
1060         }
1061 }
1062
1063 static void
1064 setupDumpWorker(Archive *AHX, DumpOptions *dopt, RestoreOptions *ropt)
1065 {
1066         setup_connection(AHX, dopt, NULL, NULL, NULL);
1067 }
1068
1069 static char *
1070 get_synchronized_snapshot(Archive *fout)
1071 {
1072         char       *query = "SELECT pg_export_snapshot()";
1073         char       *result;
1074         PGresult   *res;
1075
1076         res = ExecuteSqlQueryForSingleRow(fout, query);
1077         result = strdup(PQgetvalue(res, 0, 0));
1078         PQclear(res);
1079
1080         return result;
1081 }
1082
1083 static ArchiveFormat
1084 parseArchiveFormat(const char *format, ArchiveMode *mode)
1085 {
1086         ArchiveFormat archiveFormat;
1087
1088         *mode = archModeWrite;
1089
1090         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1091         {
1092                 /* This is used by pg_dumpall, and is not documented */
1093                 archiveFormat = archNull;
1094                 *mode = archModeAppend;
1095         }
1096         else if (pg_strcasecmp(format, "c") == 0)
1097                 archiveFormat = archCustom;
1098         else if (pg_strcasecmp(format, "custom") == 0)
1099                 archiveFormat = archCustom;
1100         else if (pg_strcasecmp(format, "d") == 0)
1101                 archiveFormat = archDirectory;
1102         else if (pg_strcasecmp(format, "directory") == 0)
1103                 archiveFormat = archDirectory;
1104         else if (pg_strcasecmp(format, "p") == 0)
1105                 archiveFormat = archNull;
1106         else if (pg_strcasecmp(format, "plain") == 0)
1107                 archiveFormat = archNull;
1108         else if (pg_strcasecmp(format, "t") == 0)
1109                 archiveFormat = archTar;
1110         else if (pg_strcasecmp(format, "tar") == 0)
1111                 archiveFormat = archTar;
1112         else
1113                 exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1114         return archiveFormat;
1115 }
1116
1117 /*
1118  * Find the OIDs of all schemas matching the given list of patterns,
1119  * and append them to the given OID list.
1120  */
1121 static void
1122 expand_schema_name_patterns(Archive *fout,
1123                                                         SimpleStringList *patterns,
1124                                                         SimpleOidList *oids)
1125 {
1126         PQExpBuffer query;
1127         PGresult   *res;
1128         SimpleStringListCell *cell;
1129         int                     i;
1130
1131         if (patterns->head == NULL)
1132                 return;                                 /* nothing to do */
1133
1134         if (fout->remoteVersion < 70300)
1135                 exit_horribly(NULL, "server version must be at least 7.3 to use schema selection switches\n");
1136
1137         query = createPQExpBuffer();
1138
1139         /*
1140          * We use UNION ALL rather than UNION; this might sometimes result in
1141          * duplicate entries in the OID list, but we don't care.
1142          */
1143
1144         for (cell = patterns->head; cell; cell = cell->next)
1145         {
1146                 if (cell != patterns->head)
1147                         appendPQExpBufferStr(query, "UNION ALL\n");
1148                 appendPQExpBuffer(query,
1149                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
1150                 processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1151                                                           false, NULL, "n.nspname", NULL, NULL);
1152         }
1153
1154         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1155
1156         for (i = 0; i < PQntuples(res); i++)
1157         {
1158                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1159         }
1160
1161         PQclear(res);
1162         destroyPQExpBuffer(query);
1163 }
1164
1165 /*
1166  * Find the OIDs of all tables matching the given list of patterns,
1167  * and append them to the given OID list.
1168  */
1169 static void
1170 expand_table_name_patterns(Archive *fout,
1171                                                    SimpleStringList *patterns, SimpleOidList *oids)
1172 {
1173         PQExpBuffer query;
1174         PGresult   *res;
1175         SimpleStringListCell *cell;
1176         int                     i;
1177
1178         if (patterns->head == NULL)
1179                 return;                                 /* nothing to do */
1180
1181         query = createPQExpBuffer();
1182
1183         /*
1184          * We use UNION ALL rather than UNION; this might sometimes result in
1185          * duplicate entries in the OID list, but we don't care.
1186          */
1187
1188         for (cell = patterns->head; cell; cell = cell->next)
1189         {
1190                 if (cell != patterns->head)
1191                         appendPQExpBufferStr(query, "UNION ALL\n");
1192                 appendPQExpBuffer(query,
1193                                                   "SELECT c.oid"
1194                                                   "\nFROM pg_catalog.pg_class c"
1195                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
1196                                          "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n",
1197                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1198                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
1199                 processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1200                                                           false, "n.nspname", "c.relname", NULL,
1201                                                           "pg_catalog.pg_table_is_visible(c.oid)");
1202         }
1203
1204         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1205
1206         for (i = 0; i < PQntuples(res); i++)
1207         {
1208                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1209         }
1210
1211         PQclear(res);
1212         destroyPQExpBuffer(query);
1213 }
1214
1215 /*
1216  * selectDumpableNamespace: policy-setting subroutine
1217  *              Mark a namespace as to be dumped or not
1218  */
1219 static void
1220 selectDumpableNamespace(NamespaceInfo *nsinfo)
1221 {
1222         /*
1223          * If specific tables are being dumped, do not dump any complete
1224          * namespaces. If specific namespaces are being dumped, dump just those
1225          * namespaces. Otherwise, dump all non-system namespaces.
1226          */
1227         if (table_include_oids.head != NULL)
1228                 nsinfo->dobj.dump = false;
1229         else if (schema_include_oids.head != NULL)
1230                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
1231                                                                                                    nsinfo->dobj.catId.oid);
1232         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1233                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
1234                 nsinfo->dobj.dump = false;
1235         else
1236                 nsinfo->dobj.dump = true;
1237
1238         /*
1239          * In any case, a namespace can be excluded by an exclusion switch
1240          */
1241         if (nsinfo->dobj.dump &&
1242                 simple_oid_list_member(&schema_exclude_oids,
1243                                                            nsinfo->dobj.catId.oid))
1244                 nsinfo->dobj.dump = false;
1245 }
1246
1247 /*
1248  * selectDumpableTable: policy-setting subroutine
1249  *              Mark a table as to be dumped or not
1250  */
1251 static void
1252 selectDumpableTable(TableInfo *tbinfo)
1253 {
1254         /*
1255          * If specific tables are being dumped, dump just those tables; else, dump
1256          * according to the parent namespace's dump flag.
1257          */
1258         if (table_include_oids.head != NULL)
1259                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1260                                                                                                    tbinfo->dobj.catId.oid);
1261         else
1262                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1263
1264         /*
1265          * In any case, a table can be excluded by an exclusion switch
1266          */
1267         if (tbinfo->dobj.dump &&
1268                 simple_oid_list_member(&table_exclude_oids,
1269                                                            tbinfo->dobj.catId.oid))
1270                 tbinfo->dobj.dump = false;
1271 }
1272
1273 /*
1274  * selectDumpableType: policy-setting subroutine
1275  *              Mark a type as to be dumped or not
1276  *
1277  * If it's a table's rowtype or an autogenerated array type, we also apply a
1278  * special type code to facilitate sorting into the desired order.  (We don't
1279  * want to consider those to be ordinary types because that would bring tables
1280  * up into the datatype part of the dump order.)  We still set the object's
1281  * dump flag; that's not going to cause the dummy type to be dumped, but we
1282  * need it so that casts involving such types will be dumped correctly -- see
1283  * dumpCast.  This means the flag should be set the same as for the underlying
1284  * object (the table or base type).
1285  */
1286 static void
1287 selectDumpableType(TypeInfo *tyinfo)
1288 {
1289         /* skip complex types, except for standalone composite types */
1290         if (OidIsValid(tyinfo->typrelid) &&
1291                 tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1292         {
1293                 TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1294
1295                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1296                 if (tytable != NULL)
1297                         tyinfo->dobj.dump = tytable->dobj.dump;
1298                 else
1299                         tyinfo->dobj.dump = false;
1300                 return;
1301         }
1302
1303         /* skip auto-generated array types */
1304         if (tyinfo->isArray)
1305         {
1306                 tyinfo->dobj.objType = DO_DUMMY_TYPE;
1307
1308                 /*
1309                  * Fall through to set the dump flag; we assume that the subsequent
1310                  * rules will do the same thing as they would for the array's base
1311                  * type.  (We cannot reliably look up the base type here, since
1312                  * getTypes may not have processed it yet.)
1313                  */
1314         }
1315
1316         /* dump only types in dumpable namespaces */
1317         if (!tyinfo->dobj.namespace->dobj.dump)
1318                 tyinfo->dobj.dump = false;
1319
1320         /* skip undefined placeholder types */
1321         else if (!tyinfo->isDefined)
1322                 tyinfo->dobj.dump = false;
1323
1324         else
1325                 tyinfo->dobj.dump = true;
1326 }
1327
1328 /*
1329  * selectDumpableDefaultACL: policy-setting subroutine
1330  *              Mark a default ACL as to be dumped or not
1331  *
1332  * For per-schema default ACLs, dump if the schema is to be dumped.
1333  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1334  * and aclsSkip are checked separately.
1335  */
1336 static void
1337 selectDumpableDefaultACL(DumpOptions *dopt, DefaultACLInfo *dinfo)
1338 {
1339         if (dinfo->dobj.namespace)
1340                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1341         else
1342                 dinfo->dobj.dump = dopt->include_everything;
1343 }
1344
1345 /*
1346  * selectDumpableExtension: policy-setting subroutine
1347  *              Mark an extension as to be dumped or not
1348  *
1349  * Normally, we dump all extensions, or none of them if include_everything
1350  * is false (i.e., a --schema or --table switch was given).  However, in
1351  * binary-upgrade mode it's necessary to skip built-in extensions, since we
1352  * assume those will already be installed in the target database.  We identify
1353  * such extensions by their having OIDs in the range reserved for initdb.
1354  */
1355 static void
1356 selectDumpableExtension(DumpOptions *dopt, ExtensionInfo *extinfo)
1357 {
1358         if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId)
1359                 extinfo->dobj.dump = false;
1360         else
1361                 extinfo->dobj.dump = dopt->include_everything;
1362 }
1363
1364 /*
1365  * selectDumpableObject: policy-setting subroutine
1366  *              Mark a generic dumpable object as to be dumped or not
1367  *
1368  * Use this only for object types without a special-case routine above.
1369  */
1370 static void
1371 selectDumpableObject(DumpableObject *dobj)
1372 {
1373         /*
1374          * Default policy is to dump if parent namespace is dumpable, or always
1375          * for non-namespace-associated items.
1376          */
1377         if (dobj->namespace)
1378                 dobj->dump = dobj->namespace->dobj.dump;
1379         else
1380                 dobj->dump = true;
1381 }
1382
1383 /*
1384  *      Dump a table's contents for loading using the COPY command
1385  *      - this routine is called by the Archiver when it wants the table
1386  *        to be dumped.
1387  */
1388
1389 static int
1390 dumpTableData_copy(Archive *fout, DumpOptions *dopt, void *dcontext)
1391 {
1392         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1393         TableInfo  *tbinfo = tdinfo->tdtable;
1394         const char *classname = tbinfo->dobj.name;
1395         const bool      hasoids = tbinfo->hasoids;
1396         const bool      oids = tdinfo->oids;
1397         PQExpBuffer q = createPQExpBuffer();
1398
1399         /*
1400          * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1401          * which uses it already.
1402          */
1403         PQExpBuffer clistBuf = createPQExpBuffer();
1404         PGconn     *conn = GetConnection(fout);
1405         PGresult   *res;
1406         int                     ret;
1407         char       *copybuf;
1408         const char *column_list;
1409
1410         if (g_verbose)
1411                 write_msg(NULL, "dumping contents of table \"%s\".\"%s\"\n",
1412                                   tbinfo->dobj.namespace->dobj.name, classname);
1413
1414         /*
1415          * Make sure we are in proper schema.  We will qualify the table name
1416          * below anyway (in case its name conflicts with a pg_catalog table); but
1417          * this ensures reproducible results in case the table contains regproc,
1418          * regclass, etc columns.
1419          */
1420         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1421
1422         /*
1423          * If possible, specify the column list explicitly so that we have no
1424          * possibility of retrieving data in the wrong column order.  (The default
1425          * column ordering of COPY will not be what we want in certain corner
1426          * cases involving ADD COLUMN and inheritance.)
1427          */
1428         if (fout->remoteVersion >= 70300)
1429                 column_list = fmtCopyColumnList(tbinfo, clistBuf);
1430         else
1431                 column_list = "";               /* can't select columns in COPY */
1432
1433         if (oids && hasoids)
1434         {
1435                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1436                                                   fmtQualifiedId(fout->remoteVersion,
1437                                                                                  tbinfo->dobj.namespace->dobj.name,
1438                                                                                  classname),
1439                                                   column_list);
1440         }
1441         else if (tdinfo->filtercond)
1442         {
1443                 /* Note: this syntax is only supported in 8.2 and up */
1444                 appendPQExpBufferStr(q, "COPY (SELECT ");
1445                 /* klugery to get rid of parens in column list */
1446                 if (strlen(column_list) > 2)
1447                 {
1448                         appendPQExpBufferStr(q, column_list + 1);
1449                         q->data[q->len - 1] = ' ';
1450                 }
1451                 else
1452                         appendPQExpBufferStr(q, "* ");
1453                 appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1454                                                   fmtQualifiedId(fout->remoteVersion,
1455                                                                                  tbinfo->dobj.namespace->dobj.name,
1456                                                                                  classname),
1457                                                   tdinfo->filtercond);
1458         }
1459         else
1460         {
1461                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1462                                                   fmtQualifiedId(fout->remoteVersion,
1463                                                                                  tbinfo->dobj.namespace->dobj.name,
1464                                                                                  classname),
1465                                                   column_list);
1466         }
1467         res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1468         PQclear(res);
1469         destroyPQExpBuffer(clistBuf);
1470
1471         for (;;)
1472         {
1473                 ret = PQgetCopyData(conn, &copybuf, 0);
1474
1475                 if (ret < 0)
1476                         break;                          /* done or error */
1477
1478                 if (copybuf)
1479                 {
1480                         WriteData(fout, copybuf, ret);
1481                         PQfreemem(copybuf);
1482                 }
1483
1484                 /* ----------
1485                  * THROTTLE:
1486                  *
1487                  * There was considerable discussion in late July, 2000 regarding
1488                  * slowing down pg_dump when backing up large tables. Users with both
1489                  * slow & fast (multi-processor) machines experienced performance
1490                  * degradation when doing a backup.
1491                  *
1492                  * Initial attempts based on sleeping for a number of ms for each ms
1493                  * of work were deemed too complex, then a simple 'sleep in each loop'
1494                  * implementation was suggested. The latter failed because the loop
1495                  * was too tight. Finally, the following was implemented:
1496                  *
1497                  * If throttle is non-zero, then
1498                  *              See how long since the last sleep.
1499                  *              Work out how long to sleep (based on ratio).
1500                  *              If sleep is more than 100ms, then
1501                  *                      sleep
1502                  *                      reset timer
1503                  *              EndIf
1504                  * EndIf
1505                  *
1506                  * where the throttle value was the number of ms to sleep per ms of
1507                  * work. The calculation was done in each loop.
1508                  *
1509                  * Most of the hard work is done in the backend, and this solution
1510                  * still did not work particularly well: on slow machines, the ratio
1511                  * was 50:1, and on medium paced machines, 1:1, and on fast
1512                  * multi-processor machines, it had little or no effect, for reasons
1513                  * that were unclear.
1514                  *
1515                  * Further discussion ensued, and the proposal was dropped.
1516                  *
1517                  * For those people who want this feature, it can be implemented using
1518                  * gettimeofday in each loop, calculating the time since last sleep,
1519                  * multiplying that by the sleep ratio, then if the result is more
1520                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1521                  * function to sleep for a subsecond period ie.
1522                  *
1523                  * select(0, NULL, NULL, NULL, &tvi);
1524                  *
1525                  * This will return after the interval specified in the structure tvi.
1526                  * Finally, call gettimeofday again to save the 'last sleep time'.
1527                  * ----------
1528                  */
1529         }
1530         archprintf(fout, "\\.\n\n\n");
1531
1532         if (ret == -2)
1533         {
1534                 /* copy data transfer failed */
1535                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1536                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1537                 write_msg(NULL, "The command was: %s\n", q->data);
1538                 exit_nicely(1);
1539         }
1540
1541         /* Check command status and return to normal libpq state */
1542         res = PQgetResult(conn);
1543         if (PQresultStatus(res) != PGRES_COMMAND_OK)
1544         {
1545                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1546                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1547                 write_msg(NULL, "The command was: %s\n", q->data);
1548                 exit_nicely(1);
1549         }
1550         PQclear(res);
1551
1552         destroyPQExpBuffer(q);
1553         return 1;
1554 }
1555
1556 /*
1557  * Dump table data using INSERT commands.
1558  *
1559  * Caution: when we restore from an archive file direct to database, the
1560  * INSERT commands emitted by this function have to be parsed by
1561  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1562  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1563  */
1564 static int
1565 dumpTableData_insert(Archive *fout, DumpOptions *dopt, void *dcontext)
1566 {
1567         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1568         TableInfo  *tbinfo = tdinfo->tdtable;
1569         const char *classname = tbinfo->dobj.name;
1570         PQExpBuffer q = createPQExpBuffer();
1571         PQExpBuffer insertStmt = NULL;
1572         PGresult   *res;
1573         int                     tuple;
1574         int                     nfields;
1575         int                     field;
1576
1577         /*
1578          * Make sure we are in proper schema.  We will qualify the table name
1579          * below anyway (in case its name conflicts with a pg_catalog table); but
1580          * this ensures reproducible results in case the table contains regproc,
1581          * regclass, etc columns.
1582          */
1583         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
1584
1585         if (fout->remoteVersion >= 70100)
1586         {
1587                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1588                                                   "SELECT * FROM ONLY %s",
1589                                                   fmtQualifiedId(fout->remoteVersion,
1590                                                                                  tbinfo->dobj.namespace->dobj.name,
1591                                                                                  classname));
1592         }
1593         else
1594         {
1595                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1596                                                   "SELECT * FROM %s",
1597                                                   fmtQualifiedId(fout->remoteVersion,
1598                                                                                  tbinfo->dobj.namespace->dobj.name,
1599                                                                                  classname));
1600         }
1601         if (tdinfo->filtercond)
1602                 appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1603
1604         ExecuteSqlStatement(fout, q->data);
1605
1606         while (1)
1607         {
1608                 res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1609                                                           PGRES_TUPLES_OK);
1610                 nfields = PQnfields(res);
1611                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1612                 {
1613                         /*
1614                          * First time through, we build as much of the INSERT statement as
1615                          * possible in "insertStmt", which we can then just print for each
1616                          * line. If the table happens to have zero columns then this will
1617                          * be a complete statement, otherwise it will end in "VALUES(" and
1618                          * be ready to have the row's column values appended.
1619                          */
1620                         if (insertStmt == NULL)
1621                         {
1622                                 insertStmt = createPQExpBuffer();
1623                                 appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1624                                                                   fmtId(classname));
1625
1626                                 /* corner case for zero-column table */
1627                                 if (nfields == 0)
1628                                 {
1629                                         appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1630                                 }
1631                                 else
1632                                 {
1633                                         /* append the list of column names if required */
1634                                         if (dopt->column_inserts)
1635                                         {
1636                                                 appendPQExpBufferStr(insertStmt, "(");
1637                                                 for (field = 0; field < nfields; field++)
1638                                                 {
1639                                                         if (field > 0)
1640                                                                 appendPQExpBufferStr(insertStmt, ", ");
1641                                                         appendPQExpBufferStr(insertStmt,
1642                                                                                                  fmtId(PQfname(res, field)));
1643                                                 }
1644                                                 appendPQExpBufferStr(insertStmt, ") ");
1645                                         }
1646
1647                                         appendPQExpBufferStr(insertStmt, "VALUES (");
1648                                 }
1649                         }
1650
1651                         archputs(insertStmt->data, fout);
1652
1653                         /* if it is zero-column table then we're done */
1654                         if (nfields == 0)
1655                                 continue;
1656
1657                         for (field = 0; field < nfields; field++)
1658                         {
1659                                 if (field > 0)
1660                                         archputs(", ", fout);
1661                                 if (PQgetisnull(res, tuple, field))
1662                                 {
1663                                         archputs("NULL", fout);
1664                                         continue;
1665                                 }
1666
1667                                 /* XXX This code is partially duplicated in ruleutils.c */
1668                                 switch (PQftype(res, field))
1669                                 {
1670                                         case INT2OID:
1671                                         case INT4OID:
1672                                         case INT8OID:
1673                                         case OIDOID:
1674                                         case FLOAT4OID:
1675                                         case FLOAT8OID:
1676                                         case NUMERICOID:
1677                                                 {
1678                                                         /*
1679                                                          * These types are printed without quotes unless
1680                                                          * they contain values that aren't accepted by the
1681                                                          * scanner unquoted (e.g., 'NaN').  Note that
1682                                                          * strtod() and friends might accept NaN, so we
1683                                                          * can't use that to test.
1684                                                          *
1685                                                          * In reality we only need to defend against
1686                                                          * infinity and NaN, so we need not get too crazy
1687                                                          * about pattern matching here.
1688                                                          */
1689                                                         const char *s = PQgetvalue(res, tuple, field);
1690
1691                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1692                                                                 archputs(s, fout);
1693                                                         else
1694                                                                 archprintf(fout, "'%s'", s);
1695                                                 }
1696                                                 break;
1697
1698                                         case BITOID:
1699                                         case VARBITOID:
1700                                                 archprintf(fout, "B'%s'",
1701                                                                    PQgetvalue(res, tuple, field));
1702                                                 break;
1703
1704                                         case BOOLOID:
1705                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1706                                                         archputs("true", fout);
1707                                                 else
1708                                                         archputs("false", fout);
1709                                                 break;
1710
1711                                         default:
1712                                                 /* All other types are printed as string literals. */
1713                                                 resetPQExpBuffer(q);
1714                                                 appendStringLiteralAH(q,
1715                                                                                           PQgetvalue(res, tuple, field),
1716                                                                                           fout);
1717                                                 archputs(q->data, fout);
1718                                                 break;
1719                                 }
1720                         }
1721                         archputs(");\n", fout);
1722                 }
1723
1724                 if (PQntuples(res) <= 0)
1725                 {
1726                         PQclear(res);
1727                         break;
1728                 }
1729                 PQclear(res);
1730         }
1731
1732         archputs("\n\n", fout);
1733
1734         ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
1735
1736         destroyPQExpBuffer(q);
1737         if (insertStmt != NULL)
1738                 destroyPQExpBuffer(insertStmt);
1739
1740         return 1;
1741 }
1742
1743
1744 /*
1745  * dumpTableData -
1746  *        dump the contents of a single table
1747  *
1748  * Actually, this just makes an ArchiveEntry for the table contents.
1749  */
1750 static void
1751 dumpTableData(Archive *fout, DumpOptions *dopt, TableDataInfo *tdinfo)
1752 {
1753         TableInfo  *tbinfo = tdinfo->tdtable;
1754         PQExpBuffer copyBuf = createPQExpBuffer();
1755         PQExpBuffer clistBuf = createPQExpBuffer();
1756         DataDumperPtr dumpFn;
1757         char       *copyStmt;
1758
1759         if (!dopt->dump_inserts)
1760         {
1761                 /* Dump/restore using COPY */
1762                 dumpFn = dumpTableData_copy;
1763                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1764                 appendPQExpBuffer(copyBuf, "COPY %s ",
1765                                                   fmtId(tbinfo->dobj.name));
1766                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1767                                                   fmtCopyColumnList(tbinfo, clistBuf),
1768                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1769                 copyStmt = copyBuf->data;
1770         }
1771         else
1772         {
1773                 /* Restore using INSERT */
1774                 dumpFn = dumpTableData_insert;
1775                 copyStmt = NULL;
1776         }
1777
1778         /*
1779          * Note: although the TableDataInfo is a full DumpableObject, we treat its
1780          * dependency on its table as "special" and pass it to ArchiveEntry now.
1781          * See comments for BuildArchiveDependencies.
1782          */
1783         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1784                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1785                                  NULL, tbinfo->rolname,
1786                                  false, "TABLE DATA", SECTION_DATA,
1787                                  "", "", copyStmt,
1788                                  &(tbinfo->dobj.dumpId), 1,
1789                                  dumpFn, tdinfo);
1790
1791         destroyPQExpBuffer(copyBuf);
1792         destroyPQExpBuffer(clistBuf);
1793 }
1794
1795 /*
1796  * refreshMatViewData -
1797  *        load or refresh the contents of a single materialized view
1798  *
1799  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
1800  * statement.
1801  */
1802 static void
1803 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
1804 {
1805         TableInfo  *tbinfo = tdinfo->tdtable;
1806         PQExpBuffer q;
1807
1808         /* If the materialized view is not flagged as populated, skip this. */
1809         if (!tbinfo->relispopulated)
1810                 return;
1811
1812         q = createPQExpBuffer();
1813
1814         appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
1815                                           fmtId(tbinfo->dobj.name));
1816
1817         ArchiveEntry(fout,
1818                                  tdinfo->dobj.catId,    /* catalog ID */
1819                                  tdinfo->dobj.dumpId,   /* dump ID */
1820                                  tbinfo->dobj.name,             /* Name */
1821                                  tbinfo->dobj.namespace->dobj.name,             /* Namespace */
1822                                  NULL,                  /* Tablespace */
1823                                  tbinfo->rolname,               /* Owner */
1824                                  false,                 /* with oids */
1825                                  "MATERIALIZED VIEW DATA",              /* Desc */
1826                                  SECTION_POST_DATA,             /* Section */
1827                                  q->data,               /* Create */
1828                                  "",                    /* Del */
1829                                  NULL,                  /* Copy */
1830                                  tdinfo->dobj.dependencies,             /* Deps */
1831                                  tdinfo->dobj.nDeps,    /* # Deps */
1832                                  NULL,                  /* Dumper */
1833                                  NULL);                 /* Dumper Arg */
1834
1835         destroyPQExpBuffer(q);
1836 }
1837
1838 /*
1839  * getTableData -
1840  *        set up dumpable objects representing the contents of tables
1841  */
1842 static void
1843 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids)
1844 {
1845         int                     i;
1846
1847         for (i = 0; i < numTables; i++)
1848         {
1849                 if (tblinfo[i].dobj.dump)
1850                         makeTableDataInfo(dopt, &(tblinfo[i]), oids);
1851         }
1852 }
1853
1854 /*
1855  * Make a dumpable object for the data of this specific table
1856  *
1857  * Note: we make a TableDataInfo if and only if we are going to dump the
1858  * table data; the "dump" flag in such objects isn't used.
1859  */
1860 static void
1861 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
1862 {
1863         TableDataInfo *tdinfo;
1864
1865         /*
1866          * Nothing to do if we already decided to dump the table.  This will
1867          * happen for "config" tables.
1868          */
1869         if (tbinfo->dataObj != NULL)
1870                 return;
1871
1872         /* Skip VIEWs (no data to dump) */
1873         if (tbinfo->relkind == RELKIND_VIEW)
1874                 return;
1875         /* Skip FOREIGN TABLEs (no data to dump) */
1876         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
1877                 return;
1878
1879         /* Don't dump data in unlogged tables, if so requested */
1880         if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
1881                 dopt->no_unlogged_table_data)
1882                 return;
1883
1884         /* Check that the data is not explicitly excluded */
1885         if (simple_oid_list_member(&tabledata_exclude_oids,
1886                                                            tbinfo->dobj.catId.oid))
1887                 return;
1888
1889         /* OK, let's dump it */
1890         tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
1891
1892         if (tbinfo->relkind == RELKIND_MATVIEW)
1893                 tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
1894         else
1895                 tdinfo->dobj.objType = DO_TABLE_DATA;
1896
1897         /*
1898          * Note: use tableoid 0 so that this object won't be mistaken for
1899          * something that pg_depend entries apply to.
1900          */
1901         tdinfo->dobj.catId.tableoid = 0;
1902         tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
1903         AssignDumpId(&tdinfo->dobj);
1904         tdinfo->dobj.name = tbinfo->dobj.name;
1905         tdinfo->dobj.namespace = tbinfo->dobj.namespace;
1906         tdinfo->tdtable = tbinfo;
1907         tdinfo->oids = oids;
1908         tdinfo->filtercond = NULL;      /* might get set later */
1909         addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
1910
1911         tbinfo->dataObj = tdinfo;
1912 }
1913
1914 /*
1915  * The refresh for a materialized view must be dependent on the refresh for
1916  * any materialized view that this one is dependent on.
1917  *
1918  * This must be called after all the objects are created, but before they are
1919  * sorted.
1920  */
1921 static void
1922 buildMatViewRefreshDependencies(Archive *fout)
1923 {
1924         PQExpBuffer query;
1925         PGresult   *res;
1926         int                     ntups,
1927                                 i;
1928         int                     i_classid,
1929                                 i_objid,
1930                                 i_refobjid;
1931
1932         /* No Mat Views before 9.3. */
1933         if (fout->remoteVersion < 90300)
1934                 return;
1935
1936         /* Make sure we are in proper schema */
1937         selectSourceSchema(fout, "pg_catalog");
1938
1939         query = createPQExpBuffer();
1940
1941         appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
1942                                                  "( "
1943                                         "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
1944                                                  "FROM pg_depend d1 "
1945                                                  "JOIN pg_class c1 ON c1.oid = d1.objid "
1946                                                  "AND c1.relkind = 'm' "
1947                                                  "JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
1948                                   "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
1949                                                  "AND d2.objid = r1.oid "
1950                                                  "AND d2.refobjid <> d1.objid "
1951                                                  "JOIN pg_class c2 ON c2.oid = d2.refobjid "
1952                                                  "AND c2.relkind IN ('m','v') "
1953                                                  "WHERE d1.classid = 'pg_class'::regclass "
1954                                                  "UNION "
1955                                                  "SELECT w.objid, d3.refobjid, c3.relkind "
1956                                                  "FROM w "
1957                                                  "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
1958                                   "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
1959                                                  "AND d3.objid = r3.oid "
1960                                                  "AND d3.refobjid <> w.refobjid "
1961                                                  "JOIN pg_class c3 ON c3.oid = d3.refobjid "
1962                                                  "AND c3.relkind IN ('m','v') "
1963                                                  ") "
1964                           "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
1965                                                  "FROM w "
1966                                                  "WHERE refrelkind = 'm'");
1967
1968         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1969
1970         ntups = PQntuples(res);
1971
1972         i_classid = PQfnumber(res, "classid");
1973         i_objid = PQfnumber(res, "objid");
1974         i_refobjid = PQfnumber(res, "refobjid");
1975
1976         for (i = 0; i < ntups; i++)
1977         {
1978                 CatalogId       objId;
1979                 CatalogId       refobjId;
1980                 DumpableObject *dobj;
1981                 DumpableObject *refdobj;
1982                 TableInfo  *tbinfo;
1983                 TableInfo  *reftbinfo;
1984
1985                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
1986                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
1987                 refobjId.tableoid = objId.tableoid;
1988                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
1989
1990                 dobj = findObjectByCatalogId(objId);
1991                 if (dobj == NULL)
1992                         continue;
1993
1994                 Assert(dobj->objType == DO_TABLE);
1995                 tbinfo = (TableInfo *) dobj;
1996                 Assert(tbinfo->relkind == RELKIND_MATVIEW);
1997                 dobj = (DumpableObject *) tbinfo->dataObj;
1998                 if (dobj == NULL)
1999                         continue;
2000                 Assert(dobj->objType == DO_REFRESH_MATVIEW);
2001
2002                 refdobj = findObjectByCatalogId(refobjId);
2003                 if (refdobj == NULL)
2004                         continue;
2005
2006                 Assert(refdobj->objType == DO_TABLE);
2007                 reftbinfo = (TableInfo *) refdobj;
2008                 Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2009                 refdobj = (DumpableObject *) reftbinfo->dataObj;
2010                 if (refdobj == NULL)
2011                         continue;
2012                 Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2013
2014                 addObjectDependency(dobj, refdobj->dumpId);
2015
2016                 if (!reftbinfo->relispopulated)
2017                         tbinfo->relispopulated = false;
2018         }
2019
2020         PQclear(res);
2021
2022         destroyPQExpBuffer(query);
2023 }
2024
2025 /*
2026  * getTableDataFKConstraints -
2027  *        add dump-order dependencies reflecting foreign key constraints
2028  *
2029  * This code is executed only in a data-only dump --- in schema+data dumps
2030  * we handle foreign key issues by not creating the FK constraints until
2031  * after the data is loaded.  In a data-only dump, however, we want to
2032  * order the table data objects in such a way that a table's referenced
2033  * tables are restored first.  (In the presence of circular references or
2034  * self-references this may be impossible; we'll detect and complain about
2035  * that during the dependency sorting step.)
2036  */
2037 static void
2038 getTableDataFKConstraints(void)
2039 {
2040         DumpableObject **dobjs;
2041         int                     numObjs;
2042         int                     i;
2043
2044         /* Search through all the dumpable objects for FK constraints */
2045         getDumpableObjects(&dobjs, &numObjs);
2046         for (i = 0; i < numObjs; i++)
2047         {
2048                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2049                 {
2050                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2051                         TableInfo  *ftable;
2052
2053                         /* Not interesting unless both tables are to be dumped */
2054                         if (cinfo->contable == NULL ||
2055                                 cinfo->contable->dataObj == NULL)
2056                                 continue;
2057                         ftable = findTableByOid(cinfo->confrelid);
2058                         if (ftable == NULL ||
2059                                 ftable->dataObj == NULL)
2060                                 continue;
2061
2062                         /*
2063                          * Okay, make referencing table's TABLE_DATA object depend on the
2064                          * referenced table's TABLE_DATA object.
2065                          */
2066                         addObjectDependency(&cinfo->contable->dataObj->dobj,
2067                                                                 ftable->dataObj->dobj.dumpId);
2068                 }
2069         }
2070         free(dobjs);
2071 }
2072
2073
2074 /*
2075  * guessConstraintInheritance:
2076  *      In pre-8.4 databases, we can't tell for certain which constraints
2077  *      are inherited.  We assume a CHECK constraint is inherited if its name
2078  *      matches the name of any constraint in the parent.  Originally this code
2079  *      tried to compare the expression texts, but that can fail for various
2080  *      reasons --- for example, if the parent and child tables are in different
2081  *      schemas, reverse-listing of function calls may produce different text
2082  *      (schema-qualified or not) depending on search path.
2083  *
2084  *      In 8.4 and up we can rely on the conislocal field to decide which
2085  *      constraints must be dumped; much safer.
2086  *
2087  *      This function assumes all conislocal flags were initialized to TRUE.
2088  *      It clears the flag on anything that seems to be inherited.
2089  */
2090 static void
2091 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2092 {
2093         int                     i,
2094                                 j,
2095                                 k;
2096
2097         for (i = 0; i < numTables; i++)
2098         {
2099                 TableInfo  *tbinfo = &(tblinfo[i]);
2100                 int                     numParents;
2101                 TableInfo **parents;
2102                 TableInfo  *parent;
2103
2104                 /* Sequences and views never have parents */
2105                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
2106                         tbinfo->relkind == RELKIND_VIEW)
2107                         continue;
2108
2109                 /* Don't bother computing anything for non-target tables, either */
2110                 if (!tbinfo->dobj.dump)
2111                         continue;
2112
2113                 numParents = tbinfo->numParents;
2114                 parents = tbinfo->parents;
2115
2116                 if (numParents == 0)
2117                         continue;                       /* nothing to see here, move along */
2118
2119                 /* scan for inherited CHECK constraints */
2120                 for (j = 0; j < tbinfo->ncheck; j++)
2121                 {
2122                         ConstraintInfo *constr;
2123
2124                         constr = &(tbinfo->checkexprs[j]);
2125
2126                         for (k = 0; k < numParents; k++)
2127                         {
2128                                 int                     l;
2129
2130                                 parent = parents[k];
2131                                 for (l = 0; l < parent->ncheck; l++)
2132                                 {
2133                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2134
2135                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2136                                         {
2137                                                 constr->conislocal = false;
2138                                                 break;
2139                                         }
2140                                 }
2141                                 if (!constr->conislocal)
2142                                         break;
2143                         }
2144                 }
2145         }
2146 }
2147
2148
2149 /*
2150  * dumpDatabase:
2151  *      dump the database definition
2152  */
2153 static void
2154 dumpDatabase(Archive *fout, DumpOptions *dopt)
2155 {
2156         PQExpBuffer dbQry = createPQExpBuffer();
2157         PQExpBuffer delQry = createPQExpBuffer();
2158         PQExpBuffer creaQry = createPQExpBuffer();
2159         PGconn     *conn = GetConnection(fout);
2160         PGresult   *res;
2161         int                     i_tableoid,
2162                                 i_oid,
2163                                 i_dba,
2164                                 i_encoding,
2165                                 i_collate,
2166                                 i_ctype,
2167                                 i_frozenxid,
2168                                 i_minmxid,
2169                                 i_tablespace;
2170         CatalogId       dbCatId;
2171         DumpId          dbDumpId;
2172         const char *datname,
2173                            *dba,
2174                            *encoding,
2175                            *collate,
2176                            *ctype,
2177                            *tablespace;
2178         uint32          frozenxid,
2179                                 minmxid;
2180
2181         datname = PQdb(conn);
2182
2183         if (g_verbose)
2184                 write_msg(NULL, "saving database definition\n");
2185
2186         /* Make sure we are in proper schema */
2187         selectSourceSchema(fout, "pg_catalog");
2188
2189         /* Get the database owner and parameters from pg_database */
2190         if (fout->remoteVersion >= 90300)
2191         {
2192                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2193                                                   "(%s datdba) AS dba, "
2194                                                   "pg_encoding_to_char(encoding) AS encoding, "
2195                                                   "datcollate, datctype, datfrozenxid, datminmxid, "
2196                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2197                                           "shobj_description(oid, 'pg_database') AS description "
2198
2199                                                   "FROM pg_database "
2200                                                   "WHERE datname = ",
2201                                                   username_subquery);
2202                 appendStringLiteralAH(dbQry, datname, fout);
2203         }
2204         else if (fout->remoteVersion >= 80400)
2205         {
2206                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2207                                                   "(%s datdba) AS dba, "
2208                                                   "pg_encoding_to_char(encoding) AS encoding, "
2209                                           "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2210                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2211                                           "shobj_description(oid, 'pg_database') AS description "
2212
2213                                                   "FROM pg_database "
2214                                                   "WHERE datname = ",
2215                                                   username_subquery);
2216                 appendStringLiteralAH(dbQry, datname, fout);
2217         }
2218         else if (fout->remoteVersion >= 80200)
2219         {
2220                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2221                                                   "(%s datdba) AS dba, "
2222                                                   "pg_encoding_to_char(encoding) AS encoding, "
2223                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2224                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2225                                           "shobj_description(oid, 'pg_database') AS description "
2226
2227                                                   "FROM pg_database "
2228                                                   "WHERE datname = ",
2229                                                   username_subquery);
2230                 appendStringLiteralAH(dbQry, datname, fout);
2231         }
2232         else if (fout->remoteVersion >= 80000)
2233         {
2234                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2235                                                   "(%s datdba) AS dba, "
2236                                                   "pg_encoding_to_char(encoding) AS encoding, "
2237                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2238                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2239                                                   "FROM pg_database "
2240                                                   "WHERE datname = ",
2241                                                   username_subquery);
2242                 appendStringLiteralAH(dbQry, datname, fout);
2243         }
2244         else if (fout->remoteVersion >= 70100)
2245         {
2246                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
2247                                                   "(%s datdba) AS dba, "
2248                                                   "pg_encoding_to_char(encoding) AS encoding, "
2249                                                   "NULL AS datcollate, NULL AS datctype, "
2250                                                   "0 AS datfrozenxid, 0 AS datminmxid, "
2251                                                   "NULL AS tablespace "
2252                                                   "FROM pg_database "
2253                                                   "WHERE datname = ",
2254                                                   username_subquery);
2255                 appendStringLiteralAH(dbQry, datname, fout);
2256         }
2257         else
2258         {
2259                 appendPQExpBuffer(dbQry, "SELECT "
2260                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
2261                                                   "oid, "
2262                                                   "(%s datdba) AS dba, "
2263                                                   "pg_encoding_to_char(encoding) AS encoding, "
2264                                                   "NULL AS datcollate, NULL AS datctype, "
2265                                                   "0 AS datfrozenxid, 0 AS datminmxid, "
2266                                                   "NULL AS tablespace "
2267                                                   "FROM pg_database "
2268                                                   "WHERE datname = ",
2269                                                   username_subquery);
2270                 appendStringLiteralAH(dbQry, datname, fout);
2271         }
2272
2273         res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2274
2275         i_tableoid = PQfnumber(res, "tableoid");
2276         i_oid = PQfnumber(res, "oid");
2277         i_dba = PQfnumber(res, "dba");
2278         i_encoding = PQfnumber(res, "encoding");
2279         i_collate = PQfnumber(res, "datcollate");
2280         i_ctype = PQfnumber(res, "datctype");
2281         i_frozenxid = PQfnumber(res, "datfrozenxid");
2282         i_minmxid = PQfnumber(res, "datminmxid");
2283         i_tablespace = PQfnumber(res, "tablespace");
2284
2285         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2286         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2287         dba = PQgetvalue(res, 0, i_dba);
2288         encoding = PQgetvalue(res, 0, i_encoding);
2289         collate = PQgetvalue(res, 0, i_collate);
2290         ctype = PQgetvalue(res, 0, i_ctype);
2291         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2292         minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2293         tablespace = PQgetvalue(res, 0, i_tablespace);
2294
2295         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2296                                           fmtId(datname));
2297         if (strlen(encoding) > 0)
2298         {
2299                 appendPQExpBufferStr(creaQry, " ENCODING = ");
2300                 appendStringLiteralAH(creaQry, encoding, fout);
2301         }
2302         if (strlen(collate) > 0)
2303         {
2304                 appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2305                 appendStringLiteralAH(creaQry, collate, fout);
2306         }
2307         if (strlen(ctype) > 0)
2308         {
2309                 appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2310                 appendStringLiteralAH(creaQry, ctype, fout);
2311         }
2312         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
2313                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2314                                                   fmtId(tablespace));
2315         appendPQExpBufferStr(creaQry, ";\n");
2316
2317         if (dopt->binary_upgrade)
2318         {
2319                 appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2320                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2321                                                   "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2322                                                   "WHERE        datname = ",
2323                                                   frozenxid, minmxid);
2324                 appendStringLiteralAH(creaQry, datname, fout);
2325                 appendPQExpBufferStr(creaQry, ";\n");
2326
2327         }
2328
2329         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2330                                           fmtId(datname));
2331
2332         dbDumpId = createDumpId();
2333
2334         ArchiveEntry(fout,
2335                                  dbCatId,               /* catalog ID */
2336                                  dbDumpId,              /* dump ID */
2337                                  datname,               /* Name */
2338                                  NULL,                  /* Namespace */
2339                                  NULL,                  /* Tablespace */
2340                                  dba,                   /* Owner */
2341                                  false,                 /* with oids */
2342                                  "DATABASE",    /* Desc */
2343                                  SECTION_PRE_DATA,              /* Section */
2344                                  creaQry->data, /* Create */
2345                                  delQry->data,  /* Del */
2346                                  NULL,                  /* Copy */
2347                                  NULL,                  /* Deps */
2348                                  0,                             /* # Deps */
2349                                  NULL,                  /* Dumper */
2350                                  NULL);                 /* Dumper Arg */
2351
2352         /*
2353          * pg_largeobject and pg_largeobject_metadata come from the old system
2354          * intact, so set their relfrozenxids and relminmxids.
2355          */
2356         if (dopt->binary_upgrade)
2357         {
2358                 PGresult   *lo_res;
2359                 PQExpBuffer loFrozenQry = createPQExpBuffer();
2360                 PQExpBuffer loOutQry = createPQExpBuffer();
2361                 int                     i_relfrozenxid,
2362                                         i_relminmxid;
2363
2364                 /*
2365                  * pg_largeobject
2366                  */
2367                 if (fout->remoteVersion >= 90300)
2368                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2369                                                           "FROM pg_catalog.pg_class\n"
2370                                                           "WHERE oid = %u;\n",
2371                                                           LargeObjectRelationId);
2372                 else
2373                         appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2374                                                           "FROM pg_catalog.pg_class\n"
2375                                                           "WHERE oid = %u;\n",
2376                                                           LargeObjectRelationId);
2377
2378                 lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2379
2380                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2381                 i_relminmxid = PQfnumber(lo_res, "relminmxid");
2382
2383                 appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2384                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2385                                                   "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2386                                                   "WHERE oid = %u;\n",
2387                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2388                                                   atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2389                                                   LargeObjectRelationId);
2390                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
2391                                          "pg_largeobject", NULL, NULL, "",
2392                                          false, "pg_largeobject", SECTION_PRE_DATA,
2393                                          loOutQry->data, "", NULL,
2394                                          NULL, 0,
2395                                          NULL, NULL);
2396
2397                 PQclear(lo_res);
2398
2399                 /*
2400                  * pg_largeobject_metadata
2401                  */
2402                 if (fout->remoteVersion >= 90000)
2403                 {
2404                         resetPQExpBuffer(loFrozenQry);
2405                         resetPQExpBuffer(loOutQry);
2406
2407                         if (fout->remoteVersion >= 90300)
2408                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2409                                                                   "FROM pg_catalog.pg_class\n"
2410                                                                   "WHERE oid = %u;\n",
2411                                                                   LargeObjectMetadataRelationId);
2412                         else
2413                                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2414                                                                   "FROM pg_catalog.pg_class\n"
2415                                                                   "WHERE oid = %u;\n",
2416                                                                   LargeObjectMetadataRelationId);
2417
2418                         lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2419
2420                         i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2421                         i_relminmxid = PQfnumber(lo_res, "relminmxid");
2422
2423                         appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2424                         appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2425                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2426                                                           "WHERE oid = %u;\n",
2427                                                           atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2428                                                           atoi(PQgetvalue(lo_res, 0, i_relminmxid)),
2429                                                           LargeObjectMetadataRelationId);
2430                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
2431                                                  "pg_largeobject_metadata", NULL, NULL, "",
2432                                                  false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2433                                                  loOutQry->data, "", NULL,
2434                                                  NULL, 0,
2435                                                  NULL, NULL);
2436
2437                         PQclear(lo_res);
2438                 }
2439
2440                 destroyPQExpBuffer(loFrozenQry);
2441                 destroyPQExpBuffer(loOutQry);
2442         }
2443
2444         /* Dump DB comment if any */
2445         if (fout->remoteVersion >= 80200)
2446         {
2447                 /*
2448                  * 8.2 keeps comments on shared objects in a shared table, so we
2449                  * cannot use the dumpComment used for other database objects.
2450                  */
2451                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2452
2453                 if (comment && strlen(comment))
2454                 {
2455                         resetPQExpBuffer(dbQry);
2456
2457                         /*
2458                          * Generates warning when loaded into a differently-named
2459                          * database.
2460                          */
2461                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
2462                         appendStringLiteralAH(dbQry, comment, fout);
2463                         appendPQExpBufferStr(dbQry, ";\n");
2464
2465                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2466                                                  dba, false, "COMMENT", SECTION_NONE,
2467                                                  dbQry->data, "", NULL,
2468                                                  &dbDumpId, 1, NULL, NULL);
2469                 }
2470         }
2471         else
2472         {
2473                 resetPQExpBuffer(dbQry);
2474                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
2475                 dumpComment(fout, dopt, dbQry->data, NULL, "",
2476                                         dbCatId, 0, dbDumpId);
2477         }
2478
2479         /* Dump shared security label. */
2480         if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2481         {
2482                 PGresult   *shres;
2483                 PQExpBuffer seclabelQry;
2484
2485                 seclabelQry = createPQExpBuffer();
2486
2487                 buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2488                 shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2489                 resetPQExpBuffer(seclabelQry);
2490                 emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2491                 if (strlen(seclabelQry->data))
2492                         ArchiveEntry(fout, dbCatId, createDumpId(), datname, NULL, NULL,
2493                                                  dba, false, "SECURITY LABEL", SECTION_NONE,
2494                                                  seclabelQry->data, "", NULL,
2495                                                  &dbDumpId, 1, NULL, NULL);
2496                 destroyPQExpBuffer(seclabelQry);
2497                 PQclear(shres);
2498         }
2499
2500         PQclear(res);
2501
2502         destroyPQExpBuffer(dbQry);
2503         destroyPQExpBuffer(delQry);
2504         destroyPQExpBuffer(creaQry);
2505 }
2506
2507 /*
2508  * dumpEncoding: put the correct encoding into the archive
2509  */
2510 static void
2511 dumpEncoding(Archive *AH)
2512 {
2513         const char *encname = pg_encoding_to_char(AH->encoding);
2514         PQExpBuffer qry = createPQExpBuffer();
2515
2516         if (g_verbose)
2517                 write_msg(NULL, "saving encoding = %s\n", encname);
2518
2519         appendPQExpBufferStr(qry, "SET client_encoding = ");
2520         appendStringLiteralAH(qry, encname, AH);
2521         appendPQExpBufferStr(qry, ";\n");
2522
2523         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2524                                  "ENCODING", NULL, NULL, "",
2525                                  false, "ENCODING", SECTION_PRE_DATA,
2526                                  qry->data, "", NULL,
2527                                  NULL, 0,
2528                                  NULL, NULL);
2529
2530         destroyPQExpBuffer(qry);
2531 }
2532
2533
2534 /*
2535  * dumpStdStrings: put the correct escape string behavior into the archive
2536  */
2537 static void
2538 dumpStdStrings(Archive *AH)
2539 {
2540         const char *stdstrings = AH->std_strings ? "on" : "off";
2541         PQExpBuffer qry = createPQExpBuffer();
2542
2543         if (g_verbose)
2544                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
2545                                   stdstrings);
2546
2547         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
2548                                           stdstrings);
2549
2550         ArchiveEntry(AH, nilCatalogId, createDumpId(),
2551                                  "STDSTRINGS", NULL, NULL, "",
2552                                  false, "STDSTRINGS", SECTION_PRE_DATA,
2553                                  qry->data, "", NULL,
2554                                  NULL, 0,
2555                                  NULL, NULL);
2556
2557         destroyPQExpBuffer(qry);
2558 }
2559
2560
2561 /*
2562  * getBlobs:
2563  *      Collect schema-level data about large objects
2564  */
2565 static void
2566 getBlobs(Archive *fout)
2567 {
2568         PQExpBuffer blobQry = createPQExpBuffer();
2569         BlobInfo   *binfo;
2570         DumpableObject *bdata;
2571         PGresult   *res;
2572         int                     ntups;
2573         int                     i;
2574
2575         /* Verbose message */
2576         if (g_verbose)
2577                 write_msg(NULL, "reading large objects\n");
2578
2579         /* Make sure we are in proper schema */
2580         selectSourceSchema(fout, "pg_catalog");
2581
2582         /* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
2583         if (fout->remoteVersion >= 90000)
2584                 appendPQExpBuffer(blobQry,
2585                                                   "SELECT oid, (%s lomowner) AS rolname, lomacl"
2586                                                   " FROM pg_largeobject_metadata",
2587                                                   username_subquery);
2588         else if (fout->remoteVersion >= 70100)
2589                 appendPQExpBufferStr(blobQry,
2590                                                          "SELECT DISTINCT loid, NULL::oid, NULL::oid"
2591                                                          " FROM pg_largeobject");
2592         else
2593                 appendPQExpBufferStr(blobQry,
2594                                                          "SELECT oid, NULL::oid, NULL::oid"
2595                                                          " FROM pg_class WHERE relkind = 'l'");
2596
2597         res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
2598
2599         ntups = PQntuples(res);
2600         if (ntups > 0)
2601         {
2602                 /*
2603                  * Each large object has its own BLOB archive entry.
2604                  */
2605                 binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
2606
2607                 for (i = 0; i < ntups; i++)
2608                 {
2609                         binfo[i].dobj.objType = DO_BLOB;
2610                         binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
2611                         binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, 0));
2612                         AssignDumpId(&binfo[i].dobj);
2613
2614                         binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, 0));
2615                         if (!PQgetisnull(res, i, 1))
2616                                 binfo[i].rolname = pg_strdup(PQgetvalue(res, i, 1));
2617                         else
2618                                 binfo[i].rolname = "";
2619                         if (!PQgetisnull(res, i, 2))
2620                                 binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, 2));
2621                         else
2622                                 binfo[i].blobacl = NULL;
2623                 }
2624
2625                 /*
2626                  * If we have any large objects, a "BLOBS" archive entry is needed.
2627                  * This is just a placeholder for sorting; it carries no data now.
2628                  */
2629                 bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
2630                 bdata->objType = DO_BLOB_DATA;
2631                 bdata->catId = nilCatalogId;
2632                 AssignDumpId(bdata);
2633                 bdata->name = pg_strdup("BLOBS");
2634         }
2635
2636         PQclear(res);
2637         destroyPQExpBuffer(blobQry);
2638 }
2639
2640 /*
2641  * dumpBlob
2642  *
2643  * dump the definition (metadata) of the given large object
2644  */
2645 static void
2646 dumpBlob(Archive *fout, DumpOptions *dopt, BlobInfo *binfo)
2647 {
2648         PQExpBuffer cquery = createPQExpBuffer();
2649         PQExpBuffer dquery = createPQExpBuffer();
2650
2651         appendPQExpBuffer(cquery,
2652                                           "SELECT pg_catalog.lo_create('%s');\n",
2653                                           binfo->dobj.name);
2654
2655         appendPQExpBuffer(dquery,
2656                                           "SELECT pg_catalog.lo_unlink('%s');\n",
2657                                           binfo->dobj.name);
2658
2659         ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
2660                                  binfo->dobj.name,
2661                                  NULL, NULL,
2662                                  binfo->rolname, false,
2663                                  "BLOB", SECTION_PRE_DATA,
2664                                  cquery->data, dquery->data, NULL,
2665                                  NULL, 0,
2666                                  NULL, NULL);
2667
2668         /* set up tag for comment and/or ACL */
2669         resetPQExpBuffer(cquery);
2670         appendPQExpBuffer(cquery, "LARGE OBJECT %s", binfo->dobj.name);
2671
2672         /* Dump comment if any */
2673         dumpComment(fout, dopt, cquery->data,
2674                                 NULL, binfo->rolname,
2675                                 binfo->dobj.catId, 0, binfo->dobj.dumpId);
2676
2677         /* Dump security label if any */
2678         dumpSecLabel(fout, dopt, cquery->data,
2679                                  NULL, binfo->rolname,
2680                                  binfo->dobj.catId, 0, binfo->dobj.dumpId);
2681
2682         /* Dump ACL if any */
2683         if (binfo->blobacl)
2684                 dumpACL(fout, dopt, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
2685                                 binfo->dobj.name, NULL, cquery->data,
2686                                 NULL, binfo->rolname, binfo->blobacl);
2687
2688         destroyPQExpBuffer(cquery);
2689         destroyPQExpBuffer(dquery);
2690 }
2691
2692 /*
2693  * dumpBlobs:
2694  *      dump the data contents of all large objects
2695  */
2696 static int
2697 dumpBlobs(Archive *fout, DumpOptions *dopt, void *arg)
2698 {
2699         const char *blobQry;
2700         const char *blobFetchQry;
2701         PGconn     *conn = GetConnection(fout);
2702         PGresult   *res;
2703         char            buf[LOBBUFSIZE];
2704         int                     ntups;
2705         int                     i;
2706         int                     cnt;
2707
2708         if (g_verbose)
2709                 write_msg(NULL, "saving large objects\n");
2710
2711         /* Make sure we are in proper schema */
2712         selectSourceSchema(fout, "pg_catalog");
2713
2714         /*
2715          * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
2716          * the already-in-memory dumpable objects instead...
2717          */
2718         if (fout->remoteVersion >= 90000)
2719                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
2720         else if (fout->remoteVersion >= 70100)
2721                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
2722         else
2723                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
2724
2725         ExecuteSqlStatement(fout, blobQry);
2726
2727         /* Command to fetch from cursor */
2728         blobFetchQry = "FETCH 1000 IN bloboid";
2729
2730         do
2731         {
2732                 /* Do a fetch */
2733                 res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
2734
2735                 /* Process the tuples, if any */
2736                 ntups = PQntuples(res);
2737                 for (i = 0; i < ntups; i++)
2738                 {
2739                         Oid                     blobOid;
2740                         int                     loFd;
2741
2742                         blobOid = atooid(PQgetvalue(res, i, 0));
2743                         /* Open the BLOB */
2744                         loFd = lo_open(conn, blobOid, INV_READ);
2745                         if (loFd == -1)
2746                                 exit_horribly(NULL, "could not open large object %u: %s",
2747                                                           blobOid, PQerrorMessage(conn));
2748
2749                         StartBlob(fout, blobOid);
2750
2751                         /* Now read it in chunks, sending data to archive */
2752                         do
2753                         {
2754                                 cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
2755                                 if (cnt < 0)
2756                                         exit_horribly(NULL, "error reading large object %u: %s",
2757                                                                   blobOid, PQerrorMessage(conn));
2758
2759                                 WriteData(fout, buf, cnt);
2760                         } while (cnt > 0);
2761
2762                         lo_close(conn, loFd);
2763
2764                         EndBlob(fout, blobOid);
2765                 }
2766
2767                 PQclear(res);
2768         } while (ntups > 0);
2769
2770         return 1;
2771 }
2772
2773 /*
2774  * getPolicies
2775  *        get information about policies on a dumpable table.
2776  */
2777 void
2778 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
2779 {
2780         PQExpBuffer query;
2781         PGresult   *res;
2782         PolicyInfo *polinfo;
2783         int                     i_oid;
2784         int                     i_tableoid;
2785         int                     i_polname;
2786         int                     i_polcmd;
2787         int                     i_polroles;
2788         int                     i_polqual;
2789         int                     i_polwithcheck;
2790         int                     i,
2791                                 j,
2792                                 ntups;
2793
2794         if (fout->remoteVersion < 90500)
2795                 return;
2796
2797         query = createPQExpBuffer();
2798
2799         for (i = 0; i < numTables; i++)
2800         {
2801                 TableInfo  *tbinfo = &tblinfo[i];
2802
2803                 /* Ignore row security on tables not to be dumped */
2804                 if (!tbinfo->dobj.dump)
2805                         continue;
2806
2807                 if (g_verbose)
2808                         write_msg(NULL, "reading row security enabled for table \"%s\".\"%s\"\n",
2809                                           tbinfo->dobj.namespace->dobj.name,
2810                                           tbinfo->dobj.name);
2811
2812                 /*
2813                  * Get row security enabled information for the table. We represent
2814                  * RLS enabled on a table by creating PolicyInfo object with an
2815                  * empty policy.
2816                  */
2817                 if (tbinfo->rowsec)
2818                 {
2819                         /*
2820                          * Note: use tableoid 0 so that this object won't be mistaken for
2821                          * something that pg_depend entries apply to.
2822                          */
2823                         polinfo = pg_malloc(sizeof(PolicyInfo));
2824                         polinfo->dobj.objType = DO_POLICY;
2825                         polinfo->dobj.catId.tableoid = 0;
2826                         polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2827                         AssignDumpId(&polinfo->dobj);
2828                         polinfo->dobj.namespace = tbinfo->dobj.namespace;
2829                         polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
2830                         polinfo->poltable = tbinfo;
2831                         polinfo->polname = NULL;
2832                         polinfo->polcmd = NULL;
2833                         polinfo->polroles = NULL;
2834                         polinfo->polqual = NULL;
2835                         polinfo->polwithcheck = NULL;
2836                 }
2837
2838                 if (g_verbose)
2839                         write_msg(NULL, "reading policies for table \"%s\".\"%s\"\n",
2840                                           tbinfo->dobj.namespace->dobj.name,
2841                                           tbinfo->dobj.name);
2842
2843                 /*
2844                  * select table schema to ensure regproc name is qualified if needed
2845                  */
2846                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
2847
2848                 resetPQExpBuffer(query);
2849
2850                 /* Get the policies for the table. */
2851                 appendPQExpBuffer(query,
2852                                                   "SELECT oid, tableoid, pol.polname, pol.polcmd, "
2853                                                   "CASE WHEN pol.polroles = '{0}' THEN 'PUBLIC' ELSE "
2854                                                   "   array_to_string(ARRAY(SELECT rolname from pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
2855                                                   "pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
2856                                 "pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
2857                                                   "FROM pg_catalog.pg_policy pol "
2858                                                   "WHERE polrelid = '%u'",
2859                                                   tbinfo->dobj.catId.oid);
2860                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2861
2862                 ntups = PQntuples(res);
2863
2864                 if (ntups == 0)
2865                 {
2866                         /*
2867                          * No explicit policies to handle (only the default-deny policy,
2868                          * which is handled as part of the table definition.  Clean up and
2869                          * return.
2870                          */
2871                         PQclear(res);
2872                         continue;
2873                 }
2874
2875                 i_oid = PQfnumber(res, "oid");
2876                 i_tableoid = PQfnumber(res, "tableoid");
2877                 i_polname = PQfnumber(res, "polname");
2878                 i_polcmd = PQfnumber(res, "polcmd");
2879                 i_polroles = PQfnumber(res, "polroles");
2880                 i_polqual = PQfnumber(res, "polqual");
2881                 i_polwithcheck = PQfnumber(res, "polwithcheck");
2882
2883                 polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
2884
2885                 for (j = 0; j < ntups; j++)
2886                 {
2887                         polinfo[j].dobj.objType = DO_POLICY;
2888                         polinfo[j].dobj.catId.tableoid =
2889                                 atooid(PQgetvalue(res, j, i_tableoid));
2890                         polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
2891                         AssignDumpId(&polinfo[j].dobj);
2892                         polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
2893                         polinfo[j].poltable = tbinfo;
2894                         polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
2895
2896                         polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
2897
2898                         if (PQgetisnull(res, j, i_polcmd))
2899                                 polinfo[j].polcmd = NULL;
2900                         else
2901                                 polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd));
2902
2903                         polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
2904
2905                         if (PQgetisnull(res, j, i_polqual))
2906                                 polinfo[j].polqual = NULL;
2907                         else
2908                                 polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
2909
2910                         if (PQgetisnull(res, j, i_polwithcheck))
2911                                 polinfo[j].polwithcheck = NULL;
2912                         else
2913                                 polinfo[j].polwithcheck
2914                                         = pg_strdup(PQgetvalue(res, j, i_polwithcheck));
2915                 }
2916                 PQclear(res);
2917         }
2918         destroyPQExpBuffer(query);
2919 }
2920
2921 /*
2922  * dumpPolicy
2923  *        dump the definition of the given policy
2924  */
2925 static void
2926 dumpPolicy(Archive *fout, DumpOptions *dopt, PolicyInfo *polinfo)
2927 {
2928         TableInfo  *tbinfo = polinfo->poltable;
2929         PQExpBuffer query;
2930         PQExpBuffer delqry;
2931         const char *cmd;
2932
2933         if (dopt->dataOnly)
2934                 return;
2935
2936         /*
2937          * If polname is NULL, then this record is just indicating that ROW
2938          * LEVEL SECURITY is enabled for the table. Dump as ALTER TABLE <table>
2939          * ENABLE ROW LEVEL SECURITY.
2940          */
2941         if (polinfo->polname == NULL)
2942         {
2943                 query = createPQExpBuffer();
2944
2945                 appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
2946                                                   fmtId(polinfo->dobj.name));
2947
2948                 ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2949                                          polinfo->dobj.name,
2950                                          polinfo->dobj.namespace->dobj.name,
2951                                          NULL,
2952                                          tbinfo->rolname, false,
2953                                          "ROW SECURITY", SECTION_POST_DATA,
2954                                          query->data, "", NULL,
2955                                          NULL, 0,
2956                                          NULL, NULL);
2957
2958                 destroyPQExpBuffer(query);
2959                 return;
2960         }
2961
2962         if (!polinfo->polcmd)
2963                 cmd = "ALL";
2964         else if (strcmp(polinfo->polcmd, "r") == 0)
2965                 cmd = "SELECT";
2966         else if (strcmp(polinfo->polcmd, "a") == 0)
2967                 cmd = "INSERT";
2968         else if (strcmp(polinfo->polcmd, "w") == 0)
2969                 cmd = "UPDATE";
2970         else if (strcmp(polinfo->polcmd, "d") == 0)
2971                 cmd = "DELETE";
2972         else
2973         {
2974                 write_msg(NULL, "unexpected command type: '%s'\n", polinfo->polcmd);
2975                 exit_nicely(1);
2976         }
2977
2978         query = createPQExpBuffer();
2979         delqry = createPQExpBuffer();
2980
2981         appendPQExpBuffer(query, "CREATE POLICY %s ON %s FOR %s",
2982                                           polinfo->polname, fmtId(tbinfo->dobj.name), cmd);
2983
2984         if (polinfo->polroles != NULL)
2985                 appendPQExpBuffer(query, " TO %s", polinfo->polroles);
2986
2987         if (polinfo->polqual != NULL)
2988                 appendPQExpBuffer(query, " USING %s", polinfo->polqual);
2989
2990         if (polinfo->polwithcheck != NULL)
2991                 appendPQExpBuffer(query, " WITH CHECK %s", polinfo->polwithcheck);
2992
2993         appendPQExpBuffer(query, ";\n");
2994
2995         appendPQExpBuffer(delqry, "DROP POLICY %s ON %s;\n",
2996                                           polinfo->polname, fmtId(tbinfo->dobj.name));
2997
2998         ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
2999                                  polinfo->dobj.name,
3000                                  polinfo->dobj.namespace->dobj.name,
3001                                  NULL,
3002                                  tbinfo->rolname, false,
3003                                  "POLICY", SECTION_POST_DATA,
3004                                  query->data, delqry->data, NULL,
3005                                  NULL, 0,
3006                                  NULL, NULL);
3007
3008         destroyPQExpBuffer(query);
3009         destroyPQExpBuffer(delqry);
3010 }
3011
3012 static void
3013 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
3014                                                                                  PQExpBuffer upgrade_buffer,
3015                                                                                  Oid pg_type_oid)
3016 {
3017         PQExpBuffer upgrade_query = createPQExpBuffer();
3018         PGresult   *upgrade_res;
3019         Oid                     pg_type_array_oid;
3020
3021         appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
3022         appendPQExpBuffer(upgrade_buffer,
3023          "SELECT binary_upgrade.set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3024                                           pg_type_oid);
3025
3026         /* we only support old >= 8.3 for binary upgrades */
3027         appendPQExpBuffer(upgrade_query,
3028                                           "SELECT typarray "
3029                                           "FROM pg_catalog.pg_type "
3030                                           "WHERE pg_type.oid = '%u'::pg_catalog.oid;",
3031                                           pg_type_oid);
3032
3033         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3034
3035         pg_type_array_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "typarray")));
3036
3037         if (OidIsValid(pg_type_array_oid))
3038         {
3039                 appendPQExpBufferStr(upgrade_buffer,
3040                            "\n-- For binary upgrade, must preserve pg_type array oid\n");
3041                 appendPQExpBuffer(upgrade_buffer,
3042                                                   "SELECT binary_upgrade.set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3043                                                   pg_type_array_oid);
3044         }
3045
3046         PQclear(upgrade_res);
3047         destroyPQExpBuffer(upgrade_query);
3048 }
3049
3050 static bool
3051 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
3052                                                                                 PQExpBuffer upgrade_buffer,
3053                                                                                 Oid pg_rel_oid)
3054 {
3055         PQExpBuffer upgrade_query = createPQExpBuffer();
3056         PGresult   *upgrade_res;
3057         Oid                     pg_type_oid;
3058         bool            toast_set = false;
3059
3060         /* we only support old >= 8.3 for binary upgrades */
3061         appendPQExpBuffer(upgrade_query,
3062                                           "SELECT c.reltype AS crel, t.reltype AS trel "
3063                                           "FROM pg_catalog.pg_class c "
3064                                           "LEFT JOIN pg_catalog.pg_class t ON "
3065                                           "  (c.reltoastrelid = t.oid) "
3066                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
3067                                           pg_rel_oid);
3068
3069         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3070
3071         pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
3072
3073         binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
3074                                                                                          pg_type_oid);
3075
3076         if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
3077         {
3078                 /* Toast tables do not have pg_type array rows */
3079                 Oid                     pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
3080                                                                                         PQfnumber(upgrade_res, "trel")));
3081
3082                 appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
3083                 appendPQExpBuffer(upgrade_buffer,
3084                                                   "SELECT binary_upgrade.set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
3085                                                   pg_type_toast_oid);
3086
3087                 toast_set = true;
3088         }
3089
3090         PQclear(upgrade_res);
3091         destroyPQExpBuffer(upgrade_query);
3092
3093         return toast_set;
3094 }
3095
3096 static void
3097 binary_upgrade_set_pg_class_oids(Archive *fout,
3098                                                                  PQExpBuffer upgrade_buffer, Oid pg_class_oid,
3099                                                                  bool is_index)
3100 {
3101         PQExpBuffer upgrade_query = createPQExpBuffer();
3102         PGresult   *upgrade_res;
3103         Oid                     pg_class_reltoastrelid;
3104         Oid                     pg_index_indexrelid;
3105
3106         appendPQExpBuffer(upgrade_query,
3107                                           "SELECT c.reltoastrelid, i.indexrelid "
3108                                           "FROM pg_catalog.pg_class c LEFT JOIN "
3109                                           "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
3110                                           "WHERE c.oid = '%u'::pg_catalog.oid;",
3111                                           pg_class_oid);
3112
3113         upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
3114
3115         pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
3116         pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
3117
3118         appendPQExpBufferStr(upgrade_buffer,
3119                                    "\n-- For binary upgrade, must preserve pg_class oids\n");
3120
3121         if (!is_index)
3122         {
3123                 appendPQExpBuffer(upgrade_buffer,
3124                                                   "SELECT binary_upgrade.set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
3125                                                   pg_class_oid);
3126                 /* only tables have toast tables, not indexes */
3127                 if (OidIsValid(pg_class_reltoastrelid))
3128                 {
3129                         /*
3130                          * One complexity is that the table definition might not require
3131                          * the creation of a TOAST table, and the TOAST table might have
3132                          * been created long after table creation, when the table was
3133                          * loaded with wide data.  By setting the TOAST oid we force
3134                          * creation of the TOAST heap and TOAST index by the backend so we
3135                          * can cleanly copy the files during binary upgrade.
3136                          */
3137
3138                         appendPQExpBuffer(upgrade_buffer,
3139                                                           "SELECT binary_upgrade.set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
3140                                                           pg_class_reltoastrelid);
3141
3142                         /* every toast table has an index */
3143                         appendPQExpBuffer(upgrade_buffer,
3144                                                           "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3145                                                           pg_index_indexrelid);
3146                 }
3147         }
3148         else
3149                 appendPQExpBuffer(upgrade_buffer,
3150                                                   "SELECT binary_upgrade.set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
3151                                                   pg_class_oid);
3152
3153         appendPQExpBufferChar(upgrade_buffer, '\n');
3154
3155         PQclear(upgrade_res);
3156         destroyPQExpBuffer(upgrade_query);
3157 }
3158
3159 /*
3160  * If the DumpableObject is a member of an extension, add a suitable
3161  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
3162  */
3163 static void
3164 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
3165                                                                 DumpableObject *dobj,
3166                                                                 const char *objlabel)
3167 {
3168         DumpableObject *extobj = NULL;
3169         int                     i;
3170
3171         if (!dobj->ext_member)
3172                 return;
3173
3174         /*
3175          * Find the parent extension.  We could avoid this search if we wanted to
3176          * add a link field to DumpableObject, but the space costs of that would
3177          * be considerable.  We assume that member objects could only have a
3178          * direct dependency on their own extension, not any others.
3179          */
3180         for (i = 0; i < dobj->nDeps; i++)
3181         {
3182                 extobj = findObjectByDumpId(dobj->dependencies[i]);
3183                 if (extobj && extobj->objType == DO_EXTENSION)
3184                         break;
3185                 extobj = NULL;
3186         }
3187         if (extobj == NULL)
3188                 exit_horribly(NULL, "could not find parent extension for %s\n", objlabel);
3189
3190         appendPQExpBufferStr(upgrade_buffer,
3191           "\n-- For binary upgrade, handle extension membership the hard way\n");
3192         appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s;\n",
3193                                           fmtId(extobj->name),
3194                                           objlabel);
3195 }
3196
3197 /*
3198  * getNamespaces:
3199  *        read all namespaces in the system catalogs and return them in the
3200  * NamespaceInfo* structure
3201  *
3202  *      numNamespaces is set to the number of namespaces read in
3203  */
3204 NamespaceInfo *
3205 getNamespaces(Archive *fout, int *numNamespaces)
3206 {
3207         PGresult   *res;
3208         int                     ntups;
3209         int                     i;
3210         PQExpBuffer query;
3211         NamespaceInfo *nsinfo;
3212         int                     i_tableoid;
3213         int                     i_oid;
3214         int                     i_nspname;
3215         int                     i_rolname;
3216         int                     i_nspacl;
3217
3218         /*
3219          * Before 7.3, there are no real namespaces; create two dummy entries, one
3220          * for user stuff and one for system stuff.
3221          */
3222         if (fout->remoteVersion < 70300)
3223         {
3224                 nsinfo = (NamespaceInfo *) pg_malloc(2 * sizeof(NamespaceInfo));
3225
3226                 nsinfo[0].dobj.objType = DO_NAMESPACE;
3227                 nsinfo[0].dobj.catId.tableoid = 0;
3228                 nsinfo[0].dobj.catId.oid = 0;
3229                 AssignDumpId(&nsinfo[0].dobj);
3230                 nsinfo[0].dobj.name = pg_strdup("public");
3231                 nsinfo[0].rolname = pg_strdup("");
3232                 nsinfo[0].nspacl = pg_strdup("");
3233
3234                 selectDumpableNamespace(&nsinfo[0]);
3235
3236                 nsinfo[1].dobj.objType = DO_NAMESPACE;
3237                 nsinfo[1].dobj.catId.tableoid = 0;
3238                 nsinfo[1].dobj.catId.oid = 1;
3239                 AssignDumpId(&nsinfo[1].dobj);
3240                 nsinfo[1].dobj.name = pg_strdup("pg_catalog");
3241                 nsinfo[1].rolname = pg_strdup("");
3242                 nsinfo[1].nspacl = pg_strdup("");
3243
3244                 selectDumpableNamespace(&nsinfo[1]);
3245
3246                 *numNamespaces = 2;
3247
3248                 return nsinfo;
3249         }
3250
3251         query = createPQExpBuffer();
3252
3253         /* Make sure we are in proper schema */
3254         selectSourceSchema(fout, "pg_catalog");
3255
3256         /*
3257          * we fetch all namespaces including system ones, so that every object we
3258          * read in can be linked to a containing namespace.
3259          */
3260         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
3261                                           "(%s nspowner) AS rolname, "
3262                                           "nspacl FROM pg_namespace",
3263                                           username_subquery);
3264
3265         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3266
3267         ntups = PQntuples(res);
3268
3269         nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
3270
3271         i_tableoid = PQfnumber(res, "tableoid");
3272         i_oid = PQfnumber(res, "oid");
3273         i_nspname = PQfnumber(res, "nspname");
3274         i_rolname = PQfnumber(res, "rolname");
3275         i_nspacl = PQfnumber(res, "nspacl");
3276
3277         for (i = 0; i < ntups; i++)
3278         {
3279                 nsinfo[i].dobj.objType = DO_NAMESPACE;
3280                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3281                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3282                 AssignDumpId(&nsinfo[i].dobj);
3283                 nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
3284                 nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3285                 nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
3286
3287                 /* Decide whether to dump this namespace */
3288                 selectDumpableNamespace(&nsinfo[i]);
3289
3290                 if (strlen(nsinfo[i].rolname) == 0)
3291                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
3292                                           nsinfo[i].dobj.name);
3293         }
3294
3295         PQclear(res);
3296         destroyPQExpBuffer(query);
3297
3298         *numNamespaces = ntups;
3299
3300         return nsinfo;
3301 }
3302
3303 /*
3304  * findNamespace:
3305  *              given a namespace OID and an object OID, look up the info read by
3306  *              getNamespaces
3307  *
3308  * NB: for pre-7.3 source database, we use object OID to guess whether it's
3309  * a system object or not.  In 7.3 and later there is no guessing, and we
3310  * don't use objoid at all.
3311  */
3312 static NamespaceInfo *
3313 findNamespace(Archive *fout, Oid nsoid, Oid objoid)
3314 {
3315         NamespaceInfo *nsinfo;
3316
3317         if (fout->remoteVersion >= 70300)
3318         {
3319                 nsinfo = findNamespaceByOid(nsoid);
3320         }
3321         else
3322         {
3323                 /* This code depends on the dummy objects set up by getNamespaces. */
3324                 Oid                     i;
3325
3326                 if (objoid > g_last_builtin_oid)
3327                         i = 0;                          /* user object */
3328                 else
3329                         i = 1;                          /* system object */
3330                 nsinfo = findNamespaceByOid(i);
3331         }
3332
3333         if (nsinfo == NULL)
3334                 exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
3335
3336         return nsinfo;
3337 }
3338
3339 /*
3340  * getExtensions:
3341  *        read all extensions in the system catalogs and return them in the
3342  * ExtensionInfo* structure
3343  *
3344  *      numExtensions is set to the number of extensions read in
3345  */
3346 ExtensionInfo *
3347 getExtensions(Archive *fout, DumpOptions *dopt, int *numExtensions)
3348 {
3349         PGresult   *res;
3350         int                     ntups;
3351         int                     i;
3352         PQExpBuffer query;
3353         ExtensionInfo *extinfo;
3354         int                     i_tableoid;
3355         int                     i_oid;
3356         int                     i_extname;
3357         int                     i_nspname;
3358         int                     i_extrelocatable;
3359         int                     i_extversion;
3360         int                     i_extconfig;
3361         int                     i_extcondition;
3362
3363         /*
3364          * Before 9.1, there are no extensions.
3365          */
3366         if (fout->remoteVersion < 90100)
3367         {
3368                 *numExtensions = 0;
3369                 return NULL;
3370         }
3371
3372         query = createPQExpBuffer();
3373
3374         /* Make sure we are in proper schema */
3375         selectSourceSchema(fout, "pg_catalog");
3376
3377         appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
3378                                                  "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
3379                                                  "FROM pg_extension x "
3380                                                  "JOIN pg_namespace n ON n.oid = x.extnamespace");
3381
3382         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3383
3384         ntups = PQntuples(res);
3385
3386         extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
3387
3388         i_tableoid = PQfnumber(res, "tableoid");
3389         i_oid = PQfnumber(res, "oid");
3390         i_extname = PQfnumber(res, "extname");
3391         i_nspname = PQfnumber(res, "nspname");
3392         i_extrelocatable = PQfnumber(res, "extrelocatable");
3393         i_extversion = PQfnumber(res, "extversion");
3394         i_extconfig = PQfnumber(res, "extconfig");
3395         i_extcondition = PQfnumber(res, "extcondition");
3396
3397         for (i = 0; i < ntups; i++)
3398         {
3399                 extinfo[i].dobj.objType = DO_EXTENSION;
3400                 extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3401                 extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3402                 AssignDumpId(&extinfo[i].dobj);
3403                 extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
3404                 extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
3405                 extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
3406                 extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
3407                 extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
3408                 extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
3409
3410                 /* Decide whether we want to dump it */
3411                 selectDumpableExtension(dopt, &(extinfo[i]));
3412         }
3413
3414         PQclear(res);
3415         destroyPQExpBuffer(query);
3416
3417         *numExtensions = ntups;
3418
3419         return extinfo;
3420 }
3421
3422 /*
3423  * getTypes:
3424  *        read all types in the system catalogs and return them in the
3425  * TypeInfo* structure
3426  *
3427  *      numTypes is set to the number of types read in
3428  *
3429  * NB: this must run after getFuncs() because we assume we can do
3430  * findFuncByOid().
3431  */
3432 TypeInfo *
3433 getTypes(Archive *fout, int *numTypes)
3434 {
3435         PGresult   *res;
3436         int                     ntups;
3437         int                     i;
3438         PQExpBuffer query = createPQExpBuffer();
3439         TypeInfo   *tyinfo;
3440         ShellTypeInfo *stinfo;
3441         int                     i_tableoid;
3442         int                     i_oid;
3443         int                     i_typname;
3444         int                     i_typnamespace;
3445         int                     i_typacl;
3446         int                     i_rolname;
3447         int                     i_typinput;
3448         int                     i_typoutput;
3449         int                     i_typelem;
3450         int                     i_typrelid;
3451         int                     i_typrelkind;
3452         int                     i_typtype;
3453         int                     i_typisdefined;
3454         int                     i_isarray;
3455
3456         /*
3457          * we include even the built-in types because those may be used as array
3458          * elements by user-defined types
3459          *
3460          * we filter out the built-in types when we dump out the types
3461          *
3462          * same approach for undefined (shell) types and array types
3463          *
3464          * Note: as of 8.3 we can reliably detect whether a type is an
3465          * auto-generated array type by checking the element type's typarray.
3466          * (Before that the test is capable of generating false positives.) We
3467          * still check for name beginning with '_', though, so as to avoid the
3468          * cost of the subselect probe for all standard types.  This would have to
3469          * be revisited if the backend ever allows renaming of array types.
3470          */
3471
3472         /* Make sure we are in proper schema */
3473         selectSourceSchema(fout, "pg_catalog");
3474
3475         if (fout->remoteVersion >= 90200)
3476         {
3477                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3478                                                   "typnamespace, typacl, "
3479                                                   "(%s typowner) AS rolname, "
3480                                                   "typinput::oid AS typinput, "
3481                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3482                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3483                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3484                                                   "typtype, typisdefined, "
3485                                                   "typname[0] = '_' AND typelem != 0 AND "
3486                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3487                                                   "FROM pg_type",
3488                                                   username_subquery);
3489         }
3490         else if (fout->remoteVersion >= 80300)
3491         {
3492                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3493                                                   "typnamespace, '{=U}' AS typacl, "
3494                                                   "(%s typowner) AS rolname, "
3495                                                   "typinput::oid AS typinput, "
3496                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3497                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3498                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3499                                                   "typtype, typisdefined, "
3500                                                   "typname[0] = '_' AND typelem != 0 AND "
3501                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
3502                                                   "FROM pg_type",
3503                                                   username_subquery);
3504         }
3505         else if (fout->remoteVersion >= 70300)
3506         {
3507                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3508                                                   "typnamespace, '{=U}' AS typacl, "
3509                                                   "(%s typowner) AS rolname, "
3510                                                   "typinput::oid AS typinput, "
3511                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3512                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3513                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3514                                                   "typtype, typisdefined, "
3515                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3516                                                   "FROM pg_type",
3517                                                   username_subquery);
3518         }
3519         else if (fout->remoteVersion >= 70100)
3520         {
3521                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
3522                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3523                                                   "(%s typowner) AS rolname, "
3524                                                   "typinput::oid AS typinput, "
3525                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3526                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3527                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3528                                                   "typtype, typisdefined, "
3529                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3530                                                   "FROM pg_type",
3531                                                   username_subquery);
3532         }
3533         else
3534         {
3535                 appendPQExpBuffer(query, "SELECT "
3536                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
3537                                                   "oid, typname, "
3538                                                   "0::oid AS typnamespace, '{=U}' AS typacl, "
3539                                                   "(%s typowner) AS rolname, "
3540                                                   "typinput::oid AS typinput, "
3541                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
3542                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
3543                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
3544                                                   "typtype, typisdefined, "
3545                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
3546                                                   "FROM pg_type",
3547                                                   username_subquery);
3548         }
3549
3550         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3551
3552         ntups = PQntuples(res);
3553
3554         tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
3555
3556         i_tableoid = PQfnumber(res, "tableoid");
3557         i_oid = PQfnumber(res, "oid");
3558         i_typname = PQfnumber(res, "typname");
3559         i_typnamespace = PQfnumber(res, "typnamespace");
3560         i_typacl = PQfnumber(res, "typacl");
3561         i_rolname = PQfnumber(res, "rolname");
3562         i_typinput = PQfnumber(res, "typinput");
3563         i_typoutput = PQfnumber(res, "typoutput");
3564         i_typelem = PQfnumber(res, "typelem");
3565         i_typrelid = PQfnumber(res, "typrelid");
3566         i_typrelkind = PQfnumber(res, "typrelkind");
3567         i_typtype = PQfnumber(res, "typtype");
3568         i_typisdefined = PQfnumber(res, "typisdefined");
3569         i_isarray = PQfnumber(res, "isarray");
3570
3571         for (i = 0; i < ntups; i++)
3572         {
3573                 tyinfo[i].dobj.objType = DO_TYPE;
3574                 tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3575                 tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3576                 AssignDumpId(&tyinfo[i].dobj);
3577                 tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
3578                 tyinfo[i].dobj.namespace =
3579                         findNamespace(fout,
3580                                                   atooid(PQgetvalue(res, i, i_typnamespace)),
3581                                                   tyinfo[i].dobj.catId.oid);
3582                 tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3583                 tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
3584                 tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
3585                 tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
3586                 tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
3587                 tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
3588                 tyinfo[i].shellType = NULL;
3589
3590                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
3591                         tyinfo[i].isDefined = true;
3592                 else
3593                         tyinfo[i].isDefined = false;
3594
3595                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
3596                         tyinfo[i].isArray = true;
3597                 else
3598                         tyinfo[i].isArray = false;
3599
3600                 /* Decide whether we want to dump it */
3601                 selectDumpableType(&tyinfo[i]);
3602
3603                 /*
3604                  * If it's a domain, fetch info about its constraints, if any
3605                  */
3606                 tyinfo[i].nDomChecks = 0;
3607                 tyinfo[i].domChecks = NULL;
3608                 if (tyinfo[i].dobj.dump && tyinfo[i].typtype == TYPTYPE_DOMAIN)
3609                         getDomainConstraints(fout, &(tyinfo[i]));
3610
3611                 /*
3612                  * If it's a base type, make a DumpableObject representing a shell
3613                  * definition of the type.  We will need to dump that ahead of the I/O
3614                  * functions for the type.  Similarly, range types need a shell
3615                  * definition in case they have a canonicalize function.
3616                  *
3617                  * Note: the shell type doesn't have a catId.  You might think it
3618                  * should copy the base type's catId, but then it might capture the
3619                  * pg_depend entries for the type, which we don't want.
3620                  */
3621                 if (tyinfo[i].dobj.dump && (tyinfo[i].typtype == TYPTYPE_BASE ||
3622                                                                         tyinfo[i].typtype == TYPTYPE_RANGE))
3623                 {
3624                         stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
3625                         stinfo->dobj.objType = DO_SHELL_TYPE;
3626                         stinfo->dobj.catId = nilCatalogId;
3627                         AssignDumpId(&stinfo->dobj);
3628                         stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
3629                         stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
3630                         stinfo->baseType = &(tyinfo[i]);
3631                         tyinfo[i].shellType = stinfo;
3632
3633                         /*
3634                          * Initially mark the shell type as not to be dumped.  We'll only
3635                          * dump it if the I/O or canonicalize functions need to be dumped;
3636                          * this is taken care of while sorting dependencies.
3637                          */
3638                         stinfo->dobj.dump = false;
3639
3640                         /*
3641                          * However, if dumping from pre-7.3, there will be no dependency
3642                          * info so we have to fake it here.  We only need to worry about
3643                          * typinput and typoutput since the other functions only exist
3644                          * post-7.3.
3645                          */
3646                         if (fout->remoteVersion < 70300)
3647                         {
3648                                 Oid                     typinput;
3649                                 Oid                     typoutput;
3650                                 FuncInfo   *funcInfo;
3651
3652                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
3653                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
3654
3655                                 funcInfo = findFuncByOid(typinput);
3656                                 if (funcInfo && funcInfo->dobj.dump)
3657                                 {
3658                                         /* base type depends on function */
3659                                         addObjectDependency(&tyinfo[i].dobj,
3660                                                                                 funcInfo->dobj.dumpId);
3661                                         /* function depends on shell type */
3662                                         addObjectDependency(&funcInfo->dobj,
3663                                                                                 stinfo->dobj.dumpId);
3664                                         /* mark shell type as to be dumped */
3665                                         stinfo->dobj.dump = true;
3666                                 }
3667
3668                                 funcInfo = findFuncByOid(typoutput);
3669                                 if (funcInfo && funcInfo->dobj.dump)
3670                                 {
3671                                         /* base type depends on function */
3672                                         addObjectDependency(&tyinfo[i].dobj,
3673                                                                                 funcInfo->dobj.dumpId);
3674                                         /* function depends on shell type */
3675                                         addObjectDependency(&funcInfo->dobj,
3676                                                                                 stinfo->dobj.dumpId);
3677                                         /* mark shell type as to be dumped */
3678                                         stinfo->dobj.dump = true;
3679                                 }
3680                         }
3681                 }
3682
3683                 if (strlen(tyinfo[i].rolname) == 0 && tyinfo[i].isDefined)
3684                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
3685                                           tyinfo[i].dobj.name);
3686         }
3687
3688         *numTypes = ntups;
3689
3690         PQclear(res);
3691
3692         destroyPQExpBuffer(query);
3693
3694         return tyinfo;
3695 }
3696
3697 /*
3698  * getOperators:
3699  *        read all operators in the system catalogs and return them in the
3700  * OprInfo* structure
3701  *
3702  *      numOprs is set to the number of operators read in
3703  */
3704 OprInfo *
3705 getOperators(Archive *fout, int *numOprs)
3706 {
3707         PGresult   *res;
3708         int                     ntups;
3709         int                     i;
3710         PQExpBuffer query = createPQExpBuffer();
3711         OprInfo    *oprinfo;
3712         int                     i_tableoid;
3713         int                     i_oid;
3714         int                     i_oprname;
3715         int                     i_oprnamespace;
3716         int                     i_rolname;
3717         int                     i_oprkind;
3718         int                     i_oprcode;
3719
3720         /*
3721          * find all operators, including builtin operators; we filter out
3722          * system-defined operators at dump-out time.
3723          */
3724
3725         /* Make sure we are in proper schema */
3726         selectSourceSchema(fout, "pg_catalog");
3727
3728         if (fout->remoteVersion >= 70300)
3729         {
3730                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3731                                                   "oprnamespace, "
3732                                                   "(%s oprowner) AS rolname, "
3733                                                   "oprkind, "
3734                                                   "oprcode::oid AS oprcode "
3735                                                   "FROM pg_operator",
3736                                                   username_subquery);
3737         }
3738         else if (fout->remoteVersion >= 70100)
3739         {
3740                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
3741                                                   "0::oid AS oprnamespace, "
3742                                                   "(%s oprowner) AS rolname, "
3743                                                   "oprkind, "
3744                                                   "oprcode::oid AS oprcode "
3745                                                   "FROM pg_operator",
3746                                                   username_subquery);
3747         }
3748         else
3749         {
3750                 appendPQExpBuffer(query, "SELECT "
3751                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
3752                                                   "oid, oprname, "
3753                                                   "0::oid AS oprnamespace, "
3754                                                   "(%s oprowner) AS rolname, "
3755                                                   "oprkind, "
3756                                                   "oprcode::oid AS oprcode "
3757                                                   "FROM pg_operator",
3758                                                   username_subquery);
3759         }
3760
3761         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3762
3763         ntups = PQntuples(res);
3764         *numOprs = ntups;
3765
3766         oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
3767
3768         i_tableoid = PQfnumber(res, "tableoid");
3769         i_oid = PQfnumber(res, "oid");
3770         i_oprname = PQfnumber(res, "oprname");
3771         i_oprnamespace = PQfnumber(res, "oprnamespace");
3772         i_rolname = PQfnumber(res, "rolname");
3773         i_oprkind = PQfnumber(res, "oprkind");
3774         i_oprcode = PQfnumber(res, "oprcode");
3775
3776         for (i = 0; i < ntups; i++)
3777         {
3778                 oprinfo[i].dobj.objType = DO_OPERATOR;
3779                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3780                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3781                 AssignDumpId(&oprinfo[i].dobj);
3782                 oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
3783                 oprinfo[i].dobj.namespace =
3784                         findNamespace(fout,
3785                                                   atooid(PQgetvalue(res, i, i_oprnamespace)),
3786                                                   oprinfo[i].dobj.catId.oid);
3787                 oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3788                 oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
3789                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
3790
3791                 /* Decide whether we want to dump it */
3792                 selectDumpableObject(&(oprinfo[i].dobj));
3793
3794                 if (strlen(oprinfo[i].rolname) == 0)
3795                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
3796                                           oprinfo[i].dobj.name);
3797         }
3798
3799         PQclear(res);
3800
3801         destroyPQExpBuffer(query);
3802
3803         return oprinfo;
3804 }
3805
3806 /*
3807  * getCollations:
3808  *        read all collations in the system catalogs and return them in the
3809  * CollInfo* structure
3810  *
3811  *      numCollations is set to the number of collations read in
3812  */
3813 CollInfo *
3814 getCollations(Archive *fout, int *numCollations)
3815 {
3816         PGresult   *res;
3817         int                     ntups;
3818         int                     i;
3819         PQExpBuffer query;
3820         CollInfo   *collinfo;
3821         int                     i_tableoid;
3822         int                     i_oid;
3823         int                     i_collname;
3824         int                     i_collnamespace;
3825         int                     i_rolname;
3826
3827         /* Collations didn't exist pre-9.1 */
3828         if (fout->remoteVersion < 90100)
3829         {
3830                 *numCollations = 0;
3831                 return NULL;
3832         }
3833
3834         query = createPQExpBuffer();
3835
3836         /*
3837          * find all collations, including builtin collations; we filter out
3838          * system-defined collations at dump-out time.
3839          */
3840
3841         /* Make sure we are in proper schema */
3842         selectSourceSchema(fout, "pg_catalog");
3843
3844         appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
3845                                           "collnamespace, "
3846                                           "(%s collowner) AS rolname "
3847                                           "FROM pg_collation",
3848                                           username_subquery);
3849
3850         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3851
3852         ntups = PQntuples(res);
3853         *numCollations = ntups;
3854
3855         collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
3856
3857         i_tableoid = PQfnumber(res, "tableoid");
3858         i_oid = PQfnumber(res, "oid");
3859         i_collname = PQfnumber(res, "collname");
3860         i_collnamespace = PQfnumber(res, "collnamespace");
3861         i_rolname = PQfnumber(res, "rolname");
3862
3863         for (i = 0; i < ntups; i++)
3864         {
3865                 collinfo[i].dobj.objType = DO_COLLATION;
3866                 collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3867                 collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3868                 AssignDumpId(&collinfo[i].dobj);
3869                 collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
3870                 collinfo[i].dobj.namespace =
3871                         findNamespace(fout,
3872                                                   atooid(PQgetvalue(res, i, i_collnamespace)),
3873                                                   collinfo[i].dobj.catId.oid);
3874                 collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3875
3876                 /* Decide whether we want to dump it */
3877                 selectDumpableObject(&(collinfo[i].dobj));
3878         }
3879
3880         PQclear(res);
3881
3882         destroyPQExpBuffer(query);
3883
3884         return collinfo;
3885 }
3886
3887 /*
3888  * getConversions:
3889  *        read all conversions in the system catalogs and return them in the
3890  * ConvInfo* structure
3891  *
3892  *      numConversions is set to the number of conversions read in
3893  */
3894 ConvInfo *
3895 getConversions(Archive *fout, int *numConversions)
3896 {
3897         PGresult   *res;
3898         int                     ntups;
3899         int                     i;
3900         PQExpBuffer query;
3901         ConvInfo   *convinfo;
3902         int                     i_tableoid;
3903         int                     i_oid;
3904         int                     i_conname;
3905         int                     i_connamespace;
3906         int                     i_rolname;
3907
3908         /* Conversions didn't exist pre-7.3 */
3909         if (fout->remoteVersion < 70300)
3910         {
3911                 *numConversions = 0;
3912                 return NULL;
3913         }
3914
3915         query = createPQExpBuffer();
3916
3917         /*
3918          * find all conversions, including builtin conversions; we filter out
3919          * system-defined conversions at dump-out time.
3920          */
3921
3922         /* Make sure we are in proper schema */
3923         selectSourceSchema(fout, "pg_catalog");
3924
3925         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3926                                           "connamespace, "
3927                                           "(%s conowner) AS rolname "
3928                                           "FROM pg_conversion",
3929                                           username_subquery);
3930
3931         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3932
3933         ntups = PQntuples(res);
3934         *numConversions = ntups;
3935
3936         convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
3937
3938         i_tableoid = PQfnumber(res, "tableoid");
3939         i_oid = PQfnumber(res, "oid");
3940         i_conname = PQfnumber(res, "conname");
3941         i_connamespace = PQfnumber(res, "connamespace");
3942         i_rolname = PQfnumber(res, "rolname");
3943
3944         for (i = 0; i < ntups; i++)
3945         {
3946                 convinfo[i].dobj.objType = DO_CONVERSION;
3947                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3948                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3949                 AssignDumpId(&convinfo[i].dobj);
3950                 convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
3951                 convinfo[i].dobj.namespace =
3952                         findNamespace(fout,
3953                                                   atooid(PQgetvalue(res, i, i_connamespace)),
3954                                                   convinfo[i].dobj.catId.oid);
3955                 convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3956
3957                 /* Decide whether we want to dump it */
3958                 selectDumpableObject(&(convinfo[i].dobj));
3959         }
3960
3961         PQclear(res);
3962
3963         destroyPQExpBuffer(query);
3964
3965         return convinfo;
3966 }
3967
3968 /*
3969  * getOpclasses:
3970  *        read all opclasses in the system catalogs and return them in the
3971  * OpclassInfo* structure
3972  *
3973  *      numOpclasses is set to the number of opclasses read in
3974  */
3975 OpclassInfo *
3976 getOpclasses(Archive *fout, int *numOpclasses)
3977 {
3978         PGresult   *res;
3979         int                     ntups;
3980         int                     i;
3981         PQExpBuffer query = createPQExpBuffer();
3982         OpclassInfo *opcinfo;
3983         int                     i_tableoid;
3984         int                     i_oid;
3985         int                     i_opcname;
3986         int                     i_opcnamespace;
3987         int                     i_rolname;
3988
3989         /*
3990          * find all opclasses, including builtin opclasses; we filter out
3991          * system-defined opclasses at dump-out time.
3992          */
3993
3994         /* Make sure we are in proper schema */
3995         selectSourceSchema(fout, "pg_catalog");
3996
3997         if (fout->remoteVersion >= 70300)
3998         {
3999                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
4000                                                   "opcnamespace, "
4001                                                   "(%s opcowner) AS rolname "
4002                                                   "FROM pg_opclass",
4003                                                   username_subquery);
4004         }
4005         else if (fout->remoteVersion >= 70100)
4006         {
4007                 appendPQExpBufferStr(query, "SELECT tableoid, oid, opcname, "
4008                                                          "0::oid AS opcnamespace, "
4009                                                          "''::name AS rolname "
4010                                                          "FROM pg_opclass");
4011         }
4012         else
4013         {
4014                 appendPQExpBufferStr(query, "SELECT "
4015                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
4016                                                          "oid, opcname, "
4017                                                          "0::oid AS opcnamespace, "
4018                                                          "''::name AS rolname "
4019                                                          "FROM pg_opclass");
4020         }
4021
4022         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4023
4024         ntups = PQntuples(res);
4025         *numOpclasses = ntups;
4026
4027         opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
4028
4029         i_tableoid = PQfnumber(res, "tableoid");
4030         i_oid = PQfnumber(res, "oid");
4031         i_opcname = PQfnumber(res, "opcname");
4032         i_opcnamespace = PQfnumber(res, "opcnamespace");
4033         i_rolname = PQfnumber(res, "rolname");
4034
4035         for (i = 0; i < ntups; i++)
4036         {
4037                 opcinfo[i].dobj.objType = DO_OPCLASS;
4038                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4039                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4040                 AssignDumpId(&opcinfo[i].dobj);
4041                 opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
4042                 opcinfo[i].dobj.namespace =
4043                         findNamespace(fout,
4044                                                   atooid(PQgetvalue(res, i, i_opcnamespace)),
4045                                                   opcinfo[i].dobj.catId.oid);
4046                 opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4047
4048                 /* Decide whether we want to dump it */
4049                 selectDumpableObject(&(opcinfo[i].dobj));
4050
4051                 if (fout->remoteVersion >= 70300)
4052                 {
4053                         if (strlen(opcinfo[i].rolname) == 0)
4054                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
4055                                                   opcinfo[i].dobj.name);
4056                 }
4057         }
4058
4059         PQclear(res);
4060
4061         destroyPQExpBuffer(query);
4062
4063         return opcinfo;
4064 }
4065
4066 /*
4067  * getOpfamilies:
4068  *        read all opfamilies in the system catalogs and return them in the
4069  * OpfamilyInfo* structure
4070  *
4071  *      numOpfamilies is set to the number of opfamilies read in
4072  */
4073 OpfamilyInfo *
4074 getOpfamilies(Archive *fout, int *numOpfamilies)
4075 {
4076         PGresult   *res;
4077         int                     ntups;
4078         int                     i;
4079         PQExpBuffer query;
4080         OpfamilyInfo *opfinfo;
4081         int                     i_tableoid;
4082         int                     i_oid;
4083         int                     i_opfname;
4084         int                     i_opfnamespace;
4085         int                     i_rolname;
4086
4087         /* Before 8.3, there is no separate concept of opfamilies */
4088         if (fout->remoteVersion < 80300)
4089         {
4090                 *numOpfamilies = 0;
4091                 return NULL;
4092         }
4093
4094         query = createPQExpBuffer();
4095
4096         /*
4097          * find all opfamilies, including builtin opfamilies; we filter out
4098          * system-defined opfamilies at dump-out time.
4099          */
4100
4101         /* Make sure we are in proper schema */
4102         selectSourceSchema(fout, "pg_catalog");
4103
4104         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
4105                                           "opfnamespace, "
4106                                           "(%s opfowner) AS rolname "
4107                                           "FROM pg_opfamily",
4108                                           username_subquery);
4109
4110         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4111
4112         ntups = PQntuples(res);
4113         *numOpfamilies = ntups;
4114
4115         opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
4116
4117         i_tableoid = PQfnumber(res, "tableoid");
4118         i_oid = PQfnumber(res, "oid");
4119         i_opfname = PQfnumber(res, "opfname");
4120         i_opfnamespace = PQfnumber(res, "opfnamespace");
4121         i_rolname = PQfnumber(res, "rolname");
4122
4123         for (i = 0; i < ntups; i++)
4124         {
4125                 opfinfo[i].dobj.objType = DO_OPFAMILY;
4126                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4127                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4128                 AssignDumpId(&opfinfo[i].dobj);
4129                 opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
4130                 opfinfo[i].dobj.namespace =
4131                         findNamespace(fout,
4132                                                   atooid(PQgetvalue(res, i, i_opfnamespace)),
4133                                                   opfinfo[i].dobj.catId.oid);
4134                 opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4135
4136                 /* Decide whether we want to dump it */
4137                 selectDumpableObject(&(opfinfo[i].dobj));
4138
4139                 if (fout->remoteVersion >= 70300)
4140                 {
4141                         if (strlen(opfinfo[i].rolname) == 0)
4142                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
4143                                                   opfinfo[i].dobj.name);
4144                 }
4145         }
4146
4147         PQclear(res);
4148
4149         destroyPQExpBuffer(query);
4150
4151         return opfinfo;
4152 }
4153
4154 /*
4155  * getAggregates:
4156  *        read all the user-defined aggregates in the system catalogs and
4157  * return them in the AggInfo* structure
4158  *
4159  * numAggs is set to the number of aggregates read in
4160  */
4161 AggInfo *
4162 getAggregates(Archive *fout, DumpOptions *dopt, int *numAggs)
4163 {
4164         PGresult   *res;
4165         int                     ntups;
4166         int                     i;
4167         PQExpBuffer query = createPQExpBuffer();
4168         AggInfo    *agginfo;
4169         int                     i_tableoid;
4170         int                     i_oid;
4171         int                     i_aggname;
4172         int                     i_aggnamespace;
4173         int                     i_pronargs;
4174         int                     i_proargtypes;
4175         int                     i_rolname;
4176         int                     i_aggacl;
4177         int                     i_proiargs;
4178
4179         /* Make sure we are in proper schema */
4180         selectSourceSchema(fout, "pg_catalog");
4181
4182         /*
4183          * Find all user-defined aggregates.  See comment in getFuncs() for the
4184          * rationale behind the filtering logic.
4185          */
4186
4187         if (fout->remoteVersion >= 80400)
4188         {
4189                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4190                                                   "pronamespace AS aggnamespace, "
4191                                                   "pronargs, proargtypes, "
4192                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4193                                                   "(%s proowner) AS rolname, "
4194                                                   "proacl AS aggacl "
4195                                                   "FROM pg_proc p "
4196                                                   "WHERE proisagg AND ("
4197                                                   "pronamespace != "
4198                                                   "(SELECT oid FROM pg_namespace "
4199                                                   "WHERE nspname = 'pg_catalog')",
4200                                                   username_subquery);
4201                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
4202                         appendPQExpBufferStr(query,
4203                                                                  " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4204                                                                  "classid = 'pg_proc'::regclass AND "
4205                                                                  "objid = p.oid AND "
4206                                                                  "refclassid = 'pg_extension'::regclass AND "
4207                                                                  "deptype = 'e')");
4208                 appendPQExpBufferChar(query, ')');
4209         }
4210         else if (fout->remoteVersion >= 80200)
4211         {
4212                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4213                                                   "pronamespace AS aggnamespace, "
4214                                                   "pronargs, proargtypes, "
4215                                                   "NULL::text AS proiargs,"
4216                                                   "(%s proowner) AS rolname, "
4217                                                   "proacl AS aggacl "
4218                                                   "FROM pg_proc p "
4219                                                   "WHERE proisagg AND ("
4220                                                   "pronamespace != "
4221                                                   "(SELECT oid FROM pg_namespace "
4222                                                   "WHERE nspname = 'pg_catalog'))",
4223                                                   username_subquery);
4224         }
4225         else if (fout->remoteVersion >= 70300)
4226         {
4227                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
4228                                                   "pronamespace AS aggnamespace, "
4229                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
4230                                                   "proargtypes, "
4231                                                   "NULL::text AS proiargs, "
4232                                                   "(%s proowner) AS rolname, "
4233                                                   "proacl AS aggacl "
4234                                                   "FROM pg_proc "
4235                                                   "WHERE proisagg "
4236                                                   "AND pronamespace != "
4237                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
4238                                                   username_subquery);
4239         }
4240         else if (fout->remoteVersion >= 70100)
4241         {
4242                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
4243                                                   "0::oid AS aggnamespace, "
4244                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
4245                                                   "aggbasetype AS proargtypes, "
4246                                                   "NULL::text AS proiargs, "
4247                                                   "(%s aggowner) AS rolname, "
4248                                                   "'{=X}' AS aggacl "
4249                                                   "FROM pg_aggregate "
4250                                                   "where oid > '%u'::oid",
4251                                                   username_subquery,
4252                                                   g_last_builtin_oid);
4253         }
4254         else
4255         {
4256                 appendPQExpBuffer(query, "SELECT "
4257                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
4258                                                   "oid, aggname, "
4259                                                   "0::oid AS aggnamespace, "
4260                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
4261                                                   "aggbasetype AS proargtypes, "
4262                                                   "NULL::text AS proiargs, "
4263                                                   "(%s aggowner) AS rolname, "
4264                                                   "'{=X}' AS aggacl "
4265                                                   "FROM pg_aggregate "
4266                                                   "where oid > '%u'::oid",
4267                                                   username_subquery,
4268                                                   g_last_builtin_oid);
4269         }
4270
4271         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4272
4273         ntups = PQntuples(res);
4274         *numAggs = ntups;
4275
4276         agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
4277
4278         i_tableoid = PQfnumber(res, "tableoid");
4279         i_oid = PQfnumber(res, "oid");
4280         i_aggname = PQfnumber(res, "aggname");
4281         i_aggnamespace = PQfnumber(res, "aggnamespace");
4282         i_pronargs = PQfnumber(res, "pronargs");
4283         i_proargtypes = PQfnumber(res, "proargtypes");
4284         i_rolname = PQfnumber(res, "rolname");
4285         i_aggacl = PQfnumber(res, "aggacl");
4286         i_proiargs = PQfnumber(res, "proiargs");
4287
4288         for (i = 0; i < ntups; i++)
4289         {
4290                 agginfo[i].aggfn.dobj.objType = DO_AGG;
4291                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4292                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4293                 AssignDumpId(&agginfo[i].aggfn.dobj);
4294                 agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
4295                 agginfo[i].aggfn.dobj.namespace =
4296                         findNamespace(fout,
4297                                                   atooid(PQgetvalue(res, i, i_aggnamespace)),
4298                                                   agginfo[i].aggfn.dobj.catId.oid);
4299                 agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4300                 if (strlen(agginfo[i].aggfn.rolname) == 0)
4301                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
4302                                           agginfo[i].aggfn.dobj.name);
4303                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
4304                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
4305                 agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
4306                 agginfo[i].aggfn.proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4307                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
4308                 if (agginfo[i].aggfn.nargs == 0)
4309                         agginfo[i].aggfn.argtypes = NULL;
4310                 else
4311                 {
4312                         agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
4313                         if (fout->remoteVersion >= 70300)
4314                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
4315                                                           agginfo[i].aggfn.argtypes,
4316                                                           agginfo[i].aggfn.nargs);
4317                         else
4318                                 /* it's just aggbasetype */
4319                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
4320                 }
4321
4322                 /* Decide whether we want to dump it */
4323                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
4324         }
4325
4326         PQclear(res);
4327
4328         destroyPQExpBuffer(query);
4329
4330         return agginfo;
4331 }
4332
4333 /*
4334  * getFuncs:
4335  *        read all the user-defined functions in the system catalogs and
4336  * return them in the FuncInfo* structure
4337  *
4338  * numFuncs is set to the number of functions read in
4339  */
4340 FuncInfo *
4341 getFuncs(Archive *fout, DumpOptions *dopt, int *numFuncs)
4342 {
4343         PGresult   *res;
4344         int                     ntups;
4345         int                     i;
4346         PQExpBuffer query = createPQExpBuffer();
4347         FuncInfo   *finfo;
4348         int                     i_tableoid;
4349         int                     i_oid;
4350         int                     i_proname;
4351         int                     i_pronamespace;
4352         int                     i_rolname;
4353         int                     i_prolang;
4354         int                     i_pronargs;
4355         int                     i_proargtypes;
4356         int                     i_prorettype;
4357         int                     i_proacl;
4358         int                     i_proiargs;
4359
4360         /* Make sure we are in proper schema */
4361         selectSourceSchema(fout, "pg_catalog");
4362
4363         /*
4364          * Find all user-defined functions.  Normally we can exclude functions in
4365          * pg_catalog, which is worth doing since there are several thousand of
4366          * 'em.  However, there are some extensions that create functions in
4367          * pg_catalog.  In normal dumps we can still ignore those --- but in
4368          * binary-upgrade mode, we must dump the member objects of the extension,
4369          * so be sure to fetch any such functions.
4370          *
4371          * Also, in 9.2 and up, exclude functions that are internally dependent on
4372          * something else, since presumably those will be created as a result of
4373          * creating the something else.  This currently only acts to suppress
4374          * constructor functions for range types.  Note that this is OK only
4375          * because the constructors don't have any dependencies the range type
4376          * doesn't have; otherwise we might not get creation ordering correct.
4377          */
4378
4379         if (fout->remoteVersion >= 80400)
4380         {
4381                 appendPQExpBuffer(query,
4382                                                   "SELECT tableoid, oid, proname, prolang, "
4383                                                   "pronargs, proargtypes, prorettype, proacl, "
4384                                                   "pronamespace, "
4385                         "pg_catalog.pg_get_function_identity_arguments(oid) AS proiargs,"
4386                                                   "(%s proowner) AS rolname "
4387                                                   "FROM pg_proc p "
4388                                                   "WHERE NOT proisagg AND ("
4389                                                   "pronamespace != "
4390                                                   "(SELECT oid FROM pg_namespace "
4391                                                   "WHERE nspname = 'pg_catalog')",
4392                                                   username_subquery);
4393                 if (fout->remoteVersion >= 90200)
4394                         appendPQExpBufferStr(query,
4395                                                            "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
4396                                                                  "WHERE classid = 'pg_proc'::regclass AND "
4397                                                                  "objid = p.oid AND deptype = 'i')");
4398                 if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
4399                         appendPQExpBufferStr(query,
4400                                                            "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
4401                                                                  "classid = 'pg_proc'::regclass AND "
4402                                                                  "objid = p.oid AND "
4403                                                                  "refclassid = 'pg_extension'::regclass AND "
4404                                                                  "deptype = 'e')");
4405                 appendPQExpBufferChar(query, ')');
4406         }
4407         else if (fout->remoteVersion >= 70300)
4408         {
4409                 appendPQExpBuffer(query,
4410                                                   "SELECT tableoid, oid, proname, prolang, "
4411                                                   "pronargs, proargtypes, prorettype, proacl, "
4412                                                   "pronamespace, "
4413                                                   "NULL::text AS proiargs,"
4414                                                   "(%s proowner) AS rolname "
4415                                                   "FROM pg_proc p "
4416                                                   "WHERE NOT proisagg AND ("
4417                                                   "pronamespace != "
4418                                                   "(SELECT oid FROM pg_namespace "
4419                                                   "WHERE nspname = 'pg_catalog'))",
4420                                                   username_subquery);
4421         }
4422         else if (fout->remoteVersion >= 70100)
4423         {
4424                 appendPQExpBuffer(query,
4425                                                   "SELECT tableoid, oid, proname, prolang, "
4426                                                   "pronargs, proargtypes, prorettype, "
4427                                                   "'{=X}' AS proacl, "
4428                                                   "0::oid AS pronamespace, "
4429                                                   "NULL::text AS proiargs,"
4430                                                   "(%s proowner) AS rolname "
4431                                                   "FROM pg_proc "
4432                                                   "WHERE pg_proc.oid > '%u'::oid",
4433                                                   username_subquery,
4434                                                   g_last_builtin_oid);
4435         }
4436         else
4437         {
4438                 appendPQExpBuffer(query,
4439                                                   "SELECT "
4440                                                   "(SELECT oid FROM pg_class "
4441                                                   " WHERE relname = 'pg_proc') AS tableoid, "
4442                                                   "oid, proname, prolang, "
4443                                                   "pronargs, proargtypes, prorettype, "
4444                                                   "'{=X}' AS proacl, "
4445                                                   "0::oid AS pronamespace, "
4446                                                   "NULL::text AS proiargs,"
4447                                                   "(%s proowner) AS rolname "
4448                                                   "FROM pg_proc "
4449                                                   "where pg_proc.oid > '%u'::oid",
4450                                                   username_subquery,
4451                                                   g_last_builtin_oid);
4452         }
4453
4454         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4455
4456         ntups = PQntuples(res);
4457
4458         *numFuncs = ntups;
4459
4460         finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
4461
4462         i_tableoid = PQfnumber(res, "tableoid");
4463         i_oid = PQfnumber(res, "oid");
4464         i_proname = PQfnumber(res, "proname");
4465         i_pronamespace = PQfnumber(res, "pronamespace");
4466         i_rolname = PQfnumber(res, "rolname");
4467         i_prolang = PQfnumber(res, "prolang");
4468         i_pronargs = PQfnumber(res, "pronargs");
4469         i_proargtypes = PQfnumber(res, "proargtypes");
4470         i_prorettype = PQfnumber(res, "prorettype");
4471         i_proacl = PQfnumber(res, "proacl");
4472         i_proiargs = PQfnumber(res, "proiargs");
4473
4474         for (i = 0; i < ntups; i++)
4475         {
4476                 finfo[i].dobj.objType = DO_FUNC;
4477                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4478                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4479                 AssignDumpId(&finfo[i].dobj);
4480                 finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
4481                 finfo[i].dobj.namespace =
4482                         findNamespace(fout,
4483                                                   atooid(PQgetvalue(res, i, i_pronamespace)),
4484                                                   finfo[i].dobj.catId.oid);
4485                 finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4486                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
4487                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
4488                 finfo[i].proiargs = pg_strdup(PQgetvalue(res, i, i_proiargs));
4489                 finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
4490                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
4491                 if (finfo[i].nargs == 0)
4492                         finfo[i].argtypes = NULL;
4493                 else
4494                 {
4495                         finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
4496                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
4497                                                   finfo[i].argtypes, finfo[i].nargs);
4498                 }
4499
4500                 /* Decide whether we want to dump it */
4501                 selectDumpableObject(&(finfo[i].dobj));
4502
4503                 if (strlen(finfo[i].rolname) == 0)
4504                         write_msg(NULL,
4505                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
4506                                           finfo[i].dobj.name);
4507         }
4508
4509         PQclear(res);
4510
4511         destroyPQExpBuffer(query);
4512
4513         return finfo;
4514 }
4515
4516 /*
4517  * getTables
4518  *        read all the user-defined tables (no indexes, no catalogs)
4519  * in the system catalogs return them in the TableInfo* structure
4520  *
4521  * numTables is set to the number of tables read in
4522  */
4523 TableInfo *
4524 getTables(Archive *fout, DumpOptions *dopt, int *numTables)
4525 {
4526         PGresult   *res;
4527         int                     ntups;
4528         int                     i;
4529         PQExpBuffer query = createPQExpBuffer();
4530         TableInfo  *tblinfo;
4531         int                     i_reltableoid;
4532         int                     i_reloid;
4533         int                     i_relname;
4534         int                     i_relnamespace;
4535         int                     i_relkind;
4536         int                     i_relacl;
4537         int                     i_rolname;
4538         int                     i_relchecks;
4539         int                     i_relhastriggers;
4540         int                     i_relhasindex;
4541         int                     i_relhasrules;
4542         int                     i_relrowsec;
4543         int                     i_relhasoids;
4544         int                     i_relfrozenxid;
4545         int                     i_relminmxid;
4546         int                     i_toastoid;
4547         int                     i_toastfrozenxid;
4548         int                     i_toastminmxid;
4549         int                     i_relpersistence;
4550         int                     i_relispopulated;
4551         int                     i_relreplident;
4552         int                     i_owning_tab;
4553         int                     i_owning_col;
4554         int                     i_reltablespace;
4555         int                     i_reloptions;
4556         int                     i_checkoption;
4557         int                     i_toastreloptions;
4558         int                     i_reloftype;
4559         int                     i_relpages;
4560
4561         /* Make sure we are in proper schema */
4562         selectSourceSchema(fout, "pg_catalog");
4563
4564         /*
4565          * Find all the tables and table-like objects.
4566          *
4567          * We include system catalogs, so that we can work if a user table is
4568          * defined to inherit from a system catalog (pretty weird, but...)
4569          *
4570          * We ignore relations that are not ordinary tables, sequences, views,
4571          * materialized views, composite types, or foreign tables.
4572          *
4573          * Composite-type table entries won't be dumped as such, but we have to
4574          * make a DumpableObject for them so that we can track dependencies of the
4575          * composite type (pg_depend entries for columns of the composite type
4576          * link to the pg_class entry not the pg_type entry).
4577          *
4578          * Note: in this phase we should collect only a minimal amount of
4579          * information about each table, basically just enough to decide if it is
4580          * interesting. We must fetch all tables in this phase because otherwise
4581          * we cannot correctly identify inherited columns, owned sequences, etc.
4582          */
4583
4584         if (fout->remoteVersion >= 90500)
4585         {
4586                 /*
4587                  * Left join to pick up dependency info linking sequences to their
4588                  * owning column, if any (note this dependency is AUTO as of 8.2)
4589                  */
4590                 appendPQExpBuffer(query,
4591                                                   "SELECT c.tableoid, c.oid, c.relname, "
4592                                                   "c.relacl, c.relkind, c.relnamespace, "
4593                                                   "(%s c.relowner) AS rolname, "
4594                                                   "c.relchecks, c.relhastriggers, "
4595                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4596                                                   "c.relrowsecurity, "
4597                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
4598                                                   "tc.relfrozenxid AS tfrozenxid, "
4599                                                   "tc.relminmxid AS tminmxid, "
4600                                                   "c.relpersistence, c.relispopulated, "
4601                                                   "c.relreplident, c.relpages, "
4602                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4603                                                   "d.refobjid AS owning_tab, "
4604                                                   "d.refobjsubid AS owning_col, "
4605                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4606                                                   "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4607                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4608                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4609                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4610                                                   "FROM pg_class c "
4611                                                   "LEFT JOIN pg_depend d ON "
4612                                                   "(c.relkind = '%c' AND "
4613                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4614                                                   "d.objsubid = 0 AND "
4615                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4616                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4617                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4618                                                   "ORDER BY c.oid",
4619                                                   username_subquery,
4620                                                   RELKIND_SEQUENCE,
4621                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4622                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4623                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4624         }
4625         else if (fout->remoteVersion >= 90400)
4626         {
4627                 /*
4628                  * Left join to pick up dependency info linking sequences to their
4629                  * owning column, if any (note this dependency is AUTO as of 8.2)
4630                  */
4631                 appendPQExpBuffer(query,
4632                                                   "SELECT c.tableoid, c.oid, c.relname, "
4633                                                   "c.relacl, c.relkind, c.relnamespace, "
4634                                                   "(%s c.relowner) AS rolname, "
4635                                                   "c.relchecks, c.relhastriggers, "
4636                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4637                                                   "'f'::bool AS relrowsecurity, "
4638                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
4639                                                   "tc.relfrozenxid AS tfrozenxid, "
4640                                                   "tc.relminmxid AS tminmxid, "
4641                                                   "c.relpersistence, c.relispopulated, "
4642                                                   "c.relreplident, c.relpages, "
4643                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4644                                                   "d.refobjid AS owning_tab, "
4645                                                   "d.refobjsubid AS owning_col, "
4646                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4647                                                   "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4648                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4649                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4650                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4651                                                   "FROM pg_class c "
4652                                                   "LEFT JOIN pg_depend d ON "
4653                                                   "(c.relkind = '%c' AND "
4654                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4655                                                   "d.objsubid = 0 AND "
4656                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4657                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4658                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4659                                                   "ORDER BY c.oid",
4660                                                   username_subquery,
4661                                                   RELKIND_SEQUENCE,
4662                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4663                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4664                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4665         }
4666         else if (fout->remoteVersion >= 90300)
4667         {
4668                 /*
4669                  * Left join to pick up dependency info linking sequences to their
4670                  * owning column, if any (note this dependency is AUTO as of 8.2)
4671                  */
4672                 appendPQExpBuffer(query,
4673                                                   "SELECT c.tableoid, c.oid, c.relname, "
4674                                                   "c.relacl, c.relkind, c.relnamespace, "
4675                                                   "(%s c.relowner) AS rolname, "
4676                                                   "c.relchecks, c.relhastriggers, "
4677                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4678                                                   "'f'::bool AS relrowsecurity, "
4679                                                   "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
4680                                                   "tc.relfrozenxid AS tfrozenxid, "
4681                                                   "tc.relminmxid AS tminmxid, "
4682                                                   "c.relpersistence, c.relispopulated, "
4683                                                   "'d' AS relreplident, c.relpages, "
4684                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4685                                                   "d.refobjid AS owning_tab, "
4686                                                   "d.refobjsubid AS owning_col, "
4687                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4688                                                   "array_to_string(array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded'), ', ') AS reloptions, "
4689                                                   "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
4690                                                   "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
4691                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4692                                                   "FROM pg_class c "
4693                                                   "LEFT JOIN pg_depend d ON "
4694                                                   "(c.relkind = '%c' AND "
4695                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4696                                                   "d.objsubid = 0 AND "
4697                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4698                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4699                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4700                                                   "ORDER BY c.oid",
4701                                                   username_subquery,
4702                                                   RELKIND_SEQUENCE,
4703                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4704                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4705                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4706         }
4707         else if (fout->remoteVersion >= 90100)
4708         {
4709                 /*
4710                  * Left join to pick up dependency info linking sequences to their
4711                  * owning column, if any (note this dependency is AUTO as of 8.2)
4712                  */
4713                 appendPQExpBuffer(query,
4714                                                   "SELECT c.tableoid, c.oid, c.relname, "
4715                                                   "c.relacl, c.relkind, c.relnamespace, "
4716                                                   "(%s c.relowner) AS rolname, "
4717                                                   "c.relchecks, c.relhastriggers, "
4718                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4719                                                   "'f'::bool AS relrowsecurity, "
4720                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
4721                                                   "tc.relfrozenxid AS tfrozenxid, "
4722                                                   "0 AS tminmxid, "
4723                                                   "c.relpersistence, 't' as relispopulated, "
4724                                                   "'d' AS relreplident, c.relpages, "
4725                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4726                                                   "d.refobjid AS owning_tab, "
4727                                                   "d.refobjsubid AS owning_col, "
4728                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4729                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4730                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4731                                                   "FROM pg_class c "
4732                                                   "LEFT JOIN pg_depend d ON "
4733                                                   "(c.relkind = '%c' AND "
4734                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4735                                                   "d.objsubid = 0 AND "
4736                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4737                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4738                                    "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
4739                                                   "ORDER BY c.oid",
4740                                                   username_subquery,
4741                                                   RELKIND_SEQUENCE,
4742                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4743                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
4744                                                   RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
4745         }
4746         else if (fout->remoteVersion >= 90000)
4747         {
4748                 /*
4749                  * Left join to pick up dependency info linking sequences to their
4750                  * owning column, if any (note this dependency is AUTO as of 8.2)
4751                  */
4752                 appendPQExpBuffer(query,
4753                                                   "SELECT c.tableoid, c.oid, c.relname, "
4754                                                   "c.relacl, c.relkind, c.relnamespace, "
4755                                                   "(%s c.relowner) AS rolname, "
4756                                                   "c.relchecks, c.relhastriggers, "
4757                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4758                                                   "'f'::bool AS relrowsecurity, "
4759                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
4760                                                   "tc.relfrozenxid AS tfrozenxid, "
4761                                                   "0 AS tminmxid, "
4762                                                   "'p' AS relpersistence, 't' as relispopulated, "
4763                                                   "'d' AS relreplident, c.relpages, "
4764                                                   "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
4765                                                   "d.refobjid AS owning_tab, "
4766                                                   "d.refobjsubid AS owning_col, "
4767                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4768                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4769                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4770                                                   "FROM pg_class c "
4771                                                   "LEFT JOIN pg_depend d ON "
4772                                                   "(c.relkind = '%c' AND "
4773                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4774                                                   "d.objsubid = 0 AND "
4775                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4776                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4777                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4778                                                   "ORDER BY c.oid",
4779                                                   username_subquery,
4780                                                   RELKIND_SEQUENCE,
4781                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4782                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4783         }
4784         else if (fout->remoteVersion >= 80400)
4785         {
4786                 /*
4787                  * Left join to pick up dependency info linking sequences to their
4788                  * owning column, if any (note this dependency is AUTO as of 8.2)
4789                  */
4790                 appendPQExpBuffer(query,
4791                                                   "SELECT c.tableoid, c.oid, c.relname, "
4792                                                   "c.relacl, c.relkind, c.relnamespace, "
4793                                                   "(%s c.relowner) AS rolname, "
4794                                                   "c.relchecks, c.relhastriggers, "
4795                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4796                                                   "'f'::bool AS relrowsecurity, "
4797                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
4798                                                   "tc.relfrozenxid AS tfrozenxid, "
4799                                                   "0 AS tminmxid, "
4800                                                   "'p' AS relpersistence, 't' as relispopulated, "
4801                                                   "'d' AS relreplident, c.relpages, "
4802                                                   "NULL AS reloftype, "
4803                                                   "d.refobjid AS owning_tab, "
4804                                                   "d.refobjsubid AS owning_col, "
4805                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4806                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4807                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
4808                                                   "FROM pg_class c "
4809                                                   "LEFT JOIN pg_depend d ON "
4810                                                   "(c.relkind = '%c' AND "
4811                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4812                                                   "d.objsubid = 0 AND "
4813                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4814                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4815                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4816                                                   "ORDER BY c.oid",
4817                                                   username_subquery,
4818                                                   RELKIND_SEQUENCE,
4819                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4820                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4821         }
4822         else if (fout->remoteVersion >= 80200)
4823         {
4824                 /*
4825                  * Left join to pick up dependency info linking sequences to their
4826                  * owning column, if any (note this dependency is AUTO as of 8.2)
4827                  */
4828                 appendPQExpBuffer(query,
4829                                                   "SELECT c.tableoid, c.oid, c.relname, "
4830                                                   "c.relacl, c.relkind, c.relnamespace, "
4831                                                   "(%s c.relowner) AS rolname, "
4832                                           "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
4833                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
4834                                                   "'f'::bool AS relrowsecurity, "
4835                                                   "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
4836                                                   "tc.relfrozenxid AS tfrozenxid, "
4837                                                   "0 AS tminmxid, "
4838                                                   "'p' AS relpersistence, 't' as relispopulated, "
4839                                                   "'d' AS relreplident, c.relpages, "
4840                                                   "NULL AS reloftype, "
4841                                                   "d.refobjid AS owning_tab, "
4842                                                   "d.refobjsubid AS owning_col, "
4843                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4844                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
4845                                                   "NULL AS toast_reloptions "
4846                                                   "FROM pg_class c "
4847                                                   "LEFT JOIN pg_depend d ON "
4848                                                   "(c.relkind = '%c' AND "
4849                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4850                                                   "d.objsubid = 0 AND "
4851                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
4852                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
4853                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
4854                                                   "ORDER BY c.oid",
4855                                                   username_subquery,
4856                                                   RELKIND_SEQUENCE,
4857                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4858                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4859         }
4860         else if (fout->remoteVersion >= 80000)
4861         {
4862                 /*
4863                  * Left join to pick up dependency info linking sequences to their
4864                  * owning column, if any
4865                  */
4866                 appendPQExpBuffer(query,
4867                                                   "SELECT c.tableoid, c.oid, relname, "
4868                                                   "relacl, relkind, relnamespace, "
4869                                                   "(%s relowner) AS rolname, "
4870                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4871                                                   "relhasindex, relhasrules, relhasoids, "
4872                                                   "'f'::bool AS relrowsecurity, "
4873                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
4874                                                   "0 AS toid, "
4875                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
4876                                                   "'p' AS relpersistence, 't' as relispopulated, "
4877                                                   "'d' AS relreplident, relpages, "
4878                                                   "NULL AS reloftype, "
4879                                                   "d.refobjid AS owning_tab, "
4880                                                   "d.refobjsubid AS owning_col, "
4881                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
4882                                                   "NULL AS reloptions, "
4883                                                   "NULL AS toast_reloptions "
4884                                                   "FROM pg_class c "
4885                                                   "LEFT JOIN pg_depend d ON "
4886                                                   "(c.relkind = '%c' AND "
4887                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4888                                                   "d.objsubid = 0 AND "
4889                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4890                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
4891                                                   "ORDER BY c.oid",
4892                                                   username_subquery,
4893                                                   RELKIND_SEQUENCE,
4894                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4895                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4896         }
4897         else if (fout->remoteVersion >= 70300)
4898         {
4899                 /*
4900                  * Left join to pick up dependency info linking sequences to their
4901                  * owning column, if any
4902                  */
4903                 appendPQExpBuffer(query,
4904                                                   "SELECT c.tableoid, c.oid, relname, "
4905                                                   "relacl, relkind, relnamespace, "
4906                                                   "(%s relowner) AS rolname, "
4907                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4908                                                   "relhasindex, relhasrules, relhasoids, "
4909                                                   "'f'::bool AS relrowsecurity, "
4910                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
4911                                                   "0 AS toid, "
4912                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
4913                                                   "'p' AS relpersistence, 't' as relispopulated, "
4914                                                   "'d' AS relreplident, relpages, "
4915                                                   "NULL AS reloftype, "
4916                                                   "d.refobjid AS owning_tab, "
4917                                                   "d.refobjsubid AS owning_col, "
4918                                                   "NULL AS reltablespace, "
4919                                                   "NULL AS reloptions, "
4920                                                   "NULL AS toast_reloptions "
4921                                                   "FROM pg_class c "
4922                                                   "LEFT JOIN pg_depend d ON "
4923                                                   "(c.relkind = '%c' AND "
4924                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
4925                                                   "d.objsubid = 0 AND "
4926                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
4927                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
4928                                                   "ORDER BY c.oid",
4929                                                   username_subquery,
4930                                                   RELKIND_SEQUENCE,
4931                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
4932                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
4933         }
4934         else if (fout->remoteVersion >= 70200)
4935         {
4936                 appendPQExpBuffer(query,
4937                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4938                                                   "0::oid AS relnamespace, "
4939                                                   "(%s relowner) AS rolname, "
4940                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4941                                                   "relhasindex, relhasrules, relhasoids, "
4942                                                   "'f'::bool AS relrowsecurity, "
4943                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
4944                                                   "0 AS toid, "
4945                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
4946                                                   "'p' AS relpersistence, 't' as relispopulated, "
4947                                                   "'d' AS relreplident, relpages, "
4948                                                   "NULL AS reloftype, "
4949                                                   "NULL::oid AS owning_tab, "
4950                                                   "NULL::int4 AS owning_col, "
4951                                                   "NULL AS reltablespace, "
4952                                                   "NULL AS reloptions, "
4953                                                   "NULL AS toast_reloptions "
4954                                                   "FROM pg_class "
4955                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4956                                                   "ORDER BY oid",
4957                                                   username_subquery,
4958                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4959         }
4960         else if (fout->remoteVersion >= 70100)
4961         {
4962                 /* all tables have oids in 7.1 */
4963                 appendPQExpBuffer(query,
4964                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
4965                                                   "0::oid AS relnamespace, "
4966                                                   "(%s relowner) AS rolname, "
4967                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
4968                                                   "relhasindex, relhasrules, "
4969                                                   "'t'::bool AS relhasoids, "
4970                                                   "'f'::bool AS relrowsecurity, "
4971                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
4972                                                   "0 AS toid, "
4973                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
4974                                                   "'p' AS relpersistence, 't' as relispopulated, "
4975                                                   "'d' AS relreplident, relpages, "
4976                                                   "NULL AS reloftype, "
4977                                                   "NULL::oid AS owning_tab, "
4978                                                   "NULL::int4 AS owning_col, "
4979                                                   "NULL AS reltablespace, "
4980                                                   "NULL AS reloptions, "
4981                                                   "NULL AS toast_reloptions "
4982                                                   "FROM pg_class "
4983                                                   "WHERE relkind IN ('%c', '%c', '%c') "
4984                                                   "ORDER BY oid",
4985                                                   username_subquery,
4986                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
4987         }
4988         else
4989         {
4990                 /*
4991                  * Before 7.1, view relkind was not set to 'v', so we must check if we
4992                  * have a view by looking for a rule in pg_rewrite.
4993                  */
4994                 appendPQExpBuffer(query,
4995                                                   "SELECT "
4996                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
4997                                                   "oid, relname, relacl, "
4998                                                   "CASE WHEN relhasrules and relkind = 'r' "
4999                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
5000                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
5001                                                   "THEN '%c'::\"char\" "
5002                                                   "ELSE relkind END AS relkind,"
5003                                                   "0::oid AS relnamespace, "
5004                                                   "(%s relowner) AS rolname, "
5005                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
5006                                                   "relhasindex, relhasrules, "
5007                                                   "'t'::bool AS relhasoids, "
5008                                                   "'f'::bool AS relrowsecurity, "
5009                                                   "0 AS relfrozenxid, 0 AS relminmxid,"
5010                                                   "0 AS toid, "
5011                                                   "0 AS tfrozenxid, 0 AS tminmxid,"
5012                                                   "'p' AS relpersistence, 't' as relispopulated, "
5013                                                   "'d' AS relreplident, 0 AS relpages, "
5014                                                   "NULL AS reloftype, "
5015                                                   "NULL::oid AS owning_tab, "
5016                                                   "NULL::int4 AS owning_col, "
5017                                                   "NULL AS reltablespace, "
5018                                                   "NULL AS reloptions, "
5019                                                   "NULL AS toast_reloptions "
5020                                                   "FROM pg_class c "
5021                                                   "WHERE relkind IN ('%c', '%c') "
5022                                                   "ORDER BY oid",
5023                                                   RELKIND_VIEW,
5024                                                   username_subquery,
5025                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
5026         }
5027
5028         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5029
5030         ntups = PQntuples(res);
5031
5032         *numTables = ntups;
5033
5034         /*
5035          * Extract data from result and lock dumpable tables.  We do the locking
5036          * before anything else, to minimize the window wherein a table could
5037          * disappear under us.
5038          *
5039          * Note that we have to save info about all tables here, even when dumping
5040          * only one, because we don't yet know which tables might be inheritance
5041          * ancestors of the target table.
5042          */
5043         tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
5044
5045         i_reltableoid = PQfnumber(res, "tableoid");
5046         i_reloid = PQfnumber(res, "oid");
5047         i_relname = PQfnumber(res, "relname");
5048         i_relnamespace = PQfnumber(res, "relnamespace");
5049         i_relacl = PQfnumber(res, "relacl");
5050         i_relkind = PQfnumber(res, "relkind");
5051         i_rolname = PQfnumber(res, "rolname");
5052         i_relchecks = PQfnumber(res, "relchecks");
5053         i_relhastriggers = PQfnumber(res, "relhastriggers");
5054         i_relhasindex = PQfnumber(res, "relhasindex");
5055         i_relhasrules = PQfnumber(res, "relhasrules");
5056         i_relrowsec = PQfnumber(res, "relrowsecurity");
5057         i_relhasoids = PQfnumber(res, "relhasoids");
5058         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
5059         i_relminmxid = PQfnumber(res, "relminmxid");
5060         i_toastoid = PQfnumber(res, "toid");
5061         i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
5062         i_toastminmxid = PQfnumber(res, "tminmxid");
5063         i_relpersistence = PQfnumber(res, "relpersistence");
5064         i_relispopulated = PQfnumber(res, "relispopulated");
5065         i_relreplident = PQfnumber(res, "relreplident");
5066         i_relpages = PQfnumber(res, "relpages");
5067         i_owning_tab = PQfnumber(res, "owning_tab");
5068         i_owning_col = PQfnumber(res, "owning_col");
5069         i_reltablespace = PQfnumber(res, "reltablespace");
5070         i_reloptions = PQfnumber(res, "reloptions");
5071         i_checkoption = PQfnumber(res, "checkoption");
5072         i_toastreloptions = PQfnumber(res, "toast_reloptions");
5073         i_reloftype = PQfnumber(res, "reloftype");
5074
5075         if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
5076         {
5077                 /*
5078                  * Arrange to fail instead of waiting forever for a table lock.
5079                  *
5080                  * NB: this coding assumes that the only queries issued within the
5081                  * following loop are LOCK TABLEs; else the timeout may be undesirably
5082                  * applied to other things too.
5083                  */
5084                 resetPQExpBuffer(query);
5085                 appendPQExpBufferStr(query, "SET statement_timeout = ");
5086                 appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
5087                 ExecuteSqlStatement(fout, query->data);
5088         }
5089
5090         for (i = 0; i < ntups; i++)
5091         {
5092                 tblinfo[i].dobj.objType = DO_TABLE;
5093                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
5094                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
5095                 AssignDumpId(&tblinfo[i].dobj);
5096                 tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
5097                 tblinfo[i].dobj.namespace =
5098                         findNamespace(fout,
5099                                                   atooid(PQgetvalue(res, i, i_relnamespace)),
5100                                                   tblinfo[i].dobj.catId.oid);
5101                 tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5102                 tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
5103                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
5104                 tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
5105                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
5106                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
5107                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
5108                 tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
5109                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
5110                 tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
5111                 tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
5112                 tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
5113                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
5114                 tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
5115                 tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
5116                 tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
5117                 tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
5118                 if (PQgetisnull(res, i, i_reloftype))
5119                         tblinfo[i].reloftype = NULL;
5120                 else
5121                         tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
5122                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
5123                 if (PQgetisnull(res, i, i_owning_tab))
5124                 {
5125                         tblinfo[i].owning_tab = InvalidOid;
5126                         tblinfo[i].owning_col = 0;
5127                 }
5128                 else
5129                 {
5130                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
5131                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
5132                 }
5133                 tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
5134                 tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
5135                 if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
5136                         tblinfo[i].checkoption = NULL;
5137                 else
5138                         tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
5139                 tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
5140
5141                 /* other fields were zeroed above */
5142
5143                 /*
5144                  * Decide whether we want to dump this table.
5145                  */
5146                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
5147                         tblinfo[i].dobj.dump = false;
5148                 else
5149                         selectDumpableTable(&tblinfo[i]);
5150                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
5151
5152                 tblinfo[i].postponed_def = false;               /* might get set during sort */
5153
5154                 /*
5155                  * Read-lock target tables to make sure they aren't DROPPED or altered
5156                  * in schema before we get around to dumping them.
5157                  *
5158                  * Note that we don't explicitly lock parents of the target tables; we
5159                  * assume our lock on the child is enough to prevent schema
5160                  * alterations to parent tables.
5161                  *
5162                  * NOTE: it'd be kinda nice to lock other relations too, not only
5163                  * plain tables, but the backend doesn't presently allow that.
5164                  */
5165                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
5166                 {
5167                         resetPQExpBuffer(query);
5168                         appendPQExpBuffer(query,
5169                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
5170                                                           fmtQualifiedId(fout->remoteVersion,
5171                                                                                 tblinfo[i].dobj.namespace->dobj.name,
5172                                                                                          tblinfo[i].dobj.name));
5173                         ExecuteSqlStatement(fout, query->data);
5174                 }
5175
5176                 /* Emit notice if join for owner failed */
5177                 if (strlen(tblinfo[i].rolname) == 0)
5178                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
5179                                           tblinfo[i].dobj.name);
5180         }
5181
5182         if (dopt->lockWaitTimeout && fout->remoteVersion >= 70300)
5183         {
5184                 ExecuteSqlStatement(fout, "SET statement_timeout = 0");
5185         }
5186
5187         PQclear(res);
5188
5189         destroyPQExpBuffer(query);
5190
5191         return tblinfo;
5192 }
5193
5194 /*
5195  * getOwnedSeqs
5196  *        identify owned sequences and mark them as dumpable if owning table is
5197  *
5198  * We used to do this in getTables(), but it's better to do it after the
5199  * index used by findTableByOid() has been set up.
5200  */
5201 void
5202 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
5203 {
5204         int                     i;
5205
5206         /*
5207          * Force sequences that are "owned" by table columns to be dumped whenever
5208          * their owning table is being dumped.
5209          */
5210         for (i = 0; i < numTables; i++)
5211         {
5212                 TableInfo  *seqinfo = &tblinfo[i];
5213                 TableInfo  *owning_tab;
5214
5215                 if (!OidIsValid(seqinfo->owning_tab))
5216                         continue;                       /* not an owned sequence */
5217                 if (seqinfo->dobj.dump)
5218                         continue;                       /* no need to search */
5219                 owning_tab = findTableByOid(seqinfo->owning_tab);
5220                 if (owning_tab && owning_tab->dobj.dump)
5221                 {
5222                         seqinfo->interesting = true;
5223                         seqinfo->dobj.dump = true;
5224                 }
5225         }
5226 }
5227
5228 /*
5229  * getInherits
5230  *        read all the inheritance information
5231  * from the system catalogs return them in the InhInfo* structure
5232  *
5233  * numInherits is set to the number of pairs read in
5234  */
5235 InhInfo *
5236 getInherits(Archive *fout, int *numInherits)
5237 {
5238         PGresult   *res;
5239         int                     ntups;
5240         int                     i;
5241         PQExpBuffer query = createPQExpBuffer();
5242         InhInfo    *inhinfo;
5243
5244         int                     i_inhrelid;
5245         int                     i_inhparent;
5246
5247         /* Make sure we are in proper schema */
5248         selectSourceSchema(fout, "pg_catalog");
5249
5250         /* find all the inheritance information */
5251
5252         appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
5253
5254         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5255
5256         ntups = PQntuples(res);
5257
5258         *numInherits = ntups;
5259
5260         inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
5261
5262         i_inhrelid = PQfnumber(res, "inhrelid");
5263         i_inhparent = PQfnumber(res, "inhparent");
5264
5265         for (i = 0; i < ntups; i++)
5266         {
5267                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
5268                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
5269         }
5270
5271         PQclear(res);
5272
5273         destroyPQExpBuffer(query);
5274
5275         return inhinfo;
5276 }
5277
5278 /*
5279  * getIndexes
5280  *        get information about every index on a dumpable table
5281  *
5282  * Note: index data is not returned directly to the caller, but it
5283  * does get entered into the DumpableObject tables.
5284  */
5285 void
5286 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
5287 {
5288         int                     i,
5289                                 j;
5290         PQExpBuffer query = createPQExpBuffer();
5291         PGresult   *res;
5292         IndxInfo   *indxinfo;
5293         ConstraintInfo *constrinfo;
5294         int                     i_tableoid,
5295                                 i_oid,
5296                                 i_indexname,
5297                                 i_indexdef,
5298                                 i_indnkeys,
5299                                 i_indkey,
5300                                 i_indisclustered,
5301                                 i_indisreplident,
5302                                 i_contype,
5303                                 i_conname,
5304                                 i_condeferrable,
5305                                 i_condeferred,
5306                                 i_contableoid,
5307                                 i_conoid,
5308                                 i_condef,
5309                                 i_tablespace,
5310                                 i_options,
5311                                 i_relpages;
5312         int                     ntups;
5313
5314         for (i = 0; i < numTables; i++)
5315         {
5316                 TableInfo  *tbinfo = &tblinfo[i];
5317
5318                 /* Only plain tables and materialized views have indexes. */
5319                 if (tbinfo->relkind != RELKIND_RELATION &&
5320                         tbinfo->relkind != RELKIND_MATVIEW)
5321                         continue;
5322                 if (!tbinfo->hasindex)
5323                         continue;
5324
5325                 /* Ignore indexes of tables not to be dumped */
5326                 if (!tbinfo->dobj.dump)
5327                         continue;
5328
5329                 if (g_verbose)
5330                         write_msg(NULL, "reading indexes for table \"%s\".\"%s\"\n",
5331                                           tbinfo->dobj.namespace->dobj.name,
5332                                           tbinfo->dobj.name);
5333
5334                 /* Make sure we are in proper schema so indexdef is right */
5335                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5336
5337                 /*
5338                  * The point of the messy-looking outer join is to find a constraint
5339                  * that is related by an internal dependency link to the index. If we
5340                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
5341                  * assume an index won't have more than one internal dependency.
5342                  *
5343                  * As of 9.0 we don't need to look at pg_depend but can check for a
5344                  * match to pg_constraint.conindid.  The check on conrelid is
5345                  * redundant but useful because that column is indexed while conindid
5346                  * is not.
5347                  */
5348                 resetPQExpBuffer(query);
5349                 if (fout->remoteVersion >= 90400)
5350                 {
5351                         /*
5352                          * the test on indisready is necessary in 9.2, and harmless in
5353                          * earlier/later versions
5354                          */
5355                         appendPQExpBuffer(query,
5356                                                           "SELECT t.tableoid, t.oid, "
5357                                                           "t.relname AS indexname, "
5358                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5359                                                           "t.relnatts AS indnkeys, "
5360                                                           "i.indkey, i.indisclustered, "
5361                                                           "i.indisreplident, t.relpages, "
5362                                                           "c.contype, c.conname, "
5363                                                           "c.condeferrable, c.condeferred, "
5364                                                           "c.tableoid AS contableoid, "
5365                                                           "c.oid AS conoid, "
5366                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5367                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5368                                                         "array_to_string(t.reloptions, ', ') AS options "
5369                                                           "FROM pg_catalog.pg_index i "
5370                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5371                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5372                                                           "ON (i.indrelid = c.conrelid AND "
5373                                                           "i.indexrelid = c.conindid AND "
5374                                                           "c.contype IN ('p','u','x')) "
5375                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5376                                                           "AND i.indisvalid AND i.indisready "
5377                                                           "ORDER BY indexname",
5378                                                           tbinfo->dobj.catId.oid);
5379                 }
5380                 else if (fout->remoteVersion >= 90000)
5381                 {
5382                         /*
5383                          * the test on indisready is necessary in 9.2, and harmless in
5384                          * earlier/later versions
5385                          */
5386                         appendPQExpBuffer(query,
5387                                                           "SELECT t.tableoid, t.oid, "
5388                                                           "t.relname AS indexname, "
5389                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5390                                                           "t.relnatts AS indnkeys, "
5391                                                           "i.indkey, i.indisclustered, "
5392                                                           "false AS indisreplident, t.relpages, "
5393                                                           "c.contype, c.conname, "
5394                                                           "c.condeferrable, c.condeferred, "
5395                                                           "c.tableoid AS contableoid, "
5396                                                           "c.oid AS conoid, "
5397                                   "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
5398                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5399                                                         "array_to_string(t.reloptions, ', ') AS options "
5400                                                           "FROM pg_catalog.pg_index i "
5401                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5402                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5403                                                           "ON (i.indrelid = c.conrelid AND "
5404                                                           "i.indexrelid = c.conindid AND "
5405                                                           "c.contype IN ('p','u','x')) "
5406                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5407                                                           "AND i.indisvalid AND i.indisready "
5408                                                           "ORDER BY indexname",
5409                                                           tbinfo->dobj.catId.oid);
5410                 }
5411                 else if (fout->remoteVersion >= 80200)
5412                 {
5413                         appendPQExpBuffer(query,
5414                                                           "SELECT t.tableoid, t.oid, "
5415                                                           "t.relname AS indexname, "
5416                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5417                                                           "t.relnatts AS indnkeys, "
5418                                                           "i.indkey, i.indisclustered, "
5419                                                           "false AS indisreplident, t.relpages, "
5420                                                           "c.contype, c.conname, "
5421                                                           "c.condeferrable, c.condeferred, "
5422                                                           "c.tableoid AS contableoid, "
5423                                                           "c.oid AS conoid, "
5424                                                           "null AS condef, "
5425                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5426                                                         "array_to_string(t.reloptions, ', ') AS options "
5427                                                           "FROM pg_catalog.pg_index i "
5428                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5429                                                           "LEFT JOIN pg_catalog.pg_depend d "
5430                                                           "ON (d.classid = t.tableoid "
5431                                                           "AND d.objid = t.oid "
5432                                                           "AND d.deptype = 'i') "
5433                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5434                                                           "ON (d.refclassid = c.tableoid "
5435                                                           "AND d.refobjid = c.oid) "
5436                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5437                                                           "AND i.indisvalid "
5438                                                           "ORDER BY indexname",
5439                                                           tbinfo->dobj.catId.oid);
5440                 }
5441                 else if (fout->remoteVersion >= 80000)
5442                 {
5443                         appendPQExpBuffer(query,
5444                                                           "SELECT t.tableoid, t.oid, "
5445                                                           "t.relname AS indexname, "
5446                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5447                                                           "t.relnatts AS indnkeys, "
5448                                                           "i.indkey, i.indisclustered, "
5449                                                           "false AS indisreplident, t.relpages, "
5450                                                           "c.contype, c.conname, "
5451                                                           "c.condeferrable, c.condeferred, "
5452                                                           "c.tableoid AS contableoid, "
5453                                                           "c.oid AS conoid, "
5454                                                           "null AS condef, "
5455                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
5456                                                           "null AS options "
5457                                                           "FROM pg_catalog.pg_index i "
5458                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5459                                                           "LEFT JOIN pg_catalog.pg_depend d "
5460                                                           "ON (d.classid = t.tableoid "
5461                                                           "AND d.objid = t.oid "
5462                                                           "AND d.deptype = 'i') "
5463                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5464                                                           "ON (d.refclassid = c.tableoid "
5465                                                           "AND d.refobjid = c.oid) "
5466                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5467                                                           "ORDER BY indexname",
5468                                                           tbinfo->dobj.catId.oid);
5469                 }
5470                 else if (fout->remoteVersion >= 70300)
5471                 {
5472                         appendPQExpBuffer(query,
5473                                                           "SELECT t.tableoid, t.oid, "
5474                                                           "t.relname AS indexname, "
5475                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
5476                                                           "t.relnatts AS indnkeys, "
5477                                                           "i.indkey, i.indisclustered, "
5478                                                           "false AS indisreplident, t.relpages, "
5479                                                           "c.contype, c.conname, "
5480                                                           "c.condeferrable, c.condeferred, "
5481                                                           "c.tableoid AS contableoid, "
5482                                                           "c.oid AS conoid, "
5483                                                           "null AS condef, "
5484                                                           "NULL AS tablespace, "
5485                                                           "null AS options "
5486                                                           "FROM pg_catalog.pg_index i "
5487                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5488                                                           "LEFT JOIN pg_catalog.pg_depend d "
5489                                                           "ON (d.classid = t.tableoid "
5490                                                           "AND d.objid = t.oid "
5491                                                           "AND d.deptype = 'i') "
5492                                                           "LEFT JOIN pg_catalog.pg_constraint c "
5493                                                           "ON (d.refclassid = c.tableoid "
5494                                                           "AND d.refobjid = c.oid) "
5495                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
5496                                                           "ORDER BY indexname",
5497                                                           tbinfo->dobj.catId.oid);
5498                 }
5499                 else if (fout->remoteVersion >= 70100)
5500                 {
5501                         appendPQExpBuffer(query,
5502                                                           "SELECT t.tableoid, t.oid, "
5503                                                           "t.relname AS indexname, "
5504                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5505                                                           "t.relnatts AS indnkeys, "
5506                                                           "i.indkey, false AS indisclustered, "
5507                                                           "false AS indisreplident, t.relpages, "
5508                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5509                                                           "ELSE '0'::char END AS contype, "
5510                                                           "t.relname AS conname, "
5511                                                           "false AS condeferrable, "
5512                                                           "false AS condeferred, "
5513                                                           "0::oid AS contableoid, "
5514                                                           "t.oid AS conoid, "
5515                                                           "null AS condef, "
5516                                                           "NULL AS tablespace, "
5517                                                           "null AS options "
5518                                                           "FROM pg_index i, pg_class t "
5519                                                           "WHERE t.oid = i.indexrelid "
5520                                                           "AND i.indrelid = '%u'::oid "
5521                                                           "ORDER BY indexname",
5522                                                           tbinfo->dobj.catId.oid);
5523                 }
5524                 else
5525                 {
5526                         appendPQExpBuffer(query,
5527                                                           "SELECT "
5528                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
5529                                                           "t.oid, "
5530                                                           "t.relname AS indexname, "
5531                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
5532                                                           "t.relnatts AS indnkeys, "
5533                                                           "i.indkey, false AS indisclustered, "
5534                                                           "false AS indisreplident, t.relpages, "
5535                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
5536                                                           "ELSE '0'::char END AS contype, "
5537                                                           "t.relname AS conname, "
5538                                                           "false AS condeferrable, "
5539                                                           "false AS condeferred, "
5540                                                           "0::oid AS contableoid, "
5541                                                           "t.oid AS conoid, "
5542                                                           "null AS condef, "
5543                                                           "NULL AS tablespace, "
5544                                                           "null AS options "
5545                                                           "FROM pg_index i, pg_class t "
5546                                                           "WHERE t.oid = i.indexrelid "
5547                                                           "AND i.indrelid = '%u'::oid "
5548                                                           "ORDER BY indexname",
5549                                                           tbinfo->dobj.catId.oid);
5550                 }
5551
5552                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5553
5554                 ntups = PQntuples(res);
5555
5556                 i_tableoid = PQfnumber(res, "tableoid");
5557                 i_oid = PQfnumber(res, "oid");
5558                 i_indexname = PQfnumber(res, "indexname");
5559                 i_indexdef = PQfnumber(res, "indexdef");
5560                 i_indnkeys = PQfnumber(res, "indnkeys");
5561                 i_indkey = PQfnumber(res, "indkey");
5562                 i_indisclustered = PQfnumber(res, "indisclustered");
5563                 i_indisreplident = PQfnumber(res, "indisreplident");
5564                 i_relpages = PQfnumber(res, "relpages");
5565                 i_contype = PQfnumber(res, "contype");
5566                 i_conname = PQfnumber(res, "conname");
5567                 i_condeferrable = PQfnumber(res, "condeferrable");
5568                 i_condeferred = PQfnumber(res, "condeferred");
5569                 i_contableoid = PQfnumber(res, "contableoid");
5570                 i_conoid = PQfnumber(res, "conoid");
5571                 i_condef = PQfnumber(res, "condef");
5572                 i_tablespace = PQfnumber(res, "tablespace");
5573                 i_options = PQfnumber(res, "options");
5574
5575                 indxinfo = (IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
5576                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5577
5578                 for (j = 0; j < ntups; j++)
5579                 {
5580                         char            contype;
5581
5582                         indxinfo[j].dobj.objType = DO_INDEX;
5583                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
5584                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
5585                         AssignDumpId(&indxinfo[j].dobj);
5586                         indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
5587                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5588                         indxinfo[j].indextable = tbinfo;
5589                         indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
5590                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5591                         indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
5592                         indxinfo[j].options = pg_strdup(PQgetvalue(res, j, i_options));
5593
5594                         /*
5595                          * In pre-7.4 releases, indkeys may contain more entries than
5596                          * indnkeys says (since indnkeys will be 1 for a functional
5597                          * index).  We don't actually care about this case since we don't
5598                          * examine indkeys except for indexes associated with PRIMARY and
5599                          * UNIQUE constraints, which are never functional indexes. But we
5600                          * have to allocate enough space to keep parseOidArray from
5601                          * complaining.
5602                          */
5603                         indxinfo[j].indkeys = (Oid *) pg_malloc(INDEX_MAX_KEYS * sizeof(Oid));
5604                         parseOidArray(PQgetvalue(res, j, i_indkey),
5605                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
5606                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5607                         indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
5608                         indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
5609                         contype = *(PQgetvalue(res, j, i_contype));
5610
5611                         if (contype == 'p' || contype == 'u' || contype == 'x')
5612                         {
5613                                 /*
5614                                  * If we found a constraint matching the index, create an
5615                                  * entry for it.
5616                                  *
5617                                  * In a pre-7.3 database, we take this path iff the index was
5618                                  * marked indisprimary.
5619                                  */
5620                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
5621                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5622                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5623                                 AssignDumpId(&constrinfo[j].dobj);
5624                                 constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5625                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5626                                 constrinfo[j].contable = tbinfo;
5627                                 constrinfo[j].condomain = NULL;
5628                                 constrinfo[j].contype = contype;
5629                                 if (contype == 'x')
5630                                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5631                                 else
5632                                         constrinfo[j].condef = NULL;
5633                                 constrinfo[j].confrelid = InvalidOid;
5634                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
5635                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
5636                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
5637                                 constrinfo[j].conislocal = true;
5638                                 constrinfo[j].separate = true;
5639
5640                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
5641
5642                                 /* If pre-7.3 DB, better make sure table comes first */
5643                                 addObjectDependency(&constrinfo[j].dobj,
5644                                                                         tbinfo->dobj.dumpId);
5645                         }
5646                         else
5647                         {
5648                                 /* Plain secondary index */
5649                                 indxinfo[j].indexconstraint = 0;
5650                         }
5651                 }
5652
5653                 PQclear(res);
5654         }
5655
5656         destroyPQExpBuffer(query);
5657 }
5658
5659 /*
5660  * getConstraints
5661  *
5662  * Get info about constraints on dumpable tables.
5663  *
5664  * Currently handles foreign keys only.
5665  * Unique and primary key constraints are handled with indexes,
5666  * while check constraints are processed in getTableAttrs().
5667  */
5668 void
5669 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
5670 {
5671         int                     i,
5672                                 j;
5673         ConstraintInfo *constrinfo;
5674         PQExpBuffer query;
5675         PGresult   *res;
5676         int                     i_contableoid,
5677                                 i_conoid,
5678                                 i_conname,
5679                                 i_confrelid,
5680                                 i_condef;
5681         int                     ntups;
5682
5683         /* pg_constraint was created in 7.3, so nothing to do if older */
5684         if (fout->remoteVersion < 70300)
5685                 return;
5686
5687         query = createPQExpBuffer();
5688
5689         for (i = 0; i < numTables; i++)
5690         {
5691                 TableInfo  *tbinfo = &tblinfo[i];
5692
5693                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
5694                         continue;
5695
5696                 if (g_verbose)
5697                         write_msg(NULL, "reading foreign key constraints for table \"%s\".\"%s\"\n",
5698                                           tbinfo->dobj.namespace->dobj.name,
5699                                           tbinfo->dobj.name);
5700
5701                 /*
5702                  * select table schema to ensure constraint expr is qualified if
5703                  * needed
5704                  */
5705                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
5706
5707                 resetPQExpBuffer(query);
5708                 appendPQExpBuffer(query,
5709                                                   "SELECT tableoid, oid, conname, confrelid, "
5710                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
5711                                                   "FROM pg_catalog.pg_constraint "
5712                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5713                                                   "AND contype = 'f'",
5714                                                   tbinfo->dobj.catId.oid);
5715                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5716
5717                 ntups = PQntuples(res);
5718
5719                 i_contableoid = PQfnumber(res, "tableoid");
5720                 i_conoid = PQfnumber(res, "oid");
5721                 i_conname = PQfnumber(res, "conname");
5722                 i_confrelid = PQfnumber(res, "confrelid");
5723                 i_condef = PQfnumber(res, "condef");
5724
5725                 constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5726
5727                 for (j = 0; j < ntups; j++)
5728                 {
5729                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
5730                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
5731                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
5732                         AssignDumpId(&constrinfo[j].dobj);
5733                         constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
5734                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
5735                         constrinfo[j].contable = tbinfo;
5736                         constrinfo[j].condomain = NULL;
5737                         constrinfo[j].contype = 'f';
5738                         constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
5739                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
5740                         constrinfo[j].conindex = 0;
5741                         constrinfo[j].condeferrable = false;
5742                         constrinfo[j].condeferred = false;
5743                         constrinfo[j].conislocal = true;
5744                         constrinfo[j].separate = true;
5745                 }
5746
5747                 PQclear(res);
5748         }
5749
5750         destroyPQExpBuffer(query);
5751 }
5752
5753 /*
5754  * getDomainConstraints
5755  *
5756  * Get info about constraints on a domain.
5757  */
5758 static void
5759 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
5760 {
5761         int                     i;
5762         ConstraintInfo *constrinfo;
5763         PQExpBuffer query;
5764         PGresult   *res;
5765         int                     i_tableoid,
5766                                 i_oid,
5767                                 i_conname,
5768                                 i_consrc;
5769         int                     ntups;
5770
5771         /* pg_constraint was created in 7.3, so nothing to do if older */
5772         if (fout->remoteVersion < 70300)
5773                 return;
5774
5775         /*
5776          * select appropriate schema to ensure names in constraint are properly
5777          * qualified
5778          */
5779         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
5780
5781         query = createPQExpBuffer();
5782
5783         if (fout->remoteVersion >= 90100)
5784                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5785                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5786                                                   "convalidated "
5787                                                   "FROM pg_catalog.pg_constraint "
5788                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5789                                                   "ORDER BY conname",
5790                                                   tyinfo->dobj.catId.oid);
5791
5792         else if (fout->remoteVersion >= 70400)
5793                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5794                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5795                                                   "true as convalidated "
5796                                                   "FROM pg_catalog.pg_constraint "
5797                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5798                                                   "ORDER BY conname",
5799                                                   tyinfo->dobj.catId.oid);
5800         else
5801                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5802                                                   "'CHECK (' || consrc || ')' AS consrc, "
5803                                                   "true as convalidated "
5804                                                   "FROM pg_catalog.pg_constraint "
5805                                                   "WHERE contypid = '%u'::pg_catalog.oid "
5806                                                   "ORDER BY conname",
5807                                                   tyinfo->dobj.catId.oid);
5808
5809         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5810
5811         ntups = PQntuples(res);
5812
5813         i_tableoid = PQfnumber(res, "tableoid");
5814         i_oid = PQfnumber(res, "oid");
5815         i_conname = PQfnumber(res, "conname");
5816         i_consrc = PQfnumber(res, "consrc");
5817
5818         constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
5819
5820         tyinfo->nDomChecks = ntups;
5821         tyinfo->domChecks = constrinfo;
5822
5823         for (i = 0; i < ntups; i++)
5824         {
5825                 bool            validated = PQgetvalue(res, i, 4)[0] == 't';
5826
5827                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
5828                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5829                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5830                 AssignDumpId(&constrinfo[i].dobj);
5831                 constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5832                 constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
5833                 constrinfo[i].contable = NULL;
5834                 constrinfo[i].condomain = tyinfo;
5835                 constrinfo[i].contype = 'c';
5836                 constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
5837                 constrinfo[i].confrelid = InvalidOid;
5838                 constrinfo[i].conindex = 0;
5839                 constrinfo[i].condeferrable = false;
5840                 constrinfo[i].condeferred = false;
5841                 constrinfo[i].conislocal = true;
5842
5843                 constrinfo[i].separate = !validated;
5844
5845                 /*
5846                  * Make the domain depend on the constraint, ensuring it won't be
5847                  * output till any constraint dependencies are OK.  If the constraint
5848                  * has not been validated, it's going to be dumped after the domain
5849                  * anyway, so this doesn't matter.
5850                  */
5851                 if (validated)
5852                         addObjectDependency(&tyinfo->dobj,
5853                                                                 constrinfo[i].dobj.dumpId);
5854         }
5855
5856         PQclear(res);
5857
5858         destroyPQExpBuffer(query);
5859 }
5860
5861 /*
5862  * getRules
5863  *        get basic information about every rule in the system
5864  *
5865  * numRules is set to the number of rules read in
5866  */
5867 RuleInfo *
5868 getRules(Archive *fout, int *numRules)
5869 {
5870         PGresult   *res;
5871         int                     ntups;
5872         int                     i;
5873         PQExpBuffer query = createPQExpBuffer();
5874         RuleInfo   *ruleinfo;
5875         int                     i_tableoid;
5876         int                     i_oid;
5877         int                     i_rulename;
5878         int                     i_ruletable;
5879         int                     i_ev_type;
5880         int                     i_is_instead;
5881         int                     i_ev_enabled;
5882
5883         /* Make sure we are in proper schema */
5884         selectSourceSchema(fout, "pg_catalog");
5885
5886         if (fout->remoteVersion >= 80300)
5887         {
5888                 appendPQExpBufferStr(query, "SELECT "
5889                                                          "tableoid, oid, rulename, "
5890                                                          "ev_class AS ruletable, ev_type, is_instead, "
5891                                                          "ev_enabled "
5892                                                          "FROM pg_rewrite "
5893                                                          "ORDER BY oid");
5894         }
5895         else if (fout->remoteVersion >= 70100)
5896         {
5897                 appendPQExpBufferStr(query, "SELECT "
5898                                                          "tableoid, oid, rulename, "
5899                                                          "ev_class AS ruletable, ev_type, is_instead, "
5900                                                          "'O'::char AS ev_enabled "
5901                                                          "FROM pg_rewrite "
5902                                                          "ORDER BY oid");
5903         }
5904         else
5905         {
5906                 appendPQExpBufferStr(query, "SELECT "
5907                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
5908                                                          "oid, rulename, "
5909                                                          "ev_class AS ruletable, ev_type, is_instead, "
5910                                                          "'O'::char AS ev_enabled "
5911                                                          "FROM pg_rewrite "
5912                                                          "ORDER BY oid");
5913         }
5914
5915         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5916
5917         ntups = PQntuples(res);
5918
5919         *numRules = ntups;
5920
5921         ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
5922
5923         i_tableoid = PQfnumber(res, "tableoid");
5924         i_oid = PQfnumber(res, "oid");
5925         i_rulename = PQfnumber(res, "rulename");
5926         i_ruletable = PQfnumber(res, "ruletable");
5927         i_ev_type = PQfnumber(res, "ev_type");
5928         i_is_instead = PQfnumber(res, "is_instead");
5929         i_ev_enabled = PQfnumber(res, "ev_enabled");
5930
5931         for (i = 0; i < ntups; i++)
5932         {
5933                 Oid                     ruletableoid;
5934
5935                 ruleinfo[i].dobj.objType = DO_RULE;
5936                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5937                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5938                 AssignDumpId(&ruleinfo[i].dobj);
5939                 ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
5940                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
5941                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
5942                 if (ruleinfo[i].ruletable == NULL)
5943                         exit_horribly(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
5944                                                   ruletableoid, ruleinfo[i].dobj.catId.oid);
5945                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
5946                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
5947                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
5948                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
5949                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
5950                 if (ruleinfo[i].ruletable)
5951                 {
5952                         /*
5953                          * If the table is a view or materialized view, force its ON
5954                          * SELECT rule to be sorted before the view itself --- this
5955                          * ensures that any dependencies for the rule affect the table's
5956                          * positioning. Other rules are forced to appear after their
5957                          * table.
5958                          */
5959                         if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
5960                                  ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
5961                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
5962                         {
5963                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
5964                                                                         ruleinfo[i].dobj.dumpId);
5965                                 /* We'll merge the rule into CREATE VIEW, if possible */
5966                                 ruleinfo[i].separate = false;
5967                         }
5968                         else
5969                         {
5970                                 addObjectDependency(&ruleinfo[i].dobj,
5971                                                                         ruleinfo[i].ruletable->dobj.dumpId);
5972                                 ruleinfo[i].separate = true;
5973                         }
5974                 }
5975                 else
5976                         ruleinfo[i].separate = true;
5977
5978                 /*
5979                  * If we're forced to break a dependency loop by dumping a view as a
5980                  * table and separate _RETURN rule, we'll move the view's reloptions
5981                  * to the rule.  (This is necessary because tables and views have
5982                  * different valid reloptions, so we can't apply the options until the
5983                  * backend knows it's a view.)  Otherwise the rule's reloptions stay
5984                  * NULL.
5985                  */
5986                 ruleinfo[i].reloptions = NULL;
5987         }
5988
5989         PQclear(res);
5990
5991         destroyPQExpBuffer(query);
5992
5993         return ruleinfo;
5994 }
5995
5996 /*
5997  * getTriggers
5998  *        get information about every trigger on a dumpable table
5999  *
6000  * Note: trigger data is not returned directly to the caller, but it
6001  * does get entered into the DumpableObject tables.
6002  */
6003 void
6004 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
6005 {
6006         int                     i,
6007                                 j;
6008         PQExpBuffer query = createPQExpBuffer();
6009         PGresult   *res;
6010         TriggerInfo *tginfo;
6011         int                     i_tableoid,
6012                                 i_oid,
6013                                 i_tgname,
6014                                 i_tgfname,
6015                                 i_tgtype,
6016                                 i_tgnargs,
6017                                 i_tgargs,
6018                                 i_tgisconstraint,
6019                                 i_tgconstrname,
6020                                 i_tgconstrrelid,
6021                                 i_tgconstrrelname,
6022                                 i_tgenabled,
6023                                 i_tgdeferrable,
6024                                 i_tginitdeferred,
6025                                 i_tgdef;
6026         int                     ntups;
6027
6028         for (i = 0; i < numTables; i++)
6029         {
6030                 TableInfo  *tbinfo = &tblinfo[i];
6031
6032                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
6033                         continue;
6034
6035                 if (g_verbose)
6036                         write_msg(NULL, "reading triggers for table \"%s\".\"%s\"\n",
6037                                           tbinfo->dobj.namespace->dobj.name,
6038                                           tbinfo->dobj.name);
6039
6040                 /*
6041                  * select table schema to ensure regproc name is qualified if needed
6042                  */
6043                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6044
6045                 resetPQExpBuffer(query);
6046                 if (fout->remoteVersion >= 90000)
6047                 {
6048                         /*
6049                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
6050                          * could result in non-forward-compatible dumps of WHEN clauses
6051                          * due to under-parenthesization.
6052                          */
6053                         appendPQExpBuffer(query,
6054                                                           "SELECT tgname, "
6055                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
6056                                                 "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
6057                                                           "tgenabled, tableoid, oid "
6058                                                           "FROM pg_catalog.pg_trigger t "
6059                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
6060                                                           "AND NOT tgisinternal",
6061                                                           tbinfo->dobj.catId.oid);
6062                 }
6063                 else if (fout->remoteVersion >= 80300)
6064                 {
6065                         /*
6066                          * We ignore triggers that are tied to a foreign-key constraint
6067                          */
6068                         appendPQExpBuffer(query,
6069                                                           "SELECT tgname, "
6070                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
6071                                                           "tgtype, tgnargs, tgargs, tgenabled, "
6072                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
6073                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
6074                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
6075                                                           "FROM pg_catalog.pg_trigger t "
6076                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
6077                                                           "AND tgconstraint = 0",
6078                                                           tbinfo->dobj.catId.oid);
6079                 }
6080                 else if (fout->remoteVersion >= 70300)
6081                 {
6082                         /*
6083                          * We ignore triggers that are tied to a foreign-key constraint,
6084                          * but in these versions we have to grovel through pg_constraint
6085                          * to find out
6086                          */
6087                         appendPQExpBuffer(query,
6088                                                           "SELECT tgname, "
6089                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
6090                                                           "tgtype, tgnargs, tgargs, tgenabled, "
6091                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
6092                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
6093                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
6094                                                           "FROM pg_catalog.pg_trigger t "
6095                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
6096                                                           "AND (NOT tgisconstraint "
6097                                                           " OR NOT EXISTS"
6098                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
6099                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
6100                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
6101                                                           tbinfo->dobj.catId.oid);
6102                 }
6103                 else if (fout->remoteVersion >= 70100)
6104                 {
6105                         appendPQExpBuffer(query,
6106                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
6107                                                           "tgtype, tgnargs, tgargs, tgenabled, "
6108                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
6109                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
6110                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
6111                                                           "             AS tgconstrrelname "
6112                                                           "FROM pg_trigger "
6113                                                           "WHERE tgrelid = '%u'::oid",
6114                                                           tbinfo->dobj.catId.oid);
6115                 }
6116                 else
6117                 {
6118                         appendPQExpBuffer(query,
6119                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
6120                                                           "tgtype, tgnargs, tgargs, tgenabled, "
6121                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
6122                                                           "tgconstrrelid, tginitdeferred, "
6123                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
6124                                                           "oid, "
6125                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
6126                                                           "             AS tgconstrrelname "
6127                                                           "FROM pg_trigger "
6128                                                           "WHERE tgrelid = '%u'::oid",
6129                                                           tbinfo->dobj.catId.oid);
6130                 }
6131                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6132
6133                 ntups = PQntuples(res);
6134
6135                 i_tableoid = PQfnumber(res, "tableoid");
6136                 i_oid = PQfnumber(res, "oid");
6137                 i_tgname = PQfnumber(res, "tgname");
6138                 i_tgfname = PQfnumber(res, "tgfname");
6139                 i_tgtype = PQfnumber(res, "tgtype");
6140                 i_tgnargs = PQfnumber(res, "tgnargs");
6141                 i_tgargs = PQfnumber(res, "tgargs");
6142                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
6143                 i_tgconstrname = PQfnumber(res, "tgconstrname");
6144                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
6145                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
6146                 i_tgenabled = PQfnumber(res, "tgenabled");
6147                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
6148                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
6149                 i_tgdef = PQfnumber(res, "tgdef");
6150
6151                 tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
6152
6153                 for (j = 0; j < ntups; j++)
6154                 {
6155                         tginfo[j].dobj.objType = DO_TRIGGER;
6156                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
6157                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
6158                         AssignDumpId(&tginfo[j].dobj);
6159                         tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
6160                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
6161                         tginfo[j].tgtable = tbinfo;
6162                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
6163                         if (i_tgdef >= 0)
6164                         {
6165                                 tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
6166
6167                                 /* remaining fields are not valid if we have tgdef */
6168                                 tginfo[j].tgfname = NULL;
6169                                 tginfo[j].tgtype = 0;
6170                                 tginfo[j].tgnargs = 0;
6171                                 tginfo[j].tgargs = NULL;
6172                                 tginfo[j].tgisconstraint = false;
6173                                 tginfo[j].tgdeferrable = false;
6174                                 tginfo[j].tginitdeferred = false;
6175                                 tginfo[j].tgconstrname = NULL;
6176                                 tginfo[j].tgconstrrelid = InvalidOid;
6177                                 tginfo[j].tgconstrrelname = NULL;
6178                         }
6179                         else
6180                         {
6181                                 tginfo[j].tgdef = NULL;
6182
6183                                 tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
6184                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
6185                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
6186                                 tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
6187                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
6188                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
6189                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
6190
6191                                 if (tginfo[j].tgisconstraint)
6192                                 {
6193                                         tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
6194                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
6195                                         if (OidIsValid(tginfo[j].tgconstrrelid))
6196                                         {
6197                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
6198                                                         exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
6199                                                                                   tginfo[j].dobj.name,
6200                                                                                   tbinfo->dobj.name,
6201                                                                                   tginfo[j].tgconstrrelid);
6202                                                 tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
6203                                         }
6204                                         else
6205                                                 tginfo[j].tgconstrrelname = NULL;
6206                                 }
6207                                 else
6208                                 {
6209                                         tginfo[j].tgconstrname = NULL;
6210                                         tginfo[j].tgconstrrelid = InvalidOid;
6211                                         tginfo[j].tgconstrrelname = NULL;
6212                                 }
6213                         }
6214                 }
6215
6216                 PQclear(res);
6217         }
6218
6219         destroyPQExpBuffer(query);
6220 }
6221
6222 /*
6223  * getEventTriggers
6224  *        get information about event triggers
6225  */
6226 EventTriggerInfo *
6227 getEventTriggers(Archive *fout, int *numEventTriggers)
6228 {
6229         int                     i;
6230         PQExpBuffer query;
6231         PGresult   *res;
6232         EventTriggerInfo *evtinfo;
6233         int                     i_tableoid,
6234                                 i_oid,
6235                                 i_evtname,
6236                                 i_evtevent,
6237                                 i_evtowner,
6238                                 i_evttags,
6239                                 i_evtfname,
6240                                 i_evtenabled;
6241         int                     ntups;
6242
6243         /* Before 9.3, there are no event triggers */
6244         if (fout->remoteVersion < 90300)
6245         {
6246                 *numEventTriggers = 0;
6247                 return NULL;
6248         }
6249
6250         query = createPQExpBuffer();
6251
6252         /* Make sure we are in proper schema */
6253         selectSourceSchema(fout, "pg_catalog");
6254
6255         appendPQExpBuffer(query,
6256                                           "SELECT e.tableoid, e.oid, evtname, evtenabled, "
6257                                           "evtevent, (%s evtowner) AS evtowner, "
6258                                           "array_to_string(array("
6259                                           "select quote_literal(x) "
6260                                           " from unnest(evttags) as t(x)), ', ') as evttags, "
6261                                           "e.evtfoid::regproc as evtfname "
6262                                           "FROM pg_event_trigger e "
6263                                           "ORDER BY e.oid",
6264                                           username_subquery);
6265
6266         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6267
6268         ntups = PQntuples(res);
6269
6270         *numEventTriggers = ntups;
6271
6272         evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
6273
6274         i_tableoid = PQfnumber(res, "tableoid");
6275         i_oid = PQfnumber(res, "oid");
6276         i_evtname = PQfnumber(res, "evtname");
6277         i_evtevent = PQfnumber(res, "evtevent");
6278         i_evtowner = PQfnumber(res, "evtowner");
6279         i_evttags = PQfnumber(res, "evttags");
6280         i_evtfname = PQfnumber(res, "evtfname");
6281         i_evtenabled = PQfnumber(res, "evtenabled");
6282
6283         for (i = 0; i < ntups; i++)
6284         {
6285                 evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
6286                 evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6287                 evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6288                 AssignDumpId(&evtinfo[i].dobj);
6289                 evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
6290                 evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
6291                 evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
6292                 evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
6293                 evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
6294                 evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
6295                 evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
6296         }
6297
6298         PQclear(res);
6299
6300         destroyPQExpBuffer(query);
6301
6302         return evtinfo;
6303 }
6304
6305 /*
6306  * getProcLangs
6307  *        get basic information about every procedural language in the system
6308  *
6309  * numProcLangs is set to the number of langs read in
6310  *
6311  * NB: this must run after getFuncs() because we assume we can do
6312  * findFuncByOid().
6313  */
6314 ProcLangInfo *
6315 getProcLangs(Archive *fout, int *numProcLangs)
6316 {
6317         PGresult   *res;
6318         int                     ntups;
6319         int                     i;
6320         PQExpBuffer query = createPQExpBuffer();
6321         ProcLangInfo *planginfo;
6322         int                     i_tableoid;
6323         int                     i_oid;
6324         int                     i_lanname;
6325         int                     i_lanpltrusted;
6326         int                     i_lanplcallfoid;
6327         int                     i_laninline;
6328         int                     i_lanvalidator;
6329         int                     i_lanacl;
6330         int                     i_lanowner;
6331
6332         /* Make sure we are in proper schema */
6333         selectSourceSchema(fout, "pg_catalog");
6334
6335         if (fout->remoteVersion >= 90000)
6336         {
6337                 /* pg_language has a laninline column */
6338                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6339                                                   "lanname, lanpltrusted, lanplcallfoid, "
6340                                                   "laninline, lanvalidator,  lanacl, "
6341                                                   "(%s lanowner) AS lanowner "
6342                                                   "FROM pg_language "
6343                                                   "WHERE lanispl "
6344                                                   "ORDER BY oid",
6345                                                   username_subquery);
6346         }
6347         else if (fout->remoteVersion >= 80300)
6348         {
6349                 /* pg_language has a lanowner column */
6350                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
6351                                                   "lanname, lanpltrusted, lanplcallfoid, "
6352                                                   "lanvalidator,  lanacl, "
6353                                                   "(%s lanowner) AS lanowner "
6354                                                   "FROM pg_language "
6355                                                   "WHERE lanispl "
6356                                                   "ORDER BY oid",
6357                                                   username_subquery);
6358         }
6359         else if (fout->remoteVersion >= 80100)
6360         {
6361                 /* Languages are owned by the bootstrap superuser, OID 10 */
6362                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6363                                                   "(%s '10') AS lanowner "
6364                                                   "FROM pg_language "
6365                                                   "WHERE lanispl "
6366                                                   "ORDER BY oid",
6367                                                   username_subquery);
6368         }
6369         else if (fout->remoteVersion >= 70400)
6370         {
6371                 /* Languages are owned by the bootstrap superuser, sysid 1 */
6372                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
6373                                                   "(%s '1') AS lanowner "
6374                                                   "FROM pg_language "
6375                                                   "WHERE lanispl "
6376                                                   "ORDER BY oid",
6377                                                   username_subquery);
6378         }
6379         else if (fout->remoteVersion >= 70100)
6380         {
6381                 /* No clear notion of an owner at all before 7.4 ... */
6382                 appendPQExpBufferStr(query, "SELECT tableoid, oid, * FROM pg_language "
6383                                                          "WHERE lanispl "
6384                                                          "ORDER BY oid");
6385         }
6386         else
6387         {
6388                 appendPQExpBufferStr(query, "SELECT "
6389                                                          "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
6390                                                          "oid, * FROM pg_language "
6391                                                          "WHERE lanispl "
6392                                                          "ORDER BY oid");
6393         }
6394
6395         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6396
6397         ntups = PQntuples(res);
6398
6399         *numProcLangs = ntups;
6400
6401         planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
6402
6403         i_tableoid = PQfnumber(res, "tableoid");
6404         i_oid = PQfnumber(res, "oid");
6405         i_lanname = PQfnumber(res, "lanname");
6406         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
6407         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
6408         /* these may fail and return -1: */
6409         i_laninline = PQfnumber(res, "laninline");
6410         i_lanvalidator = PQfnumber(res, "lanvalidator");
6411         i_lanacl = PQfnumber(res, "lanacl");
6412         i_lanowner = PQfnumber(res, "lanowner");
6413
6414         for (i = 0; i < ntups; i++)
6415         {
6416                 planginfo[i].dobj.objType = DO_PROCLANG;
6417                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6418                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6419                 AssignDumpId(&planginfo[i].dobj);
6420
6421                 planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
6422                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
6423                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
6424                 if (i_laninline >= 0)
6425                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
6426                 else
6427                         planginfo[i].laninline = InvalidOid;
6428                 if (i_lanvalidator >= 0)
6429                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
6430                 else
6431                         planginfo[i].lanvalidator = InvalidOid;
6432                 if (i_lanacl >= 0)
6433                         planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
6434                 else
6435                         planginfo[i].lanacl = pg_strdup("{=U}");
6436                 if (i_lanowner >= 0)
6437                         planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
6438                 else
6439                         planginfo[i].lanowner = pg_strdup("");
6440
6441                 if (fout->remoteVersion < 70300)
6442                 {
6443                         /*
6444                          * We need to make a dependency to ensure the function will be
6445                          * dumped first.  (In 7.3 and later the regular dependency
6446                          * mechanism will handle this for us.)
6447                          */
6448                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
6449
6450                         if (funcInfo)
6451                                 addObjectDependency(&planginfo[i].dobj,
6452                                                                         funcInfo->dobj.dumpId);
6453                 }
6454         }
6455
6456         PQclear(res);
6457
6458         destroyPQExpBuffer(query);
6459
6460         return planginfo;
6461 }
6462
6463 /*
6464  * getCasts
6465  *        get basic information about every cast in the system
6466  *
6467  * numCasts is set to the number of casts read in
6468  */
6469 CastInfo *
6470 getCasts(Archive *fout, int *numCasts)
6471 {
6472         PGresult   *res;
6473         int                     ntups;
6474         int                     i;
6475         PQExpBuffer query = createPQExpBuffer();
6476         CastInfo   *castinfo;
6477         int                     i_tableoid;
6478         int                     i_oid;
6479         int                     i_castsource;
6480         int                     i_casttarget;
6481         int                     i_castfunc;
6482         int                     i_castcontext;
6483         int                     i_castmethod;
6484
6485         /* Make sure we are in proper schema */
6486         selectSourceSchema(fout, "pg_catalog");
6487
6488         if (fout->remoteVersion >= 80400)
6489         {
6490                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6491                                                          "castsource, casttarget, castfunc, castcontext, "
6492                                                          "castmethod "
6493                                                          "FROM pg_cast ORDER BY 3,4");
6494         }
6495         else if (fout->remoteVersion >= 70300)
6496         {
6497                 appendPQExpBufferStr(query, "SELECT tableoid, oid, "
6498                                                          "castsource, casttarget, castfunc, castcontext, "
6499                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
6500                                                          "FROM pg_cast ORDER BY 3,4");
6501         }
6502         else
6503         {
6504                 appendPQExpBufferStr(query, "SELECT 0 AS tableoid, p.oid, "
6505                                                          "t1.oid AS castsource, t2.oid AS casttarget, "
6506                                                          "p.oid AS castfunc, 'e' AS castcontext, "
6507                                                          "'f' AS castmethod "
6508                                                          "FROM pg_type t1, pg_type t2, pg_proc p "
6509                                                          "WHERE p.pronargs = 1 AND "
6510                                                          "p.proargtypes[0] = t1.oid AND "
6511                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
6512                                                          "ORDER BY 3,4");
6513         }
6514
6515         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6516
6517         ntups = PQntuples(res);
6518
6519         *numCasts = ntups;
6520
6521         castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
6522
6523         i_tableoid = PQfnumber(res, "tableoid");
6524         i_oid = PQfnumber(res, "oid");
6525         i_castsource = PQfnumber(res, "castsource");
6526         i_casttarget = PQfnumber(res, "casttarget");
6527         i_castfunc = PQfnumber(res, "castfunc");
6528         i_castcontext = PQfnumber(res, "castcontext");
6529         i_castmethod = PQfnumber(res, "castmethod");
6530
6531         for (i = 0; i < ntups; i++)
6532         {
6533                 PQExpBufferData namebuf;
6534                 TypeInfo   *sTypeInfo;
6535                 TypeInfo   *tTypeInfo;
6536
6537                 castinfo[i].dobj.objType = DO_CAST;
6538                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
6539                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
6540                 AssignDumpId(&castinfo[i].dobj);
6541                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
6542                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
6543                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
6544                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
6545                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
6546
6547                 /*
6548                  * Try to name cast as concatenation of typnames.  This is only used
6549                  * for purposes of sorting.  If we fail to find either type, the name
6550                  * will be an empty string.
6551                  */
6552                 initPQExpBuffer(&namebuf);
6553                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
6554                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
6555                 if (sTypeInfo && tTypeInfo)
6556                         appendPQExpBuffer(&namebuf, "%s %s",
6557                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
6558                 castinfo[i].dobj.name = namebuf.data;
6559
6560                 if (OidIsValid(castinfo[i].castfunc))
6561                 {
6562                         /*
6563                          * We need to make a dependency to ensure the function will be
6564                          * dumped first.  (In 7.3 and later the regular dependency
6565                          * mechanism will handle this for us.)
6566                          */
6567                         FuncInfo   *funcInfo;
6568
6569                         funcInfo = findFuncByOid(castinfo[i].castfunc);
6570                         if (funcInfo)
6571                                 addObjectDependency(&castinfo[i].dobj,
6572                                                                         funcInfo->dobj.dumpId);
6573                 }
6574         }
6575
6576         PQclear(res);
6577
6578         destroyPQExpBuffer(query);
6579
6580         return castinfo;
6581 }
6582
6583 /*
6584  * getTableAttrs -
6585  *        for each interesting table, read info about its attributes
6586  *        (names, types, default values, CHECK constraints, etc)
6587  *
6588  * This is implemented in a very inefficient way right now, looping
6589  * through the tblinfo and doing a join per table to find the attrs and their
6590  * types.  However, because we want type names and so forth to be named
6591  * relative to the schema of each table, we couldn't do it in just one
6592  * query.  (Maybe one query per schema?)
6593  *
6594  *      modifies tblinfo
6595  */
6596 void
6597 getTableAttrs(Archive *fout, DumpOptions *dopt, TableInfo *tblinfo, int numTables)
6598 {
6599         int                     i,
6600                                 j;
6601         PQExpBuffer q = createPQExpBuffer();
6602         int                     i_attnum;
6603         int                     i_attname;
6604         int                     i_atttypname;
6605         int                     i_atttypmod;
6606         int                     i_attstattarget;
6607         int                     i_attstorage;
6608         int                     i_typstorage;
6609         int                     i_attnotnull;
6610         int                     i_atthasdef;
6611         int                     i_attisdropped;
6612         int                     i_attlen;
6613         int                     i_attalign;
6614         int                     i_attislocal;
6615         int                     i_attoptions;
6616         int                     i_attcollation;
6617         int                     i_attfdwoptions;
6618         PGresult   *res;
6619         int                     ntups;
6620         bool            hasdefaults;
6621
6622         for (i = 0; i < numTables; i++)
6623         {
6624                 TableInfo  *tbinfo = &tblinfo[i];
6625
6626                 /* Don't bother to collect info for sequences */
6627                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6628                         continue;
6629
6630                 /* Don't bother with uninteresting tables, either */
6631                 if (!tbinfo->interesting)
6632                         continue;
6633
6634                 /*
6635                  * Make sure we are in proper schema for this table; this allows
6636                  * correct retrieval of formatted type names and default exprs
6637                  */
6638                 selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
6639
6640                 /* find all the user attributes and their types */
6641
6642                 /*
6643                  * we must read the attribute names in attribute number order! because
6644                  * we will use the attnum to index into the attnames array later.  We
6645                  * actually ask to order by "attrelid, attnum" because (at least up to
6646                  * 7.3) the planner is not smart enough to realize it needn't re-sort
6647                  * the output of an indexscan on pg_attribute_relid_attnum_index.
6648                  */
6649                 if (g_verbose)
6650                         write_msg(NULL, "finding the columns and types of table \"%s\".\"%s\"\n",
6651                                           tbinfo->dobj.namespace->dobj.name,
6652                                           tbinfo->dobj.name);
6653
6654                 resetPQExpBuffer(q);
6655
6656                 if (fout->remoteVersion >= 90200)
6657                 {
6658                         /*
6659                          * attfdwoptions is new in 9.2.
6660                          */
6661                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6662                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6663                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6664                                                           "a.attlen, a.attalign, a.attislocal, "
6665                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6666                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6667                                                           "CASE WHEN a.attcollation <> t.typcollation "
6668                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6669                                                           "pg_catalog.array_to_string(ARRAY("
6670                                                           "SELECT pg_catalog.quote_ident(option_name) || "
6671                                                           "' ' || pg_catalog.quote_literal(option_value) "
6672                                                 "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
6673                                                           "ORDER BY option_name"
6674                                                           "), E',\n    ') AS attfdwoptions "
6675                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6676                                                           "ON a.atttypid = t.oid "
6677                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6678                                                           "AND a.attnum > 0::pg_catalog.int2 "
6679                                                           "ORDER BY a.attrelid, a.attnum",
6680                                                           tbinfo->dobj.catId.oid);
6681                 }
6682                 else if (fout->remoteVersion >= 90100)
6683                 {
6684                         /*
6685                          * attcollation is new in 9.1.  Since we only want to dump COLLATE
6686                          * clauses for attributes whose collation is different from their
6687                          * type's default, we use a CASE here to suppress uninteresting
6688                          * attcollations cheaply.
6689                          */
6690                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6691                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6692                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6693                                                           "a.attlen, a.attalign, a.attislocal, "
6694                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6695                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6696                                                           "CASE WHEN a.attcollation <> t.typcollation "
6697                                                    "THEN a.attcollation ELSE 0 END AS attcollation, "
6698                                                           "NULL AS attfdwoptions "
6699                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6700                                                           "ON a.atttypid = t.oid "
6701                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6702                                                           "AND a.attnum > 0::pg_catalog.int2 "
6703                                                           "ORDER BY a.attrelid, a.attnum",
6704                                                           tbinfo->dobj.catId.oid);
6705                 }
6706                 else if (fout->remoteVersion >= 90000)
6707                 {
6708                         /* attoptions is new in 9.0 */
6709                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6710                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6711                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6712                                                           "a.attlen, a.attalign, a.attislocal, "
6713                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6714                                                 "array_to_string(a.attoptions, ', ') AS attoptions, "
6715                                                           "0 AS attcollation, "
6716                                                           "NULL AS attfdwoptions "
6717                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6718                                                           "ON a.atttypid = t.oid "
6719                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6720                                                           "AND a.attnum > 0::pg_catalog.int2 "
6721                                                           "ORDER BY a.attrelid, a.attnum",
6722                                                           tbinfo->dobj.catId.oid);
6723                 }
6724                 else if (fout->remoteVersion >= 70300)
6725                 {
6726                         /* need left join here to not fail on dropped columns ... */
6727                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6728                                                           "a.attstattarget, a.attstorage, t.typstorage, "
6729                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
6730                                                           "a.attlen, a.attalign, a.attislocal, "
6731                                   "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
6732                                                           "'' AS attoptions, 0 AS attcollation, "
6733                                                           "NULL AS attfdwoptions "
6734                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
6735                                                           "ON a.atttypid = t.oid "
6736                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
6737                                                           "AND a.attnum > 0::pg_catalog.int2 "
6738                                                           "ORDER BY a.attrelid, a.attnum",
6739                                                           tbinfo->dobj.catId.oid);
6740                 }
6741                 else if (fout->remoteVersion >= 70100)
6742                 {
6743                         /*
6744                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
6745                          * we don't dump it because we can't tell whether it's been
6746                          * explicitly set or was just a default.
6747                          *
6748                          * attislocal doesn't exist before 7.3, either; in older databases
6749                          * we assume it's TRUE, else we'd fail to dump non-inherited atts.
6750                          */
6751                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
6752                                                           "-1 AS attstattarget, a.attstorage, "
6753                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
6754                                                           "false AS attisdropped, a.attlen, "
6755                                                           "a.attalign, true AS attislocal, "
6756                                                           "format_type(t.oid,a.atttypmod) AS atttypname, "
6757                                                           "'' AS attoptions, 0 AS attcollation, "
6758                                                           "NULL AS attfdwoptions "
6759                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
6760                                                           "ON a.atttypid = t.oid "
6761                                                           "WHERE a.attrelid = '%u'::oid "
6762                                                           "AND a.attnum > 0::int2 "
6763                                                           "ORDER BY a.attrelid, a.attnum",
6764                                                           tbinfo->dobj.catId.oid);
6765                 }
6766                 else
6767                 {
6768                         /* format_type not available before 7.1 */
6769                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
6770                                                           "-1 AS attstattarget, "
6771                                                           "attstorage, attstorage AS typstorage, "
6772                                                           "attnotnull, atthasdef, false AS attisdropped, "
6773                                                           "attlen, attalign, "
6774                                                           "true AS attislocal, "
6775                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname, "
6776                                                           "'' AS attoptions, 0 AS attcollation, "
6777                                                           "NULL AS attfdwoptions "
6778                                                           "FROM pg_attribute a "
6779                                                           "WHERE attrelid = '%u'::oid "
6780                                                           "AND attnum > 0::int2 "
6781                                                           "ORDER BY attrelid, attnum",
6782                                                           tbinfo->dobj.catId.oid);
6783                 }
6784
6785                 res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6786
6787                 ntups = PQntuples(res);
6788
6789                 i_attnum = PQfnumber(res, "attnum");
6790                 i_attname = PQfnumber(res, "attname");
6791                 i_atttypname = PQfnumber(res, "atttypname");
6792                 i_atttypmod = PQfnumber(res, "atttypmod");
6793                 i_attstattarget = PQfnumber(res, "attstattarget");
6794                 i_attstorage = PQfnumber(res, "attstorage");
6795                 i_typstorage = PQfnumber(res, "typstorage");
6796                 i_attnotnull = PQfnumber(res, "attnotnull");
6797                 i_atthasdef = PQfnumber(res, "atthasdef");
6798                 i_attisdropped = PQfnumber(res, "attisdropped");
6799                 i_attlen = PQfnumber(res, "attlen");
6800                 i_attalign = PQfnumber(res, "attalign");
6801                 i_attislocal = PQfnumber(res, "attislocal");
6802                 i_attoptions = PQfnumber(res, "attoptions");
6803                 i_attcollation = PQfnumber(res, "attcollation");
6804                 i_attfdwoptions = PQfnumber(res, "attfdwoptions");
6805
6806                 tbinfo->numatts = ntups;
6807                 tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
6808                 tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
6809                 tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
6810                 tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
6811                 tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
6812                 tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
6813                 tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
6814                 tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
6815                 tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
6816                 tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
6817                 tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
6818                 tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
6819                 tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
6820                 tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
6821                 tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
6822                 tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
6823                 hasdefaults = false;
6824
6825                 for (j = 0; j < ntups; j++)
6826                 {
6827                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
6828                                 exit_horribly(NULL,
6829                                                           "invalid column numbering in table \"%s\"\n",
6830                                                           tbinfo->dobj.name);
6831                         tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
6832                         tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
6833                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
6834                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
6835                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
6836                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
6837                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
6838                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
6839                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
6840                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
6841                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
6842                         tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
6843                         tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
6844                         tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
6845                         tbinfo->attrdefs[j] = NULL; /* fix below */
6846                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
6847                                 hasdefaults = true;
6848                         /* these flags will be set in flagInhAttrs() */
6849                         tbinfo->inhNotNull[j] = false;
6850                 }
6851
6852                 PQclear(res);
6853
6854                 /*
6855                  * Get info about column defaults
6856                  */
6857                 if (hasdefaults)
6858                 {
6859                         AttrDefInfo *attrdefs;
6860                         int                     numDefaults;
6861
6862                         if (g_verbose)
6863                                 write_msg(NULL, "finding default expressions of table \"%s\".\"%s\"\n",
6864                                                   tbinfo->dobj.namespace->dobj.name,
6865                                                   tbinfo->dobj.name);
6866
6867                         resetPQExpBuffer(q);
6868                         if (fout->remoteVersion >= 70300)
6869                         {
6870                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
6871                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
6872                                                                   "FROM pg_catalog.pg_attrdef "
6873                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
6874                                                                   tbinfo->dobj.catId.oid);
6875                         }
6876                         else if (fout->remoteVersion >= 70200)
6877                         {
6878                                 /* 7.2 did not have OIDs in pg_attrdef */
6879                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
6880                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
6881                                                                   "FROM pg_attrdef "
6882                                                                   "WHERE adrelid = '%u'::oid",
6883                                                                   tbinfo->dobj.catId.oid);
6884                         }
6885                         else if (fout->remoteVersion >= 70100)
6886                         {
6887                                 /* no pg_get_expr, so must rely on adsrc */
6888                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
6889                                                                   "FROM pg_attrdef "
6890                                                                   "WHERE adrelid = '%u'::oid",
6891                                                                   tbinfo->dobj.catId.oid);
6892                         }
6893                         else
6894                         {
6895                                 /* no pg_get_expr, no tableoid either */
6896                                 appendPQExpBuffer(q, "SELECT "
6897                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
6898                                                                   "oid, adnum, adsrc "
6899                                                                   "FROM pg_attrdef "
6900                                                                   "WHERE adrelid = '%u'::oid",
6901                                                                   tbinfo->dobj.catId.oid);
6902                         }
6903                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
6904
6905                         numDefaults = PQntuples(res);
6906                         attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
6907
6908                         for (j = 0; j < numDefaults; j++)
6909                         {
6910                                 int                     adnum;
6911
6912                                 adnum = atoi(PQgetvalue(res, j, 2));
6913
6914                                 if (adnum <= 0 || adnum > ntups)
6915                                         exit_horribly(NULL,
6916                                                                   "invalid adnum value %d for table \"%s\"\n",
6917                                                                   adnum, tbinfo->dobj.name);
6918
6919                                 /*
6920                                  * dropped columns shouldn't have defaults, but just in case,
6921                                  * ignore 'em
6922                                  */
6923                                 if (tbinfo->attisdropped[adnum - 1])
6924                                         continue;
6925
6926                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
6927                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
6928                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
6929                                 AssignDumpId(&attrdefs[j].dobj);
6930                                 attrdefs[j].adtable = tbinfo;
6931                                 attrdefs[j].adnum = adnum;
6932                                 attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
6933
6934                                 attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
6935                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
6936
6937                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
6938
6939                                 /*
6940                                  * Defaults on a VIEW must always be dumped as separate ALTER
6941                                  * TABLE commands.  Defaults on regular tables are dumped as
6942                                  * part of the CREATE TABLE if possible, which it won't be if
6943                                  * the column is not going to be emitted explicitly.
6944                                  */
6945                                 if (tbinfo->relkind == RELKIND_VIEW)
6946                                 {
6947                                         attrdefs[j].separate = true;
6948                                         /* needed in case pre-7.3 DB: */
6949                                         addObjectDependency(&attrdefs[j].dobj,
6950                                                                                 tbinfo->dobj.dumpId);
6951                                 }
6952                                 else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
6953                                 {
6954                                         /* column will be suppressed, print default separately */
6955                                         attrdefs[j].separate = true;
6956                                         /* needed in case pre-7.3 DB: */
6957                                         addObjectDependency(&attrdefs[j].dobj,
6958                                                                                 tbinfo->dobj.dumpId);
6959                                 }
6960                                 else
6961                                 {
6962                                         attrdefs[j].separate = false;
6963
6964                                         /*
6965                                          * Mark the default as needing to appear before the table,
6966                                          * so that any dependencies it has must be emitted before
6967                                          * the CREATE TABLE.  If this is not possible, we'll
6968                                          * change to "separate" mode while sorting dependencies.
6969                                          */
6970                                         addObjectDependency(&tbinfo->dobj,
6971                                                                                 attrdefs[j].dobj.dumpId);
6972                                 }
6973
6974                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
6975                         }
6976                         PQclear(res);
6977                 }
6978
6979                 /*
6980                  * Get info about table CHECK constraints
6981                  */
6982                 if (tbinfo->ncheck > 0)
6983                 {
6984                         ConstraintInfo *constrs;
6985                         int                     numConstrs;
6986
6987                         if (g_verbose)
6988                                 write_msg(NULL, "finding check constraints for table \"%s\".\"%s\"\n",
6989                                                   tbinfo->dobj.namespace->dobj.name,
6990                                                   tbinfo->dobj.name);
6991
6992                         resetPQExpBuffer(q);
6993                         if (fout->remoteVersion >= 90200)
6994                         {
6995                                 /*
6996                                  * convalidated is new in 9.2 (actually, it is there in 9.1,
6997                                  * but it wasn't ever false for check constraints until 9.2).
6998                                  */
6999                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
7000                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7001                                                                   "conislocal, convalidated "
7002                                                                   "FROM pg_catalog.pg_constraint "
7003                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
7004                                                                   "   AND contype = 'c' "
7005                                                                   "ORDER BY conname",
7006                                                                   tbinfo->dobj.catId.oid);
7007                         }
7008                         else if (fout->remoteVersion >= 80400)
7009                         {
7010                                 /* conislocal is new in 8.4 */
7011                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
7012                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7013                                                                   "conislocal, true AS convalidated "
7014                                                                   "FROM pg_catalog.pg_constraint "
7015                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
7016                                                                   "   AND contype = 'c' "
7017                                                                   "ORDER BY conname",
7018                                                                   tbinfo->dobj.catId.oid);
7019                         }
7020                         else if (fout->remoteVersion >= 70400)
7021                         {
7022                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
7023                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7024                                                                   "true AS conislocal, true AS convalidated "
7025                                                                   "FROM pg_catalog.pg_constraint "
7026                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
7027                                                                   "   AND contype = 'c' "
7028                                                                   "ORDER BY conname",
7029                                                                   tbinfo->dobj.catId.oid);
7030                         }
7031                         else if (fout->remoteVersion >= 70300)
7032                         {
7033                                 /* no pg_get_constraintdef, must use consrc */
7034                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
7035                                                                   "'CHECK (' || consrc || ')' AS consrc, "
7036                                                                   "true AS conislocal, true AS convalidated "
7037                                                                   "FROM pg_catalog.pg_constraint "
7038                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
7039                                                                   "   AND contype = 'c' "
7040                                                                   "ORDER BY conname",
7041                                                                   tbinfo->dobj.catId.oid);
7042                         }
7043                         else if (fout->remoteVersion >= 70200)
7044                         {
7045                                 /* 7.2 did not have OIDs in pg_relcheck */
7046                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
7047                                                                   "rcname AS conname, "
7048                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
7049                                                                   "true AS conislocal, true AS convalidated "
7050                                                                   "FROM pg_relcheck "
7051                                                                   "WHERE rcrelid = '%u'::oid "
7052                                                                   "ORDER BY rcname",
7053                                                                   tbinfo->dobj.catId.oid);
7054                         }
7055                         else if (fout->remoteVersion >= 70100)
7056                         {
7057                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
7058                                                                   "rcname AS conname, "
7059                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
7060                                                                   "true AS conislocal, true AS convalidated "
7061                                                                   "FROM pg_relcheck "
7062                                                                   "WHERE rcrelid = '%u'::oid "
7063                                                                   "ORDER BY rcname",
7064                                                                   tbinfo->dobj.catId.oid);
7065                         }
7066                         else
7067                         {
7068                                 /* no tableoid in 7.0 */
7069                                 appendPQExpBuffer(q, "SELECT "
7070                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
7071                                                                   "oid, rcname AS conname, "
7072                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
7073                                                                   "true AS conislocal, true AS convalidated "
7074                                                                   "FROM pg_relcheck "
7075                                                                   "WHERE rcrelid = '%u'::oid "
7076                                                                   "ORDER BY rcname",
7077                                                                   tbinfo->dobj.catId.oid);
7078                         }
7079                         res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
7080
7081                         numConstrs = PQntuples(res);
7082                         if (numConstrs != tbinfo->ncheck)
7083                         {
7084                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
7085                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
7086                                                                                  tbinfo->ncheck),
7087                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
7088                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
7089                                 exit_nicely(1);
7090                         }
7091
7092                         constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
7093                         tbinfo->checkexprs = constrs;
7094
7095                         for (j = 0; j < numConstrs; j++)
7096                         {
7097                                 bool            validated = PQgetvalue(res, j, 5)[0] == 't';
7098
7099                                 constrs[j].dobj.objType = DO_CONSTRAINT;
7100                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
7101                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
7102                                 AssignDumpId(&constrs[j].dobj);
7103                                 constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
7104                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
7105                                 constrs[j].contable = tbinfo;
7106                                 constrs[j].condomain = NULL;
7107                                 constrs[j].contype = 'c';
7108                                 constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
7109                                 constrs[j].confrelid = InvalidOid;
7110                                 constrs[j].conindex = 0;
7111                                 constrs[j].condeferrable = false;
7112                                 constrs[j].condeferred = false;
7113                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
7114
7115                                 /*
7116                                  * An unvalidated constraint needs to be dumped separately, so
7117                                  * that potentially-violating existing data is loaded before
7118                                  * the constraint.
7119                                  */
7120                                 constrs[j].separate = !validated;
7121
7122                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
7123
7124                                 /*
7125                                  * Mark the constraint as needing to appear before the table
7126                                  * --- this is so that any other dependencies of the
7127                                  * constraint will be emitted before we try to create the
7128                                  * table.  If the constraint is to be dumped separately, it
7129                                  * will be dumped after data is loaded anyway, so don't do it.
7130                                  * (There's an automatic dependency in the opposite direction
7131                                  * anyway, so don't need to add one manually here.)
7132                                  */
7133                                 if (!constrs[j].separate)
7134                                         addObjectDependency(&tbinfo->dobj,
7135                                                                                 constrs[j].dobj.dumpId);
7136
7137                                 /*
7138                                  * If the constraint is inherited, this will be detected later
7139                                  * (in pre-8.4 databases).  We also detect later if the
7140                                  * constraint must be split out from the table definition.
7141                                  */
7142                         }
7143                         PQclear(res);
7144                 }
7145         }
7146
7147         destroyPQExpBuffer(q);
7148 }
7149
7150 /*
7151  * Test whether a column should be printed as part of table's CREATE TABLE.
7152  * Column number is zero-based.
7153  *
7154  * Normally this is always true, but it's false for dropped columns, as well
7155  * as those that were inherited without any local definition.  (If we print
7156  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
7157  * However, in binary_upgrade mode, we must print all such columns anyway and
7158  * fix the attislocal/attisdropped state later, so as to keep control of the
7159  * physical column order.
7160  *
7161  * This function exists because there are scattered nonobvious places that
7162  * must be kept in sync with this decision.
7163  */
7164 bool
7165 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
7166 {
7167         if (dopt->binary_upgrade)
7168                 return true;
7169         return (tbinfo->attislocal[colno] && !tbinfo->attisdropped[colno]);
7170 }
7171
7172
7173 /*
7174  * getTSParsers:
7175  *        read all text search parsers in the system catalogs and return them
7176  *        in the TSParserInfo* structure
7177  *
7178  *      numTSParsers is set to the number of parsers read in
7179  */
7180 TSParserInfo *
7181 getTSParsers(Archive *fout, int *numTSParsers)
7182 {
7183         PGresult   *res;
7184         int                     ntups;
7185         int                     i;
7186         PQExpBuffer query;
7187         TSParserInfo *prsinfo;
7188         int                     i_tableoid;
7189         int                     i_oid;
7190         int                     i_prsname;
7191         int                     i_prsnamespace;
7192         int                     i_prsstart;
7193         int                     i_prstoken;
7194         int                     i_prsend;
7195         int                     i_prsheadline;
7196         int                     i_prslextype;
7197
7198         /* Before 8.3, there is no built-in text search support */
7199         if (fout->remoteVersion < 80300)
7200         {
7201                 *numTSParsers = 0;
7202                 return NULL;
7203         }
7204
7205         query = createPQExpBuffer();
7206
7207         /*
7208          * find all text search objects, including builtin ones; we filter out
7209          * system-defined objects at dump-out time.
7210          */
7211
7212         /* Make sure we are in proper schema */
7213         selectSourceSchema(fout, "pg_catalog");
7214
7215         appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
7216                                                  "prsstart::oid, prstoken::oid, "
7217                                                  "prsend::oid, prsheadline::oid, prslextype::oid "
7218                                                  "FROM pg_ts_parser");
7219
7220         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7221
7222         ntups = PQntuples(res);
7223         *numTSParsers = ntups;
7224
7225         prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
7226
7227         i_tableoid = PQfnumber(res, "tableoid");
7228         i_oid = PQfnumber(res, "oid");
7229         i_prsname = PQfnumber(res, "prsname");
7230         i_prsnamespace = PQfnumber(res, "prsnamespace");
7231         i_prsstart = PQfnumber(res, "prsstart");
7232         i_prstoken = PQfnumber(res, "prstoken");
7233         i_prsend = PQfnumber(res, "prsend");
7234         i_prsheadline = PQfnumber(res, "prsheadline");
7235         i_prslextype = PQfnumber(res, "prslextype");
7236
7237         for (i = 0; i < ntups; i++)
7238         {
7239                 prsinfo[i].dobj.objType = DO_TSPARSER;
7240                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7241                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7242                 AssignDumpId(&prsinfo[i].dobj);
7243                 prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
7244                 prsinfo[i].dobj.namespace =
7245                         findNamespace(fout,
7246                                                   atooid(PQgetvalue(res, i, i_prsnamespace)),
7247                                                   prsinfo[i].dobj.catId.oid);
7248                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
7249                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
7250                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
7251                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
7252                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
7253
7254                 /* Decide whether we want to dump it */
7255                 selectDumpableObject(&(prsinfo[i].dobj));
7256         }
7257
7258         PQclear(res);
7259
7260         destroyPQExpBuffer(query);
7261
7262         return prsinfo;
7263 }
7264
7265 /*
7266  * getTSDictionaries:
7267  *        read all text search dictionaries in the system catalogs and return them
7268  *        in the TSDictInfo* structure
7269  *
7270  *      numTSDicts is set to the number of dictionaries read in
7271  */
7272 TSDictInfo *
7273 getTSDictionaries(Archive *fout, int *numTSDicts)
7274 {
7275         PGresult   *res;
7276         int                     ntups;
7277         int                     i;
7278         PQExpBuffer query;
7279         TSDictInfo *dictinfo;
7280         int                     i_tableoid;
7281         int                     i_oid;
7282         int                     i_dictname;
7283         int                     i_dictnamespace;
7284         int                     i_rolname;
7285         int                     i_dicttemplate;
7286         int                     i_dictinitoption;
7287
7288         /* Before 8.3, there is no built-in text search support */
7289         if (fout->remoteVersion < 80300)
7290         {
7291                 *numTSDicts = 0;
7292                 return NULL;
7293         }
7294
7295         query = createPQExpBuffer();
7296
7297         /* Make sure we are in proper schema */
7298         selectSourceSchema(fout, "pg_catalog");
7299
7300         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
7301                                           "dictnamespace, (%s dictowner) AS rolname, "
7302                                           "dicttemplate, dictinitoption "
7303                                           "FROM pg_ts_dict",
7304                                           username_subquery);
7305
7306         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7307
7308         ntups = PQntuples(res);
7309         *numTSDicts = ntups;
7310
7311         dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
7312
7313         i_tableoid = PQfnumber(res, "tableoid");
7314         i_oid = PQfnumber(res, "oid");
7315         i_dictname = PQfnumber(res, "dictname");
7316         i_dictnamespace = PQfnumber(res, "dictnamespace");
7317         i_rolname = PQfnumber(res, "rolname");
7318         i_dictinitoption = PQfnumber(res, "dictinitoption");
7319         i_dicttemplate = PQfnumber(res, "dicttemplate");
7320
7321         for (i = 0; i < ntups; i++)
7322         {
7323                 dictinfo[i].dobj.objType = DO_TSDICT;
7324                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7325                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7326                 AssignDumpId(&dictinfo[i].dobj);
7327                 dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
7328                 dictinfo[i].dobj.namespace =
7329                         findNamespace(fout,
7330                                                   atooid(PQgetvalue(res, i, i_dictnamespace)),
7331                                                   dictinfo[i].dobj.catId.oid);
7332                 dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7333                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
7334                 if (PQgetisnull(res, i, i_dictinitoption))
7335                         dictinfo[i].dictinitoption = NULL;
7336                 else
7337                         dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
7338
7339                 /* Decide whether we want to dump it */
7340                 selectDumpableObject(&(dictinfo[i].dobj));
7341         }
7342
7343         PQclear(res);
7344
7345         destroyPQExpBuffer(query);
7346
7347         return dictinfo;
7348 }
7349
7350 /*
7351  * getTSTemplates:
7352  *        read all text search templates in the system catalogs and return them
7353  *        in the TSTemplateInfo* structure
7354  *
7355  *      numTSTemplates is set to the number of templates read in
7356  */
7357 TSTemplateInfo *
7358 getTSTemplates(Archive *fout, int *numTSTemplates)
7359 {
7360         PGresult   *res;
7361         int                     ntups;
7362         int                     i;
7363         PQExpBuffer query;
7364         TSTemplateInfo *tmplinfo;
7365         int                     i_tableoid;
7366         int                     i_oid;
7367         int                     i_tmplname;
7368         int                     i_tmplnamespace;
7369         int                     i_tmplinit;
7370         int                     i_tmpllexize;
7371
7372         /* Before 8.3, there is no built-in text search support */
7373         if (fout->remoteVersion < 80300)
7374         {
7375                 *numTSTemplates = 0;
7376                 return NULL;
7377         }
7378
7379         query = createPQExpBuffer();
7380
7381         /* Make sure we are in proper schema */
7382         selectSourceSchema(fout, "pg_catalog");
7383
7384         appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
7385                                                  "tmplnamespace, tmplinit::oid, tmpllexize::oid "
7386                                                  "FROM pg_ts_template");
7387
7388         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7389
7390         ntups = PQntuples(res);
7391         *numTSTemplates = ntups;
7392
7393         tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
7394
7395         i_tableoid = PQfnumber(res, "tableoid");
7396         i_oid = PQfnumber(res, "oid");
7397         i_tmplname = PQfnumber(res, "tmplname");
7398         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
7399         i_tmplinit = PQfnumber(res, "tmplinit");
7400         i_tmpllexize = PQfnumber(res, "tmpllexize");
7401
7402         for (i = 0; i < ntups; i++)
7403         {
7404                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
7405                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7406                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7407                 AssignDumpId(&tmplinfo[i].dobj);
7408                 tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
7409                 tmplinfo[i].dobj.namespace =
7410                         findNamespace(fout,
7411                                                   atooid(PQgetvalue(res, i, i_tmplnamespace)),
7412                                                   tmplinfo[i].dobj.catId.oid);
7413                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
7414                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
7415
7416                 /* Decide whether we want to dump it */
7417                 selectDumpableObject(&(tmplinfo[i].dobj));
7418         }
7419
7420         PQclear(res);
7421
7422         destroyPQExpBuffer(query);
7423
7424         return tmplinfo;
7425 }
7426
7427 /*
7428  * getTSConfigurations:
7429  *        read all text search configurations in the system catalogs and return
7430  *        them in the TSConfigInfo* structure
7431  *
7432  *      numTSConfigs is set to the number of configurations read in
7433  */
7434 TSConfigInfo *
7435 getTSConfigurations(Archive *fout, int *numTSConfigs)
7436 {
7437         PGresult   *res;
7438         int                     ntups;
7439         int                     i;
7440         PQExpBuffer query;
7441         TSConfigInfo *cfginfo;
7442         int                     i_tableoid;
7443         int                     i_oid;
7444         int                     i_cfgname;
7445         int                     i_cfgnamespace;
7446         int                     i_rolname;
7447         int                     i_cfgparser;
7448
7449         /* Before 8.3, there is no built-in text search support */
7450         if (fout->remoteVersion < 80300)
7451         {
7452                 *numTSConfigs = 0;
7453                 return NULL;
7454         }
7455
7456         query = createPQExpBuffer();
7457
7458         /* Make sure we are in proper schema */
7459         selectSourceSchema(fout, "pg_catalog");
7460
7461         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
7462                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
7463                                           "FROM pg_ts_config",
7464                                           username_subquery);
7465
7466         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7467
7468         ntups = PQntuples(res);
7469         *numTSConfigs = ntups;
7470
7471         cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
7472
7473         i_tableoid = PQfnumber(res, "tableoid");
7474         i_oid = PQfnumber(res, "oid");
7475         i_cfgname = PQfnumber(res, "cfgname");
7476         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
7477         i_rolname = PQfnumber(res, "rolname");
7478         i_cfgparser = PQfnumber(res, "cfgparser");
7479
7480         for (i = 0; i < ntups; i++)
7481         {
7482                 cfginfo[i].dobj.objType = DO_TSCONFIG;
7483                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7484                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7485                 AssignDumpId(&cfginfo[i].dobj);
7486                 cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
7487                 cfginfo[i].dobj.namespace =
7488                         findNamespace(fout,
7489                                                   atooid(PQgetvalue(res, i, i_cfgnamespace)),
7490                                                   cfginfo[i].dobj.catId.oid);
7491                 cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7492                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
7493
7494                 /* Decide whether we want to dump it */
7495                 selectDumpableObject(&(cfginfo[i].dobj));
7496         }
7497
7498         PQclear(res);
7499
7500         destroyPQExpBuffer(query);
7501
7502         return cfginfo;
7503 }
7504
7505 /*
7506  * getForeignDataWrappers:
7507  *        read all foreign-data wrappers in the system catalogs and return
7508  *        them in the FdwInfo* structure
7509  *
7510  *      numForeignDataWrappers is set to the number of fdws read in
7511  */
7512 FdwInfo *
7513 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
7514 {
7515         PGresult   *res;
7516         int                     ntups;
7517         int                     i;
7518         PQExpBuffer query;
7519         FdwInfo    *fdwinfo;
7520         int                     i_tableoid;
7521         int                     i_oid;
7522         int                     i_fdwname;
7523         int                     i_rolname;
7524         int                     i_fdwhandler;
7525         int                     i_fdwvalidator;
7526         int                     i_fdwacl;
7527         int                     i_fdwoptions;
7528
7529         /* Before 8.4, there are no foreign-data wrappers */
7530         if (fout->remoteVersion < 80400)
7531         {
7532                 *numForeignDataWrappers = 0;
7533                 return NULL;
7534         }
7535
7536         query = createPQExpBuffer();
7537
7538         /* Make sure we are in proper schema */
7539         selectSourceSchema(fout, "pg_catalog");
7540
7541         if (fout->remoteVersion >= 90100)
7542         {
7543                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7544                                                   "(%s fdwowner) AS rolname, "
7545                                                   "fdwhandler::pg_catalog.regproc, "
7546                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7547                                                   "array_to_string(ARRAY("
7548                                                   "SELECT quote_ident(option_name) || ' ' || "
7549                                                   "quote_literal(option_value) "
7550                                                   "FROM pg_options_to_table(fdwoptions) "
7551                                                   "ORDER BY option_name"
7552                                                   "), E',\n    ') AS fdwoptions "
7553                                                   "FROM pg_foreign_data_wrapper",
7554                                                   username_subquery);
7555         }
7556         else
7557         {
7558                 appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
7559                                                   "(%s fdwowner) AS rolname, "
7560                                                   "'-' AS fdwhandler, "
7561                                                   "fdwvalidator::pg_catalog.regproc, fdwacl, "
7562                                                   "array_to_string(ARRAY("
7563                                                   "SELECT quote_ident(option_name) || ' ' || "
7564                                                   "quote_literal(option_value) "
7565                                                   "FROM pg_options_to_table(fdwoptions) "
7566                                                   "ORDER BY option_name"
7567                                                   "), E',\n    ') AS fdwoptions "
7568                                                   "FROM pg_foreign_data_wrapper",
7569                                                   username_subquery);
7570         }
7571
7572         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7573
7574         ntups = PQntuples(res);
7575         *numForeignDataWrappers = ntups;
7576
7577         fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
7578
7579         i_tableoid = PQfnumber(res, "tableoid");
7580         i_oid = PQfnumber(res, "oid");
7581         i_fdwname = PQfnumber(res, "fdwname");
7582         i_rolname = PQfnumber(res, "rolname");
7583         i_fdwhandler = PQfnumber(res, "fdwhandler");
7584         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
7585         i_fdwacl = PQfnumber(res, "fdwacl");
7586         i_fdwoptions = PQfnumber(res, "fdwoptions");
7587
7588         for (i = 0; i < ntups; i++)
7589         {
7590                 fdwinfo[i].dobj.objType = DO_FDW;
7591                 fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7592                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7593                 AssignDumpId(&fdwinfo[i].dobj);
7594                 fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
7595                 fdwinfo[i].dobj.namespace = NULL;
7596                 fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7597                 fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
7598                 fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
7599                 fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
7600                 fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
7601
7602                 /* Decide whether we want to dump it */
7603                 selectDumpableObject(&(fdwinfo[i].dobj));
7604         }
7605
7606         PQclear(res);
7607
7608         destroyPQExpBuffer(query);
7609
7610         return fdwinfo;
7611 }
7612
7613 /*
7614  * getForeignServers:
7615  *        read all foreign servers in the system catalogs and return
7616  *        them in the ForeignServerInfo * structure
7617  *
7618  *      numForeignServers is set to the number of servers read in
7619  */
7620 ForeignServerInfo *
7621 getForeignServers(Archive *fout, int *numForeignServers)
7622 {
7623         PGresult   *res;
7624         int                     ntups;
7625         int                     i;
7626         PQExpBuffer query;
7627         ForeignServerInfo *srvinfo;
7628         int                     i_tableoid;
7629         int                     i_oid;
7630         int                     i_srvname;
7631         int                     i_rolname;
7632         int                     i_srvfdw;
7633         int                     i_srvtype;
7634         int                     i_srvversion;
7635         int                     i_srvacl;
7636         int                     i_srvoptions;
7637
7638         /* Before 8.4, there are no foreign servers */
7639         if (fout->remoteVersion < 80400)
7640         {
7641                 *numForeignServers = 0;
7642                 return NULL;
7643         }
7644
7645         query = createPQExpBuffer();
7646
7647         /* Make sure we are in proper schema */
7648         selectSourceSchema(fout, "pg_catalog");
7649
7650         appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
7651                                           "(%s srvowner) AS rolname, "
7652                                           "srvfdw, srvtype, srvversion, srvacl,"
7653                                           "array_to_string(ARRAY("
7654                                           "SELECT quote_ident(option_name) || ' ' || "
7655                                           "quote_literal(option_value) "
7656                                           "FROM pg_options_to_table(srvoptions) "
7657                                           "ORDER BY option_name"
7658                                           "), E',\n    ') AS srvoptions "
7659                                           "FROM pg_foreign_server",
7660                                           username_subquery);
7661
7662         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7663
7664         ntups = PQntuples(res);
7665         *numForeignServers = ntups;
7666
7667         srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
7668
7669         i_tableoid = PQfnumber(res, "tableoid");
7670         i_oid = PQfnumber(res, "oid");
7671         i_srvname = PQfnumber(res, "srvname");
7672         i_rolname = PQfnumber(res, "rolname");
7673         i_srvfdw = PQfnumber(res, "srvfdw");
7674         i_srvtype = PQfnumber(res, "srvtype");
7675         i_srvversion = PQfnumber(res, "srvversion");
7676         i_srvacl = PQfnumber(res, "srvacl");
7677         i_srvoptions = PQfnumber(res, "srvoptions");
7678
7679         for (i = 0; i < ntups; i++)
7680         {
7681                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
7682                 srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7683                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7684                 AssignDumpId(&srvinfo[i].dobj);
7685                 srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
7686                 srvinfo[i].dobj.namespace = NULL;
7687                 srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7688                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
7689                 srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
7690                 srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
7691                 srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
7692                 srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
7693
7694                 /* Decide whether we want to dump it */
7695                 selectDumpableObject(&(srvinfo[i].dobj));
7696         }
7697
7698         PQclear(res);
7699
7700         destroyPQExpBuffer(query);
7701
7702         return srvinfo;
7703 }
7704
7705 /*
7706  * getDefaultACLs:
7707  *        read all default ACL information in the system catalogs and return
7708  *        them in the DefaultACLInfo structure
7709  *
7710  *      numDefaultACLs is set to the number of ACLs read in
7711  */
7712 DefaultACLInfo *
7713 getDefaultACLs(Archive *fout, DumpOptions *dopt, int *numDefaultACLs)
7714 {
7715         DefaultACLInfo *daclinfo;
7716         PQExpBuffer query;
7717         PGresult   *res;
7718         int                     i_oid;
7719         int                     i_tableoid;
7720         int                     i_defaclrole;
7721         int                     i_defaclnamespace;
7722         int                     i_defaclobjtype;
7723         int                     i_defaclacl;
7724         int                     i,
7725                                 ntups;
7726
7727         if (fout->remoteVersion < 90000)
7728         {
7729                 *numDefaultACLs = 0;
7730                 return NULL;
7731         }
7732
7733         query = createPQExpBuffer();
7734
7735         /* Make sure we are in proper schema */
7736         selectSourceSchema(fout, "pg_catalog");
7737
7738         appendPQExpBuffer(query, "SELECT oid, tableoid, "
7739                                           "(%s defaclrole) AS defaclrole, "
7740                                           "defaclnamespace, "
7741                                           "defaclobjtype, "
7742                                           "defaclacl "
7743                                           "FROM pg_default_acl",
7744                                           username_subquery);
7745
7746         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7747
7748         ntups = PQntuples(res);
7749         *numDefaultACLs = ntups;
7750
7751         daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
7752
7753         i_oid = PQfnumber(res, "oid");
7754         i_tableoid = PQfnumber(res, "tableoid");
7755         i_defaclrole = PQfnumber(res, "defaclrole");
7756         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
7757         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
7758         i_defaclacl = PQfnumber(res, "defaclacl");
7759
7760         for (i = 0; i < ntups; i++)
7761         {
7762                 Oid                     nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
7763
7764                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
7765                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7766                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7767                 AssignDumpId(&daclinfo[i].dobj);
7768                 /* cheesy ... is it worth coming up with a better object name? */
7769                 daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
7770
7771                 if (nspid != InvalidOid)
7772                         daclinfo[i].dobj.namespace = findNamespace(fout, nspid,
7773                                                                                                  daclinfo[i].dobj.catId.oid);
7774                 else
7775                         daclinfo[i].dobj.namespace = NULL;
7776
7777                 daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
7778                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
7779                 daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
7780
7781                 /* Decide whether we want to dump it */
7782                 selectDumpableDefaultACL(dopt, &(daclinfo[i]));
7783         }
7784
7785         PQclear(res);
7786
7787         destroyPQExpBuffer(query);
7788
7789         return daclinfo;
7790 }
7791
7792 /*
7793  * dumpComment --
7794  *
7795  * This routine is used to dump any comments associated with the
7796  * object handed to this routine. The routine takes a constant character
7797  * string for the target part of the comment-creation command, plus
7798  * the namespace and owner of the object (for labeling the ArchiveEntry),
7799  * plus catalog ID and subid which are the lookup key for pg_description,
7800  * plus the dump ID for the object (for setting a dependency).
7801  * If a matching pg_description entry is found, it is dumped.
7802  *
7803  * Note: although this routine takes a dumpId for dependency purposes,
7804  * that purpose is just to mark the dependency in the emitted dump file
7805  * for possible future use by pg_restore.  We do NOT use it for determining
7806  * ordering of the comment in the dump file, because this routine is called
7807  * after dependency sorting occurs.  This routine should be called just after
7808  * calling ArchiveEntry() for the specified object.
7809  */
7810 static void
7811 dumpComment(Archive *fout, DumpOptions *dopt, const char *target,
7812                         const char *namespace, const char *owner,
7813                         CatalogId catalogId, int subid, DumpId dumpId)
7814 {
7815         CommentItem *comments;
7816         int                     ncomments;
7817
7818         /* Comments are schema not data ... except blob comments are data */
7819         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
7820         {
7821                 if (dopt->dataOnly)
7822                         return;
7823         }
7824         else
7825         {
7826                 if (dopt->schemaOnly)
7827                         return;
7828         }
7829
7830         /* Search for comments associated with catalogId, using table */
7831         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
7832                                                          &comments);
7833
7834         /* Is there one matching the subid? */
7835         while (ncomments > 0)
7836         {
7837                 if (comments->objsubid == subid)
7838                         break;
7839                 comments++;
7840                 ncomments--;
7841         }
7842
7843         /* If a comment exists, build COMMENT ON statement */
7844         if (ncomments > 0)
7845         {
7846                 PQExpBuffer query = createPQExpBuffer();
7847
7848                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
7849                 appendStringLiteralAH(query, comments->descr, fout);
7850                 appendPQExpBufferStr(query, ";\n");
7851
7852                 /*
7853                  * We mark comments as SECTION_NONE because they really belong in the
7854                  * same section as their parent, whether that is pre-data or
7855                  * post-data.
7856                  */
7857                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7858                                          target, namespace, NULL, owner,
7859                                          false, "COMMENT", SECTION_NONE,
7860                                          query->data, "", NULL,
7861                                          &(dumpId), 1,
7862                                          NULL, NULL);
7863
7864                 destroyPQExpBuffer(query);
7865         }
7866 }
7867
7868 /*
7869  * dumpTableComment --
7870  *
7871  * As above, but dump comments for both the specified table (or view)
7872  * and its columns.
7873  */
7874 static void
7875 dumpTableComment(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo,
7876                                  const char *reltypename)
7877 {
7878         CommentItem *comments;
7879         int                     ncomments;
7880         PQExpBuffer query;
7881         PQExpBuffer target;
7882
7883         /* Comments are SCHEMA not data */
7884         if (dopt->dataOnly)
7885                 return;
7886
7887         /* Search for comments associated with relation, using table */
7888         ncomments = findComments(fout,
7889                                                          tbinfo->dobj.catId.tableoid,
7890                                                          tbinfo->dobj.catId.oid,
7891                                                          &comments);
7892
7893         /* If comments exist, build COMMENT ON statements */
7894         if (ncomments <= 0)
7895                 return;
7896
7897         query = createPQExpBuffer();
7898         target = createPQExpBuffer();
7899
7900         while (ncomments > 0)
7901         {
7902                 const char *descr = comments->descr;
7903                 int                     objsubid = comments->objsubid;
7904
7905                 if (objsubid == 0)
7906                 {
7907                         resetPQExpBuffer(target);
7908                         appendPQExpBuffer(target, "%s %s", reltypename,
7909                                                           fmtId(tbinfo->dobj.name));
7910
7911                         resetPQExpBuffer(query);
7912                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7913                         appendStringLiteralAH(query, descr, fout);
7914                         appendPQExpBufferStr(query, ";\n");
7915
7916                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7917                                                  target->data,
7918                                                  tbinfo->dobj.namespace->dobj.name,
7919                                                  NULL, tbinfo->rolname,
7920                                                  false, "COMMENT", SECTION_NONE,
7921                                                  query->data, "", NULL,
7922                                                  &(tbinfo->dobj.dumpId), 1,
7923                                                  NULL, NULL);
7924                 }
7925                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
7926                 {
7927                         resetPQExpBuffer(target);
7928                         appendPQExpBuffer(target, "COLUMN %s.",
7929                                                           fmtId(tbinfo->dobj.name));
7930                         appendPQExpBufferStr(target, fmtId(tbinfo->attnames[objsubid - 1]));
7931
7932                         resetPQExpBuffer(query);
7933                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7934                         appendStringLiteralAH(query, descr, fout);
7935                         appendPQExpBufferStr(query, ";\n");
7936
7937                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7938                                                  target->data,
7939                                                  tbinfo->dobj.namespace->dobj.name,
7940                                                  NULL, tbinfo->rolname,
7941                                                  false, "COMMENT", SECTION_NONE,
7942                                                  query->data, "", NULL,
7943                                                  &(tbinfo->dobj.dumpId), 1,
7944                                                  NULL, NULL);
7945                 }
7946
7947                 comments++;
7948                 ncomments--;
7949         }
7950
7951         destroyPQExpBuffer(query);
7952         destroyPQExpBuffer(target);
7953 }
7954
7955 /*
7956  * findComments --
7957  *
7958  * Find the comment(s), if any, associated with the given object.  All the
7959  * objsubid values associated with the given classoid/objoid are found with
7960  * one search.
7961  */
7962 static int
7963 findComments(Archive *fout, Oid classoid, Oid objoid,
7964                          CommentItem **items)
7965 {
7966         /* static storage for table of comments */
7967         static CommentItem *comments = NULL;
7968         static int      ncomments = -1;
7969
7970         CommentItem *middle = NULL;
7971         CommentItem *low;
7972         CommentItem *high;
7973         int                     nmatch;
7974
7975         /* Get comments if we didn't already */
7976         if (ncomments < 0)
7977                 ncomments = collectComments(fout, &comments);
7978
7979         /*
7980          * Pre-7.2, pg_description does not contain classoid, so collectComments
7981          * just stores a zero.  If there's a collision on object OID, well, you
7982          * get duplicate comments.
7983          */
7984         if (fout->remoteVersion < 70200)
7985                 classoid = 0;
7986
7987         /*
7988          * Do binary search to find some item matching the object.
7989          */
7990         low = &comments[0];
7991         high = &comments[ncomments - 1];
7992         while (low <= high)
7993         {
7994                 middle = low + (high - low) / 2;
7995
7996                 if (classoid < middle->classoid)
7997                         high = middle - 1;
7998                 else if (classoid > middle->classoid)
7999                         low = middle + 1;
8000                 else if (objoid < middle->objoid)
8001                         high = middle - 1;
8002                 else if (objoid > middle->objoid)
8003                         low = middle + 1;
8004                 else
8005                         break;                          /* found a match */
8006         }
8007
8008         if (low > high)                         /* no matches */
8009         {
8010                 *items = NULL;
8011                 return 0;
8012         }
8013
8014         /*
8015          * Now determine how many items match the object.  The search loop
8016          * invariant still holds: only items between low and high inclusive could
8017          * match.
8018          */
8019         nmatch = 1;
8020         while (middle > low)
8021         {
8022                 if (classoid != middle[-1].classoid ||
8023                         objoid != middle[-1].objoid)
8024                         break;
8025                 middle--;
8026                 nmatch++;
8027         }
8028
8029         *items = middle;
8030
8031         middle += nmatch;
8032         while (middle <= high)
8033         {
8034                 if (classoid != middle->classoid ||
8035                         objoid != middle->objoid)
8036                         break;
8037                 middle++;
8038                 nmatch++;
8039         }
8040
8041         return nmatch;
8042 }
8043
8044 /*
8045  * collectComments --
8046  *
8047  * Construct a table of all comments available for database objects.
8048  * We used to do per-object queries for the comments, but it's much faster
8049  * to pull them all over at once, and on most databases the memory cost
8050  * isn't high.
8051  *
8052  * The table is sorted by classoid/objid/objsubid for speed in lookup.
8053  */
8054 static int
8055 collectComments(Archive *fout, CommentItem **items)
8056 {
8057         PGresult   *res;
8058         PQExpBuffer query;
8059         int                     i_description;
8060         int                     i_classoid;
8061         int                     i_objoid;
8062         int                     i_objsubid;
8063         int                     ntups;
8064         int                     i;
8065         CommentItem *comments;
8066
8067         /*
8068          * Note we do NOT change source schema here; preserve the caller's
8069          * setting, instead.
8070          */
8071
8072         query = createPQExpBuffer();
8073
8074         if (fout->remoteVersion >= 70300)
8075         {
8076                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
8077                                                          "FROM pg_catalog.pg_description "
8078                                                          "ORDER BY classoid, objoid, objsubid");
8079         }
8080         else if (fout->remoteVersion >= 70200)
8081         {
8082                 appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
8083                                                          "FROM pg_description "
8084                                                          "ORDER BY classoid, objoid, objsubid");
8085         }
8086         else
8087         {
8088                 /* Note: this will fail to find attribute comments in pre-7.2... */
8089                 appendPQExpBufferStr(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
8090                                                          "FROM pg_description "
8091                                                          "ORDER BY objoid");
8092         }
8093
8094         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8095
8096         /* Construct lookup table containing OIDs in numeric form */
8097
8098         i_description = PQfnumber(res, "description");
8099         i_classoid = PQfnumber(res, "classoid");
8100         i_objoid = PQfnumber(res, "objoid");
8101         i_objsubid = PQfnumber(res, "objsubid");
8102
8103         ntups = PQntuples(res);
8104
8105         comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
8106
8107         for (i = 0; i < ntups; i++)
8108         {
8109                 comments[i].descr = PQgetvalue(res, i, i_description);
8110                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
8111                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
8112                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
8113         }
8114
8115         /* Do NOT free the PGresult since we are keeping pointers into it */
8116         destroyPQExpBuffer(query);
8117
8118         *items = comments;
8119         return ntups;
8120 }
8121
8122 /*
8123  * dumpDumpableObject
8124  *
8125  * This routine and its subsidiaries are responsible for creating
8126  * ArchiveEntries (TOC objects) for each object to be dumped.
8127  */
8128 static void
8129 dumpDumpableObject(Archive *fout, DumpOptions *dopt, DumpableObject *dobj)
8130 {
8131         switch (dobj->objType)
8132         {
8133                 case DO_NAMESPACE:
8134                         dumpNamespace(fout, dopt, (NamespaceInfo *) dobj);
8135                         break;
8136                 case DO_EXTENSION:
8137                         dumpExtension(fout, dopt, (ExtensionInfo *) dobj);
8138                         break;
8139                 case DO_TYPE:
8140                         dumpType(fout, dopt, (TypeInfo *) dobj);
8141                         break;
8142                 case DO_SHELL_TYPE:
8143                         dumpShellType(fout, dopt, (ShellTypeInfo *) dobj);
8144                         break;
8145                 case DO_FUNC:
8146                         dumpFunc(fout, dopt, (FuncInfo *) dobj);
8147                         break;
8148                 case DO_AGG:
8149                         dumpAgg(fout, dopt, (AggInfo *) dobj);
8150                         break;
8151                 case DO_OPERATOR:
8152                         dumpOpr(fout, dopt, (OprInfo *) dobj);
8153                         break;
8154                 case DO_OPCLASS:
8155                         dumpOpclass(fout, dopt, (OpclassInfo *) dobj);
8156                         break;
8157                 case DO_OPFAMILY:
8158                         dumpOpfamily(fout, dopt, (OpfamilyInfo *) dobj);
8159                         break;
8160                 case DO_COLLATION:
8161                         dumpCollation(fout, dopt, (CollInfo *) dobj);
8162                         break;
8163                 case DO_CONVERSION:
8164                         dumpConversion(fout, dopt, (ConvInfo *) dobj);
8165                         break;
8166                 case DO_TABLE:
8167                         dumpTable(fout, dopt, (TableInfo *) dobj);
8168                         break;
8169                 case DO_ATTRDEF:
8170                         dumpAttrDef(fout, dopt, (AttrDefInfo *) dobj);
8171                         break;
8172                 case DO_INDEX:
8173                         dumpIndex(fout, dopt, (IndxInfo *) dobj);
8174                         break;
8175                 case DO_REFRESH_MATVIEW:
8176                         refreshMatViewData(fout, (TableDataInfo *) dobj);
8177                         break;
8178                 case DO_RULE:
8179                         dumpRule(fout, dopt, (RuleInfo *) dobj);
8180                         break;
8181                 case DO_TRIGGER:
8182                         dumpTrigger(fout, dopt, (TriggerInfo *) dobj);
8183                         break;
8184                 case DO_EVENT_TRIGGER:
8185                         dumpEventTrigger(fout, dopt, (EventTriggerInfo *) dobj);
8186                         break;
8187                 case DO_CONSTRAINT:
8188                         dumpConstraint(fout, dopt, (ConstraintInfo *) dobj);
8189                         break;
8190                 case DO_FK_CONSTRAINT:
8191                         dumpConstraint(fout, dopt, (ConstraintInfo *) dobj);
8192                         break;
8193                 case DO_PROCLANG:
8194                         dumpProcLang(fout, dopt, (ProcLangInfo *) dobj);
8195                         break;
8196                 case DO_CAST:
8197                         dumpCast(fout, dopt, (CastInfo *) dobj);
8198                         break;
8199                 case DO_TABLE_DATA:
8200                         if (((TableDataInfo *) dobj)->tdtable->relkind == RELKIND_SEQUENCE)
8201                                 dumpSequenceData(fout, (TableDataInfo *) dobj);
8202                         else
8203                                 dumpTableData(fout, dopt, (TableDataInfo *) dobj);
8204                         break;
8205                 case DO_DUMMY_TYPE:
8206                         /* table rowtypes and array types are never dumped separately */
8207                         break;
8208                 case DO_TSPARSER:
8209                         dumpTSParser(fout, dopt, (TSParserInfo *) dobj);
8210                         break;
8211                 case DO_TSDICT:
8212                         dumpTSDictionary(fout, dopt, (TSDictInfo *) dobj);
8213                         break;
8214                 case DO_TSTEMPLATE:
8215                         dumpTSTemplate(fout, dopt, (TSTemplateInfo *) dobj);
8216                         break;
8217                 case DO_TSCONFIG:
8218                         dumpTSConfig(fout, dopt, (TSConfigInfo *) dobj);
8219                         break;
8220                 case DO_FDW:
8221                         dumpForeignDataWrapper(fout, dopt, (FdwInfo *) dobj);
8222                         break;
8223                 case DO_FOREIGN_SERVER:
8224                         dumpForeignServer(fout, dopt, (ForeignServerInfo *) dobj);
8225                         break;
8226                 case DO_DEFAULT_ACL:
8227                         dumpDefaultACL(fout, dopt, (DefaultACLInfo *) dobj);
8228                         break;
8229                 case DO_BLOB:
8230                         dumpBlob(fout, dopt, (BlobInfo *) dobj);
8231                         break;
8232                 case DO_BLOB_DATA:
8233                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
8234                                                  dobj->name, NULL, NULL, "",
8235                                                  false, "BLOBS", SECTION_DATA,
8236                                                  "", "", NULL,
8237                                                  NULL, 0,
8238                                                  dumpBlobs, NULL);
8239                         break;
8240                 case DO_POLICY:
8241                         dumpPolicy(fout, dopt, (PolicyInfo *) dobj);
8242                         break;
8243                 case DO_PRE_DATA_BOUNDARY:
8244                 case DO_POST_DATA_BOUNDARY:
8245                         /* never dumped, nothing to do */
8246                         break;
8247         }
8248 }
8249
8250 /*
8251  * dumpNamespace
8252  *        writes out to fout the queries to recreate a user-defined namespace
8253  */
8254 static void
8255 dumpNamespace(Archive *fout, DumpOptions *dopt, NamespaceInfo *nspinfo)
8256 {
8257         PQExpBuffer q;
8258         PQExpBuffer delq;
8259         PQExpBuffer labelq;
8260         char       *qnspname;
8261
8262         /* Skip if not to be dumped */
8263         if (!nspinfo->dobj.dump || dopt->dataOnly)
8264                 return;
8265
8266         /* don't dump dummy namespace from pre-7.3 source */
8267         if (strlen(nspinfo->dobj.name) == 0)
8268                 return;
8269
8270         q = createPQExpBuffer();
8271         delq = createPQExpBuffer();
8272         labelq = createPQExpBuffer();
8273
8274         qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
8275
8276         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
8277
8278         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
8279
8280         appendPQExpBuffer(labelq, "SCHEMA %s", qnspname);
8281
8282         if (dopt->binary_upgrade)
8283                 binary_upgrade_extension_member(q, &nspinfo->dobj, labelq->data);
8284
8285         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
8286                                  nspinfo->dobj.name,
8287                                  NULL, NULL,
8288                                  nspinfo->rolname,
8289                                  false, "SCHEMA", SECTION_PRE_DATA,
8290                                  q->data, delq->data, NULL,
8291                                  NULL, 0,
8292                                  NULL, NULL);
8293
8294         /* Dump Schema Comments and Security Labels */
8295         dumpComment(fout, dopt, labelq->data,
8296                                 NULL, nspinfo->rolname,
8297                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
8298         dumpSecLabel(fout, dopt, labelq->data,
8299                                  NULL, nspinfo->rolname,
8300                                  nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
8301
8302         dumpACL(fout, dopt, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
8303                         qnspname, NULL, nspinfo->dobj.name, NULL,
8304                         nspinfo->rolname, nspinfo->nspacl);
8305
8306         free(qnspname);
8307
8308         destroyPQExpBuffer(q);
8309         destroyPQExpBuffer(delq);
8310         destroyPQExpBuffer(labelq);
8311 }
8312
8313 /*
8314  * dumpExtension
8315  *        writes out to fout the queries to recreate an extension
8316  */
8317 static void
8318 dumpExtension(Archive *fout, DumpOptions *dopt, ExtensionInfo *extinfo)
8319 {
8320         PQExpBuffer q;
8321         PQExpBuffer delq;
8322         PQExpBuffer labelq;
8323         char       *qextname;
8324
8325         /* Skip if not to be dumped */
8326         if (!extinfo->dobj.dump || dopt->dataOnly)
8327                 return;
8328
8329         q = createPQExpBuffer();
8330         delq = createPQExpBuffer();
8331         labelq = createPQExpBuffer();
8332
8333         qextname = pg_strdup(fmtId(extinfo->dobj.name));
8334
8335         appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
8336
8337         if (!dopt->binary_upgrade)
8338         {
8339                 /*
8340                  * In a regular dump, we use IF NOT EXISTS so that there isn't a
8341                  * problem if the extension already exists in the target database;
8342                  * this is essential for installed-by-default extensions such as
8343                  * plpgsql.
8344                  *
8345                  * In binary-upgrade mode, that doesn't work well, so instead we skip
8346                  * built-in extensions based on their OIDs; see
8347                  * selectDumpableExtension.
8348                  */
8349                 appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
8350                                                   qextname, fmtId(extinfo->namespace));
8351         }
8352         else
8353         {
8354                 int                     i;
8355                 int                     n;
8356
8357                 appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
8358
8359                 /*
8360                  * We unconditionally create the extension, so we must drop it if it
8361                  * exists.  This could happen if the user deleted 'plpgsql' and then
8362                  * readded it, causing its oid to be greater than FirstNormalObjectId.
8363                  * The FirstNormalObjectId test was kept to avoid repeatedly dropping
8364                  * and recreating extensions like 'plpgsql'.
8365                  */
8366                 appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
8367
8368                 appendPQExpBufferStr(q,
8369                                                          "SELECT binary_upgrade.create_empty_extension(");
8370                 appendStringLiteralAH(q, extinfo->dobj.name, fout);
8371                 appendPQExpBufferStr(q, ", ");
8372                 appendStringLiteralAH(q, extinfo->namespace, fout);
8373                 appendPQExpBufferStr(q, ", ");
8374                 appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
8375                 appendStringLiteralAH(q, extinfo->extversion, fout);
8376                 appendPQExpBufferStr(q, ", ");
8377
8378                 /*
8379                  * Note that we're pushing extconfig (an OID array) back into
8380                  * pg_extension exactly as-is.  This is OK because pg_class OIDs are
8381                  * preserved in binary upgrade.
8382                  */
8383                 if (strlen(extinfo->extconfig) > 2)
8384                         appendStringLiteralAH(q, extinfo->extconfig, fout);
8385                 else
8386                         appendPQExpBufferStr(q, "NULL");
8387                 appendPQExpBufferStr(q, ", ");
8388                 if (strlen(extinfo->extcondition) > 2)
8389                         appendStringLiteralAH(q, extinfo->extcondition, fout);
8390                 else
8391                         appendPQExpBufferStr(q, "NULL");
8392                 appendPQExpBufferStr(q, ", ");
8393                 appendPQExpBufferStr(q, "ARRAY[");
8394                 n = 0;
8395                 for (i = 0; i < extinfo->dobj.nDeps; i++)
8396                 {
8397                         DumpableObject *extobj;
8398
8399                         extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
8400                         if (extobj && extobj->objType == DO_EXTENSION)
8401                         {
8402                                 if (n++ > 0)
8403                                         appendPQExpBufferChar(q, ',');
8404                                 appendStringLiteralAH(q, extobj->name, fout);
8405                         }
8406                 }
8407                 appendPQExpBufferStr(q, "]::pg_catalog.text[]");
8408                 appendPQExpBufferStr(q, ");\n");
8409         }
8410
8411         appendPQExpBuffer(labelq, "EXTENSION %s", qextname);
8412
8413         ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
8414                                  extinfo->dobj.name,
8415                                  NULL, NULL,
8416                                  "",
8417                                  false, "EXTENSION", SECTION_PRE_DATA,
8418                                  q->data, delq->data, NULL,
8419                                  NULL, 0,
8420                                  NULL, NULL);
8421
8422         /* Dump Extension Comments and Security Labels */
8423         dumpComment(fout, dopt, labelq->data,
8424                                 NULL, "",
8425                                 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8426         dumpSecLabel(fout, dopt, labelq->data,
8427                                  NULL, "",
8428                                  extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
8429
8430         free(qextname);
8431
8432         destroyPQExpBuffer(q);
8433         destroyPQExpBuffer(delq);
8434         destroyPQExpBuffer(labelq);
8435 }
8436
8437 /*
8438  * dumpType
8439  *        writes out to fout the queries to recreate a user-defined type
8440  */
8441 static void
8442 dumpType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
8443 {
8444         /* Skip if not to be dumped */
8445         if (!tyinfo->dobj.dump || dopt->dataOnly)
8446                 return;
8447
8448         /* Dump out in proper style */
8449         if (tyinfo->typtype == TYPTYPE_BASE)
8450                 dumpBaseType(fout, dopt, tyinfo);
8451         else if (tyinfo->typtype == TYPTYPE_DOMAIN)
8452                 dumpDomain(fout, dopt, tyinfo);
8453         else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
8454                 dumpCompositeType(fout, dopt, tyinfo);
8455         else if (tyinfo->typtype == TYPTYPE_ENUM)
8456                 dumpEnumType(fout, dopt, tyinfo);
8457         else if (tyinfo->typtype == TYPTYPE_RANGE)
8458                 dumpRangeType(fout, dopt, tyinfo);
8459         else
8460                 write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
8461                                   tyinfo->dobj.name);
8462 }
8463
8464 /*
8465  * dumpEnumType
8466  *        writes out to fout the queries to recreate a user-defined enum type
8467  */
8468 static void
8469 dumpEnumType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
8470 {
8471         PQExpBuffer q = createPQExpBuffer();
8472         PQExpBuffer delq = createPQExpBuffer();
8473         PQExpBuffer labelq = createPQExpBuffer();
8474         PQExpBuffer query = createPQExpBuffer();
8475         PGresult   *res;
8476         int                     num,
8477                                 i;
8478         Oid                     enum_oid;
8479         char       *qtypname;
8480         char       *label;
8481
8482         /* Set proper schema search path */
8483         selectSourceSchema(fout, "pg_catalog");
8484
8485         if (fout->remoteVersion >= 90100)
8486                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8487                                                   "FROM pg_catalog.pg_enum "
8488                                                   "WHERE enumtypid = '%u'"
8489                                                   "ORDER BY enumsortorder",
8490                                                   tyinfo->dobj.catId.oid);
8491         else
8492                 appendPQExpBuffer(query, "SELECT oid, enumlabel "
8493                                                   "FROM pg_catalog.pg_enum "
8494                                                   "WHERE enumtypid = '%u'"
8495                                                   "ORDER BY oid",
8496                                                   tyinfo->dobj.catId.oid);
8497
8498         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8499
8500         num = PQntuples(res);
8501
8502         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8503
8504         /*
8505          * DROP must be fully qualified in case same name appears in pg_catalog.
8506          * CASCADE shouldn't be required here as for normal types since the I/O
8507          * functions are generic and do not get dropped.
8508          */
8509         appendPQExpBuffer(delq, "DROP TYPE %s.",
8510                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8511         appendPQExpBuffer(delq, "%s;\n",
8512                                           qtypname);
8513
8514         if (dopt->binary_upgrade)
8515                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8516                                                                                                  tyinfo->dobj.catId.oid);
8517
8518         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
8519                                           qtypname);
8520
8521         if (!dopt->binary_upgrade)
8522         {
8523                 /* Labels with server-assigned oids */
8524                 for (i = 0; i < num; i++)
8525                 {
8526                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8527                         if (i > 0)
8528                                 appendPQExpBufferChar(q, ',');
8529                         appendPQExpBufferStr(q, "\n    ");
8530                         appendStringLiteralAH(q, label, fout);
8531                 }
8532         }
8533
8534         appendPQExpBufferStr(q, "\n);\n");
8535
8536         if (dopt->binary_upgrade)
8537         {
8538                 /* Labels with dump-assigned (preserved) oids */
8539                 for (i = 0; i < num; i++)
8540                 {
8541                         enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
8542                         label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
8543
8544                         if (i == 0)
8545                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
8546                         appendPQExpBuffer(q,
8547                                                           "SELECT binary_upgrade.set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
8548                                                           enum_oid);
8549                         appendPQExpBuffer(q, "ALTER TYPE %s.",
8550                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8551                         appendPQExpBuffer(q, "%s ADD VALUE ",
8552                                                           qtypname);
8553                         appendStringLiteralAH(q, label, fout);
8554                         appendPQExpBufferStr(q, ";\n\n");
8555                 }
8556         }
8557
8558         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8559
8560         if (dopt->binary_upgrade)
8561                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8562
8563         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8564                                  tyinfo->dobj.name,
8565                                  tyinfo->dobj.namespace->dobj.name,
8566                                  NULL,
8567                                  tyinfo->rolname, false,
8568                                  "TYPE", SECTION_PRE_DATA,
8569                                  q->data, delq->data, NULL,
8570                                  NULL, 0,
8571                                  NULL, NULL);
8572
8573         /* Dump Type Comments and Security Labels */
8574         dumpComment(fout, dopt, labelq->data,
8575                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8576                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8577         dumpSecLabel(fout, dopt, labelq->data,
8578                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8579                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8580
8581         dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8582                         qtypname, NULL, tyinfo->dobj.name,
8583                         tyinfo->dobj.namespace->dobj.name,
8584                         tyinfo->rolname, tyinfo->typacl);
8585
8586         PQclear(res);
8587         destroyPQExpBuffer(q);
8588         destroyPQExpBuffer(delq);
8589         destroyPQExpBuffer(labelq);
8590         destroyPQExpBuffer(query);
8591 }
8592
8593 /*
8594  * dumpRangeType
8595  *        writes out to fout the queries to recreate a user-defined range type
8596  */
8597 static void
8598 dumpRangeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
8599 {
8600         PQExpBuffer q = createPQExpBuffer();
8601         PQExpBuffer delq = createPQExpBuffer();
8602         PQExpBuffer labelq = createPQExpBuffer();
8603         PQExpBuffer query = createPQExpBuffer();
8604         PGresult   *res;
8605         Oid                     collationOid;
8606         char       *qtypname;
8607         char       *procname;
8608
8609         /*
8610          * select appropriate schema to ensure names in CREATE are properly
8611          * qualified
8612          */
8613         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8614
8615         appendPQExpBuffer(query,
8616                         "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
8617                                           "opc.opcname AS opcname, "
8618                                           "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
8619                                           "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
8620                                           "opc.opcdefault, "
8621                                           "CASE WHEN rngcollation = st.typcollation THEN 0 "
8622                                           "     ELSE rngcollation END AS collation, "
8623                                           "rngcanonical, rngsubdiff "
8624                                           "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
8625                                           "     pg_catalog.pg_opclass opc "
8626                                           "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
8627                                           "rngtypid = '%u'",
8628                                           tyinfo->dobj.catId.oid);
8629
8630         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8631
8632         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8633
8634         /*
8635          * DROP must be fully qualified in case same name appears in pg_catalog.
8636          * CASCADE shouldn't be required here as for normal types since the I/O
8637          * functions are generic and do not get dropped.
8638          */
8639         appendPQExpBuffer(delq, "DROP TYPE %s.",
8640                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8641         appendPQExpBuffer(delq, "%s;\n",
8642                                           qtypname);
8643
8644         if (dopt->binary_upgrade)
8645                 binary_upgrade_set_type_oids_by_type_oid(fout,
8646                                                                                                  q, tyinfo->dobj.catId.oid);
8647
8648         appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
8649                                           qtypname);
8650
8651         appendPQExpBuffer(q, "\n    subtype = %s",
8652                                           PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
8653
8654         /* print subtype_opclass only if not default for subtype */
8655         if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
8656         {
8657                 char       *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
8658                 char       *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
8659
8660                 /* always schema-qualify, don't try to be smart */
8661                 appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
8662                                                   fmtId(nspname));
8663                 appendPQExpBufferStr(q, fmtId(opcname));
8664         }
8665
8666         collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
8667         if (OidIsValid(collationOid))
8668         {
8669                 CollInfo   *coll = findCollationByOid(collationOid);
8670
8671                 if (coll)
8672                 {
8673                         /* always schema-qualify, don't try to be smart */
8674                         appendPQExpBuffer(q, ",\n    collation = %s.",
8675                                                           fmtId(coll->dobj.namespace->dobj.name));
8676                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
8677                 }
8678         }
8679
8680         procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
8681         if (strcmp(procname, "-") != 0)
8682                 appendPQExpBuffer(q, ",\n    canonical = %s", procname);
8683
8684         procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
8685         if (strcmp(procname, "-") != 0)
8686                 appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
8687
8688         appendPQExpBufferStr(q, "\n);\n");
8689
8690         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
8691
8692         if (dopt->binary_upgrade)
8693                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
8694
8695         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
8696                                  tyinfo->dobj.name,
8697                                  tyinfo->dobj.namespace->dobj.name,
8698                                  NULL,
8699                                  tyinfo->rolname, false,
8700                                  "TYPE", SECTION_PRE_DATA,
8701                                  q->data, delq->data, NULL,
8702                                  NULL, 0,
8703                                  NULL, NULL);
8704
8705         /* Dump Type Comments and Security Labels */
8706         dumpComment(fout, dopt, labelq->data,
8707                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8708                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8709         dumpSecLabel(fout, dopt, labelq->data,
8710                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
8711                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
8712
8713         dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
8714                         qtypname, NULL, tyinfo->dobj.name,
8715                         tyinfo->dobj.namespace->dobj.name,
8716                         tyinfo->rolname, tyinfo->typacl);
8717
8718         PQclear(res);
8719         destroyPQExpBuffer(q);
8720         destroyPQExpBuffer(delq);
8721         destroyPQExpBuffer(labelq);
8722         destroyPQExpBuffer(query);
8723 }
8724
8725 /*
8726  * dumpBaseType
8727  *        writes out to fout the queries to recreate a user-defined base type
8728  */
8729 static void
8730 dumpBaseType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
8731 {
8732         PQExpBuffer q = createPQExpBuffer();
8733         PQExpBuffer delq = createPQExpBuffer();
8734         PQExpBuffer labelq = createPQExpBuffer();
8735         PQExpBuffer query = createPQExpBuffer();
8736         PGresult   *res;
8737         char       *qtypname;
8738         char       *typlen;
8739         char       *typinput;
8740         char       *typoutput;
8741         char       *typreceive;
8742         char       *typsend;
8743         char       *typmodin;
8744         char       *typmodout;
8745         char       *typanalyze;
8746         Oid                     typreceiveoid;
8747         Oid                     typsendoid;
8748         Oid                     typmodinoid;
8749         Oid                     typmodoutoid;
8750         Oid                     typanalyzeoid;
8751         char       *typcategory;
8752         char       *typispreferred;
8753         char       *typdelim;
8754         char       *typbyval;
8755         char       *typalign;
8756         char       *typstorage;
8757         char       *typcollatable;
8758         char       *typdefault;
8759         bool            typdefault_is_literal = false;
8760
8761         /* Set proper schema search path so regproc references list correctly */
8762         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
8763
8764         /* Fetch type-specific details */
8765         if (fout->remoteVersion >= 90100)
8766         {
8767                 appendPQExpBuffer(query, "SELECT typlen, "
8768                                                   "typinput, typoutput, typreceive, typsend, "
8769                                                   "typmodin, typmodout, typanalyze, "
8770                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8771                                                   "typsend::pg_catalog.oid AS typsendoid, "
8772                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8773                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8774                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8775                                                   "typcategory, typispreferred, "
8776                                                   "typdelim, typbyval, typalign, typstorage, "
8777                                                   "(typcollation <> 0) AS typcollatable, "
8778                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8779                                                   "FROM pg_catalog.pg_type "
8780                                                   "WHERE oid = '%u'::pg_catalog.oid",
8781                                                   tyinfo->dobj.catId.oid);
8782         }
8783         else if (fout->remoteVersion >= 80400)
8784         {
8785                 appendPQExpBuffer(query, "SELECT typlen, "
8786                                                   "typinput, typoutput, typreceive, typsend, "
8787                                                   "typmodin, typmodout, typanalyze, "
8788                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8789                                                   "typsend::pg_catalog.oid AS typsendoid, "
8790                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8791                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8792                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8793                                                   "typcategory, typispreferred, "
8794                                                   "typdelim, typbyval, typalign, typstorage, "
8795                                                   "false AS typcollatable, "
8796                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
8797                                                   "FROM pg_catalog.pg_type "
8798                                                   "WHERE oid = '%u'::pg_catalog.oid",
8799                                                   tyinfo->dobj.catId.oid);
8800         }
8801         else if (fout->remoteVersion >= 80300)
8802         {
8803                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
8804                 appendPQExpBuffer(query, "SELECT typlen, "
8805                                                   "typinput, typoutput, typreceive, typsend, "
8806                                                   "typmodin, typmodout, typanalyze, "
8807                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8808                                                   "typsend::pg_catalog.oid AS typsendoid, "
8809                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
8810                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
8811                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8812                                                   "'U' AS typcategory, false AS typispreferred, "
8813                                                   "typdelim, typbyval, typalign, typstorage, "
8814                                                   "false AS typcollatable, "
8815                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8816                                                   "FROM pg_catalog.pg_type "
8817                                                   "WHERE oid = '%u'::pg_catalog.oid",
8818                                                   tyinfo->dobj.catId.oid);
8819         }
8820         else if (fout->remoteVersion >= 80000)
8821         {
8822                 appendPQExpBuffer(query, "SELECT typlen, "
8823                                                   "typinput, typoutput, typreceive, typsend, "
8824                                                   "'-' AS typmodin, '-' AS typmodout, "
8825                                                   "typanalyze, "
8826                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8827                                                   "typsend::pg_catalog.oid AS typsendoid, "
8828                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8829                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
8830                                                   "'U' AS typcategory, false AS typispreferred, "
8831                                                   "typdelim, typbyval, typalign, typstorage, "
8832                                                   "false AS typcollatable, "
8833                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8834                                                   "FROM pg_catalog.pg_type "
8835                                                   "WHERE oid = '%u'::pg_catalog.oid",
8836                                                   tyinfo->dobj.catId.oid);
8837         }
8838         else if (fout->remoteVersion >= 70400)
8839         {
8840                 appendPQExpBuffer(query, "SELECT typlen, "
8841                                                   "typinput, typoutput, typreceive, typsend, "
8842                                                   "'-' AS typmodin, '-' AS typmodout, "
8843                                                   "'-' AS typanalyze, "
8844                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
8845                                                   "typsend::pg_catalog.oid AS typsendoid, "
8846                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8847                                                   "0 AS typanalyzeoid, "
8848                                                   "'U' AS typcategory, false AS typispreferred, "
8849                                                   "typdelim, typbyval, typalign, typstorage, "
8850                                                   "false AS typcollatable, "
8851                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8852                                                   "FROM pg_catalog.pg_type "
8853                                                   "WHERE oid = '%u'::pg_catalog.oid",
8854                                                   tyinfo->dobj.catId.oid);
8855         }
8856         else if (fout->remoteVersion >= 70300)
8857         {
8858                 appendPQExpBuffer(query, "SELECT typlen, "
8859                                                   "typinput, typoutput, "
8860                                                   "'-' AS typreceive, '-' AS typsend, "
8861                                                   "'-' AS typmodin, '-' AS typmodout, "
8862                                                   "'-' AS typanalyze, "
8863                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8864                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8865                                                   "0 AS typanalyzeoid, "
8866                                                   "'U' AS typcategory, false AS typispreferred, "
8867                                                   "typdelim, typbyval, typalign, typstorage, "
8868                                                   "false AS typcollatable, "
8869                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
8870                                                   "FROM pg_catalog.pg_type "
8871                                                   "WHERE oid = '%u'::pg_catalog.oid",
8872                                                   tyinfo->dobj.catId.oid);
8873         }
8874         else if (fout->remoteVersion >= 70200)
8875         {
8876                 /*
8877                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
8878                  * ignore them because they are not right.
8879                  */
8880                 appendPQExpBuffer(query, "SELECT typlen, "
8881                                                   "typinput, typoutput, "
8882                                                   "'-' AS typreceive, '-' AS typsend, "
8883                                                   "'-' AS typmodin, '-' AS typmodout, "
8884                                                   "'-' AS typanalyze, "
8885                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8886                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8887                                                   "0 AS typanalyzeoid, "
8888                                                   "'U' AS typcategory, false AS typispreferred, "
8889                                                   "typdelim, typbyval, typalign, typstorage, "
8890                                                   "false AS typcollatable, "
8891                                                   "NULL AS typdefaultbin, typdefault "
8892                                                   "FROM pg_type "
8893                                                   "WHERE oid = '%u'::oid",
8894                                                   tyinfo->dobj.catId.oid);
8895         }
8896         else if (fout->remoteVersion >= 70100)
8897         {
8898                 /*
8899                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
8900                  * representation.
8901                  */
8902                 appendPQExpBuffer(query, "SELECT typlen, "
8903                                                   "typinput, typoutput, "
8904                                                   "'-' AS typreceive, '-' AS typsend, "
8905                                                   "'-' AS typmodin, '-' AS typmodout, "
8906                                                   "'-' AS typanalyze, "
8907                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8908                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8909                                                   "0 AS typanalyzeoid, "
8910                                                   "'U' AS typcategory, false AS typispreferred, "
8911                                                   "typdelim, typbyval, typalign, typstorage, "
8912                                                   "false AS typcollatable, "
8913                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8914                                                   "FROM pg_type "
8915                                                   "WHERE oid = '%u'::oid",
8916                                                   tyinfo->dobj.catId.oid);
8917         }
8918         else
8919         {
8920                 appendPQExpBuffer(query, "SELECT typlen, "
8921                                                   "typinput, typoutput, "
8922                                                   "'-' AS typreceive, '-' AS typsend, "
8923                                                   "'-' AS typmodin, '-' AS typmodout, "
8924                                                   "'-' AS typanalyze, "
8925                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
8926                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
8927                                                   "0 AS typanalyzeoid, "
8928                                                   "'U' AS typcategory, false AS typispreferred, "
8929                                                   "typdelim, typbyval, typalign, "
8930                                                   "'p'::char AS typstorage, "
8931                                                   "false AS typcollatable, "
8932                                                   "NULL AS typdefaultbin, NULL AS typdefault "
8933                                                   "FROM pg_type "
8934                                                   "WHERE oid = '%u'::oid",
8935                                                   tyinfo->dobj.catId.oid);
8936         }
8937
8938         res = ExecuteSqlQueryForSingleRow(fout, query->data);
8939
8940         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
8941         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
8942         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
8943         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
8944         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
8945         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
8946         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
8947         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
8948         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
8949         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
8950         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
8951         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
8952         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
8953         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
8954         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
8955         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
8956         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
8957         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
8958         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
8959         typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
8960         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
8961                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
8962         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
8963         {
8964                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
8965                 typdefault_is_literal = true;   /* it needs quotes */
8966         }
8967         else
8968                 typdefault = NULL;
8969
8970         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
8971
8972         /*
8973          * DROP must be fully qualified in case same name appears in pg_catalog.
8974          * The reason we include CASCADE is that the circular dependency between
8975          * the type and its I/O functions makes it impossible to drop the type any
8976          * other way.
8977          */
8978         appendPQExpBuffer(delq, "DROP TYPE %s.",
8979                                           fmtId(tyinfo->dobj.namespace->dobj.name));
8980         appendPQExpBuffer(delq, "%s CASCADE;\n",
8981                                           qtypname);
8982
8983         /* We might already have a shell type, but setting pg_type_oid is harmless */
8984         if (dopt->binary_upgrade)
8985                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
8986                                                                                                  tyinfo->dobj.catId.oid);
8987
8988         appendPQExpBuffer(q,
8989                                           "CREATE TYPE %s (\n"
8990                                           "    INTERNALLENGTH = %s",
8991                                           qtypname,
8992                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
8993
8994         if (fout->remoteVersion >= 70300)
8995         {
8996                 /* regproc result is correctly quoted as of 7.3 */
8997                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
8998                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
8999                 if (OidIsValid(typreceiveoid))
9000                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
9001                 if (OidIsValid(typsendoid))
9002                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
9003                 if (OidIsValid(typmodinoid))
9004                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
9005                 if (OidIsValid(typmodoutoid))
9006                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
9007                 if (OidIsValid(typanalyzeoid))
9008                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
9009         }
9010         else
9011         {
9012                 /* regproc delivers an unquoted name before 7.3 */
9013                 /* cannot combine these because fmtId uses static result area */
9014                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
9015                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
9016                 /* receive/send/typmodin/typmodout/analyze need not be printed */
9017         }
9018
9019         if (strcmp(typcollatable, "t") == 0)
9020                 appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
9021
9022         if (typdefault != NULL)
9023         {
9024                 appendPQExpBufferStr(q, ",\n    DEFAULT = ");
9025                 if (typdefault_is_literal)
9026                         appendStringLiteralAH(q, typdefault, fout);
9027                 else
9028                         appendPQExpBufferStr(q, typdefault);
9029         }
9030
9031         if (OidIsValid(tyinfo->typelem))
9032         {
9033                 char       *elemType;
9034
9035                 /* reselect schema in case changed by function dump */
9036                 selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
9037                 elemType = getFormattedTypeName(fout, tyinfo->typelem, zeroAsOpaque);
9038                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
9039                 free(elemType);
9040         }
9041
9042         if (strcmp(typcategory, "U") != 0)
9043         {
9044                 appendPQExpBufferStr(q, ",\n    CATEGORY = ");
9045                 appendStringLiteralAH(q, typcategory, fout);
9046         }
9047
9048         if (strcmp(typispreferred, "t") == 0)
9049                 appendPQExpBufferStr(q, ",\n    PREFERRED = true");
9050
9051         if (typdelim && strcmp(typdelim, ",") != 0)
9052         {
9053                 appendPQExpBufferStr(q, ",\n    DELIMITER = ");
9054                 appendStringLiteralAH(q, typdelim, fout);
9055         }
9056
9057         if (strcmp(typalign, "c") == 0)
9058                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
9059         else if (strcmp(typalign, "s") == 0)
9060                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
9061         else if (strcmp(typalign, "i") == 0)
9062                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
9063         else if (strcmp(typalign, "d") == 0)
9064                 appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
9065
9066         if (strcmp(typstorage, "p") == 0)
9067                 appendPQExpBufferStr(q, ",\n    STORAGE = plain");
9068         else if (strcmp(typstorage, "e") == 0)
9069                 appendPQExpBufferStr(q, ",\n    STORAGE = external");
9070         else if (strcmp(typstorage, "x") == 0)
9071                 appendPQExpBufferStr(q, ",\n    STORAGE = extended");
9072         else if (strcmp(typstorage, "m") == 0)
9073                 appendPQExpBufferStr(q, ",\n    STORAGE = main");
9074
9075         if (strcmp(typbyval, "t") == 0)
9076                 appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
9077
9078         appendPQExpBufferStr(q, "\n);\n");
9079
9080         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9081
9082         if (dopt->binary_upgrade)
9083                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9084
9085         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9086                                  tyinfo->dobj.name,
9087                                  tyinfo->dobj.namespace->dobj.name,
9088                                  NULL,
9089                                  tyinfo->rolname, false,
9090                                  "TYPE", SECTION_PRE_DATA,
9091                                  q->data, delq->data, NULL,
9092                                  NULL, 0,
9093                                  NULL, NULL);
9094
9095         /* Dump Type Comments and Security Labels */
9096         dumpComment(fout, dopt, labelq->data,
9097                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9098                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9099         dumpSecLabel(fout, dopt, labelq->data,
9100                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9101                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9102
9103         dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9104                         qtypname, NULL, tyinfo->dobj.name,
9105                         tyinfo->dobj.namespace->dobj.name,
9106                         tyinfo->rolname, tyinfo->typacl);
9107
9108         PQclear(res);
9109         destroyPQExpBuffer(q);
9110         destroyPQExpBuffer(delq);
9111         destroyPQExpBuffer(labelq);
9112         destroyPQExpBuffer(query);
9113 }
9114
9115 /*
9116  * dumpDomain
9117  *        writes out to fout the queries to recreate a user-defined domain
9118  */
9119 static void
9120 dumpDomain(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
9121 {
9122         PQExpBuffer q = createPQExpBuffer();
9123         PQExpBuffer delq = createPQExpBuffer();
9124         PQExpBuffer labelq = createPQExpBuffer();
9125         PQExpBuffer query = createPQExpBuffer();
9126         PGresult   *res;
9127         int                     i;
9128         char       *qtypname;
9129         char       *typnotnull;
9130         char       *typdefn;
9131         char       *typdefault;
9132         Oid                     typcollation;
9133         bool            typdefault_is_literal = false;
9134
9135         /* Set proper schema search path so type references list correctly */
9136         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
9137
9138         /* Fetch domain specific details */
9139         if (fout->remoteVersion >= 90100)
9140         {
9141                 /* typcollation is new in 9.1 */
9142                 appendPQExpBuffer(query, "SELECT t.typnotnull, "
9143                         "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
9144                                                   "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
9145                                                   "t.typdefault, "
9146                                                   "CASE WHEN t.typcollation <> u.typcollation "
9147                                                   "THEN t.typcollation ELSE 0 END AS typcollation "
9148                                                   "FROM pg_catalog.pg_type t "
9149                                  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
9150                                                   "WHERE t.oid = '%u'::pg_catalog.oid",
9151                                                   tyinfo->dobj.catId.oid);
9152         }
9153         else
9154         {
9155                 /* We assume here that remoteVersion must be at least 70300 */
9156                 appendPQExpBuffer(query, "SELECT typnotnull, "
9157                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
9158                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
9159                                                   "typdefault, 0 AS typcollation "
9160                                                   "FROM pg_catalog.pg_type "
9161                                                   "WHERE oid = '%u'::pg_catalog.oid",
9162                                                   tyinfo->dobj.catId.oid);
9163         }
9164
9165         res = ExecuteSqlQueryForSingleRow(fout, query->data);
9166
9167         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
9168         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
9169         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
9170                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
9171         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
9172         {
9173                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
9174                 typdefault_is_literal = true;   /* it needs quotes */
9175         }
9176         else
9177                 typdefault = NULL;
9178         typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
9179
9180         if (dopt->binary_upgrade)
9181                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9182                                                                                                  tyinfo->dobj.catId.oid);
9183
9184         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9185
9186         appendPQExpBuffer(q,
9187                                           "CREATE DOMAIN %s AS %s",
9188                                           qtypname,
9189                                           typdefn);
9190
9191         /* Print collation only if different from base type's collation */
9192         if (OidIsValid(typcollation))
9193         {
9194                 CollInfo   *coll;
9195
9196                 coll = findCollationByOid(typcollation);
9197                 if (coll)
9198                 {
9199                         /* always schema-qualify, don't try to be smart */
9200                         appendPQExpBuffer(q, " COLLATE %s.",
9201                                                           fmtId(coll->dobj.namespace->dobj.name));
9202                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
9203                 }
9204         }
9205
9206         if (typnotnull[0] == 't')
9207                 appendPQExpBufferStr(q, " NOT NULL");
9208
9209         if (typdefault != NULL)
9210         {
9211                 appendPQExpBufferStr(q, " DEFAULT ");
9212                 if (typdefault_is_literal)
9213                         appendStringLiteralAH(q, typdefault, fout);
9214                 else
9215                         appendPQExpBufferStr(q, typdefault);
9216         }
9217
9218         PQclear(res);
9219
9220         /*
9221          * Add any CHECK constraints for the domain
9222          */
9223         for (i = 0; i < tyinfo->nDomChecks; i++)
9224         {
9225                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
9226
9227                 if (!domcheck->separate)
9228                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
9229                                                           fmtId(domcheck->dobj.name), domcheck->condef);
9230         }
9231
9232         appendPQExpBufferStr(q, ";\n");
9233
9234         /*
9235          * DROP must be fully qualified in case same name appears in pg_catalog
9236          */
9237         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
9238                                           fmtId(tyinfo->dobj.namespace->dobj.name));
9239         appendPQExpBuffer(delq, "%s;\n",
9240                                           qtypname);
9241
9242         appendPQExpBuffer(labelq, "DOMAIN %s", qtypname);
9243
9244         if (dopt->binary_upgrade)
9245                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9246
9247         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9248                                  tyinfo->dobj.name,
9249                                  tyinfo->dobj.namespace->dobj.name,
9250                                  NULL,
9251                                  tyinfo->rolname, false,
9252                                  "DOMAIN", SECTION_PRE_DATA,
9253                                  q->data, delq->data, NULL,
9254                                  NULL, 0,
9255                                  NULL, NULL);
9256
9257         /* Dump Domain Comments and Security Labels */
9258         dumpComment(fout, dopt, labelq->data,
9259                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9260                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9261         dumpSecLabel(fout, dopt, labelq->data,
9262                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9263                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9264
9265         dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9266                         qtypname, NULL, tyinfo->dobj.name,
9267                         tyinfo->dobj.namespace->dobj.name,
9268                         tyinfo->rolname, tyinfo->typacl);
9269
9270         /* Dump any per-constraint comments */
9271         for (i = 0; i < tyinfo->nDomChecks; i++)
9272         {
9273                 ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
9274                 PQExpBuffer     labelq = createPQExpBuffer();
9275
9276                 appendPQExpBuffer(labelq, "CONSTRAINT %s ",
9277                                                   fmtId(domcheck->dobj.name));
9278                 appendPQExpBuffer(labelq, "ON DOMAIN %s",
9279                                                   fmtId(qtypname));
9280                 dumpComment(fout, dopt, labelq->data,
9281                                         tyinfo->dobj.namespace->dobj.name,
9282                                         tyinfo->rolname,
9283                                         domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
9284                 destroyPQExpBuffer(labelq);
9285         }
9286
9287         destroyPQExpBuffer(q);
9288         destroyPQExpBuffer(delq);
9289         destroyPQExpBuffer(labelq);
9290         destroyPQExpBuffer(query);
9291 }
9292
9293 /*
9294  * dumpCompositeType
9295  *        writes out to fout the queries to recreate a user-defined stand-alone
9296  *        composite type
9297  */
9298 static void
9299 dumpCompositeType(Archive *fout, DumpOptions *dopt, TypeInfo *tyinfo)
9300 {
9301         PQExpBuffer q = createPQExpBuffer();
9302         PQExpBuffer dropped = createPQExpBuffer();
9303         PQExpBuffer delq = createPQExpBuffer();
9304         PQExpBuffer labelq = createPQExpBuffer();
9305         PQExpBuffer query = createPQExpBuffer();
9306         PGresult   *res;
9307         char       *qtypname;
9308         int                     ntups;
9309         int                     i_attname;
9310         int                     i_atttypdefn;
9311         int                     i_attlen;
9312         int                     i_attalign;
9313         int                     i_attisdropped;
9314         int                     i_attcollation;
9315         int                     i;
9316         int                     actual_atts;
9317
9318         /* Set proper schema search path so type references list correctly */
9319         selectSourceSchema(fout, tyinfo->dobj.namespace->dobj.name);
9320
9321         /* Fetch type specific details */
9322         if (fout->remoteVersion >= 90100)
9323         {
9324                 /*
9325                  * attcollation is new in 9.1.  Since we only want to dump COLLATE
9326                  * clauses for attributes whose collation is different from their
9327                  * type's default, we use a CASE here to suppress uninteresting
9328                  * attcollations cheaply.  atttypid will be 0 for dropped columns;
9329                  * collation does not matter for those.
9330                  */
9331                 appendPQExpBuffer(query, "SELECT a.attname, "
9332                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
9333                                                   "a.attlen, a.attalign, a.attisdropped, "
9334                                                   "CASE WHEN a.attcollation <> at.typcollation "
9335                                                   "THEN a.attcollation ELSE 0 END AS attcollation "
9336                                                   "FROM pg_catalog.pg_type ct "
9337                                 "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
9338                                         "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
9339                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
9340                                                   "ORDER BY a.attnum ",
9341                                                   tyinfo->dobj.catId.oid);
9342         }
9343         else
9344         {
9345                 /*
9346                  * We assume here that remoteVersion must be at least 70300.  Since
9347                  * ALTER TYPE could not drop columns until 9.1, attisdropped should
9348                  * always be false.
9349                  */
9350                 appendPQExpBuffer(query, "SELECT a.attname, "
9351                         "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
9352                                                   "a.attlen, a.attalign, a.attisdropped, "
9353                                                   "0 AS attcollation "
9354                                          "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
9355                                                   "WHERE ct.oid = '%u'::pg_catalog.oid "
9356                                                   "AND a.attrelid = ct.typrelid "
9357                                                   "ORDER BY a.attnum ",
9358                                                   tyinfo->dobj.catId.oid);
9359         }
9360
9361         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9362
9363         ntups = PQntuples(res);
9364
9365         i_attname = PQfnumber(res, "attname");
9366         i_atttypdefn = PQfnumber(res, "atttypdefn");
9367         i_attlen = PQfnumber(res, "attlen");
9368         i_attalign = PQfnumber(res, "attalign");
9369         i_attisdropped = PQfnumber(res, "attisdropped");
9370         i_attcollation = PQfnumber(res, "attcollation");
9371
9372         if (dopt->binary_upgrade)
9373         {
9374                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9375                                                                                                  tyinfo->dobj.catId.oid);
9376                 binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
9377         }
9378
9379         qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
9380
9381         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
9382                                           qtypname);
9383
9384         actual_atts = 0;
9385         for (i = 0; i < ntups; i++)
9386         {
9387                 char       *attname;
9388                 char       *atttypdefn;
9389                 char       *attlen;
9390                 char       *attalign;
9391                 bool            attisdropped;
9392                 Oid                     attcollation;
9393
9394                 attname = PQgetvalue(res, i, i_attname);
9395                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
9396                 attlen = PQgetvalue(res, i, i_attlen);
9397                 attalign = PQgetvalue(res, i, i_attalign);
9398                 attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
9399                 attcollation = atooid(PQgetvalue(res, i, i_attcollation));
9400
9401                 if (attisdropped && !dopt->binary_upgrade)
9402                         continue;
9403
9404                 /* Format properly if not first attr */
9405                 if (actual_atts++ > 0)
9406                         appendPQExpBufferChar(q, ',');
9407                 appendPQExpBufferStr(q, "\n\t");
9408
9409                 if (!attisdropped)
9410                 {
9411                         appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
9412
9413                         /* Add collation if not default for the column type */
9414                         if (OidIsValid(attcollation))
9415                         {
9416                                 CollInfo   *coll;
9417
9418                                 coll = findCollationByOid(attcollation);
9419                                 if (coll)
9420                                 {
9421                                         /* always schema-qualify, don't try to be smart */
9422                                         appendPQExpBuffer(q, " COLLATE %s.",
9423                                                                           fmtId(coll->dobj.namespace->dobj.name));
9424                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
9425                                 }
9426                         }
9427                 }
9428                 else
9429                 {
9430                         /*
9431                          * This is a dropped attribute and we're in binary_upgrade mode.
9432                          * Insert a placeholder for it in the CREATE TYPE command, and set
9433                          * length and alignment with direct UPDATE to the catalogs
9434                          * afterwards. See similar code in dumpTableSchema().
9435                          */
9436                         appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
9437
9438                         /* stash separately for insertion after the CREATE TYPE */
9439                         appendPQExpBufferStr(dropped,
9440                                           "\n-- For binary upgrade, recreate dropped column.\n");
9441                         appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
9442                                                           "SET attlen = %s, "
9443                                                           "attalign = '%s', attbyval = false\n"
9444                                                           "WHERE attname = ", attlen, attalign);
9445                         appendStringLiteralAH(dropped, attname, fout);
9446                         appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
9447                         appendStringLiteralAH(dropped, qtypname, fout);
9448                         appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
9449
9450                         appendPQExpBuffer(dropped, "ALTER TYPE %s ",
9451                                                           qtypname);
9452                         appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
9453                                                           fmtId(attname));
9454                 }
9455         }
9456         appendPQExpBufferStr(q, "\n);\n");
9457         appendPQExpBufferStr(q, dropped->data);
9458
9459         /*
9460          * DROP must be fully qualified in case same name appears in pg_catalog
9461          */
9462         appendPQExpBuffer(delq, "DROP TYPE %s.",
9463                                           fmtId(tyinfo->dobj.namespace->dobj.name));
9464         appendPQExpBuffer(delq, "%s;\n",
9465                                           qtypname);
9466
9467         appendPQExpBuffer(labelq, "TYPE %s", qtypname);
9468
9469         if (dopt->binary_upgrade)
9470                 binary_upgrade_extension_member(q, &tyinfo->dobj, labelq->data);
9471
9472         ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
9473                                  tyinfo->dobj.name,
9474                                  tyinfo->dobj.namespace->dobj.name,
9475                                  NULL,
9476                                  tyinfo->rolname, false,
9477                                  "TYPE", SECTION_PRE_DATA,
9478                                  q->data, delq->data, NULL,
9479                                  NULL, 0,
9480                                  NULL, NULL);
9481
9482
9483         /* Dump Type Comments and Security Labels */
9484         dumpComment(fout, dopt, labelq->data,
9485                                 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9486                                 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9487         dumpSecLabel(fout, dopt, labelq->data,
9488                                  tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
9489                                  tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
9490
9491         dumpACL(fout, dopt, tyinfo->dobj.catId, tyinfo->dobj.dumpId, "TYPE",
9492                         qtypname, NULL, tyinfo->dobj.name,
9493                         tyinfo->dobj.namespace->dobj.name,
9494                         tyinfo->rolname, tyinfo->typacl);
9495
9496         PQclear(res);
9497         destroyPQExpBuffer(q);
9498         destroyPQExpBuffer(dropped);
9499         destroyPQExpBuffer(delq);
9500         destroyPQExpBuffer(labelq);
9501         destroyPQExpBuffer(query);
9502
9503         /* Dump any per-column comments */
9504         dumpCompositeTypeColComments(fout, tyinfo);
9505 }
9506
9507 /*
9508  * dumpCompositeTypeColComments
9509  *        writes out to fout the queries to recreate comments on the columns of
9510  *        a user-defined stand-alone composite type
9511  */
9512 static void
9513 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
9514 {
9515         CommentItem *comments;
9516         int                     ncomments;
9517         PGresult   *res;
9518         PQExpBuffer query;
9519         PQExpBuffer target;
9520         Oid                     pgClassOid;
9521         int                     i;
9522         int                     ntups;
9523         int                     i_attname;
9524         int                     i_attnum;
9525
9526         query = createPQExpBuffer();
9527
9528         /* We assume here that remoteVersion must be at least 70300 */
9529         appendPQExpBuffer(query,
9530                                           "SELECT c.tableoid, a.attname, a.attnum "
9531                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
9532                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
9533                                           "  AND NOT a.attisdropped "
9534                                           "ORDER BY a.attnum ",
9535                                           tyinfo->typrelid);
9536
9537         /* Fetch column attnames */
9538         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9539
9540         ntups = PQntuples(res);
9541         if (ntups < 1)
9542         {
9543                 PQclear(res);
9544                 destroyPQExpBuffer(query);
9545                 return;
9546         }
9547
9548         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
9549
9550         /* Search for comments associated with type's pg_class OID */
9551         ncomments = findComments(fout,
9552                                                          pgClassOid,
9553                                                          tyinfo->typrelid,
9554                                                          &comments);
9555
9556         /* If no comments exist, we're done */
9557         if (ncomments <= 0)
9558         {
9559                 PQclear(res);
9560                 destroyPQExpBuffer(query);
9561                 return;
9562         }
9563
9564         /* Build COMMENT ON statements */
9565         target = createPQExpBuffer();
9566
9567         i_attnum = PQfnumber(res, "attnum");
9568         i_attname = PQfnumber(res, "attname");
9569         while (ncomments > 0)
9570         {
9571                 const char *attname;
9572
9573                 attname = NULL;
9574                 for (i = 0; i < ntups; i++)
9575                 {
9576                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
9577                         {
9578                                 attname = PQgetvalue(res, i, i_attname);
9579                                 break;
9580                         }
9581                 }
9582                 if (attname)                    /* just in case we don't find it */
9583                 {
9584                         const char *descr = comments->descr;
9585
9586                         resetPQExpBuffer(target);
9587                         appendPQExpBuffer(target, "COLUMN %s.",
9588                                                           fmtId(tyinfo->dobj.name));
9589                         appendPQExpBufferStr(target, fmtId(attname));
9590
9591                         resetPQExpBuffer(query);
9592                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
9593                         appendStringLiteralAH(query, descr, fout);
9594                         appendPQExpBufferStr(query, ";\n");
9595
9596                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
9597                                                  target->data,
9598                                                  tyinfo->dobj.namespace->dobj.name,
9599                                                  NULL, tyinfo->rolname,
9600                                                  false, "COMMENT", SECTION_NONE,
9601                                                  query->data, "", NULL,
9602                                                  &(tyinfo->dobj.dumpId), 1,
9603                                                  NULL, NULL);
9604                 }
9605
9606                 comments++;
9607                 ncomments--;
9608         }
9609
9610         PQclear(res);
9611         destroyPQExpBuffer(query);
9612         destroyPQExpBuffer(target);
9613 }
9614
9615 /*
9616  * dumpShellType
9617  *        writes out to fout the queries to create a shell type
9618  *
9619  * We dump a shell definition in advance of the I/O functions for the type.
9620  */
9621 static void
9622 dumpShellType(Archive *fout, DumpOptions *dopt, ShellTypeInfo *stinfo)
9623 {
9624         PQExpBuffer q;
9625
9626         /* Skip if not to be dumped */
9627         if (!stinfo->dobj.dump || dopt->dataOnly)
9628                 return;
9629
9630         q = createPQExpBuffer();
9631
9632         /*
9633          * Note the lack of a DROP command for the shell type; any required DROP
9634          * is driven off the base type entry, instead.  This interacts with
9635          * _printTocEntry()'s use of the presence of a DROP command to decide
9636          * whether an entry needs an ALTER OWNER command.  We don't want to alter
9637          * the shell type's owner immediately on creation; that should happen only
9638          * after it's filled in, otherwise the backend complains.
9639          */
9640
9641         if (dopt->binary_upgrade)
9642                 binary_upgrade_set_type_oids_by_type_oid(fout, q,
9643                                                                                    stinfo->baseType->dobj.catId.oid);
9644
9645         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
9646                                           fmtId(stinfo->dobj.name));
9647
9648         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
9649                                  stinfo->dobj.name,
9650                                  stinfo->dobj.namespace->dobj.name,
9651                                  NULL,
9652                                  stinfo->baseType->rolname, false,
9653                                  "SHELL TYPE", SECTION_PRE_DATA,
9654                                  q->data, "", NULL,
9655                                  NULL, 0,
9656                                  NULL, NULL);
9657
9658         destroyPQExpBuffer(q);
9659 }
9660
9661 /*
9662  * Determine whether we want to dump definitions for procedural languages.
9663  * Since the languages themselves don't have schemas, we can't rely on
9664  * the normal schema-based selection mechanism.  We choose to dump them
9665  * whenever neither --schema nor --table was given.  (Before 8.1, we used
9666  * the dump flag of the PL's call handler function, but in 8.1 this will
9667  * probably always be false since call handlers are created in pg_catalog.)
9668  *
9669  * For some backwards compatibility with the older behavior, we forcibly
9670  * dump a PL if its handler function (and validator if any) are in a
9671  * dumpable namespace.  That case is not checked here.
9672  *
9673  * Also, if the PL belongs to an extension, we do not use this heuristic.
9674  * That case isn't checked here either.
9675  */
9676 static bool
9677 shouldDumpProcLangs(DumpOptions *dopt)
9678 {
9679         if (!dopt->include_everything)
9680                 return false;
9681         /* And they're schema not data */
9682         if (dopt->dataOnly)
9683                 return false;
9684         return true;
9685 }
9686
9687 /*
9688  * dumpProcLang
9689  *                writes out to fout the queries to recreate a user-defined
9690  *                procedural language
9691  */
9692 static void
9693 dumpProcLang(Archive *fout, DumpOptions *dopt, ProcLangInfo *plang)
9694 {
9695         PQExpBuffer defqry;
9696         PQExpBuffer delqry;
9697         PQExpBuffer labelq;
9698         bool            useParams;
9699         char       *qlanname;
9700         char       *lanschema;
9701         FuncInfo   *funcInfo;
9702         FuncInfo   *inlineInfo = NULL;
9703         FuncInfo   *validatorInfo = NULL;
9704
9705         /* Skip if not to be dumped */
9706         if (!plang->dobj.dump || dopt->dataOnly)
9707                 return;
9708
9709         /*
9710          * Try to find the support function(s).  It is not an error if we don't
9711          * find them --- if the functions are in the pg_catalog schema, as is
9712          * standard in 8.1 and up, then we won't have loaded them. (In this case
9713          * we will emit a parameterless CREATE LANGUAGE command, which will
9714          * require PL template knowledge in the backend to reload.)
9715          */
9716
9717         funcInfo = findFuncByOid(plang->lanplcallfoid);
9718         if (funcInfo != NULL && !funcInfo->dobj.dump)
9719                 funcInfo = NULL;                /* treat not-dumped same as not-found */
9720
9721         if (OidIsValid(plang->laninline))
9722         {
9723                 inlineInfo = findFuncByOid(plang->laninline);
9724                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
9725                         inlineInfo = NULL;
9726         }
9727
9728         if (OidIsValid(plang->lanvalidator))
9729         {
9730                 validatorInfo = findFuncByOid(plang->lanvalidator);
9731                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
9732                         validatorInfo = NULL;
9733         }
9734
9735         /*
9736          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
9737          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
9738          * dump it.
9739          *
9740          * However, for a language that belongs to an extension, we must not use
9741          * the shouldDumpProcLangs heuristic, but just dump the language iff we're
9742          * told to (via dobj.dump).  Generally the support functions will belong
9743          * to the same extension and so have the same dump flags ... if they
9744          * don't, this might not work terribly nicely.
9745          */
9746         useParams = (funcInfo != NULL &&
9747                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
9748                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
9749
9750         if (!plang->dobj.ext_member)
9751         {
9752                 if (!useParams && !shouldDumpProcLangs(dopt))
9753                         return;
9754         }
9755
9756         defqry = createPQExpBuffer();
9757         delqry = createPQExpBuffer();
9758         labelq = createPQExpBuffer();
9759
9760         qlanname = pg_strdup(fmtId(plang->dobj.name));
9761
9762         /*
9763          * If dumping a HANDLER clause, treat the language as being in the handler
9764          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
9765          * it doesn't really have a schema.
9766          */
9767         if (useParams)
9768                 lanschema = funcInfo->dobj.namespace->dobj.name;
9769         else
9770                 lanschema = NULL;
9771
9772         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
9773                                           qlanname);
9774
9775         if (useParams)
9776         {
9777                 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
9778                                                   plang->lanpltrusted ? "TRUSTED " : "",
9779                                                   qlanname);
9780                 appendPQExpBuffer(defqry, " HANDLER %s",
9781                                                   fmtId(funcInfo->dobj.name));
9782                 if (OidIsValid(plang->laninline))
9783                 {
9784                         appendPQExpBufferStr(defqry, " INLINE ");
9785                         /* Cope with possibility that inline is in different schema */
9786                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
9787                                 appendPQExpBuffer(defqry, "%s.",
9788                                                            fmtId(inlineInfo->dobj.namespace->dobj.name));
9789                         appendPQExpBufferStr(defqry, fmtId(inlineInfo->dobj.name));
9790                 }
9791                 if (OidIsValid(plang->lanvalidator))
9792                 {
9793                         appendPQExpBufferStr(defqry, " VALIDATOR ");
9794                         /* Cope with possibility that validator is in different schema */
9795                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
9796                                 appendPQExpBuffer(defqry, "%s.",
9797                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
9798                         appendPQExpBufferStr(defqry, fmtId(validatorInfo->dobj.name));
9799                 }
9800         }
9801         else
9802         {
9803                 /*
9804                  * If not dumping parameters, then use CREATE OR REPLACE so that the
9805                  * command will not fail if the language is preinstalled in the target
9806                  * database.  We restrict the use of REPLACE to this case so as to
9807                  * eliminate the risk of replacing a language with incompatible
9808                  * parameter settings: this command will only succeed at all if there
9809                  * is a pg_pltemplate entry, and if there is one, the existing entry
9810                  * must match it too.
9811                  */
9812                 appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
9813                                                   qlanname);
9814         }
9815         appendPQExpBufferStr(defqry, ";\n");
9816
9817         appendPQExpBuffer(labelq, "LANGUAGE %s", qlanname);
9818
9819         if (dopt->binary_upgrade)
9820                 binary_upgrade_extension_member(defqry, &plang->dobj, labelq->data);
9821
9822         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
9823                                  plang->dobj.name,
9824                                  lanschema, NULL, plang->lanowner,
9825                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
9826                                  defqry->data, delqry->data, NULL,
9827                                  NULL, 0,
9828                                  NULL, NULL);
9829
9830         /* Dump Proc Lang Comments and Security Labels */
9831         dumpComment(fout, dopt, labelq->data,
9832                                 NULL, "",
9833                                 plang->dobj.catId, 0, plang->dobj.dumpId);
9834         dumpSecLabel(fout, dopt, labelq->data,
9835                                  NULL, "",
9836                                  plang->dobj.catId, 0, plang->dobj.dumpId);
9837
9838         if (plang->lanpltrusted)
9839                 dumpACL(fout, dopt, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
9840                                 qlanname, NULL, plang->dobj.name,
9841                                 lanschema,
9842                                 plang->lanowner, plang->lanacl);
9843
9844         free(qlanname);
9845
9846         destroyPQExpBuffer(defqry);
9847         destroyPQExpBuffer(delqry);
9848         destroyPQExpBuffer(labelq);
9849 }
9850
9851 /*
9852  * format_function_arguments: generate function name and argument list
9853  *
9854  * This is used when we can rely on pg_get_function_arguments to format
9855  * the argument list.  Note, however, that pg_get_function_arguments
9856  * does not special-case zero-argument aggregates.
9857  */
9858 static char *
9859 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
9860 {
9861         PQExpBufferData fn;
9862
9863         initPQExpBuffer(&fn);
9864         appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
9865         if (is_agg && finfo->nargs == 0)
9866                 appendPQExpBufferStr(&fn, "(*)");
9867         else
9868                 appendPQExpBuffer(&fn, "(%s)", funcargs);
9869         return fn.data;
9870 }
9871
9872 /*
9873  * format_function_arguments_old: generate function name and argument list
9874  *
9875  * The argument type names are qualified if needed.  The function name
9876  * is never qualified.
9877  *
9878  * This is used only with pre-8.4 servers, so we aren't expecting to see
9879  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
9880  *
9881  * Any or all of allargtypes, argmodes, argnames may be NULL.
9882  */
9883 static char *
9884 format_function_arguments_old(Archive *fout,
9885                                                           FuncInfo *finfo, int nallargs,
9886                                                           char **allargtypes,
9887                                                           char **argmodes,
9888                                                           char **argnames)
9889 {
9890         PQExpBufferData fn;
9891         int                     j;
9892
9893         initPQExpBuffer(&fn);
9894         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9895         for (j = 0; j < nallargs; j++)
9896         {
9897                 Oid                     typid;
9898                 char       *typname;
9899                 const char *argmode;
9900                 const char *argname;
9901
9902                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
9903                 typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
9904
9905                 if (argmodes)
9906                 {
9907                         switch (argmodes[j][0])
9908                         {
9909                                 case PROARGMODE_IN:
9910                                         argmode = "";
9911                                         break;
9912                                 case PROARGMODE_OUT:
9913                                         argmode = "OUT ";
9914                                         break;
9915                                 case PROARGMODE_INOUT:
9916                                         argmode = "INOUT ";
9917                                         break;
9918                                 default:
9919                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
9920                                         argmode = "";
9921                                         break;
9922                         }
9923                 }
9924                 else
9925                         argmode = "";
9926
9927                 argname = argnames ? argnames[j] : (char *) NULL;
9928                 if (argname && argname[0] == '\0')
9929                         argname = NULL;
9930
9931                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
9932                                                   (j > 0) ? ", " : "",
9933                                                   argmode,
9934                                                   argname ? fmtId(argname) : "",
9935                                                   argname ? " " : "",
9936                                                   typname);
9937                 free(typname);
9938         }
9939         appendPQExpBufferChar(&fn, ')');
9940         return fn.data;
9941 }
9942
9943 /*
9944  * format_function_signature: generate function name and argument list
9945  *
9946  * This is like format_function_arguments_old except that only a minimal
9947  * list of input argument types is generated; this is sufficient to
9948  * reference the function, but not to define it.
9949  *
9950  * If honor_quotes is false then the function name is never quoted.
9951  * This is appropriate for use in TOC tags, but not in SQL commands.
9952  */
9953 static char *
9954 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
9955 {
9956         PQExpBufferData fn;
9957         int                     j;
9958
9959         initPQExpBuffer(&fn);
9960         if (honor_quotes)
9961                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
9962         else
9963                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
9964         for (j = 0; j < finfo->nargs; j++)
9965         {
9966                 char       *typname;
9967
9968                 if (j > 0)
9969                         appendPQExpBufferStr(&fn, ", ");
9970
9971                 typname = getFormattedTypeName(fout, finfo->argtypes[j],
9972                                                                            zeroAsOpaque);
9973                 appendPQExpBufferStr(&fn, typname);
9974                 free(typname);
9975         }
9976         appendPQExpBufferChar(&fn, ')');
9977         return fn.data;
9978 }
9979
9980
9981 /*
9982  * dumpFunc:
9983  *        dump out one function
9984  */
9985 static void
9986 dumpFunc(Archive *fout, DumpOptions *dopt, FuncInfo *finfo)
9987 {
9988         PQExpBuffer query;
9989         PQExpBuffer q;
9990         PQExpBuffer delqry;
9991         PQExpBuffer labelq;
9992         PQExpBuffer asPart;
9993         PGresult   *res;
9994         char       *funcsig;            /* identity signature */
9995         char       *funcfullsig = NULL;         /* full signature */
9996         char       *funcsig_tag;
9997         char       *proretset;
9998         char       *prosrc;
9999         char       *probin;
10000         char       *funcargs;
10001         char       *funciargs;
10002         char       *funcresult;
10003         char       *proallargtypes;
10004         char       *proargmodes;
10005         char       *proargnames;
10006         char       *proiswindow;
10007         char       *provolatile;
10008         char       *proisstrict;
10009         char       *prosecdef;
10010         char       *proleakproof;
10011         char       *proconfig;
10012         char       *procost;
10013         char       *prorows;
10014         char       *lanname;
10015         char       *rettypename;
10016         int                     nallargs;
10017         char      **allargtypes = NULL;
10018         char      **argmodes = NULL;
10019         char      **argnames = NULL;
10020         char      **configitems = NULL;
10021         int                     nconfigitems = 0;
10022         int                     i;
10023
10024         /* Skip if not to be dumped */
10025         if (!finfo->dobj.dump || dopt->dataOnly)
10026                 return;
10027
10028         query = createPQExpBuffer();
10029         q = createPQExpBuffer();
10030         delqry = createPQExpBuffer();
10031         labelq = createPQExpBuffer();
10032         asPart = createPQExpBuffer();
10033
10034         /* Set proper schema search path so type references list correctly */
10035         selectSourceSchema(fout, finfo->dobj.namespace->dobj.name);
10036
10037         /* Fetch function-specific details */
10038         if (fout->remoteVersion >= 90200)
10039         {
10040                 /*
10041                  * proleakproof was added at v9.2
10042                  */
10043                 appendPQExpBuffer(query,
10044                                                   "SELECT proretset, prosrc, probin, "
10045                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
10046                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
10047                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
10048                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
10049                                                   "proleakproof, proconfig, procost, prorows, "
10050                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10051                                                   "FROM pg_catalog.pg_proc "
10052                                                   "WHERE oid = '%u'::pg_catalog.oid",
10053                                                   finfo->dobj.catId.oid);
10054         }
10055         else if (fout->remoteVersion >= 80400)
10056         {
10057                 /*
10058                  * In 8.4 and up we rely on pg_get_function_arguments and
10059                  * pg_get_function_result instead of examining proallargtypes etc.
10060                  */
10061                 appendPQExpBuffer(query,
10062                                                   "SELECT proretset, prosrc, probin, "
10063                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
10064                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
10065                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
10066                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
10067                                                   "false AS proleakproof, "
10068                                                   " proconfig, procost, prorows, "
10069                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10070                                                   "FROM pg_catalog.pg_proc "
10071                                                   "WHERE oid = '%u'::pg_catalog.oid",
10072                                                   finfo->dobj.catId.oid);
10073         }
10074         else if (fout->remoteVersion >= 80300)
10075         {
10076                 appendPQExpBuffer(query,
10077                                                   "SELECT proretset, prosrc, probin, "
10078                                                   "proallargtypes, proargmodes, proargnames, "
10079                                                   "false AS proiswindow, "
10080                                                   "provolatile, proisstrict, prosecdef, "
10081                                                   "false AS proleakproof, "
10082                                                   "proconfig, procost, prorows, "
10083                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10084                                                   "FROM pg_catalog.pg_proc "
10085                                                   "WHERE oid = '%u'::pg_catalog.oid",
10086                                                   finfo->dobj.catId.oid);
10087         }
10088         else if (fout->remoteVersion >= 80100)
10089         {
10090                 appendPQExpBuffer(query,
10091                                                   "SELECT proretset, prosrc, probin, "
10092                                                   "proallargtypes, proargmodes, proargnames, "
10093                                                   "false AS proiswindow, "
10094                                                   "provolatile, proisstrict, prosecdef, "
10095                                                   "false AS proleakproof, "
10096                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
10097                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10098                                                   "FROM pg_catalog.pg_proc "
10099                                                   "WHERE oid = '%u'::pg_catalog.oid",
10100                                                   finfo->dobj.catId.oid);
10101         }
10102         else if (fout->remoteVersion >= 80000)
10103         {
10104                 appendPQExpBuffer(query,
10105                                                   "SELECT proretset, prosrc, probin, "
10106                                                   "null AS proallargtypes, "
10107                                                   "null AS proargmodes, "
10108                                                   "proargnames, "
10109                                                   "false AS proiswindow, "
10110                                                   "provolatile, proisstrict, prosecdef, "
10111                                                   "false AS proleakproof, "
10112                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
10113                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10114                                                   "FROM pg_catalog.pg_proc "
10115                                                   "WHERE oid = '%u'::pg_catalog.oid",
10116                                                   finfo->dobj.catId.oid);
10117         }
10118         else if (fout->remoteVersion >= 70300)
10119         {
10120                 appendPQExpBuffer(query,
10121                                                   "SELECT proretset, prosrc, probin, "
10122                                                   "null AS proallargtypes, "
10123                                                   "null AS proargmodes, "
10124                                                   "null AS proargnames, "
10125                                                   "false AS proiswindow, "
10126                                                   "provolatile, proisstrict, prosecdef, "
10127                                                   "false AS proleakproof, "
10128                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
10129                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
10130                                                   "FROM pg_catalog.pg_proc "
10131                                                   "WHERE oid = '%u'::pg_catalog.oid",
10132                                                   finfo->dobj.catId.oid);
10133         }
10134         else if (fout->remoteVersion >= 70100)
10135         {
10136                 appendPQExpBuffer(query,
10137                                                   "SELECT proretset, prosrc, probin, "
10138                                                   "null AS proallargtypes, "
10139                                                   "null AS proargmodes, "
10140                                                   "null AS proargnames, "
10141                                                   "false AS proiswindow, "
10142                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
10143                                                   "proisstrict, "
10144                                                   "false AS prosecdef, "
10145                                                   "false AS proleakproof, "
10146                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
10147                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
10148                                                   "FROM pg_proc "
10149                                                   "WHERE oid = '%u'::oid",
10150                                                   finfo->dobj.catId.oid);
10151         }
10152         else
10153         {
10154                 appendPQExpBuffer(query,
10155                                                   "SELECT proretset, prosrc, probin, "
10156                                                   "null AS proallargtypes, "
10157                                                   "null AS proargmodes, "
10158                                                   "null AS proargnames, "
10159                                                   "false AS proiswindow, "
10160                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
10161                                                   "false AS proisstrict, "
10162                                                   "false AS prosecdef, "
10163                                                   "false AS proleakproof, "
10164                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
10165                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
10166                                                   "FROM pg_proc "
10167                                                   "WHERE oid = '%u'::oid",
10168                                                   finfo->dobj.catId.oid);
10169         }
10170
10171         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10172
10173         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
10174         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
10175         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
10176         if (fout->remoteVersion >= 80400)
10177         {
10178                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
10179                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
10180                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
10181                 proallargtypes = proargmodes = proargnames = NULL;
10182         }
10183         else
10184         {
10185                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
10186                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
10187                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
10188                 funcargs = funciargs = funcresult = NULL;
10189         }
10190         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
10191         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
10192         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
10193         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
10194         proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
10195         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
10196         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
10197         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
10198         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
10199
10200         /*
10201          * See backend/commands/functioncmds.c for details of how the 'AS' clause
10202          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
10203          * versions would set it to "-".  There are no known cases in which prosrc
10204          * is unused, so the tests below for "-" are probably useless.
10205          */
10206         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
10207         {
10208                 appendPQExpBufferStr(asPart, "AS ");
10209                 appendStringLiteralAH(asPart, probin, fout);
10210                 if (strcmp(prosrc, "-") != 0)
10211                 {
10212                         appendPQExpBufferStr(asPart, ", ");
10213
10214                         /*
10215                          * where we have bin, use dollar quoting if allowed and src
10216                          * contains quote or backslash; else use regular quoting.
10217                          */
10218                         if (dopt->disable_dollar_quoting ||
10219                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
10220                                 appendStringLiteralAH(asPart, prosrc, fout);
10221                         else
10222                                 appendStringLiteralDQ(asPart, prosrc, NULL);
10223                 }
10224         }
10225         else
10226         {
10227                 if (strcmp(prosrc, "-") != 0)
10228                 {
10229                         appendPQExpBufferStr(asPart, "AS ");
10230                         /* with no bin, dollar quote src unconditionally if allowed */
10231                         if (dopt->disable_dollar_quoting)
10232                                 appendStringLiteralAH(asPart, prosrc, fout);
10233                         else
10234                                 appendStringLiteralDQ(asPart, prosrc, NULL);
10235                 }
10236         }
10237
10238         nallargs = finfo->nargs;        /* unless we learn different from allargs */
10239
10240         if (proallargtypes && *proallargtypes)
10241         {
10242                 int                     nitems = 0;
10243
10244                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
10245                         nitems < finfo->nargs)
10246                 {
10247                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
10248                         if (allargtypes)
10249                                 free(allargtypes);
10250                         allargtypes = NULL;
10251                 }
10252                 else
10253                         nallargs = nitems;
10254         }
10255
10256         if (proargmodes && *proargmodes)
10257         {
10258                 int                     nitems = 0;
10259
10260                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
10261                         nitems != nallargs)
10262                 {
10263                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
10264                         if (argmodes)
10265                                 free(argmodes);
10266                         argmodes = NULL;
10267                 }
10268         }
10269
10270         if (proargnames && *proargnames)
10271         {
10272                 int                     nitems = 0;
10273
10274                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
10275                         nitems != nallargs)
10276                 {
10277                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
10278                         if (argnames)
10279                                 free(argnames);
10280                         argnames = NULL;
10281                 }
10282         }
10283
10284         if (proconfig && *proconfig)
10285         {
10286                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
10287                 {
10288                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
10289                         if (configitems)
10290                                 free(configitems);
10291                         configitems = NULL;
10292                         nconfigitems = 0;
10293                 }
10294         }
10295
10296         if (funcargs)
10297         {
10298                 /* 8.4 or later; we rely on server-side code for most of the work */
10299                 funcfullsig = format_function_arguments(finfo, funcargs, false);
10300                 funcsig = format_function_arguments(finfo, funciargs, false);
10301         }
10302         else
10303                 /* pre-8.4, do it ourselves */
10304                 funcsig = format_function_arguments_old(fout,
10305                                                                                                 finfo, nallargs, allargtypes,
10306                                                                                                 argmodes, argnames);
10307
10308         funcsig_tag = format_function_signature(fout, finfo, false);
10309
10310         /*
10311          * DROP must be fully qualified in case same name appears in pg_catalog
10312          */
10313         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
10314                                           fmtId(finfo->dobj.namespace->dobj.name),
10315                                           funcsig);
10316
10317         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig ? funcfullsig :
10318                                           funcsig);
10319         if (funcresult)
10320                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
10321         else
10322         {
10323                 rettypename = getFormattedTypeName(fout, finfo->prorettype,
10324                                                                                    zeroAsOpaque);
10325                 appendPQExpBuffer(q, "RETURNS %s%s",
10326                                                   (proretset[0] == 't') ? "SETOF " : "",
10327                                                   rettypename);
10328                 free(rettypename);
10329         }
10330
10331         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
10332
10333         if (proiswindow[0] == 't')
10334                 appendPQExpBufferStr(q, " WINDOW");
10335
10336         if (provolatile[0] != PROVOLATILE_VOLATILE)
10337         {
10338                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
10339                         appendPQExpBufferStr(q, " IMMUTABLE");
10340                 else if (provolatile[0] == PROVOLATILE_STABLE)
10341                         appendPQExpBufferStr(q, " STABLE");
10342                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
10343                         exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
10344                                                   finfo->dobj.name);
10345         }
10346
10347         if (proisstrict[0] == 't')
10348                 appendPQExpBufferStr(q, " STRICT");
10349
10350         if (prosecdef[0] == 't')
10351                 appendPQExpBufferStr(q, " SECURITY DEFINER");
10352
10353         if (proleakproof[0] == 't')
10354                 appendPQExpBufferStr(q, " LEAKPROOF");
10355
10356         /*
10357          * COST and ROWS are emitted only if present and not default, so as not to
10358          * break backwards-compatibility of the dump without need.  Keep this code
10359          * in sync with the defaults in functioncmds.c.
10360          */
10361         if (strcmp(procost, "0") != 0)
10362         {
10363                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
10364                 {
10365                         /* default cost is 1 */
10366                         if (strcmp(procost, "1") != 0)
10367                                 appendPQExpBuffer(q, " COST %s", procost);
10368                 }
10369                 else
10370                 {
10371                         /* default cost is 100 */
10372                         if (strcmp(procost, "100") != 0)
10373                                 appendPQExpBuffer(q, " COST %s", procost);
10374                 }
10375         }
10376         if (proretset[0] == 't' &&
10377                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
10378                 appendPQExpBuffer(q, " ROWS %s", prorows);
10379
10380         for (i = 0; i < nconfigitems; i++)
10381         {
10382                 /* we feel free to scribble on configitems[] here */
10383                 char       *configitem = configitems[i];
10384                 char       *pos;
10385
10386                 pos = strchr(configitem, '=');
10387                 if (pos == NULL)
10388                         continue;
10389                 *pos++ = '\0';
10390                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
10391
10392                 /*
10393                  * Some GUC variable names are 'LIST' type and hence must not be
10394                  * quoted.
10395                  */
10396                 if (pg_strcasecmp(configitem, "DateStyle") == 0
10397                         || pg_strcasecmp(configitem, "search_path") == 0)
10398                         appendPQExpBufferStr(q, pos);
10399                 else
10400                         appendStringLiteralAH(q, pos, fout);
10401         }
10402
10403         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
10404
10405         appendPQExpBuffer(labelq, "FUNCTION %s", funcsig);
10406
10407         if (dopt->binary_upgrade)
10408                 binary_upgrade_extension_member(q, &finfo->dobj, labelq->data);
10409
10410         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
10411                                  funcsig_tag,
10412                                  finfo->dobj.namespace->dobj.name,
10413                                  NULL,
10414                                  finfo->rolname, false,
10415                                  "FUNCTION", SECTION_PRE_DATA,
10416                                  q->data, delqry->data, NULL,
10417                                  NULL, 0,
10418                                  NULL, NULL);
10419
10420         /* Dump Function Comments and Security Labels */
10421         dumpComment(fout, dopt, labelq->data,
10422                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
10423                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
10424         dumpSecLabel(fout, dopt, labelq->data,
10425                                  finfo->dobj.namespace->dobj.name, finfo->rolname,
10426                                  finfo->dobj.catId, 0, finfo->dobj.dumpId);
10427
10428         dumpACL(fout, dopt, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
10429                         funcsig, NULL, funcsig_tag,
10430                         finfo->dobj.namespace->dobj.name,
10431                         finfo->rolname, finfo->proacl);
10432
10433         PQclear(res);
10434
10435         destroyPQExpBuffer(query);
10436         destroyPQExpBuffer(q);
10437         destroyPQExpBuffer(delqry);
10438         destroyPQExpBuffer(labelq);
10439         destroyPQExpBuffer(asPart);
10440         free(funcsig);
10441         if (funcfullsig)
10442                 free(funcfullsig);
10443         free(funcsig_tag);
10444         if (allargtypes)
10445                 free(allargtypes);
10446         if (argmodes)
10447                 free(argmodes);
10448         if (argnames)
10449                 free(argnames);
10450         if (configitems)
10451                 free(configitems);
10452 }
10453
10454
10455 /*
10456  * Dump a user-defined cast
10457  */
10458 static void
10459 dumpCast(Archive *fout, DumpOptions *dopt, CastInfo *cast)
10460 {
10461         PQExpBuffer defqry;
10462         PQExpBuffer delqry;
10463         PQExpBuffer labelq;
10464         FuncInfo   *funcInfo = NULL;
10465
10466         /* Skip if not to be dumped */
10467         if (!cast->dobj.dump || dopt->dataOnly)
10468                 return;
10469
10470         /* Cannot dump if we don't have the cast function's info */
10471         if (OidIsValid(cast->castfunc))
10472         {
10473                 funcInfo = findFuncByOid(cast->castfunc);
10474                 if (funcInfo == NULL)
10475                         return;
10476         }
10477
10478         /*
10479          * As per discussion we dump casts if one or more of the underlying
10480          * objects (the conversion function and the two data types) are not
10481          * builtin AND if all of the non-builtin objects are included in the dump.
10482          * Builtin meaning, the namespace name does not start with "pg_".
10483          *
10484          * However, for a cast that belongs to an extension, we must not use this
10485          * heuristic, but just dump the cast iff we're told to (via dobj.dump).
10486          */
10487         if (!cast->dobj.ext_member)
10488         {
10489                 TypeInfo   *sourceInfo = findTypeByOid(cast->castsource);
10490                 TypeInfo   *targetInfo = findTypeByOid(cast->casttarget);
10491
10492                 if (sourceInfo == NULL || targetInfo == NULL)
10493                         return;
10494
10495                 /*
10496                  * Skip this cast if all objects are from pg_
10497                  */
10498                 if ((funcInfo == NULL ||
10499                          strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
10500                         strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
10501                         strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
10502                         return;
10503
10504                 /*
10505                  * Skip cast if function isn't from pg_ and is not to be dumped.
10506                  */
10507                 if (funcInfo &&
10508                         strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10509                         !funcInfo->dobj.dump)
10510                         return;
10511
10512                 /*
10513                  * Same for the source type
10514                  */
10515                 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10516                         !sourceInfo->dobj.dump)
10517                         return;
10518
10519                 /*
10520                  * and the target type.
10521                  */
10522                 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
10523                         !targetInfo->dobj.dump)
10524                         return;
10525         }
10526
10527         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
10528         selectSourceSchema(fout, "pg_catalog");
10529
10530         defqry = createPQExpBuffer();
10531         delqry = createPQExpBuffer();
10532         labelq = createPQExpBuffer();
10533
10534         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
10535                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10536                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10537
10538         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
10539                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10540                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10541
10542         switch (cast->castmethod)
10543         {
10544                 case COERCION_METHOD_BINARY:
10545                         appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
10546                         break;
10547                 case COERCION_METHOD_INOUT:
10548                         appendPQExpBufferStr(defqry, "WITH INOUT");
10549                         break;
10550                 case COERCION_METHOD_FUNCTION:
10551                         if (funcInfo)
10552                         {
10553                                 char       *fsig = format_function_signature(fout, funcInfo, true);
10554
10555                                 /*
10556                                  * Always qualify the function name, in case it is not in
10557                                  * pg_catalog schema (format_function_signature won't qualify
10558                                  * it).
10559                                  */
10560                                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
10561                                                    fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
10562                                 free(fsig);
10563                         }
10564                         else
10565                                 write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
10566                         break;
10567                 default:
10568                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
10569         }
10570
10571         if (cast->castcontext == 'a')
10572                 appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
10573         else if (cast->castcontext == 'i')
10574                 appendPQExpBufferStr(defqry, " AS IMPLICIT");
10575         appendPQExpBufferStr(defqry, ";\n");
10576
10577         appendPQExpBuffer(labelq, "CAST (%s AS %s)",
10578                                         getFormattedTypeName(fout, cast->castsource, zeroAsNone),
10579                                    getFormattedTypeName(fout, cast->casttarget, zeroAsNone));
10580
10581         if (dopt->binary_upgrade)
10582                 binary_upgrade_extension_member(defqry, &cast->dobj, labelq->data);
10583
10584         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
10585                                  labelq->data,
10586                                  "pg_catalog", NULL, "",
10587                                  false, "CAST", SECTION_PRE_DATA,
10588                                  defqry->data, delqry->data, NULL,
10589                                  NULL, 0,
10590                                  NULL, NULL);
10591
10592         /* Dump Cast Comments */
10593         dumpComment(fout, dopt, labelq->data,
10594                                 NULL, "",
10595                                 cast->dobj.catId, 0, cast->dobj.dumpId);
10596
10597         destroyPQExpBuffer(defqry);
10598         destroyPQExpBuffer(delqry);
10599         destroyPQExpBuffer(labelq);
10600 }
10601
10602 /*
10603  * dumpOpr
10604  *        write out a single operator definition
10605  */
10606 static void
10607 dumpOpr(Archive *fout, DumpOptions *dopt, OprInfo *oprinfo)
10608 {
10609         PQExpBuffer query;
10610         PQExpBuffer q;
10611         PQExpBuffer delq;
10612         PQExpBuffer labelq;
10613         PQExpBuffer oprid;
10614         PQExpBuffer details;
10615         const char *name;
10616         PGresult   *res;
10617         int                     i_oprkind;
10618         int                     i_oprcode;
10619         int                     i_oprleft;
10620         int                     i_oprright;
10621         int                     i_oprcom;
10622         int                     i_oprnegate;
10623         int                     i_oprrest;
10624         int                     i_oprjoin;
10625         int                     i_oprcanmerge;
10626         int                     i_oprcanhash;
10627         char       *oprkind;
10628         char       *oprcode;
10629         char       *oprleft;
10630         char       *oprright;
10631         char       *oprcom;
10632         char       *oprnegate;
10633         char       *oprrest;
10634         char       *oprjoin;
10635         char       *oprcanmerge;
10636         char       *oprcanhash;
10637         char       *oprregproc;
10638         char       *oprref;
10639
10640         /* Skip if not to be dumped */
10641         if (!oprinfo->dobj.dump || dopt->dataOnly)
10642                 return;
10643
10644         /*
10645          * some operators are invalid because they were the result of user
10646          * defining operators before commutators exist
10647          */
10648         if (!OidIsValid(oprinfo->oprcode))
10649                 return;
10650
10651         query = createPQExpBuffer();
10652         q = createPQExpBuffer();
10653         delq = createPQExpBuffer();
10654         labelq = createPQExpBuffer();
10655         oprid = createPQExpBuffer();
10656         details = createPQExpBuffer();
10657
10658         /* Make sure we are in proper schema so regoperator works correctly */
10659         selectSourceSchema(fout, oprinfo->dobj.namespace->dobj.name);
10660
10661         if (fout->remoteVersion >= 80300)
10662         {
10663                 appendPQExpBuffer(query, "SELECT oprkind, "
10664                                                   "oprcode::pg_catalog.regprocedure, "
10665                                                   "oprleft::pg_catalog.regtype, "
10666                                                   "oprright::pg_catalog.regtype, "
10667                                                   "oprcom::pg_catalog.regoperator, "
10668                                                   "oprnegate::pg_catalog.regoperator, "
10669                                                   "oprrest::pg_catalog.regprocedure, "
10670                                                   "oprjoin::pg_catalog.regprocedure, "
10671                                                   "oprcanmerge, oprcanhash "
10672                                                   "FROM pg_catalog.pg_operator "
10673                                                   "WHERE oid = '%u'::pg_catalog.oid",
10674                                                   oprinfo->dobj.catId.oid);
10675         }
10676         else if (fout->remoteVersion >= 70300)
10677         {
10678                 appendPQExpBuffer(query, "SELECT oprkind, "
10679                                                   "oprcode::pg_catalog.regprocedure, "
10680                                                   "oprleft::pg_catalog.regtype, "
10681                                                   "oprright::pg_catalog.regtype, "
10682                                                   "oprcom::pg_catalog.regoperator, "
10683                                                   "oprnegate::pg_catalog.regoperator, "
10684                                                   "oprrest::pg_catalog.regprocedure, "
10685                                                   "oprjoin::pg_catalog.regprocedure, "
10686                                                   "(oprlsortop != 0) AS oprcanmerge, "
10687                                                   "oprcanhash "
10688                                                   "FROM pg_catalog.pg_operator "
10689                                                   "WHERE oid = '%u'::pg_catalog.oid",
10690                                                   oprinfo->dobj.catId.oid);
10691         }
10692         else if (fout->remoteVersion >= 70100)
10693         {
10694                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10695                                                   "CASE WHEN oprleft = 0 THEN '-' "
10696                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
10697                                                   "CASE WHEN oprright = 0 THEN '-' "
10698                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
10699                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10700                                                   "(oprlsortop != 0) AS oprcanmerge, "
10701                                                   "oprcanhash "
10702                                                   "FROM pg_operator "
10703                                                   "WHERE oid = '%u'::oid",
10704                                                   oprinfo->dobj.catId.oid);
10705         }
10706         else
10707         {
10708                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
10709                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
10710                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
10711                                                   "CASE WHEN oprright = 0 THEN '-'::name "
10712                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
10713                                                   "oprcom, oprnegate, oprrest, oprjoin, "
10714                                                   "(oprlsortop != 0) AS oprcanmerge, "
10715                                                   "oprcanhash "
10716                                                   "FROM pg_operator "
10717                                                   "WHERE oid = '%u'::oid",
10718                                                   oprinfo->dobj.catId.oid);
10719         }
10720
10721         res = ExecuteSqlQueryForSingleRow(fout, query->data);
10722
10723         i_oprkind = PQfnumber(res, "oprkind");
10724         i_oprcode = PQfnumber(res, "oprcode");
10725         i_oprleft = PQfnumber(res, "oprleft");
10726         i_oprright = PQfnumber(res, "oprright");
10727         i_oprcom = PQfnumber(res, "oprcom");
10728         i_oprnegate = PQfnumber(res, "oprnegate");
10729         i_oprrest = PQfnumber(res, "oprrest");
10730         i_oprjoin = PQfnumber(res, "oprjoin");
10731         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
10732         i_oprcanhash = PQfnumber(res, "oprcanhash");
10733
10734         oprkind = PQgetvalue(res, 0, i_oprkind);
10735         oprcode = PQgetvalue(res, 0, i_oprcode);
10736         oprleft = PQgetvalue(res, 0, i_oprleft);
10737         oprright = PQgetvalue(res, 0, i_oprright);
10738         oprcom = PQgetvalue(res, 0, i_oprcom);
10739         oprnegate = PQgetvalue(res, 0, i_oprnegate);
10740         oprrest = PQgetvalue(res, 0, i_oprrest);
10741         oprjoin = PQgetvalue(res, 0, i_oprjoin);
10742         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
10743         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
10744
10745         oprregproc = convertRegProcReference(fout, oprcode);
10746         if (oprregproc)
10747         {
10748                 appendPQExpBuffer(details, "    PROCEDURE = %s", oprregproc);
10749                 free(oprregproc);
10750         }
10751
10752         appendPQExpBuffer(oprid, "%s (",
10753                                           oprinfo->dobj.name);
10754
10755         /*
10756          * right unary means there's a left arg and left unary means there's a
10757          * right arg
10758          */
10759         if (strcmp(oprkind, "r") == 0 ||
10760                 strcmp(oprkind, "b") == 0)
10761         {
10762                 if (fout->remoteVersion >= 70100)
10763                         name = oprleft;
10764                 else
10765                         name = fmtId(oprleft);
10766                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
10767                 appendPQExpBufferStr(oprid, name);
10768         }
10769         else
10770                 appendPQExpBufferStr(oprid, "NONE");
10771
10772         if (strcmp(oprkind, "l") == 0 ||
10773                 strcmp(oprkind, "b") == 0)
10774         {
10775                 if (fout->remoteVersion >= 70100)
10776                         name = oprright;
10777                 else
10778                         name = fmtId(oprright);
10779                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
10780                 appendPQExpBuffer(oprid, ", %s)", name);
10781         }
10782         else
10783                 appendPQExpBufferStr(oprid, ", NONE)");
10784
10785         oprref = convertOperatorReference(fout, oprcom);
10786         if (oprref)
10787         {
10788                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
10789                 free(oprref);
10790         }
10791
10792         oprref = convertOperatorReference(fout, oprnegate);
10793         if (oprref)
10794         {
10795                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
10796                 free(oprref);
10797         }
10798
10799         if (strcmp(oprcanmerge, "t") == 0)
10800                 appendPQExpBufferStr(details, ",\n    MERGES");
10801
10802         if (strcmp(oprcanhash, "t") == 0)
10803                 appendPQExpBufferStr(details, ",\n    HASHES");
10804
10805         oprregproc = convertRegProcReference(fout, oprrest);
10806         if (oprregproc)
10807         {
10808                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
10809                 free(oprregproc);
10810         }
10811
10812         oprregproc = convertRegProcReference(fout, oprjoin);
10813         if (oprregproc)
10814         {
10815                 appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
10816                 free(oprregproc);
10817         }
10818
10819         /*
10820          * DROP must be fully qualified in case same name appears in pg_catalog
10821          */
10822         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
10823                                           fmtId(oprinfo->dobj.namespace->dobj.name),
10824                                           oprid->data);
10825
10826         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
10827                                           oprinfo->dobj.name, details->data);
10828
10829         appendPQExpBuffer(labelq, "OPERATOR %s", oprid->data);
10830
10831         if (dopt->binary_upgrade)
10832                 binary_upgrade_extension_member(q, &oprinfo->dobj, labelq->data);
10833
10834         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
10835                                  oprinfo->dobj.name,
10836                                  oprinfo->dobj.namespace->dobj.name,
10837                                  NULL,
10838                                  oprinfo->rolname,
10839                                  false, "OPERATOR", SECTION_PRE_DATA,
10840                                  q->data, delq->data, NULL,
10841                                  NULL, 0,
10842                                  NULL, NULL);
10843
10844         /* Dump Operator Comments */
10845         dumpComment(fout, dopt, labelq->data,
10846                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
10847                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
10848
10849         PQclear(res);
10850
10851         destroyPQExpBuffer(query);
10852         destroyPQExpBuffer(q);
10853         destroyPQExpBuffer(delq);
10854         destroyPQExpBuffer(labelq);
10855         destroyPQExpBuffer(oprid);
10856         destroyPQExpBuffer(details);
10857 }
10858
10859 /*
10860  * Convert a function reference obtained from pg_operator
10861  *
10862  * Returns allocated string of what to print, or NULL if function references
10863  * is InvalidOid. Returned string is expected to be free'd by the caller.
10864  *
10865  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
10866  * argument-types part.  In prior versions, the input is a REGPROC display.
10867  */
10868 static char *
10869 convertRegProcReference(Archive *fout, const char *proc)
10870 {
10871         /* In all cases "-" means a null reference */
10872         if (strcmp(proc, "-") == 0)
10873                 return NULL;
10874
10875         if (fout->remoteVersion >= 70300)
10876         {
10877                 char       *name;
10878                 char       *paren;
10879                 bool            inquote;
10880
10881                 name = pg_strdup(proc);
10882                 /* find non-double-quoted left paren */
10883                 inquote = false;
10884                 for (paren = name; *paren; paren++)
10885                 {
10886                         if (*paren == '(' && !inquote)
10887                         {
10888                                 *paren = '\0';
10889                                 break;
10890                         }
10891                         if (*paren == '"')
10892                                 inquote = !inquote;
10893                 }
10894                 return name;
10895         }
10896
10897         /* REGPROC before 7.3 does not quote its result */
10898         return pg_strdup(fmtId(proc));
10899 }
10900
10901 /*
10902  * Convert an operator cross-reference obtained from pg_operator
10903  *
10904  * Returns an allocated string of what to print, or NULL to print nothing.
10905  * Caller is responsible for free'ing result string.
10906  *
10907  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
10908  * argument-types part, and add OPERATOR() decoration if the name is
10909  * schema-qualified.  In older versions, the input is just a numeric OID,
10910  * which we search our operator list for.
10911  */
10912 static char *
10913 convertOperatorReference(Archive *fout, const char *opr)
10914 {
10915         OprInfo    *oprInfo;
10916
10917         /* In all cases "0" means a null reference */
10918         if (strcmp(opr, "0") == 0)
10919                 return NULL;
10920
10921         if (fout->remoteVersion >= 70300)
10922         {
10923                 char       *name;
10924                 char       *oname;
10925                 char       *ptr;
10926                 bool            inquote;
10927                 bool            sawdot;
10928
10929                 name = pg_strdup(opr);
10930                 /* find non-double-quoted left paren, and check for non-quoted dot */
10931                 inquote = false;
10932                 sawdot = false;
10933                 for (ptr = name; *ptr; ptr++)
10934                 {
10935                         if (*ptr == '"')
10936                                 inquote = !inquote;
10937                         else if (*ptr == '.' && !inquote)
10938                                 sawdot = true;
10939                         else if (*ptr == '(' && !inquote)
10940                         {
10941                                 *ptr = '\0';
10942                                 break;
10943                         }
10944                 }
10945                 /* If not schema-qualified, don't need to add OPERATOR() */
10946                 if (!sawdot)
10947                         return name;
10948                 oname = psprintf("OPERATOR(%s)", name);
10949                 free(name);
10950                 return oname;
10951         }
10952
10953         oprInfo = findOprByOid(atooid(opr));
10954         if (oprInfo == NULL)
10955         {
10956                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
10957                                   opr);
10958                 return NULL;
10959         }
10960         return pg_strdup(oprInfo->dobj.name);
10961 }
10962
10963 /*
10964  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
10965  *
10966  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
10967  * argument lists of these functions are predetermined.  Note that the
10968  * caller should ensure we are in the proper schema, because the results
10969  * are search path dependent!
10970  */
10971 static const char *
10972 convertTSFunction(Archive *fout, Oid funcOid)
10973 {
10974         char       *result;
10975         char            query[128];
10976         PGresult   *res;
10977
10978         snprintf(query, sizeof(query),
10979                          "SELECT '%u'::pg_catalog.regproc", funcOid);
10980         res = ExecuteSqlQueryForSingleRow(fout, query);
10981
10982         result = pg_strdup(PQgetvalue(res, 0, 0));
10983
10984         PQclear(res);
10985
10986         return result;
10987 }
10988
10989
10990 /*
10991  * dumpOpclass
10992  *        write out a single operator class definition
10993  */
10994 static void
10995 dumpOpclass(Archive *fout, DumpOptions *dopt, OpclassInfo *opcinfo)
10996 {
10997         PQExpBuffer query;
10998         PQExpBuffer q;
10999         PQExpBuffer delq;
11000         PQExpBuffer labelq;
11001         PGresult   *res;
11002         int                     ntups;
11003         int                     i_opcintype;
11004         int                     i_opckeytype;
11005         int                     i_opcdefault;
11006         int                     i_opcfamily;
11007         int                     i_opcfamilyname;
11008         int                     i_opcfamilynsp;
11009         int                     i_amname;
11010         int                     i_amopstrategy;
11011         int                     i_amopreqcheck;
11012         int                     i_amopopr;
11013         int                     i_sortfamily;
11014         int                     i_sortfamilynsp;
11015         int                     i_amprocnum;
11016         int                     i_amproc;
11017         int                     i_amproclefttype;
11018         int                     i_amprocrighttype;
11019         char       *opcintype;
11020         char       *opckeytype;
11021         char       *opcdefault;
11022         char       *opcfamily;
11023         char       *opcfamilyname;
11024         char       *opcfamilynsp;
11025         char       *amname;
11026         char       *amopstrategy;
11027         char       *amopreqcheck;
11028         char       *amopopr;
11029         char       *sortfamily;
11030         char       *sortfamilynsp;
11031         char       *amprocnum;
11032         char       *amproc;
11033         char       *amproclefttype;
11034         char       *amprocrighttype;
11035         bool            needComma;
11036         int                     i;
11037
11038         /* Skip if not to be dumped */
11039         if (!opcinfo->dobj.dump || dopt->dataOnly)
11040                 return;
11041
11042         /*
11043          * XXX currently we do not implement dumping of operator classes from
11044          * pre-7.3 databases.  This could be done but it seems not worth the
11045          * trouble.
11046          */
11047         if (fout->remoteVersion < 70300)
11048                 return;
11049
11050         query = createPQExpBuffer();
11051         q = createPQExpBuffer();
11052         delq = createPQExpBuffer();
11053         labelq = createPQExpBuffer();
11054
11055         /* Make sure we are in proper schema so regoperator works correctly */
11056         selectSourceSchema(fout, opcinfo->dobj.namespace->dobj.name);
11057
11058         /* Get additional fields from the pg_opclass row */
11059         if (fout->remoteVersion >= 80300)
11060         {
11061                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
11062                                                   "opckeytype::pg_catalog.regtype, "
11063                                                   "opcdefault, opcfamily, "
11064                                                   "opfname AS opcfamilyname, "
11065                                                   "nspname AS opcfamilynsp, "
11066                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
11067                                                   "FROM pg_catalog.pg_opclass c "
11068                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
11069                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11070                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
11071                                                   opcinfo->dobj.catId.oid);
11072         }
11073         else
11074         {
11075                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
11076                                                   "opckeytype::pg_catalog.regtype, "
11077                                                   "opcdefault, NULL AS opcfamily, "
11078                                                   "NULL AS opcfamilyname, "
11079                                                   "NULL AS opcfamilynsp, "
11080                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
11081                                                   "FROM pg_catalog.pg_opclass "
11082                                                   "WHERE oid = '%u'::pg_catalog.oid",
11083                                                   opcinfo->dobj.catId.oid);
11084         }
11085
11086         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11087
11088         i_opcintype = PQfnumber(res, "opcintype");
11089         i_opckeytype = PQfnumber(res, "opckeytype");
11090         i_opcdefault = PQfnumber(res, "opcdefault");
11091         i_opcfamily = PQfnumber(res, "opcfamily");
11092         i_opcfamilyname = PQfnumber(res, "opcfamilyname");
11093         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
11094         i_amname = PQfnumber(res, "amname");
11095
11096         opcintype = PQgetvalue(res, 0, i_opcintype);
11097         opckeytype = PQgetvalue(res, 0, i_opckeytype);
11098         opcdefault = PQgetvalue(res, 0, i_opcdefault);
11099         /* opcfamily will still be needed after we PQclear res */
11100         opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
11101         opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
11102         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
11103         /* amname will still be needed after we PQclear res */
11104         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11105
11106         /*
11107          * DROP must be fully qualified in case same name appears in pg_catalog
11108          */
11109         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
11110                                           fmtId(opcinfo->dobj.namespace->dobj.name));
11111         appendPQExpBuffer(delq, ".%s",
11112                                           fmtId(opcinfo->dobj.name));
11113         appendPQExpBuffer(delq, " USING %s;\n",
11114                                           fmtId(amname));
11115
11116         /* Build the fixed portion of the CREATE command */
11117         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
11118                                           fmtId(opcinfo->dobj.name));
11119         if (strcmp(opcdefault, "t") == 0)
11120                 appendPQExpBufferStr(q, "DEFAULT ");
11121         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
11122                                           opcintype,
11123                                           fmtId(amname));
11124         if (strlen(opcfamilyname) > 0 &&
11125                 (strcmp(opcfamilyname, opcinfo->dobj.name) != 0 ||
11126                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
11127         {
11128                 appendPQExpBufferStr(q, " FAMILY ");
11129                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
11130                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
11131                 appendPQExpBuffer(q, "%s", fmtId(opcfamilyname));
11132         }
11133         appendPQExpBufferStr(q, " AS\n    ");
11134
11135         needComma = false;
11136
11137         if (strcmp(opckeytype, "-") != 0)
11138         {
11139                 appendPQExpBuffer(q, "STORAGE %s",
11140                                                   opckeytype);
11141                 needComma = true;
11142         }
11143
11144         PQclear(res);
11145
11146         /*
11147          * Now fetch and print the OPERATOR entries (pg_amop rows).
11148          *
11149          * Print only those opfamily members that are tied to the opclass by
11150          * pg_depend entries.
11151          *
11152          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
11153          * older server's opclass in which it is used.  This is to avoid
11154          * hard-to-detect breakage if a newer pg_dump is used to dump from an
11155          * older server and then reload into that old version.  This can go away
11156          * once 8.3 is so old as to not be of interest to anyone.
11157          */
11158         resetPQExpBuffer(query);
11159
11160         if (fout->remoteVersion >= 90100)
11161         {
11162                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11163                                                   "amopopr::pg_catalog.regoperator, "
11164                                                   "opfname AS sortfamily, "
11165                                                   "nspname AS sortfamilynsp "
11166                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
11167                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
11168                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
11169                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11170                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11171                                                   "AND refobjid = '%u'::pg_catalog.oid "
11172                                                   "AND amopfamily = '%s'::pg_catalog.oid "
11173                                                   "ORDER BY amopstrategy",
11174                                                   opcinfo->dobj.catId.oid,
11175                                                   opcfamily);
11176         }
11177         else if (fout->remoteVersion >= 80400)
11178         {
11179                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11180                                                   "amopopr::pg_catalog.regoperator, "
11181                                                   "NULL AS sortfamily, "
11182                                                   "NULL AS sortfamilynsp "
11183                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11184                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11185                                                   "AND refobjid = '%u'::pg_catalog.oid "
11186                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11187                                                   "AND objid = ao.oid "
11188                                                   "ORDER BY amopstrategy",
11189                                                   opcinfo->dobj.catId.oid);
11190         }
11191         else if (fout->remoteVersion >= 80300)
11192         {
11193                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11194                                                   "amopopr::pg_catalog.regoperator, "
11195                                                   "NULL AS sortfamily, "
11196                                                   "NULL AS sortfamilynsp "
11197                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11198                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11199                                                   "AND refobjid = '%u'::pg_catalog.oid "
11200                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11201                                                   "AND objid = ao.oid "
11202                                                   "ORDER BY amopstrategy",
11203                                                   opcinfo->dobj.catId.oid);
11204         }
11205         else
11206         {
11207                 /*
11208                  * Here, we print all entries since there are no opfamilies and hence
11209                  * no loose operators to worry about.
11210                  */
11211                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11212                                                   "amopopr::pg_catalog.regoperator, "
11213                                                   "NULL AS sortfamily, "
11214                                                   "NULL AS sortfamilynsp "
11215                                                   "FROM pg_catalog.pg_amop "
11216                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
11217                                                   "ORDER BY amopstrategy",
11218                                                   opcinfo->dobj.catId.oid);
11219         }
11220
11221         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11222
11223         ntups = PQntuples(res);
11224
11225         i_amopstrategy = PQfnumber(res, "amopstrategy");
11226         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
11227         i_amopopr = PQfnumber(res, "amopopr");
11228         i_sortfamily = PQfnumber(res, "sortfamily");
11229         i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
11230
11231         for (i = 0; i < ntups; i++)
11232         {
11233                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
11234                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
11235                 amopopr = PQgetvalue(res, i, i_amopopr);
11236                 sortfamily = PQgetvalue(res, i, i_sortfamily);
11237                 sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
11238
11239                 if (needComma)
11240                         appendPQExpBufferStr(q, " ,\n    ");
11241
11242                 appendPQExpBuffer(q, "OPERATOR %s %s",
11243                                                   amopstrategy, amopopr);
11244
11245                 if (strlen(sortfamily) > 0)
11246                 {
11247                         appendPQExpBufferStr(q, " FOR ORDER BY ");
11248                         if (strcmp(sortfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
11249                                 appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11250                         appendPQExpBufferStr(q, fmtId(sortfamily));
11251                 }
11252
11253                 if (strcmp(amopreqcheck, "t") == 0)
11254                         appendPQExpBufferStr(q, " RECHECK");
11255
11256                 needComma = true;
11257         }
11258
11259         PQclear(res);
11260
11261         /*
11262          * Now fetch and print the FUNCTION entries (pg_amproc rows).
11263          *
11264          * Print only those opfamily members that are tied to the opclass by
11265          * pg_depend entries.
11266          *
11267          * We print the amproclefttype/amprocrighttype even though in most cases
11268          * the backend could deduce the right values, because of the corner case
11269          * of a btree sort support function for a cross-type comparison.  That's
11270          * only allowed in 9.2 and later, but for simplicity print them in all
11271          * versions that have the columns.
11272          */
11273         resetPQExpBuffer(query);
11274
11275         if (fout->remoteVersion >= 80300)
11276         {
11277                 appendPQExpBuffer(query, "SELECT amprocnum, "
11278                                                   "amproc::pg_catalog.regprocedure, "
11279                                                   "amproclefttype::pg_catalog.regtype, "
11280                                                   "amprocrighttype::pg_catalog.regtype "
11281                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
11282                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11283                                                   "AND refobjid = '%u'::pg_catalog.oid "
11284                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
11285                                                   "AND objid = ap.oid "
11286                                                   "ORDER BY amprocnum",
11287                                                   opcinfo->dobj.catId.oid);
11288         }
11289         else
11290         {
11291                 appendPQExpBuffer(query, "SELECT amprocnum, "
11292                                                   "amproc::pg_catalog.regprocedure, "
11293                                                   "'' AS amproclefttype, "
11294                                                   "'' AS amprocrighttype "
11295                                                   "FROM pg_catalog.pg_amproc "
11296                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
11297                                                   "ORDER BY amprocnum",
11298                                                   opcinfo->dobj.catId.oid);
11299         }
11300
11301         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11302
11303         ntups = PQntuples(res);
11304
11305         i_amprocnum = PQfnumber(res, "amprocnum");
11306         i_amproc = PQfnumber(res, "amproc");
11307         i_amproclefttype = PQfnumber(res, "amproclefttype");
11308         i_amprocrighttype = PQfnumber(res, "amprocrighttype");
11309
11310         for (i = 0; i < ntups; i++)
11311         {
11312                 amprocnum = PQgetvalue(res, i, i_amprocnum);
11313                 amproc = PQgetvalue(res, i, i_amproc);
11314                 amproclefttype = PQgetvalue(res, i, i_amproclefttype);
11315                 amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
11316
11317                 if (needComma)
11318                         appendPQExpBufferStr(q, " ,\n    ");
11319
11320                 appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
11321
11322                 if (*amproclefttype && *amprocrighttype)
11323                         appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
11324
11325                 appendPQExpBuffer(q, " %s", amproc);
11326
11327                 needComma = true;
11328         }
11329
11330         PQclear(res);
11331
11332         appendPQExpBufferStr(q, ";\n");
11333
11334         appendPQExpBuffer(labelq, "OPERATOR CLASS %s",
11335                                           fmtId(opcinfo->dobj.name));
11336         appendPQExpBuffer(labelq, " USING %s",
11337                                           fmtId(amname));
11338
11339         if (dopt->binary_upgrade)
11340                 binary_upgrade_extension_member(q, &opcinfo->dobj, labelq->data);
11341
11342         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
11343                                  opcinfo->dobj.name,
11344                                  opcinfo->dobj.namespace->dobj.name,
11345                                  NULL,
11346                                  opcinfo->rolname,
11347                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
11348                                  q->data, delq->data, NULL,
11349                                  NULL, 0,
11350                                  NULL, NULL);
11351
11352         /* Dump Operator Class Comments */
11353         dumpComment(fout, dopt, labelq->data,
11354                                 NULL, opcinfo->rolname,
11355                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
11356
11357         free(amname);
11358         destroyPQExpBuffer(query);
11359         destroyPQExpBuffer(q);
11360         destroyPQExpBuffer(delq);
11361         destroyPQExpBuffer(labelq);
11362 }
11363
11364 /*
11365  * dumpOpfamily
11366  *        write out a single operator family definition
11367  *
11368  * Note: this also dumps any "loose" operator members that aren't bound to a
11369  * specific opclass within the opfamily.
11370  */
11371 static void
11372 dumpOpfamily(Archive *fout, DumpOptions *dopt, OpfamilyInfo *opfinfo)
11373 {
11374         PQExpBuffer query;
11375         PQExpBuffer q;
11376         PQExpBuffer delq;
11377         PQExpBuffer labelq;
11378         PGresult   *res;
11379         PGresult   *res_ops;
11380         PGresult   *res_procs;
11381         int                     ntups;
11382         int                     i_amname;
11383         int                     i_amopstrategy;
11384         int                     i_amopreqcheck;
11385         int                     i_amopopr;
11386         int                     i_sortfamily;
11387         int                     i_sortfamilynsp;
11388         int                     i_amprocnum;
11389         int                     i_amproc;
11390         int                     i_amproclefttype;
11391         int                     i_amprocrighttype;
11392         char       *amname;
11393         char       *amopstrategy;
11394         char       *amopreqcheck;
11395         char       *amopopr;
11396         char       *sortfamily;
11397         char       *sortfamilynsp;
11398         char       *amprocnum;
11399         char       *amproc;
11400         char       *amproclefttype;
11401         char       *amprocrighttype;
11402         bool            needComma;
11403         int                     i;
11404
11405         /* Skip if not to be dumped */
11406         if (!opfinfo->dobj.dump || dopt->dataOnly)
11407                 return;
11408
11409         /*
11410          * We want to dump the opfamily only if (1) it contains "loose" operators
11411          * or functions, or (2) it contains an opclass with a different name or
11412          * owner.  Otherwise it's sufficient to let it be created during creation
11413          * of the contained opclass, and not dumping it improves portability of
11414          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
11415          * that first.
11416          */
11417
11418         query = createPQExpBuffer();
11419         q = createPQExpBuffer();
11420         delq = createPQExpBuffer();
11421         labelq = createPQExpBuffer();
11422
11423         /* Make sure we are in proper schema so regoperator works correctly */
11424         selectSourceSchema(fout, opfinfo->dobj.namespace->dobj.name);
11425
11426         /*
11427          * Fetch only those opfamily members that are tied directly to the
11428          * opfamily by pg_depend entries.
11429          *
11430          * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
11431          * older server's opclass in which it is used.  This is to avoid
11432          * hard-to-detect breakage if a newer pg_dump is used to dump from an
11433          * older server and then reload into that old version.  This can go away
11434          * once 8.3 is so old as to not be of interest to anyone.
11435          */
11436         if (fout->remoteVersion >= 90100)
11437         {
11438                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11439                                                   "amopopr::pg_catalog.regoperator, "
11440                                                   "opfname AS sortfamily, "
11441                                                   "nspname AS sortfamilynsp "
11442                                    "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
11443                                                   "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
11444                           "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
11445                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
11446                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11447                                                   "AND refobjid = '%u'::pg_catalog.oid "
11448                                                   "AND amopfamily = '%u'::pg_catalog.oid "
11449                                                   "ORDER BY amopstrategy",
11450                                                   opfinfo->dobj.catId.oid,
11451                                                   opfinfo->dobj.catId.oid);
11452         }
11453         else if (fout->remoteVersion >= 80400)
11454         {
11455                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
11456                                                   "amopopr::pg_catalog.regoperator, "
11457                                                   "NULL AS sortfamily, "
11458                                                   "NULL AS sortfamilynsp "
11459                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11460                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11461                                                   "AND refobjid = '%u'::pg_catalog.oid "
11462                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11463                                                   "AND objid = ao.oid "
11464                                                   "ORDER BY amopstrategy",
11465                                                   opfinfo->dobj.catId.oid);
11466         }
11467         else
11468         {
11469                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
11470                                                   "amopopr::pg_catalog.regoperator, "
11471                                                   "NULL AS sortfamily, "
11472                                                   "NULL AS sortfamilynsp "
11473                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
11474                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11475                                                   "AND refobjid = '%u'::pg_catalog.oid "
11476                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
11477                                                   "AND objid = ao.oid "
11478                                                   "ORDER BY amopstrategy",
11479                                                   opfinfo->dobj.catId.oid);
11480         }
11481
11482         res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11483
11484         resetPQExpBuffer(query);
11485
11486         appendPQExpBuffer(query, "SELECT amprocnum, "
11487                                           "amproc::pg_catalog.regprocedure, "
11488                                           "amproclefttype::pg_catalog.regtype, "
11489                                           "amprocrighttype::pg_catalog.regtype "
11490                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
11491                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11492                                           "AND refobjid = '%u'::pg_catalog.oid "
11493                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
11494                                           "AND objid = ap.oid "
11495                                           "ORDER BY amprocnum",
11496                                           opfinfo->dobj.catId.oid);
11497
11498         res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11499
11500         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
11501         {
11502                 /* No loose members, so check contained opclasses */
11503                 resetPQExpBuffer(query);
11504
11505                 appendPQExpBuffer(query, "SELECT 1 "
11506                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
11507                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
11508                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
11509                                                   "AND refobjid = f.oid "
11510                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
11511                                                   "AND objid = c.oid "
11512                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
11513                                                   "LIMIT 1",
11514                                                   opfinfo->dobj.catId.oid);
11515
11516                 res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11517
11518                 if (PQntuples(res) == 0)
11519                 {
11520                         /* no need to dump it, so bail out */
11521                         PQclear(res);
11522                         PQclear(res_ops);
11523                         PQclear(res_procs);
11524                         destroyPQExpBuffer(query);
11525                         destroyPQExpBuffer(q);
11526                         destroyPQExpBuffer(delq);
11527                         destroyPQExpBuffer(labelq);
11528                         return;
11529                 }
11530
11531                 PQclear(res);
11532         }
11533
11534         /* Get additional fields from the pg_opfamily row */
11535         resetPQExpBuffer(query);
11536
11537         appendPQExpBuffer(query, "SELECT "
11538          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
11539                                           "FROM pg_catalog.pg_opfamily "
11540                                           "WHERE oid = '%u'::pg_catalog.oid",
11541                                           opfinfo->dobj.catId.oid);
11542
11543         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11544
11545         i_amname = PQfnumber(res, "amname");
11546
11547         /* amname will still be needed after we PQclear res */
11548         amname = pg_strdup(PQgetvalue(res, 0, i_amname));
11549
11550         /*
11551          * DROP must be fully qualified in case same name appears in pg_catalog
11552          */
11553         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
11554                                           fmtId(opfinfo->dobj.namespace->dobj.name));
11555         appendPQExpBuffer(delq, ".%s",
11556                                           fmtId(opfinfo->dobj.name));
11557         appendPQExpBuffer(delq, " USING %s;\n",
11558                                           fmtId(amname));
11559
11560         /* Build the fixed portion of the CREATE command */
11561         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
11562                                           fmtId(opfinfo->dobj.name));
11563         appendPQExpBuffer(q, " USING %s;\n",
11564                                           fmtId(amname));
11565
11566         PQclear(res);
11567
11568         /* Do we need an ALTER to add loose members? */
11569         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
11570         {
11571                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
11572                                                   fmtId(opfinfo->dobj.name));
11573                 appendPQExpBuffer(q, " USING %s ADD\n    ",
11574                                                   fmtId(amname));
11575
11576                 needComma = false;
11577
11578                 /*
11579                  * Now fetch and print the OPERATOR entries (pg_amop rows).
11580                  */
11581                 ntups = PQntuples(res_ops);
11582
11583                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
11584                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
11585                 i_amopopr = PQfnumber(res_ops, "amopopr");
11586                 i_sortfamily = PQfnumber(res_ops, "sortfamily");
11587                 i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
11588
11589                 for (i = 0; i < ntups; i++)
11590                 {
11591                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
11592                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
11593                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
11594                         sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
11595                         sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
11596
11597                         if (needComma)
11598                                 appendPQExpBufferStr(q, " ,\n    ");
11599
11600                         appendPQExpBuffer(q, "OPERATOR %s %s",
11601                                                           amopstrategy, amopopr);
11602
11603                         if (strlen(sortfamily) > 0)
11604                         {
11605                                 appendPQExpBufferStr(q, " FOR ORDER BY ");
11606                                 if (strcmp(sortfamilynsp, opfinfo->dobj.namespace->dobj.name) != 0)
11607                                         appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
11608                                 appendPQExpBufferStr(q, fmtId(sortfamily));
11609                         }
11610
11611                         if (strcmp(amopreqcheck, "t") == 0)
11612                                 appendPQExpBufferStr(q, " RECHECK");
11613
11614                         needComma = true;
11615                 }
11616
11617                 /*
11618                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
11619                  */
11620                 ntups = PQntuples(res_procs);
11621
11622                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
11623                 i_amproc = PQfnumber(res_procs, "amproc");
11624                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
11625                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
11626
11627                 for (i = 0; i < ntups; i++)
11628                 {
11629                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
11630                         amproc = PQgetvalue(res_procs, i, i_amproc);
11631                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
11632                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
11633
11634                         if (needComma)
11635                                 appendPQExpBufferStr(q, " ,\n    ");
11636
11637                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
11638                                                           amprocnum, amproclefttype, amprocrighttype,
11639                                                           amproc);
11640
11641                         needComma = true;
11642                 }
11643
11644                 appendPQExpBufferStr(q, ";\n");
11645         }
11646
11647         appendPQExpBuffer(labelq, "OPERATOR FAMILY %s",
11648                                           fmtId(opfinfo->dobj.name));
11649         appendPQExpBuffer(labelq, " USING %s",
11650                                           fmtId(amname));
11651
11652         if (dopt->binary_upgrade)
11653                 binary_upgrade_extension_member(q, &opfinfo->dobj, labelq->data);
11654
11655         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
11656                                  opfinfo->dobj.name,
11657                                  opfinfo->dobj.namespace->dobj.name,
11658                                  NULL,
11659                                  opfinfo->rolname,
11660                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
11661                                  q->data, delq->data, NULL,
11662                                  NULL, 0,
11663                                  NULL, NULL);
11664
11665         /* Dump Operator Family Comments */
11666         dumpComment(fout, dopt, labelq->data,
11667                                 NULL, opfinfo->rolname,
11668                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
11669
11670         free(amname);
11671         PQclear(res_ops);
11672         PQclear(res_procs);
11673         destroyPQExpBuffer(query);
11674         destroyPQExpBuffer(q);
11675         destroyPQExpBuffer(delq);
11676         destroyPQExpBuffer(labelq);
11677 }
11678
11679 /*
11680  * dumpCollation
11681  *        write out a single collation definition
11682  */
11683 static void
11684 dumpCollation(Archive *fout, DumpOptions *dopt, CollInfo *collinfo)
11685 {
11686         PQExpBuffer query;
11687         PQExpBuffer q;
11688         PQExpBuffer delq;
11689         PQExpBuffer labelq;
11690         PGresult   *res;
11691         int                     i_collcollate;
11692         int                     i_collctype;
11693         const char *collcollate;
11694         const char *collctype;
11695
11696         /* Skip if not to be dumped */
11697         if (!collinfo->dobj.dump || dopt->dataOnly)
11698                 return;
11699
11700         query = createPQExpBuffer();
11701         q = createPQExpBuffer();
11702         delq = createPQExpBuffer();
11703         labelq = createPQExpBuffer();
11704
11705         /* Make sure we are in proper schema */
11706         selectSourceSchema(fout, collinfo->dobj.namespace->dobj.name);
11707
11708         /* Get collation-specific details */
11709         appendPQExpBuffer(query, "SELECT "
11710                                           "collcollate, "
11711                                           "collctype "
11712                                           "FROM pg_catalog.pg_collation c "
11713                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11714                                           collinfo->dobj.catId.oid);
11715
11716         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11717
11718         i_collcollate = PQfnumber(res, "collcollate");
11719         i_collctype = PQfnumber(res, "collctype");
11720
11721         collcollate = PQgetvalue(res, 0, i_collcollate);
11722         collctype = PQgetvalue(res, 0, i_collctype);
11723
11724         /*
11725          * DROP must be fully qualified in case same name appears in pg_catalog
11726          */
11727         appendPQExpBuffer(delq, "DROP COLLATION %s",
11728                                           fmtId(collinfo->dobj.namespace->dobj.name));
11729         appendPQExpBuffer(delq, ".%s;\n",
11730                                           fmtId(collinfo->dobj.name));
11731
11732         appendPQExpBuffer(q, "CREATE COLLATION %s (lc_collate = ",
11733                                           fmtId(collinfo->dobj.name));
11734         appendStringLiteralAH(q, collcollate, fout);
11735         appendPQExpBufferStr(q, ", lc_ctype = ");
11736         appendStringLiteralAH(q, collctype, fout);
11737         appendPQExpBufferStr(q, ");\n");
11738
11739         appendPQExpBuffer(labelq, "COLLATION %s", fmtId(collinfo->dobj.name));
11740
11741         if (dopt->binary_upgrade)
11742                 binary_upgrade_extension_member(q, &collinfo->dobj, labelq->data);
11743
11744         ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
11745                                  collinfo->dobj.name,
11746                                  collinfo->dobj.namespace->dobj.name,
11747                                  NULL,
11748                                  collinfo->rolname,
11749                                  false, "COLLATION", SECTION_PRE_DATA,
11750                                  q->data, delq->data, NULL,
11751                                  NULL, 0,
11752                                  NULL, NULL);
11753
11754         /* Dump Collation Comments */
11755         dumpComment(fout, dopt, labelq->data,
11756                                 collinfo->dobj.namespace->dobj.name, collinfo->rolname,
11757                                 collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
11758
11759         PQclear(res);
11760
11761         destroyPQExpBuffer(query);
11762         destroyPQExpBuffer(q);
11763         destroyPQExpBuffer(delq);
11764         destroyPQExpBuffer(labelq);
11765 }
11766
11767 /*
11768  * dumpConversion
11769  *        write out a single conversion definition
11770  */
11771 static void
11772 dumpConversion(Archive *fout, DumpOptions *dopt, ConvInfo *convinfo)
11773 {
11774         PQExpBuffer query;
11775         PQExpBuffer q;
11776         PQExpBuffer delq;
11777         PQExpBuffer labelq;
11778         PGresult   *res;
11779         int                     i_conforencoding;
11780         int                     i_contoencoding;
11781         int                     i_conproc;
11782         int                     i_condefault;
11783         const char *conforencoding;
11784         const char *contoencoding;
11785         const char *conproc;
11786         bool            condefault;
11787
11788         /* Skip if not to be dumped */
11789         if (!convinfo->dobj.dump || dopt->dataOnly)
11790                 return;
11791
11792         query = createPQExpBuffer();
11793         q = createPQExpBuffer();
11794         delq = createPQExpBuffer();
11795         labelq = createPQExpBuffer();
11796
11797         /* Make sure we are in proper schema */
11798         selectSourceSchema(fout, convinfo->dobj.namespace->dobj.name);
11799
11800         /* Get conversion-specific details */
11801         appendPQExpBuffer(query, "SELECT "
11802                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
11803                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
11804                                           "conproc, condefault "
11805                                           "FROM pg_catalog.pg_conversion c "
11806                                           "WHERE c.oid = '%u'::pg_catalog.oid",
11807                                           convinfo->dobj.catId.oid);
11808
11809         res = ExecuteSqlQueryForSingleRow(fout, query->data);
11810
11811         i_conforencoding = PQfnumber(res, "conforencoding");
11812         i_contoencoding = PQfnumber(res, "contoencoding");
11813         i_conproc = PQfnumber(res, "conproc");
11814         i_condefault = PQfnumber(res, "condefault");
11815
11816         conforencoding = PQgetvalue(res, 0, i_conforencoding);
11817         contoencoding = PQgetvalue(res, 0, i_contoencoding);
11818         conproc = PQgetvalue(res, 0, i_conproc);
11819         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
11820
11821         /*
11822          * DROP must be fully qualified in case same name appears in pg_catalog
11823          */
11824         appendPQExpBuffer(delq, "DROP CONVERSION %s",
11825                                           fmtId(convinfo->dobj.namespace->dobj.name));
11826         appendPQExpBuffer(delq, ".%s;\n",
11827                                           fmtId(convinfo->dobj.name));
11828
11829         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
11830                                           (condefault) ? "DEFAULT " : "",
11831                                           fmtId(convinfo->dobj.name));
11832         appendStringLiteralAH(q, conforencoding, fout);
11833         appendPQExpBufferStr(q, " TO ");
11834         appendStringLiteralAH(q, contoencoding, fout);
11835         /* regproc is automatically quoted in 7.3 and above */
11836         appendPQExpBuffer(q, " FROM %s;\n", conproc);
11837
11838         appendPQExpBuffer(labelq, "CONVERSION %s", fmtId(convinfo->dobj.name));
11839
11840         if (dopt->binary_upgrade)
11841                 binary_upgrade_extension_member(q, &convinfo->dobj, labelq->data);
11842
11843         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
11844                                  convinfo->dobj.name,
11845                                  convinfo->dobj.namespace->dobj.name,
11846                                  NULL,
11847                                  convinfo->rolname,
11848                                  false, "CONVERSION", SECTION_PRE_DATA,
11849                                  q->data, delq->data, NULL,
11850                                  NULL, 0,
11851                                  NULL, NULL);
11852
11853         /* Dump Conversion Comments */
11854         dumpComment(fout, dopt, labelq->data,
11855                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
11856                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
11857
11858         PQclear(res);
11859
11860         destroyPQExpBuffer(query);
11861         destroyPQExpBuffer(q);
11862         destroyPQExpBuffer(delq);
11863         destroyPQExpBuffer(labelq);
11864 }
11865
11866 /*
11867  * format_aggregate_signature: generate aggregate name and argument list
11868  *
11869  * The argument type names are qualified if needed.  The aggregate name
11870  * is never qualified.
11871  */
11872 static char *
11873 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
11874 {
11875         PQExpBufferData buf;
11876         int                     j;
11877
11878         initPQExpBuffer(&buf);
11879         if (honor_quotes)
11880                 appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
11881         else
11882                 appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
11883
11884         if (agginfo->aggfn.nargs == 0)
11885                 appendPQExpBuffer(&buf, "(*)");
11886         else
11887         {
11888                 appendPQExpBufferChar(&buf, '(');
11889                 for (j = 0; j < agginfo->aggfn.nargs; j++)
11890                 {
11891                         char       *typname;
11892
11893                         typname = getFormattedTypeName(fout, agginfo->aggfn.argtypes[j],
11894                                                                                    zeroAsOpaque);
11895
11896                         appendPQExpBuffer(&buf, "%s%s",
11897                                                           (j > 0) ? ", " : "",
11898                                                           typname);
11899                         free(typname);
11900                 }
11901                 appendPQExpBufferChar(&buf, ')');
11902         }
11903         return buf.data;
11904 }
11905
11906 /*
11907  * dumpAgg
11908  *        write out a single aggregate definition
11909  */
11910 static void
11911 dumpAgg(Archive *fout, DumpOptions *dopt, AggInfo *agginfo)
11912 {
11913         PQExpBuffer query;
11914         PQExpBuffer q;
11915         PQExpBuffer delq;
11916         PQExpBuffer labelq;
11917         PQExpBuffer details;
11918         char       *aggsig;                     /* identity signature */
11919         char       *aggfullsig = NULL;          /* full signature */
11920         char       *aggsig_tag;
11921         PGresult   *res;
11922         int                     i_aggtransfn;
11923         int                     i_aggfinalfn;
11924         int                     i_aggmtransfn;
11925         int                     i_aggminvtransfn;
11926         int                     i_aggmfinalfn;
11927         int                     i_aggfinalextra;
11928         int                     i_aggmfinalextra;
11929         int                     i_aggsortop;
11930         int                     i_hypothetical;
11931         int                     i_aggtranstype;
11932         int                     i_aggtransspace;
11933         int                     i_aggmtranstype;
11934         int                     i_aggmtransspace;
11935         int                     i_agginitval;
11936         int                     i_aggminitval;
11937         int                     i_convertok;
11938         const char *aggtransfn;
11939         const char *aggfinalfn;
11940         const char *aggmtransfn;
11941         const char *aggminvtransfn;
11942         const char *aggmfinalfn;
11943         bool            aggfinalextra;
11944         bool            aggmfinalextra;
11945         const char *aggsortop;
11946         char       *aggsortconvop;
11947         bool            hypothetical;
11948         const char *aggtranstype;
11949         const char *aggtransspace;
11950         const char *aggmtranstype;
11951         const char *aggmtransspace;
11952         const char *agginitval;
11953         const char *aggminitval;
11954         bool            convertok;
11955
11956         /* Skip if not to be dumped */
11957         if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
11958                 return;
11959
11960         query = createPQExpBuffer();
11961         q = createPQExpBuffer();
11962         delq = createPQExpBuffer();
11963         labelq = createPQExpBuffer();
11964         details = createPQExpBuffer();
11965
11966         /* Make sure we are in proper schema */
11967         selectSourceSchema(fout, agginfo->aggfn.dobj.namespace->dobj.name);
11968
11969         /* Get aggregate-specific details */
11970         if (fout->remoteVersion >= 90400)
11971         {
11972                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11973                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11974                                                   "aggmtransfn, aggminvtransfn, aggmfinalfn, "
11975                                                   "aggmtranstype::pg_catalog.regtype, "
11976                                                   "aggfinalextra, aggmfinalextra, "
11977                                                   "aggsortop::pg_catalog.regoperator, "
11978                                                   "(aggkind = 'h') AS hypothetical, "
11979                                                   "aggtransspace, agginitval, "
11980                                                   "aggmtransspace, aggminitval, "
11981                                                   "true AS convertok, "
11982                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
11983                  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
11984                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
11985                                                   "WHERE a.aggfnoid = p.oid "
11986                                                   "AND p.oid = '%u'::pg_catalog.oid",
11987                                                   agginfo->aggfn.dobj.catId.oid);
11988         }
11989         else if (fout->remoteVersion >= 80400)
11990         {
11991                 appendPQExpBuffer(query, "SELECT aggtransfn, "
11992                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
11993                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
11994                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
11995                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
11996                                                   "aggsortop::pg_catalog.regoperator, "
11997                                                   "false AS hypothetical, "
11998                                                   "0 AS aggtransspace, agginitval, "
11999                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
12000                                                   "true AS convertok, "
12001                                   "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
12002                  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
12003                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
12004                                                   "WHERE a.aggfnoid = p.oid "
12005                                                   "AND p.oid = '%u'::pg_catalog.oid",
12006                                                   agginfo->aggfn.dobj.catId.oid);
12007         }
12008         else if (fout->remoteVersion >= 80100)
12009         {
12010                 appendPQExpBuffer(query, "SELECT aggtransfn, "
12011                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
12012                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
12013                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
12014                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
12015                                                   "aggsortop::pg_catalog.regoperator, "
12016                                                   "false AS hypothetical, "
12017                                                   "0 AS aggtransspace, agginitval, "
12018                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
12019                                                   "true AS convertok "
12020                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
12021                                                   "WHERE a.aggfnoid = p.oid "
12022                                                   "AND p.oid = '%u'::pg_catalog.oid",
12023                                                   agginfo->aggfn.dobj.catId.oid);
12024         }
12025         else if (fout->remoteVersion >= 70300)
12026         {
12027                 appendPQExpBuffer(query, "SELECT aggtransfn, "
12028                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
12029                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
12030                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
12031                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
12032                                                   "0 AS aggsortop, "
12033                                                   "false AS hypothetical, "
12034                                                   "0 AS aggtransspace, agginitval, "
12035                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
12036                                                   "true AS convertok "
12037                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
12038                                                   "WHERE a.aggfnoid = p.oid "
12039                                                   "AND p.oid = '%u'::pg_catalog.oid",
12040                                                   agginfo->aggfn.dobj.catId.oid);
12041         }
12042         else if (fout->remoteVersion >= 70100)
12043         {
12044                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
12045                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
12046                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
12047                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
12048                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
12049                                                   "0 AS aggsortop, "
12050                                                   "false AS hypothetical, "
12051                                                   "0 AS aggtransspace, agginitval, "
12052                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
12053                                                   "true AS convertok "
12054                                                   "FROM pg_aggregate "
12055                                                   "WHERE oid = '%u'::oid",
12056                                                   agginfo->aggfn.dobj.catId.oid);
12057         }
12058         else
12059         {
12060                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
12061                                                   "aggfinalfn, "
12062                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
12063                                                   "'-' AS aggmtransfn, '-' AS aggminvtransfn, "
12064                                                   "'-' AS aggmfinalfn, 0 AS aggmtranstype, "
12065                                                   "false AS aggfinalextra, false AS aggmfinalextra, "
12066                                                   "0 AS aggsortop, "
12067                                                   "false AS hypothetical, "
12068                                                   "0 AS aggtransspace, agginitval1 AS agginitval, "
12069                                                   "0 AS aggmtransspace, NULL AS aggminitval, "
12070                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
12071                                                   "FROM pg_aggregate "
12072                                                   "WHERE oid = '%u'::oid",
12073                                                   agginfo->aggfn.dobj.catId.oid);
12074         }
12075
12076         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12077
12078         i_aggtransfn = PQfnumber(res, "aggtransfn");
12079         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
12080         i_aggmtransfn = PQfnumber(res, "aggmtransfn");
12081         i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
12082         i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
12083         i_aggfinalextra = PQfnumber(res, "aggfinalextra");
12084         i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
12085         i_aggsortop = PQfnumber(res, "aggsortop");
12086         i_hypothetical = PQfnumber(res, "hypothetical");
12087         i_aggtranstype = PQfnumber(res, "aggtranstype");
12088         i_aggtransspace = PQfnumber(res, "aggtransspace");
12089         i_aggmtranstype = PQfnumber(res, "aggmtranstype");
12090         i_aggmtransspace = PQfnumber(res, "aggmtransspace");
12091         i_agginitval = PQfnumber(res, "agginitval");
12092         i_aggminitval = PQfnumber(res, "aggminitval");
12093         i_convertok = PQfnumber(res, "convertok");
12094
12095         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
12096         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
12097         aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
12098         aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
12099         aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
12100         aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
12101         aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
12102         aggsortop = PQgetvalue(res, 0, i_aggsortop);
12103         hypothetical = (PQgetvalue(res, 0, i_hypothetical)[0] == 't');
12104         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
12105         aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
12106         aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
12107         aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
12108         agginitval = PQgetvalue(res, 0, i_agginitval);
12109         aggminitval = PQgetvalue(res, 0, i_aggminitval);
12110         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
12111
12112         if (fout->remoteVersion >= 80400)
12113         {
12114                 /* 8.4 or later; we rely on server-side code for most of the work */
12115                 char       *funcargs;
12116                 char       *funciargs;
12117
12118                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
12119                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
12120                 aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
12121                 aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
12122         }
12123         else
12124                 /* pre-8.4, do it ourselves */
12125                 aggsig = format_aggregate_signature(agginfo, fout, true);
12126
12127         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
12128
12129         if (!convertok)
12130         {
12131                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
12132                                   aggsig);
12133
12134                 if (aggfullsig)
12135                         free(aggfullsig);
12136
12137                 free(aggsig);
12138
12139                 return;
12140         }
12141
12142         if (fout->remoteVersion >= 70300)
12143         {
12144                 /* If using 7.3's regproc or regtype, data is already quoted */
12145                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
12146                                                   aggtransfn,
12147                                                   aggtranstype);
12148         }
12149         else if (fout->remoteVersion >= 70100)
12150         {
12151                 /* format_type quotes, regproc does not */
12152                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
12153                                                   fmtId(aggtransfn),
12154                                                   aggtranstype);
12155         }
12156         else
12157         {
12158                 /* need quotes all around */
12159                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
12160                                                   fmtId(aggtransfn));
12161                 appendPQExpBuffer(details, "    STYPE = %s",
12162                                                   fmtId(aggtranstype));
12163         }
12164
12165         if (strcmp(aggtransspace, "0") != 0)
12166         {
12167                 appendPQExpBuffer(details, ",\n    SSPACE = %s",
12168                                                   aggtransspace);
12169         }
12170
12171         if (!PQgetisnull(res, 0, i_agginitval))
12172         {
12173                 appendPQExpBufferStr(details, ",\n    INITCOND = ");
12174                 appendStringLiteralAH(details, agginitval, fout);
12175         }
12176
12177         if (strcmp(aggfinalfn, "-") != 0)
12178         {
12179                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
12180                                                   aggfinalfn);
12181                 if (aggfinalextra)
12182                         appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
12183         }
12184
12185         if (strcmp(aggmtransfn, "-") != 0)
12186         {
12187                 appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
12188                                                   aggmtransfn,
12189                                                   aggminvtransfn,
12190                                                   aggmtranstype);
12191         }
12192
12193         if (strcmp(aggmtransspace, "0") != 0)
12194         {
12195                 appendPQExpBuffer(details, ",\n    MSSPACE = %s",
12196                                                   aggmtransspace);
12197         }
12198
12199         if (!PQgetisnull(res, 0, i_aggminitval))
12200         {
12201                 appendPQExpBufferStr(details, ",\n    MINITCOND = ");
12202                 appendStringLiteralAH(details, aggminitval, fout);
12203         }
12204
12205         if (strcmp(aggmfinalfn, "-") != 0)
12206         {
12207                 appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
12208                                                   aggmfinalfn);
12209                 if (aggmfinalextra)
12210                         appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
12211         }
12212
12213         aggsortconvop = convertOperatorReference(fout, aggsortop);
12214         if (aggsortconvop)
12215         {
12216                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
12217                                                   aggsortconvop);
12218                 free(aggsortconvop);
12219         }
12220
12221         if (hypothetical)
12222                 appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
12223
12224         /*
12225          * DROP must be fully qualified in case same name appears in pg_catalog
12226          */
12227         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
12228                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
12229                                           aggsig);
12230
12231         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
12232                                           aggfullsig ? aggfullsig : aggsig, details->data);
12233
12234         appendPQExpBuffer(labelq, "AGGREGATE %s", aggsig);
12235
12236         if (dopt->binary_upgrade)
12237                 binary_upgrade_extension_member(q, &agginfo->aggfn.dobj, labelq->data);
12238
12239         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
12240                                  aggsig_tag,
12241                                  agginfo->aggfn.dobj.namespace->dobj.name,
12242                                  NULL,
12243                                  agginfo->aggfn.rolname,
12244                                  false, "AGGREGATE", SECTION_PRE_DATA,
12245                                  q->data, delq->data, NULL,
12246                                  NULL, 0,
12247                                  NULL, NULL);
12248
12249         /* Dump Aggregate Comments */
12250         dumpComment(fout, dopt, labelq->data,
12251                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
12252                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
12253         dumpSecLabel(fout, dopt, labelq->data,
12254                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
12255                                  agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
12256
12257         /*
12258          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
12259          * command look like a function's GRANT; in particular this affects the
12260          * syntax for zero-argument aggregates and ordered-set aggregates.
12261          */
12262         free(aggsig);
12263         free(aggsig_tag);
12264
12265         aggsig = format_function_signature(fout, &agginfo->aggfn, true);
12266         aggsig_tag = format_function_signature(fout, &agginfo->aggfn, false);
12267
12268         dumpACL(fout, dopt, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
12269                         "FUNCTION",
12270                         aggsig, NULL, aggsig_tag,
12271                         agginfo->aggfn.dobj.namespace->dobj.name,
12272                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
12273
12274         free(aggsig);
12275         if (aggfullsig)
12276                 free(aggfullsig);
12277         free(aggsig_tag);
12278
12279         PQclear(res);
12280
12281         destroyPQExpBuffer(query);
12282         destroyPQExpBuffer(q);
12283         destroyPQExpBuffer(delq);
12284         destroyPQExpBuffer(labelq);
12285         destroyPQExpBuffer(details);
12286 }
12287
12288 /*
12289  * dumpTSParser
12290  *        write out a single text search parser
12291  */
12292 static void
12293 dumpTSParser(Archive *fout, DumpOptions *dopt, TSParserInfo *prsinfo)
12294 {
12295         PQExpBuffer q;
12296         PQExpBuffer delq;
12297         PQExpBuffer labelq;
12298
12299         /* Skip if not to be dumped */
12300         if (!prsinfo->dobj.dump || dopt->dataOnly)
12301                 return;
12302
12303         q = createPQExpBuffer();
12304         delq = createPQExpBuffer();
12305         labelq = createPQExpBuffer();
12306
12307         /* Make sure we are in proper schema */
12308         selectSourceSchema(fout, prsinfo->dobj.namespace->dobj.name);
12309
12310         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
12311                                           fmtId(prsinfo->dobj.name));
12312
12313         appendPQExpBuffer(q, "    START = %s,\n",
12314                                           convertTSFunction(fout, prsinfo->prsstart));
12315         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
12316                                           convertTSFunction(fout, prsinfo->prstoken));
12317         appendPQExpBuffer(q, "    END = %s,\n",
12318                                           convertTSFunction(fout, prsinfo->prsend));
12319         if (prsinfo->prsheadline != InvalidOid)
12320                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
12321                                                   convertTSFunction(fout, prsinfo->prsheadline));
12322         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
12323                                           convertTSFunction(fout, prsinfo->prslextype));
12324
12325         /*
12326          * DROP must be fully qualified in case same name appears in pg_catalog
12327          */
12328         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
12329                                           fmtId(prsinfo->dobj.namespace->dobj.name));
12330         appendPQExpBuffer(delq, ".%s;\n",
12331                                           fmtId(prsinfo->dobj.name));
12332
12333         appendPQExpBuffer(labelq, "TEXT SEARCH PARSER %s",
12334                                           fmtId(prsinfo->dobj.name));
12335
12336         if (dopt->binary_upgrade)
12337                 binary_upgrade_extension_member(q, &prsinfo->dobj, labelq->data);
12338
12339         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
12340                                  prsinfo->dobj.name,
12341                                  prsinfo->dobj.namespace->dobj.name,
12342                                  NULL,
12343                                  "",
12344                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
12345                                  q->data, delq->data, NULL,
12346                                  NULL, 0,
12347                                  NULL, NULL);
12348
12349         /* Dump Parser Comments */
12350         dumpComment(fout, dopt, labelq->data,
12351                                 NULL, "",
12352                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
12353
12354         destroyPQExpBuffer(q);
12355         destroyPQExpBuffer(delq);
12356         destroyPQExpBuffer(labelq);
12357 }
12358
12359 /*
12360  * dumpTSDictionary
12361  *        write out a single text search dictionary
12362  */
12363 static void
12364 dumpTSDictionary(Archive *fout, DumpOptions *dopt, TSDictInfo *dictinfo)
12365 {
12366         PQExpBuffer q;
12367         PQExpBuffer delq;
12368         PQExpBuffer labelq;
12369         PQExpBuffer query;
12370         PGresult   *res;
12371         char       *nspname;
12372         char       *tmplname;
12373
12374         /* Skip if not to be dumped */
12375         if (!dictinfo->dobj.dump || dopt->dataOnly)
12376                 return;
12377
12378         q = createPQExpBuffer();
12379         delq = createPQExpBuffer();
12380         labelq = createPQExpBuffer();
12381         query = createPQExpBuffer();
12382
12383         /* Fetch name and namespace of the dictionary's template */
12384         selectSourceSchema(fout, "pg_catalog");
12385         appendPQExpBuffer(query, "SELECT nspname, tmplname "
12386                                           "FROM pg_ts_template p, pg_namespace n "
12387                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
12388                                           dictinfo->dicttemplate);
12389         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12390         nspname = PQgetvalue(res, 0, 0);
12391         tmplname = PQgetvalue(res, 0, 1);
12392
12393         /* Make sure we are in proper schema */
12394         selectSourceSchema(fout, dictinfo->dobj.namespace->dobj.name);
12395
12396         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
12397                                           fmtId(dictinfo->dobj.name));
12398
12399         appendPQExpBufferStr(q, "    TEMPLATE = ");
12400         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
12401                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12402         appendPQExpBufferStr(q, fmtId(tmplname));
12403
12404         PQclear(res);
12405
12406         /* the dictinitoption can be dumped straight into the command */
12407         if (dictinfo->dictinitoption)
12408                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
12409
12410         appendPQExpBufferStr(q, " );\n");
12411
12412         /*
12413          * DROP must be fully qualified in case same name appears in pg_catalog
12414          */
12415         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
12416                                           fmtId(dictinfo->dobj.namespace->dobj.name));
12417         appendPQExpBuffer(delq, ".%s;\n",
12418                                           fmtId(dictinfo->dobj.name));
12419
12420         appendPQExpBuffer(labelq, "TEXT SEARCH DICTIONARY %s",
12421                                           fmtId(dictinfo->dobj.name));
12422
12423         if (dopt->binary_upgrade)
12424                 binary_upgrade_extension_member(q, &dictinfo->dobj, labelq->data);
12425
12426         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
12427                                  dictinfo->dobj.name,
12428                                  dictinfo->dobj.namespace->dobj.name,
12429                                  NULL,
12430                                  dictinfo->rolname,
12431                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
12432                                  q->data, delq->data, NULL,
12433                                  NULL, 0,
12434                                  NULL, NULL);
12435
12436         /* Dump Dictionary Comments */
12437         dumpComment(fout, dopt, labelq->data,
12438                                 NULL, dictinfo->rolname,
12439                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
12440
12441         destroyPQExpBuffer(q);
12442         destroyPQExpBuffer(delq);
12443         destroyPQExpBuffer(labelq);
12444         destroyPQExpBuffer(query);
12445 }
12446
12447 /*
12448  * dumpTSTemplate
12449  *        write out a single text search template
12450  */
12451 static void
12452 dumpTSTemplate(Archive *fout, DumpOptions *dopt, TSTemplateInfo *tmplinfo)
12453 {
12454         PQExpBuffer q;
12455         PQExpBuffer delq;
12456         PQExpBuffer labelq;
12457
12458         /* Skip if not to be dumped */
12459         if (!tmplinfo->dobj.dump || dopt->dataOnly)
12460                 return;
12461
12462         q = createPQExpBuffer();
12463         delq = createPQExpBuffer();
12464         labelq = createPQExpBuffer();
12465
12466         /* Make sure we are in proper schema */
12467         selectSourceSchema(fout, tmplinfo->dobj.namespace->dobj.name);
12468
12469         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
12470                                           fmtId(tmplinfo->dobj.name));
12471
12472         if (tmplinfo->tmplinit != InvalidOid)
12473                 appendPQExpBuffer(q, "    INIT = %s,\n",
12474                                                   convertTSFunction(fout, tmplinfo->tmplinit));
12475         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
12476                                           convertTSFunction(fout, tmplinfo->tmpllexize));
12477
12478         /*
12479          * DROP must be fully qualified in case same name appears in pg_catalog
12480          */
12481         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
12482                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
12483         appendPQExpBuffer(delq, ".%s;\n",
12484                                           fmtId(tmplinfo->dobj.name));
12485
12486         appendPQExpBuffer(labelq, "TEXT SEARCH TEMPLATE %s",
12487                                           fmtId(tmplinfo->dobj.name));
12488
12489         if (dopt->binary_upgrade)
12490                 binary_upgrade_extension_member(q, &tmplinfo->dobj, labelq->data);
12491
12492         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
12493                                  tmplinfo->dobj.name,
12494                                  tmplinfo->dobj.namespace->dobj.name,
12495                                  NULL,
12496                                  "",
12497                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
12498                                  q->data, delq->data, NULL,
12499                                  NULL, 0,
12500                                  NULL, NULL);
12501
12502         /* Dump Template Comments */
12503         dumpComment(fout, dopt, labelq->data,
12504                                 NULL, "",
12505                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
12506
12507         destroyPQExpBuffer(q);
12508         destroyPQExpBuffer(delq);
12509         destroyPQExpBuffer(labelq);
12510 }
12511
12512 /*
12513  * dumpTSConfig
12514  *        write out a single text search configuration
12515  */
12516 static void
12517 dumpTSConfig(Archive *fout, DumpOptions *dopt, TSConfigInfo *cfginfo)
12518 {
12519         PQExpBuffer q;
12520         PQExpBuffer delq;
12521         PQExpBuffer labelq;
12522         PQExpBuffer query;
12523         PGresult   *res;
12524         char       *nspname;
12525         char       *prsname;
12526         int                     ntups,
12527                                 i;
12528         int                     i_tokenname;
12529         int                     i_dictname;
12530
12531         /* Skip if not to be dumped */
12532         if (!cfginfo->dobj.dump || dopt->dataOnly)
12533                 return;
12534
12535         q = createPQExpBuffer();
12536         delq = createPQExpBuffer();
12537         labelq = createPQExpBuffer();
12538         query = createPQExpBuffer();
12539
12540         /* Fetch name and namespace of the config's parser */
12541         selectSourceSchema(fout, "pg_catalog");
12542         appendPQExpBuffer(query, "SELECT nspname, prsname "
12543                                           "FROM pg_ts_parser p, pg_namespace n "
12544                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
12545                                           cfginfo->cfgparser);
12546         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12547         nspname = PQgetvalue(res, 0, 0);
12548         prsname = PQgetvalue(res, 0, 1);
12549
12550         /* Make sure we are in proper schema */
12551         selectSourceSchema(fout, cfginfo->dobj.namespace->dobj.name);
12552
12553         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
12554                                           fmtId(cfginfo->dobj.name));
12555
12556         appendPQExpBufferStr(q, "    PARSER = ");
12557         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
12558                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
12559         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
12560
12561         PQclear(res);
12562
12563         resetPQExpBuffer(query);
12564         appendPQExpBuffer(query,
12565                                           "SELECT \n"
12566                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
12567                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
12568                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
12569                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
12570                                           "WHERE m.mapcfg = '%u' \n"
12571                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
12572                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
12573
12574         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12575         ntups = PQntuples(res);
12576
12577         i_tokenname = PQfnumber(res, "tokenname");
12578         i_dictname = PQfnumber(res, "dictname");
12579
12580         for (i = 0; i < ntups; i++)
12581         {
12582                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
12583                 char       *dictname = PQgetvalue(res, i, i_dictname);
12584
12585                 if (i == 0 ||
12586                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
12587                 {
12588                         /* starting a new token type, so start a new command */
12589                         if (i > 0)
12590                                 appendPQExpBufferStr(q, ";\n");
12591                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
12592                                                           fmtId(cfginfo->dobj.name));
12593                         /* tokenname needs quoting, dictname does NOT */
12594                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
12595                                                           fmtId(tokenname), dictname);
12596                 }
12597                 else
12598                         appendPQExpBuffer(q, ", %s", dictname);
12599         }
12600
12601         if (ntups > 0)
12602                 appendPQExpBufferStr(q, ";\n");
12603
12604         PQclear(res);
12605
12606         /*
12607          * DROP must be fully qualified in case same name appears in pg_catalog
12608          */
12609         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
12610                                           fmtId(cfginfo->dobj.namespace->dobj.name));
12611         appendPQExpBuffer(delq, ".%s;\n",
12612                                           fmtId(cfginfo->dobj.name));
12613
12614         appendPQExpBuffer(labelq, "TEXT SEARCH CONFIGURATION %s",
12615                                           fmtId(cfginfo->dobj.name));
12616
12617         if (dopt->binary_upgrade)
12618                 binary_upgrade_extension_member(q, &cfginfo->dobj, labelq->data);
12619
12620         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
12621                                  cfginfo->dobj.name,
12622                                  cfginfo->dobj.namespace->dobj.name,
12623                                  NULL,
12624                                  cfginfo->rolname,
12625                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
12626                                  q->data, delq->data, NULL,
12627                                  NULL, 0,
12628                                  NULL, NULL);
12629
12630         /* Dump Configuration Comments */
12631         dumpComment(fout, dopt, labelq->data,
12632                                 NULL, cfginfo->rolname,
12633                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
12634
12635         destroyPQExpBuffer(q);
12636         destroyPQExpBuffer(delq);
12637         destroyPQExpBuffer(labelq);
12638         destroyPQExpBuffer(query);
12639 }
12640
12641 /*
12642  * dumpForeignDataWrapper
12643  *        write out a single foreign-data wrapper definition
12644  */
12645 static void
12646 dumpForeignDataWrapper(Archive *fout, DumpOptions *dopt, FdwInfo *fdwinfo)
12647 {
12648         PQExpBuffer q;
12649         PQExpBuffer delq;
12650         PQExpBuffer labelq;
12651         char       *qfdwname;
12652
12653         /* Skip if not to be dumped */
12654         if (!fdwinfo->dobj.dump || dopt->dataOnly)
12655                 return;
12656
12657         /*
12658          * FDWs that belong to an extension are dumped based on their "dump"
12659          * field. Otherwise omit them if we are only dumping some specific object.
12660          */
12661         if (!fdwinfo->dobj.ext_member)
12662                 if (!dopt->include_everything)
12663                         return;
12664
12665         q = createPQExpBuffer();
12666         delq = createPQExpBuffer();
12667         labelq = createPQExpBuffer();
12668
12669         qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
12670
12671         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
12672                                           qfdwname);
12673
12674         if (strcmp(fdwinfo->fdwhandler, "-") != 0)
12675                 appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
12676
12677         if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
12678                 appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
12679
12680         if (strlen(fdwinfo->fdwoptions) > 0)
12681                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
12682
12683         appendPQExpBufferStr(q, ";\n");
12684
12685         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
12686                                           qfdwname);
12687
12688         appendPQExpBuffer(labelq, "FOREIGN DATA WRAPPER %s",
12689                                           qfdwname);
12690
12691         if (dopt->binary_upgrade)
12692                 binary_upgrade_extension_member(q, &fdwinfo->dobj, labelq->data);
12693
12694         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12695                                  fdwinfo->dobj.name,
12696                                  NULL,
12697                                  NULL,
12698                                  fdwinfo->rolname,
12699                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
12700                                  q->data, delq->data, NULL,
12701                                  NULL, 0,
12702                                  NULL, NULL);
12703
12704         /* Handle the ACL */
12705         dumpACL(fout, dopt, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
12706                         "FOREIGN DATA WRAPPER",
12707                         qfdwname, NULL, fdwinfo->dobj.name,
12708                         NULL, fdwinfo->rolname,
12709                         fdwinfo->fdwacl);
12710
12711         /* Dump Foreign Data Wrapper Comments */
12712         dumpComment(fout, dopt, labelq->data,
12713                                 NULL, fdwinfo->rolname,
12714                                 fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
12715
12716         free(qfdwname);
12717
12718         destroyPQExpBuffer(q);
12719         destroyPQExpBuffer(delq);
12720         destroyPQExpBuffer(labelq);
12721 }
12722
12723 /*
12724  * dumpForeignServer
12725  *        write out a foreign server definition
12726  */
12727 static void
12728 dumpForeignServer(Archive *fout, DumpOptions *dopt, ForeignServerInfo *srvinfo)
12729 {
12730         PQExpBuffer q;
12731         PQExpBuffer delq;
12732         PQExpBuffer labelq;
12733         PQExpBuffer query;
12734         PGresult   *res;
12735         char       *qsrvname;
12736         char       *fdwname;
12737
12738         /* Skip if not to be dumped */
12739         if (!srvinfo->dobj.dump || dopt->dataOnly || !dopt->include_everything)
12740                 return;
12741
12742         q = createPQExpBuffer();
12743         delq = createPQExpBuffer();
12744         labelq = createPQExpBuffer();
12745         query = createPQExpBuffer();
12746
12747         qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
12748
12749         /* look up the foreign-data wrapper */
12750         selectSourceSchema(fout, "pg_catalog");
12751         appendPQExpBuffer(query, "SELECT fdwname "
12752                                           "FROM pg_foreign_data_wrapper w "
12753                                           "WHERE w.oid = '%u'",
12754                                           srvinfo->srvfdw);
12755         res = ExecuteSqlQueryForSingleRow(fout, query->data);
12756         fdwname = PQgetvalue(res, 0, 0);
12757
12758         appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
12759         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
12760         {
12761                 appendPQExpBufferStr(q, " TYPE ");
12762                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
12763         }
12764         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
12765         {
12766                 appendPQExpBufferStr(q, " VERSION ");
12767                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
12768         }
12769
12770         appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
12771         appendPQExpBufferStr(q, fmtId(fdwname));
12772
12773         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
12774                 appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
12775
12776         appendPQExpBufferStr(q, ";\n");
12777
12778         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
12779                                           qsrvname);
12780
12781         appendPQExpBuffer(labelq, "SERVER %s", qsrvname);
12782
12783         if (dopt->binary_upgrade)
12784                 binary_upgrade_extension_member(q, &srvinfo->dobj, labelq->data);
12785
12786         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12787                                  srvinfo->dobj.name,
12788                                  NULL,
12789                                  NULL,
12790                                  srvinfo->rolname,
12791                                  false, "SERVER", SECTION_PRE_DATA,
12792                                  q->data, delq->data, NULL,
12793                                  NULL, 0,
12794                                  NULL, NULL);
12795
12796         /* Handle the ACL */
12797         dumpACL(fout, dopt, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
12798                         "FOREIGN SERVER",
12799                         qsrvname, NULL, srvinfo->dobj.name,
12800                         NULL, srvinfo->rolname,
12801                         srvinfo->srvacl);
12802
12803         /* Dump user mappings */
12804         dumpUserMappings(fout,
12805                                          srvinfo->dobj.name, NULL,
12806                                          srvinfo->rolname,
12807                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
12808
12809         /* Dump Foreign Server Comments */
12810         dumpComment(fout, dopt, labelq->data,
12811                                 NULL, srvinfo->rolname,
12812                                 srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
12813
12814         free(qsrvname);
12815
12816         destroyPQExpBuffer(q);
12817         destroyPQExpBuffer(delq);
12818         destroyPQExpBuffer(labelq);
12819 }
12820
12821 /*
12822  * dumpUserMappings
12823  *
12824  * This routine is used to dump any user mappings associated with the
12825  * server handed to this routine. Should be called after ArchiveEntry()
12826  * for the server.
12827  */
12828 static void
12829 dumpUserMappings(Archive *fout,
12830                                  const char *servername, const char *namespace,
12831                                  const char *owner,
12832                                  CatalogId catalogId, DumpId dumpId)
12833 {
12834         PQExpBuffer q;
12835         PQExpBuffer delq;
12836         PQExpBuffer query;
12837         PQExpBuffer tag;
12838         PGresult   *res;
12839         int                     ntups;
12840         int                     i_usename;
12841         int                     i_umoptions;
12842         int                     i;
12843
12844         q = createPQExpBuffer();
12845         tag = createPQExpBuffer();
12846         delq = createPQExpBuffer();
12847         query = createPQExpBuffer();
12848
12849         /*
12850          * We read from the publicly accessible view pg_user_mappings, so as not
12851          * to fail if run by a non-superuser.  Note that the view will show
12852          * umoptions as null if the user hasn't got privileges for the associated
12853          * server; this means that pg_dump will dump such a mapping, but with no
12854          * OPTIONS clause.  A possible alternative is to skip such mappings
12855          * altogether, but it's not clear that that's an improvement.
12856          */
12857         selectSourceSchema(fout, "pg_catalog");
12858
12859         appendPQExpBuffer(query,
12860                                           "SELECT usename, "
12861                                           "array_to_string(ARRAY("
12862                                           "SELECT quote_ident(option_name) || ' ' || "
12863                                           "quote_literal(option_value) "
12864                                           "FROM pg_options_to_table(umoptions) "
12865                                           "ORDER BY option_name"
12866                                           "), E',\n    ') AS umoptions "
12867                                           "FROM pg_user_mappings "
12868                                           "WHERE srvid = '%u' "
12869                                           "ORDER BY usename",
12870                                           catalogId.oid);
12871
12872         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
12873
12874         ntups = PQntuples(res);
12875         i_usename = PQfnumber(res, "usename");
12876         i_umoptions = PQfnumber(res, "umoptions");
12877
12878         for (i = 0; i < ntups; i++)
12879         {
12880                 char       *usename;
12881                 char       *umoptions;
12882
12883                 usename = PQgetvalue(res, i, i_usename);
12884                 umoptions = PQgetvalue(res, i, i_umoptions);
12885
12886                 resetPQExpBuffer(q);
12887                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
12888                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
12889
12890                 if (umoptions && strlen(umoptions) > 0)
12891                         appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
12892
12893                 appendPQExpBufferStr(q, ";\n");
12894
12895                 resetPQExpBuffer(delq);
12896                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
12897                 appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
12898
12899                 resetPQExpBuffer(tag);
12900                 appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
12901                                                   usename, servername);
12902
12903                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
12904                                          tag->data,
12905                                          namespace,
12906                                          NULL,
12907                                          owner, false,
12908                                          "USER MAPPING", SECTION_PRE_DATA,
12909                                          q->data, delq->data, NULL,
12910                                          &dumpId, 1,
12911                                          NULL, NULL);
12912         }
12913
12914         PQclear(res);
12915
12916         destroyPQExpBuffer(query);
12917         destroyPQExpBuffer(delq);
12918         destroyPQExpBuffer(tag);
12919         destroyPQExpBuffer(q);
12920 }
12921
12922 /*
12923  * Write out default privileges information
12924  */
12925 static void
12926 dumpDefaultACL(Archive *fout, DumpOptions *dopt, DefaultACLInfo *daclinfo)
12927 {
12928         PQExpBuffer q;
12929         PQExpBuffer tag;
12930         const char *type;
12931
12932         /* Skip if not to be dumped */
12933         if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
12934                 return;
12935
12936         q = createPQExpBuffer();
12937         tag = createPQExpBuffer();
12938
12939         switch (daclinfo->defaclobjtype)
12940         {
12941                 case DEFACLOBJ_RELATION:
12942                         type = "TABLES";
12943                         break;
12944                 case DEFACLOBJ_SEQUENCE:
12945                         type = "SEQUENCES";
12946                         break;
12947                 case DEFACLOBJ_FUNCTION:
12948                         type = "FUNCTIONS";
12949                         break;
12950                 case DEFACLOBJ_TYPE:
12951                         type = "TYPES";
12952                         break;
12953                 default:
12954                         /* shouldn't get here */
12955                         exit_horribly(NULL,
12956                                           "unrecognized object type in default privileges: %d\n",
12957                                                   (int) daclinfo->defaclobjtype);
12958                         type = "";                      /* keep compiler quiet */
12959         }
12960
12961         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
12962
12963         /* build the actual command(s) for this tuple */
12964         if (!buildDefaultACLCommands(type,
12965                                                                  daclinfo->dobj.namespace != NULL ?
12966                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
12967                                                                  daclinfo->defaclacl,
12968                                                                  daclinfo->defaclrole,
12969                                                                  fout->remoteVersion,
12970                                                                  q))
12971                 exit_horribly(NULL, "could not parse default ACL list (%s)\n",
12972                                           daclinfo->defaclacl);
12973
12974         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
12975                                  tag->data,
12976            daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
12977                                  NULL,
12978                                  daclinfo->defaclrole,
12979                                  false, "DEFAULT ACL", SECTION_POST_DATA,
12980                                  q->data, "", NULL,
12981                                  NULL, 0,
12982                                  NULL, NULL);
12983
12984         destroyPQExpBuffer(tag);
12985         destroyPQExpBuffer(q);
12986 }
12987
12988 /*----------
12989  * Write out grant/revoke information
12990  *
12991  * 'objCatId' is the catalog ID of the underlying object.
12992  * 'objDumpId' is the dump ID of the underlying object.
12993  * 'type' must be one of
12994  *              TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
12995  *              FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
12996  * 'name' is the formatted name of the object.  Must be quoted etc. already.
12997  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
12998  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
12999  * 'nspname' is the namespace the object is in (NULL if none).
13000  * 'owner' is the owner, NULL if there is no owner (for languages).
13001  * 'acls' is the string read out of the fooacl system catalog field;
13002  *              it will be parsed here.
13003  *----------
13004  */
13005 static void
13006 dumpACL(Archive *fout, DumpOptions *dopt, CatalogId objCatId, DumpId objDumpId,
13007                 const char *type, const char *name, const char *subname,
13008                 const char *tag, const char *nspname, const char *owner,
13009                 const char *acls)
13010 {
13011         PQExpBuffer sql;
13012
13013         /* Do nothing if ACL dump is not enabled */
13014         if (dopt->aclsSkip)
13015                 return;
13016
13017         /* --data-only skips ACLs *except* BLOB ACLs */
13018         if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
13019                 return;
13020
13021         sql = createPQExpBuffer();
13022
13023         if (!buildACLCommands(name, subname, type, acls, owner,
13024                                                   "", fout->remoteVersion, sql))
13025                 exit_horribly(NULL,
13026                                         "could not parse ACL list (%s) for object \"%s\" (%s)\n",
13027                                           acls, name, type);
13028
13029         if (sql->len > 0)
13030                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13031                                          tag, nspname,
13032                                          NULL,
13033                                          owner ? owner : "",
13034                                          false, "ACL", SECTION_NONE,
13035                                          sql->data, "", NULL,
13036                                          &(objDumpId), 1,
13037                                          NULL, NULL);
13038
13039         destroyPQExpBuffer(sql);
13040 }
13041
13042 /*
13043  * dumpSecLabel
13044  *
13045  * This routine is used to dump any security labels associated with the
13046  * object handed to this routine. The routine takes a constant character
13047  * string for the target part of the security-label command, plus
13048  * the namespace and owner of the object (for labeling the ArchiveEntry),
13049  * plus catalog ID and subid which are the lookup key for pg_seclabel,
13050  * plus the dump ID for the object (for setting a dependency).
13051  * If a matching pg_seclabel entry is found, it is dumped.
13052  *
13053  * Note: although this routine takes a dumpId for dependency purposes,
13054  * that purpose is just to mark the dependency in the emitted dump file
13055  * for possible future use by pg_restore.  We do NOT use it for determining
13056  * ordering of the label in the dump file, because this routine is called
13057  * after dependency sorting occurs.  This routine should be called just after
13058  * calling ArchiveEntry() for the specified object.
13059  */
13060 static void
13061 dumpSecLabel(Archive *fout, DumpOptions *dopt, const char *target,
13062                          const char *namespace, const char *owner,
13063                          CatalogId catalogId, int subid, DumpId dumpId)
13064 {
13065         SecLabelItem *labels;
13066         int                     nlabels;
13067         int                     i;
13068         PQExpBuffer query;
13069
13070         /* do nothing, if --no-security-labels is supplied */
13071         if (dopt->no_security_labels)
13072                 return;
13073
13074         /* Comments are schema not data ... except blob comments are data */
13075         if (strncmp(target, "LARGE OBJECT ", 13) != 0)
13076         {
13077                 if (dopt->dataOnly)
13078                         return;
13079         }
13080         else
13081         {
13082                 if (dopt->schemaOnly)
13083                         return;
13084         }
13085
13086         /* Search for security labels associated with catalogId, using table */
13087         nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
13088
13089         query = createPQExpBuffer();
13090
13091         for (i = 0; i < nlabels; i++)
13092         {
13093                 /*
13094                  * Ignore label entries for which the subid doesn't match.
13095                  */
13096                 if (labels[i].objsubid != subid)
13097                         continue;
13098
13099                 appendPQExpBuffer(query,
13100                                                   "SECURITY LABEL FOR %s ON %s IS ",
13101                                                   fmtId(labels[i].provider), target);
13102                 appendStringLiteralAH(query, labels[i].label, fout);
13103                 appendPQExpBufferStr(query, ";\n");
13104         }
13105
13106         if (query->len > 0)
13107         {
13108                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13109                                          target, namespace, NULL, owner,
13110                                          false, "SECURITY LABEL", SECTION_NONE,
13111                                          query->data, "", NULL,
13112                                          &(dumpId), 1,
13113                                          NULL, NULL);
13114         }
13115         destroyPQExpBuffer(query);
13116 }
13117
13118 /*
13119  * dumpTableSecLabel
13120  *
13121  * As above, but dump security label for both the specified table (or view)
13122  * and its columns.
13123  */
13124 static void
13125 dumpTableSecLabel(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo, const char *reltypename)
13126 {
13127         SecLabelItem *labels;
13128         int                     nlabels;
13129         int                     i;
13130         PQExpBuffer query;
13131         PQExpBuffer target;
13132
13133         /* do nothing, if --no-security-labels is supplied */
13134         if (dopt->no_security_labels)
13135                 return;
13136
13137         /* SecLabel are SCHEMA not data */
13138         if (dopt->dataOnly)
13139                 return;
13140
13141         /* Search for comments associated with relation, using table */
13142         nlabels = findSecLabels(fout,
13143                                                         tbinfo->dobj.catId.tableoid,
13144                                                         tbinfo->dobj.catId.oid,
13145                                                         &labels);
13146
13147         /* If security labels exist, build SECURITY LABEL statements */
13148         if (nlabels <= 0)
13149                 return;
13150
13151         query = createPQExpBuffer();
13152         target = createPQExpBuffer();
13153
13154         for (i = 0; i < nlabels; i++)
13155         {
13156                 const char *colname;
13157                 const char *provider = labels[i].provider;
13158                 const char *label = labels[i].label;
13159                 int                     objsubid = labels[i].objsubid;
13160
13161                 resetPQExpBuffer(target);
13162                 if (objsubid == 0)
13163                 {
13164                         appendPQExpBuffer(target, "%s %s", reltypename,
13165                                                           fmtId(tbinfo->dobj.name));
13166                 }
13167                 else
13168                 {
13169                         colname = getAttrName(objsubid, tbinfo);
13170                         /* first fmtId result must be consumed before calling it again */
13171                         appendPQExpBuffer(target, "COLUMN %s", fmtId(tbinfo->dobj.name));
13172                         appendPQExpBuffer(target, ".%s", fmtId(colname));
13173                 }
13174                 appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
13175                                                   fmtId(provider), target->data);
13176                 appendStringLiteralAH(query, label, fout);
13177                 appendPQExpBufferStr(query, ";\n");
13178         }
13179         if (query->len > 0)
13180         {
13181                 resetPQExpBuffer(target);
13182                 appendPQExpBuffer(target, "%s %s", reltypename,
13183                                                   fmtId(tbinfo->dobj.name));
13184                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
13185                                          target->data,
13186                                          tbinfo->dobj.namespace->dobj.name,
13187                                          NULL, tbinfo->rolname,
13188                                          false, "SECURITY LABEL", SECTION_NONE,
13189                                          query->data, "", NULL,
13190                                          &(tbinfo->dobj.dumpId), 1,
13191                                          NULL, NULL);
13192         }
13193         destroyPQExpBuffer(query);
13194         destroyPQExpBuffer(target);
13195 }
13196
13197 /*
13198  * findSecLabels
13199  *
13200  * Find the security label(s), if any, associated with the given object.
13201  * All the objsubid values associated with the given classoid/objoid are
13202  * found with one search.
13203  */
13204 static int
13205 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
13206 {
13207         /* static storage for table of security labels */
13208         static SecLabelItem *labels = NULL;
13209         static int      nlabels = -1;
13210
13211         SecLabelItem *middle = NULL;
13212         SecLabelItem *low;
13213         SecLabelItem *high;
13214         int                     nmatch;
13215
13216         /* Get security labels if we didn't already */
13217         if (nlabels < 0)
13218                 nlabels = collectSecLabels(fout, &labels);
13219
13220         if (nlabels <= 0)                       /* no labels, so no match is possible */
13221         {
13222                 *items = NULL;
13223                 return 0;
13224         }
13225
13226         /*
13227          * Do binary search to find some item matching the object.
13228          */
13229         low = &labels[0];
13230         high = &labels[nlabels - 1];
13231         while (low <= high)
13232         {
13233                 middle = low + (high - low) / 2;
13234
13235                 if (classoid < middle->classoid)
13236                         high = middle - 1;
13237                 else if (classoid > middle->classoid)
13238                         low = middle + 1;
13239                 else if (objoid < middle->objoid)
13240                         high = middle - 1;
13241                 else if (objoid > middle->objoid)
13242                         low = middle + 1;
13243                 else
13244                         break;                          /* found a match */
13245         }
13246
13247         if (low > high)                         /* no matches */
13248         {
13249                 *items = NULL;
13250                 return 0;
13251         }
13252
13253         /*
13254          * Now determine how many items match the object.  The search loop
13255          * invariant still holds: only items between low and high inclusive could
13256          * match.
13257          */
13258         nmatch = 1;
13259         while (middle > low)
13260         {
13261                 if (classoid != middle[-1].classoid ||
13262                         objoid != middle[-1].objoid)
13263                         break;
13264                 middle--;
13265                 nmatch++;
13266         }
13267
13268         *items = middle;
13269
13270         middle += nmatch;
13271         while (middle <= high)
13272         {
13273                 if (classoid != middle->classoid ||
13274                         objoid != middle->objoid)
13275                         break;
13276                 middle++;
13277                 nmatch++;
13278         }
13279
13280         return nmatch;
13281 }
13282
13283 /*
13284  * collectSecLabels
13285  *
13286  * Construct a table of all security labels available for database objects.
13287  * It's much faster to pull them all at once.
13288  *
13289  * The table is sorted by classoid/objid/objsubid for speed in lookup.
13290  */
13291 static int
13292 collectSecLabels(Archive *fout, SecLabelItem **items)
13293 {
13294         PGresult   *res;
13295         PQExpBuffer query;
13296         int                     i_label;
13297         int                     i_provider;
13298         int                     i_classoid;
13299         int                     i_objoid;
13300         int                     i_objsubid;
13301         int                     ntups;
13302         int                     i;
13303         SecLabelItem *labels;
13304
13305         query = createPQExpBuffer();
13306
13307         appendPQExpBufferStr(query,
13308                                                  "SELECT label, provider, classoid, objoid, objsubid "
13309                                                  "FROM pg_catalog.pg_seclabel "
13310                                                  "ORDER BY classoid, objoid, objsubid");
13311
13312         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13313
13314         /* Construct lookup table containing OIDs in numeric form */
13315         i_label = PQfnumber(res, "label");
13316         i_provider = PQfnumber(res, "provider");
13317         i_classoid = PQfnumber(res, "classoid");
13318         i_objoid = PQfnumber(res, "objoid");
13319         i_objsubid = PQfnumber(res, "objsubid");
13320
13321         ntups = PQntuples(res);
13322
13323         labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
13324
13325         for (i = 0; i < ntups; i++)
13326         {
13327                 labels[i].label = PQgetvalue(res, i, i_label);
13328                 labels[i].provider = PQgetvalue(res, i, i_provider);
13329                 labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
13330                 labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
13331                 labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
13332         }
13333
13334         /* Do NOT free the PGresult since we are keeping pointers into it */
13335         destroyPQExpBuffer(query);
13336
13337         *items = labels;
13338         return ntups;
13339 }
13340
13341 /*
13342  * dumpTable
13343  *        write out to fout the declarations (not data) of a user-defined table
13344  */
13345 static void
13346 dumpTable(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
13347 {
13348         if (tbinfo->dobj.dump && !dopt->dataOnly)
13349         {
13350                 char       *namecopy;
13351
13352                 if (tbinfo->relkind == RELKIND_SEQUENCE)
13353                         dumpSequence(fout, dopt, tbinfo);
13354                 else
13355                         dumpTableSchema(fout, dopt, tbinfo);
13356
13357                 /* Handle the ACL here */
13358                 namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
13359                 dumpACL(fout, dopt, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
13360                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" :
13361                                 "TABLE",
13362                                 namecopy, NULL, tbinfo->dobj.name,
13363                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13364                                 tbinfo->relacl);
13365
13366                 /*
13367                  * Handle column ACLs, if any.  Note: we pull these with a separate
13368                  * query rather than trying to fetch them during getTableAttrs, so
13369                  * that we won't miss ACLs on system columns.
13370                  */
13371                 if (fout->remoteVersion >= 80400)
13372                 {
13373                         PQExpBuffer query = createPQExpBuffer();
13374                         PGresult   *res;
13375                         int                     i;
13376
13377                         appendPQExpBuffer(query,
13378                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
13379                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
13380                                                           "ORDER BY attnum",
13381                                                           tbinfo->dobj.catId.oid);
13382                         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13383
13384                         for (i = 0; i < PQntuples(res); i++)
13385                         {
13386                                 char       *attname = PQgetvalue(res, i, 0);
13387                                 char       *attacl = PQgetvalue(res, i, 1);
13388                                 char       *attnamecopy;
13389                                 char       *acltag;
13390
13391                                 attnamecopy = pg_strdup(fmtId(attname));
13392                                 acltag = psprintf("%s.%s", tbinfo->dobj.name, attname);
13393                                 /* Column's GRANT type is always TABLE */
13394                                 dumpACL(fout, dopt, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
13395                                                 namecopy, attnamecopy, acltag,
13396                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
13397                                                 attacl);
13398                                 free(attnamecopy);
13399                                 free(acltag);
13400                         }
13401                         PQclear(res);
13402                         destroyPQExpBuffer(query);
13403                 }
13404
13405                 free(namecopy);
13406         }
13407 }
13408
13409 /*
13410  * Create the AS clause for a view or materialized view. The semicolon is
13411  * stripped because a materialized view must add a WITH NO DATA clause.
13412  *
13413  * This returns a new buffer which must be freed by the caller.
13414  */
13415 static PQExpBuffer
13416 createViewAsClause(Archive *fout, TableInfo *tbinfo)
13417 {
13418         PQExpBuffer query = createPQExpBuffer();
13419         PQExpBuffer result = createPQExpBuffer();
13420         PGresult   *res;
13421         int                     len;
13422
13423         /* Fetch the view definition */
13424         if (fout->remoteVersion >= 70300)
13425         {
13426                 /* Beginning in 7.3, viewname is not unique; rely on OID */
13427                 appendPQExpBuffer(query,
13428                  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
13429                                                   tbinfo->dobj.catId.oid);
13430         }
13431         else
13432         {
13433                 appendPQExpBufferStr(query, "SELECT definition AS viewdef "
13434                                                          "FROM pg_views WHERE viewname = ");
13435                 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
13436         }
13437
13438         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13439
13440         if (PQntuples(res) != 1)
13441         {
13442                 if (PQntuples(res) < 1)
13443                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
13444                                                   tbinfo->dobj.name);
13445                 else
13446                         exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
13447                                                   tbinfo->dobj.name);
13448         }
13449
13450         len = PQgetlength(res, 0, 0);
13451
13452         if (len == 0)
13453                 exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
13454                                           tbinfo->dobj.name);
13455
13456         /* Strip off the trailing semicolon so that other things may follow. */
13457         Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
13458         appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
13459
13460         PQclear(res);
13461         destroyPQExpBuffer(query);
13462
13463         return result;
13464 }
13465
13466 /*
13467  * dumpTableSchema
13468  *        write the declaration (not data) of one user-defined table or view
13469  */
13470 static void
13471 dumpTableSchema(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
13472 {
13473         PQExpBuffer q = createPQExpBuffer();
13474         PQExpBuffer delq = createPQExpBuffer();
13475         PQExpBuffer labelq = createPQExpBuffer();
13476         int                     numParents;
13477         TableInfo **parents;
13478         int                     actual_atts;    /* number of attrs in this CREATE statement */
13479         const char *reltypename;
13480         char       *storage;
13481         char       *srvname;
13482         char       *ftoptions;
13483         int                     j,
13484                                 k;
13485
13486         /* Make sure we are in proper schema */
13487         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
13488
13489         if (dopt->binary_upgrade)
13490                 binary_upgrade_set_type_oids_by_rel_oid(fout, q,
13491                                                                                                 tbinfo->dobj.catId.oid);
13492
13493         /* Is it a table or a view? */
13494         if (tbinfo->relkind == RELKIND_VIEW)
13495         {
13496                 PQExpBuffer result;
13497
13498                 reltypename = "VIEW";
13499
13500                 /*
13501                  * DROP must be fully qualified in case same name appears in
13502                  * pg_catalog
13503                  */
13504                 appendPQExpBuffer(delq, "DROP VIEW %s.",
13505                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13506                 appendPQExpBuffer(delq, "%s;\n",
13507                                                   fmtId(tbinfo->dobj.name));
13508
13509                 if (dopt->binary_upgrade)
13510                         binary_upgrade_set_pg_class_oids(fout, q,
13511                                                                                          tbinfo->dobj.catId.oid, false);
13512
13513                 appendPQExpBuffer(q, "CREATE VIEW %s", fmtId(tbinfo->dobj.name));
13514                 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13515                         appendPQExpBuffer(q, " WITH (%s)", tbinfo->reloptions);
13516                 result = createViewAsClause(fout, tbinfo);
13517                 appendPQExpBuffer(q, " AS\n%s", result->data);
13518                 destroyPQExpBuffer(result);
13519
13520                 if (tbinfo->checkoption != NULL)
13521                         appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
13522                 appendPQExpBufferStr(q, ";\n");
13523
13524                 appendPQExpBuffer(labelq, "VIEW %s",
13525                                                   fmtId(tbinfo->dobj.name));
13526         }
13527         else
13528         {
13529                 switch (tbinfo->relkind)
13530                 {
13531                         case (RELKIND_FOREIGN_TABLE):
13532                                 {
13533                                         PQExpBuffer query = createPQExpBuffer();
13534                                         PGresult   *res;
13535                                         int                     i_srvname;
13536                                         int                     i_ftoptions;
13537
13538                                         reltypename = "FOREIGN TABLE";
13539
13540                                         /* retrieve name of foreign server and generic options */
13541                                         appendPQExpBuffer(query,
13542                                                                           "SELECT fs.srvname, "
13543                                                                           "pg_catalog.array_to_string(ARRAY("
13544                                                          "SELECT pg_catalog.quote_ident(option_name) || "
13545                                                          "' ' || pg_catalog.quote_literal(option_value) "
13546                                                         "FROM pg_catalog.pg_options_to_table(ftoptions) "
13547                                                                           "ORDER BY option_name"
13548                                                                           "), E',\n    ') AS ftoptions "
13549                                                                           "FROM pg_catalog.pg_foreign_table ft "
13550                                                                           "JOIN pg_catalog.pg_foreign_server fs "
13551                                                                           "ON (fs.oid = ft.ftserver) "
13552                                                                           "WHERE ft.ftrelid = '%u'",
13553                                                                           tbinfo->dobj.catId.oid);
13554                                         res = ExecuteSqlQueryForSingleRow(fout, query->data);
13555                                         i_srvname = PQfnumber(res, "srvname");
13556                                         i_ftoptions = PQfnumber(res, "ftoptions");
13557                                         srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
13558                                         ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
13559                                         PQclear(res);
13560                                         destroyPQExpBuffer(query);
13561                                         break;
13562                                 }
13563                         case (RELKIND_MATVIEW):
13564                                 reltypename = "MATERIALIZED VIEW";
13565                                 srvname = NULL;
13566                                 ftoptions = NULL;
13567                                 break;
13568                         default:
13569                                 reltypename = "TABLE";
13570                                 srvname = NULL;
13571                                 ftoptions = NULL;
13572                 }
13573
13574                 numParents = tbinfo->numParents;
13575                 parents = tbinfo->parents;
13576
13577                 /*
13578                  * DROP must be fully qualified in case same name appears in
13579                  * pg_catalog
13580                  */
13581                 appendPQExpBuffer(delq, "DROP %s %s.", reltypename,
13582                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
13583                 appendPQExpBuffer(delq, "%s;\n",
13584                                                   fmtId(tbinfo->dobj.name));
13585
13586                 appendPQExpBuffer(labelq, "%s %s", reltypename,
13587                                                   fmtId(tbinfo->dobj.name));
13588
13589                 if (dopt->binary_upgrade)
13590                         binary_upgrade_set_pg_class_oids(fout, q,
13591                                                                                          tbinfo->dobj.catId.oid, false);
13592
13593                 appendPQExpBuffer(q, "CREATE %s%s %s",
13594                                                   tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
13595                                                   "UNLOGGED " : "",
13596                                                   reltypename,
13597                                                   fmtId(tbinfo->dobj.name));
13598
13599                 /*
13600                  * Attach to type, if reloftype; except in case of a binary upgrade,
13601                  * we dump the table normally and attach it to the type afterward.
13602                  */
13603                 if (tbinfo->reloftype && !dopt->binary_upgrade)
13604                         appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
13605
13606                 if (tbinfo->relkind != RELKIND_MATVIEW)
13607                 {
13608                         /* Dump the attributes */
13609                         actual_atts = 0;
13610                         for (j = 0; j < tbinfo->numatts; j++)
13611                         {
13612                                 /*
13613                                  * Normally, dump if it's locally defined in this table, and
13614                                  * not dropped.  But for binary upgrade, we'll dump all the
13615                                  * columns, and then fix up the dropped and nonlocal cases
13616                                  * below.
13617                                  */
13618                                 if (shouldPrintColumn(dopt, tbinfo, j))
13619                                 {
13620                                         /*
13621                                          * Default value --- suppress if to be printed separately.
13622                                          */
13623                                         bool            has_default = (tbinfo->attrdefs[j] != NULL &&
13624                                                                                          !tbinfo->attrdefs[j]->separate);
13625
13626                                         /*
13627                                          * Not Null constraint --- suppress if inherited, except
13628                                          * in binary-upgrade case where that won't work.
13629                                          */
13630                                         bool            has_notnull = (tbinfo->notnull[j] &&
13631                                                                                            (!tbinfo->inhNotNull[j] ||
13632                                                                                                 dopt->binary_upgrade));
13633
13634                                         /* Skip column if fully defined by reloftype */
13635                                         if (tbinfo->reloftype &&
13636                                                 !has_default && !has_notnull && !dopt->binary_upgrade)
13637                                                 continue;
13638
13639                                         /* Format properly if not first attr */
13640                                         if (actual_atts == 0)
13641                                                 appendPQExpBufferStr(q, " (");
13642                                         else
13643                                                 appendPQExpBufferStr(q, ",");
13644                                         appendPQExpBufferStr(q, "\n    ");
13645                                         actual_atts++;
13646
13647                                         /* Attribute name */
13648                                         appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
13649
13650                                         if (tbinfo->attisdropped[j])
13651                                         {
13652                                                 /*
13653                                                  * ALTER TABLE DROP COLUMN clears
13654                                                  * pg_attribute.atttypid, so we will not have gotten a
13655                                                  * valid type name; insert INTEGER as a stopgap. We'll
13656                                                  * clean things up later.
13657                                                  */
13658                                                 appendPQExpBufferStr(q, " INTEGER /* dummy */");
13659                                                 /* Skip all the rest, too */
13660                                                 continue;
13661                                         }
13662
13663                                         /* Attribute type */
13664                                         if (tbinfo->reloftype && !dopt->binary_upgrade)
13665                                         {
13666                                                 appendPQExpBufferStr(q, " WITH OPTIONS");
13667                                         }
13668                                         else if (fout->remoteVersion >= 70100)
13669                                         {
13670                                                 appendPQExpBuffer(q, " %s",
13671                                                                                   tbinfo->atttypnames[j]);
13672                                         }
13673                                         else
13674                                         {
13675                                                 /* If no format_type, fake it */
13676                                                 appendPQExpBuffer(q, " %s",
13677                                                                                   myFormatType(tbinfo->atttypnames[j],
13678                                                                                                            tbinfo->atttypmod[j]));
13679                                         }
13680
13681                                         /* Add collation if not default for the type */
13682                                         if (OidIsValid(tbinfo->attcollation[j]))
13683                                         {
13684                                                 CollInfo   *coll;
13685
13686                                                 coll = findCollationByOid(tbinfo->attcollation[j]);
13687                                                 if (coll)
13688                                                 {
13689                                                         /* always schema-qualify, don't try to be smart */
13690                                                         appendPQExpBuffer(q, " COLLATE %s.",
13691                                                                          fmtId(coll->dobj.namespace->dobj.name));
13692                                                         appendPQExpBufferStr(q, fmtId(coll->dobj.name));
13693                                                 }
13694                                         }
13695
13696                                         if (has_default)
13697                                                 appendPQExpBuffer(q, " DEFAULT %s",
13698                                                                                   tbinfo->attrdefs[j]->adef_expr);
13699
13700                                         if (has_notnull)
13701                                                 appendPQExpBufferStr(q, " NOT NULL");
13702                                 }
13703                         }
13704
13705                         /*
13706                          * Add non-inherited CHECK constraints, if any.
13707                          */
13708                         for (j = 0; j < tbinfo->ncheck; j++)
13709                         {
13710                                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
13711
13712                                 if (constr->separate || !constr->conislocal)
13713                                         continue;
13714
13715                                 if (actual_atts == 0)
13716                                         appendPQExpBufferStr(q, " (\n    ");
13717                                 else
13718                                         appendPQExpBufferStr(q, ",\n    ");
13719
13720                                 appendPQExpBuffer(q, "CONSTRAINT %s ",
13721                                                                   fmtId(constr->dobj.name));
13722                                 appendPQExpBufferStr(q, constr->condef);
13723
13724                                 actual_atts++;
13725                         }
13726
13727                         if (actual_atts)
13728                                 appendPQExpBufferStr(q, "\n)");
13729                         else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
13730                         {
13731                                 /*
13732                                  * We must have a parenthesized attribute list, even though
13733                                  * empty, when not using the OF TYPE syntax.
13734                                  */
13735                                 appendPQExpBufferStr(q, " (\n)");
13736                         }
13737
13738                         if (numParents > 0 && !dopt->binary_upgrade)
13739                         {
13740                                 appendPQExpBufferStr(q, "\nINHERITS (");
13741                                 for (k = 0; k < numParents; k++)
13742                                 {
13743                                         TableInfo  *parentRel = parents[k];
13744
13745                                         if (k > 0)
13746                                                 appendPQExpBufferStr(q, ", ");
13747                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13748                                                 appendPQExpBuffer(q, "%s.",
13749                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13750                                         appendPQExpBufferStr(q, fmtId(parentRel->dobj.name));
13751                                 }
13752                                 appendPQExpBufferChar(q, ')');
13753                         }
13754
13755                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
13756                                 appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
13757                 }
13758
13759                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
13760                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
13761                 {
13762                         bool            addcomma = false;
13763
13764                         appendPQExpBufferStr(q, "\nWITH (");
13765                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
13766                         {
13767                                 addcomma = true;
13768                                 appendPQExpBufferStr(q, tbinfo->reloptions);
13769                         }
13770                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
13771                         {
13772                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
13773                                                                   tbinfo->toast_reloptions);
13774                         }
13775                         appendPQExpBufferChar(q, ')');
13776                 }
13777
13778                 /* Dump generic options if any */
13779                 if (ftoptions && ftoptions[0])
13780                         appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
13781
13782                 /*
13783                  * For materialized views, create the AS clause just like a view. At
13784                  * this point, we always mark the view as not populated.
13785                  */
13786                 if (tbinfo->relkind == RELKIND_MATVIEW)
13787                 {
13788                         PQExpBuffer result;
13789
13790                         result = createViewAsClause(fout, tbinfo);
13791                         appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
13792                                                           result->data);
13793                         destroyPQExpBuffer(result);
13794                 }
13795                 else
13796                         appendPQExpBufferStr(q, ";\n");
13797
13798                 /*
13799                  * To create binary-compatible heap files, we have to ensure the same
13800                  * physical column order, including dropped columns, as in the
13801                  * original.  Therefore, we create dropped columns above and drop them
13802                  * here, also updating their attlen/attalign values so that the
13803                  * dropped column can be skipped properly.  (We do not bother with
13804                  * restoring the original attbyval setting.)  Also, inheritance
13805                  * relationships are set up by doing ALTER INHERIT rather than using
13806                  * an INHERITS clause --- the latter would possibly mess up the column
13807                  * order.  That also means we have to take care about setting
13808                  * attislocal correctly, plus fix up any inherited CHECK constraints.
13809                  * Analogously, we set up typed tables using ALTER TABLE / OF here.
13810                  */
13811                 if (dopt->binary_upgrade && (tbinfo->relkind == RELKIND_RELATION ||
13812                                                                    tbinfo->relkind == RELKIND_FOREIGN_TABLE))
13813                 {
13814                         for (j = 0; j < tbinfo->numatts; j++)
13815                         {
13816                                 if (tbinfo->attisdropped[j])
13817                                 {
13818                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
13819                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
13820                                                                           "SET attlen = %d, "
13821                                                                           "attalign = '%c', attbyval = false\n"
13822                                                                           "WHERE attname = ",
13823                                                                           tbinfo->attlen[j],
13824                                                                           tbinfo->attalign[j]);
13825                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13826                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13827                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13828                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13829
13830                                         if (tbinfo->relkind == RELKIND_RELATION)
13831                                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13832                                                                                   fmtId(tbinfo->dobj.name));
13833                                         else
13834                                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
13835                                                                                   fmtId(tbinfo->dobj.name));
13836
13837                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
13838                                                                           fmtId(tbinfo->attnames[j]));
13839                                 }
13840                                 else if (!tbinfo->attislocal[j])
13841                                 {
13842                                         Assert(tbinfo->relkind != RELKIND_FOREIGN_TABLE);
13843                                         appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
13844                                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
13845                                                                                  "SET attislocal = false\n"
13846                                                                                  "WHERE attname = ");
13847                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
13848                                         appendPQExpBufferStr(q, "\n  AND attrelid = ");
13849                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13850                                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13851                                 }
13852                         }
13853
13854                         for (k = 0; k < tbinfo->ncheck; k++)
13855                         {
13856                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
13857
13858                                 if (constr->separate || constr->conislocal)
13859                                         continue;
13860
13861                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
13862                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13863                                                                   fmtId(tbinfo->dobj.name));
13864                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
13865                                                                   fmtId(constr->dobj.name));
13866                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
13867                                 appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
13868                                                                          "SET conislocal = false\n"
13869                                                                          "WHERE contype = 'c' AND conname = ");
13870                                 appendStringLiteralAH(q, constr->dobj.name, fout);
13871                                 appendPQExpBufferStr(q, "\n  AND conrelid = ");
13872                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13873                                 appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13874                         }
13875
13876                         if (numParents > 0)
13877                         {
13878                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
13879                                 for (k = 0; k < numParents; k++)
13880                                 {
13881                                         TableInfo  *parentRel = parents[k];
13882
13883                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
13884                                                                           fmtId(tbinfo->dobj.name));
13885                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
13886                                                 appendPQExpBuffer(q, "%s.",
13887                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
13888                                         appendPQExpBuffer(q, "%s;\n",
13889                                                                           fmtId(parentRel->dobj.name));
13890                                 }
13891                         }
13892
13893                         if (tbinfo->reloftype)
13894                         {
13895                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
13896                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
13897                                                                   fmtId(tbinfo->dobj.name),
13898                                                                   tbinfo->reloftype);
13899                         }
13900
13901                         appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
13902                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13903                                                           "SET relfrozenxid = '%u', relminmxid = '%u'\n"
13904                                                           "WHERE oid = ",
13905                                                           tbinfo->frozenxid, tbinfo->minmxid);
13906                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13907                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13908
13909                         if (tbinfo->toast_oid)
13910                         {
13911                                 /* We preserve the toast oids, so we can use it during restore */
13912                                 appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
13913                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
13914                                                            "SET relfrozenxid = '%u', relminmxid = '%u'\n"
13915                                                                   "WHERE oid = '%u';\n",
13916                                                                   tbinfo->toast_frozenxid,
13917                                                                   tbinfo->toast_minmxid, tbinfo->toast_oid);
13918                         }
13919                 }
13920
13921                 /*
13922                  * In binary_upgrade mode, restore matviews' populated status by
13923                  * poking pg_class directly.  This is pretty ugly, but we can't use
13924                  * REFRESH MATERIALIZED VIEW since it's possible that some underlying
13925                  * matview is not populated even though this matview is.
13926                  */
13927                 if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
13928                         tbinfo->relispopulated)
13929                 {
13930                         appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
13931                         appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
13932                                                                  "SET relispopulated = 't'\n"
13933                                                                  "WHERE oid = ");
13934                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
13935                         appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
13936                 }
13937
13938                 /*
13939                  * Dump additional per-column properties that we can't handle in the
13940                  * main CREATE TABLE command.
13941                  */
13942                 for (j = 0; j < tbinfo->numatts; j++)
13943                 {
13944                         /* None of this applies to dropped columns */
13945                         if (tbinfo->attisdropped[j])
13946                                 continue;
13947
13948                         /*
13949                          * If we didn't dump the column definition explicitly above, and
13950                          * it is NOT NULL and did not inherit that property from a parent,
13951                          * we have to mark it separately.
13952                          */
13953                         if (!shouldPrintColumn(dopt, tbinfo, j) &&
13954                                 tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
13955                         {
13956                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13957                                                                   fmtId(tbinfo->dobj.name));
13958                                 appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
13959                                                                   fmtId(tbinfo->attnames[j]));
13960                         }
13961
13962                         /*
13963                          * Dump per-column statistics information. We only issue an ALTER
13964                          * TABLE statement if the attstattarget entry for this column is
13965                          * non-negative (i.e. it's not the default value)
13966                          */
13967                         if (tbinfo->attstattarget[j] >= 0)
13968                         {
13969                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
13970                                                                   fmtId(tbinfo->dobj.name));
13971                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
13972                                                                   fmtId(tbinfo->attnames[j]));
13973                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
13974                                                                   tbinfo->attstattarget[j]);
13975                         }
13976
13977                         /*
13978                          * Dump per-column storage information.  The statement is only
13979                          * dumped if the storage has been changed from the type's default.
13980                          */
13981                         if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
13982                         {
13983                                 switch (tbinfo->attstorage[j])
13984                                 {
13985                                         case 'p':
13986                                                 storage = "PLAIN";
13987                                                 break;
13988                                         case 'e':
13989                                                 storage = "EXTERNAL";
13990                                                 break;
13991                                         case 'm':
13992                                                 storage = "MAIN";
13993                                                 break;
13994                                         case 'x':
13995                                                 storage = "EXTENDED";
13996                                                 break;
13997                                         default:
13998                                                 storage = NULL;
13999                                 }
14000
14001                                 /*
14002                                  * Only dump the statement if it's a storage type we recognize
14003                                  */
14004                                 if (storage != NULL)
14005                                 {
14006                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
14007                                                                           fmtId(tbinfo->dobj.name));
14008                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
14009                                                                           fmtId(tbinfo->attnames[j]));
14010                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
14011                                                                           storage);
14012                                 }
14013                         }
14014
14015                         /*
14016                          * Dump per-column attributes.
14017                          */
14018                         if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
14019                         {
14020                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
14021                                                                   fmtId(tbinfo->dobj.name));
14022                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
14023                                                                   fmtId(tbinfo->attnames[j]));
14024                                 appendPQExpBuffer(q, "SET (%s);\n",
14025                                                                   tbinfo->attoptions[j]);
14026                         }
14027
14028                         /*
14029                          * Dump per-column fdw options.
14030                          */
14031                         if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
14032                                 tbinfo->attfdwoptions[j] &&
14033                                 tbinfo->attfdwoptions[j][0] != '\0')
14034                         {
14035                                 appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
14036                                                                   fmtId(tbinfo->dobj.name));
14037                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
14038                                                                   fmtId(tbinfo->attnames[j]));
14039                                 appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
14040                                                                   tbinfo->attfdwoptions[j]);
14041                         }
14042                 }
14043         }
14044
14045         /*
14046          * dump properties we only have ALTER TABLE syntax for
14047          */
14048         if ((tbinfo->relkind == RELKIND_RELATION || tbinfo->relkind == RELKIND_MATVIEW) &&
14049                 tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
14050         {
14051                 if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
14052                 {
14053                         /* nothing to do, will be set when the index is dumped */
14054                 }
14055                 else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
14056                 {
14057                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
14058                                                           fmtId(tbinfo->dobj.name));
14059                 }
14060                 else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
14061                 {
14062                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
14063                                                           fmtId(tbinfo->dobj.name));
14064                 }
14065         }
14066
14067         if (dopt->binary_upgrade)
14068                 binary_upgrade_extension_member(q, &tbinfo->dobj, labelq->data);
14069
14070         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14071                                  tbinfo->dobj.name,
14072                                  tbinfo->dobj.namespace->dobj.name,
14073                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
14074                                  tbinfo->rolname,
14075                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
14076                                  reltypename,
14077                                  tbinfo->postponed_def ? SECTION_POST_DATA : SECTION_PRE_DATA,
14078                                  q->data, delq->data, NULL,
14079                                  NULL, 0,
14080                                  NULL, NULL);
14081
14082
14083         /* Dump Table Comments */
14084         dumpTableComment(fout, dopt, tbinfo, reltypename);
14085
14086         /* Dump Table Security Labels */
14087         dumpTableSecLabel(fout, dopt, tbinfo, reltypename);
14088
14089         /* Dump comments on inlined table constraints */
14090         for (j = 0; j < tbinfo->ncheck; j++)
14091         {
14092                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
14093
14094                 if (constr->separate || !constr->conislocal)
14095                         continue;
14096
14097                 dumpTableConstraintComment(fout, dopt, constr);
14098         }
14099
14100         destroyPQExpBuffer(q);
14101         destroyPQExpBuffer(delq);
14102         destroyPQExpBuffer(labelq);
14103 }
14104
14105 /*
14106  * dumpAttrDef --- dump an attribute's default-value declaration
14107  */
14108 static void
14109 dumpAttrDef(Archive *fout, DumpOptions *dopt, AttrDefInfo *adinfo)
14110 {
14111         TableInfo  *tbinfo = adinfo->adtable;
14112         int                     adnum = adinfo->adnum;
14113         PQExpBuffer q;
14114         PQExpBuffer delq;
14115
14116         /* Skip if table definition not to be dumped */
14117         if (!tbinfo->dobj.dump || dopt->dataOnly)
14118                 return;
14119
14120         /* Skip if not "separate"; it was dumped in the table's definition */
14121         if (!adinfo->separate)
14122                 return;
14123
14124         q = createPQExpBuffer();
14125         delq = createPQExpBuffer();
14126
14127         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
14128                                           fmtId(tbinfo->dobj.name));
14129         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
14130                                           fmtId(tbinfo->attnames[adnum - 1]),
14131                                           adinfo->adef_expr);
14132
14133         /*
14134          * DROP must be fully qualified in case same name appears in pg_catalog
14135          */
14136         appendPQExpBuffer(delq, "ALTER TABLE %s.",
14137                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14138         appendPQExpBuffer(delq, "%s ",
14139                                           fmtId(tbinfo->dobj.name));
14140         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
14141                                           fmtId(tbinfo->attnames[adnum - 1]));
14142
14143         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
14144                                  tbinfo->attnames[adnum - 1],
14145                                  tbinfo->dobj.namespace->dobj.name,
14146                                  NULL,
14147                                  tbinfo->rolname,
14148                                  false, "DEFAULT", SECTION_PRE_DATA,
14149                                  q->data, delq->data, NULL,
14150                                  NULL, 0,
14151                                  NULL, NULL);
14152
14153         destroyPQExpBuffer(q);
14154         destroyPQExpBuffer(delq);
14155 }
14156
14157 /*
14158  * getAttrName: extract the correct name for an attribute
14159  *
14160  * The array tblInfo->attnames[] only provides names of user attributes;
14161  * if a system attribute number is supplied, we have to fake it.
14162  * We also do a little bit of bounds checking for safety's sake.
14163  */
14164 static const char *
14165 getAttrName(int attrnum, TableInfo *tblInfo)
14166 {
14167         if (attrnum > 0 && attrnum <= tblInfo->numatts)
14168                 return tblInfo->attnames[attrnum - 1];
14169         switch (attrnum)
14170         {
14171                 case SelfItemPointerAttributeNumber:
14172                         return "ctid";
14173                 case ObjectIdAttributeNumber:
14174                         return "oid";
14175                 case MinTransactionIdAttributeNumber:
14176                         return "xmin";
14177                 case MinCommandIdAttributeNumber:
14178                         return "cmin";
14179                 case MaxTransactionIdAttributeNumber:
14180                         return "xmax";
14181                 case MaxCommandIdAttributeNumber:
14182                         return "cmax";
14183                 case TableOidAttributeNumber:
14184                         return "tableoid";
14185         }
14186         exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
14187                                   attrnum, tblInfo->dobj.name);
14188         return NULL;                            /* keep compiler quiet */
14189 }
14190
14191 /*
14192  * dumpIndex
14193  *        write out to fout a user-defined index
14194  */
14195 static void
14196 dumpIndex(Archive *fout, DumpOptions *dopt, IndxInfo *indxinfo)
14197 {
14198         TableInfo  *tbinfo = indxinfo->indextable;
14199         bool            is_constraint = (indxinfo->indexconstraint != 0);
14200         PQExpBuffer q;
14201         PQExpBuffer delq;
14202         PQExpBuffer labelq;
14203
14204         if (dopt->dataOnly)
14205                 return;
14206
14207         q = createPQExpBuffer();
14208         delq = createPQExpBuffer();
14209         labelq = createPQExpBuffer();
14210
14211         appendPQExpBuffer(labelq, "INDEX %s",
14212                                           fmtId(indxinfo->dobj.name));
14213
14214         /*
14215          * If there's an associated constraint, don't dump the index per se, but
14216          * do dump any comment for it.  (This is safe because dependency ordering
14217          * will have ensured the constraint is emitted first.)  Note that the
14218          * emitted comment has to be shown as depending on the constraint, not the
14219          * index, in such cases.
14220          */
14221         if (!is_constraint)
14222         {
14223                 if (dopt->binary_upgrade)
14224                         binary_upgrade_set_pg_class_oids(fout, q,
14225                                                                                          indxinfo->dobj.catId.oid, true);
14226
14227                 /* Plain secondary index */
14228                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
14229
14230                 /* If the index is clustered, we need to record that. */
14231                 if (indxinfo->indisclustered)
14232                 {
14233                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
14234                                                           fmtId(tbinfo->dobj.name));
14235                         appendPQExpBuffer(q, " ON %s;\n",
14236                                                           fmtId(indxinfo->dobj.name));
14237                 }
14238
14239                 /* If the index defines identity, we need to record that. */
14240                 if (indxinfo->indisreplident)
14241                 {
14242                         appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
14243                                                           fmtId(tbinfo->dobj.name));
14244                         appendPQExpBuffer(q, " INDEX %s;\n",
14245                                                           fmtId(indxinfo->dobj.name));
14246                 }
14247
14248                 /*
14249                  * DROP must be fully qualified in case same name appears in
14250                  * pg_catalog
14251                  */
14252                 appendPQExpBuffer(delq, "DROP INDEX %s.",
14253                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
14254                 appendPQExpBuffer(delq, "%s;\n",
14255                                                   fmtId(indxinfo->dobj.name));
14256
14257                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
14258                                          indxinfo->dobj.name,
14259                                          tbinfo->dobj.namespace->dobj.name,
14260                                          indxinfo->tablespace,
14261                                          tbinfo->rolname, false,
14262                                          "INDEX", SECTION_POST_DATA,
14263                                          q->data, delq->data, NULL,
14264                                          NULL, 0,
14265                                          NULL, NULL);
14266         }
14267
14268         /* Dump Index Comments */
14269         dumpComment(fout, dopt, labelq->data,
14270                                 tbinfo->dobj.namespace->dobj.name,
14271                                 tbinfo->rolname,
14272                                 indxinfo->dobj.catId, 0,
14273                                 is_constraint ? indxinfo->indexconstraint :
14274                                 indxinfo->dobj.dumpId);
14275
14276         destroyPQExpBuffer(q);
14277         destroyPQExpBuffer(delq);
14278         destroyPQExpBuffer(labelq);
14279 }
14280
14281 /*
14282  * dumpConstraint
14283  *        write out to fout a user-defined constraint
14284  */
14285 static void
14286 dumpConstraint(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo)
14287 {
14288         TableInfo  *tbinfo = coninfo->contable;
14289         PQExpBuffer q;
14290         PQExpBuffer delq;
14291
14292         /* Skip if not to be dumped */
14293         if (!coninfo->dobj.dump || dopt->dataOnly)
14294                 return;
14295
14296         q = createPQExpBuffer();
14297         delq = createPQExpBuffer();
14298
14299         if (coninfo->contype == 'p' ||
14300                 coninfo->contype == 'u' ||
14301                 coninfo->contype == 'x')
14302         {
14303                 /* Index-related constraint */
14304                 IndxInfo   *indxinfo;
14305                 int                     k;
14306
14307                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
14308
14309                 if (indxinfo == NULL)
14310                         exit_horribly(NULL, "missing index for constraint \"%s\"\n",
14311                                                   coninfo->dobj.name);
14312
14313                 if (dopt->binary_upgrade)
14314                         binary_upgrade_set_pg_class_oids(fout, q,
14315                                                                                          indxinfo->dobj.catId.oid, true);
14316
14317                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
14318                                                   fmtId(tbinfo->dobj.name));
14319                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
14320                                                   fmtId(coninfo->dobj.name));
14321
14322                 if (coninfo->condef)
14323                 {
14324                         /* pg_get_constraintdef should have provided everything */
14325                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
14326                 }
14327                 else
14328                 {
14329                         appendPQExpBuffer(q, "%s (",
14330                                                  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
14331                         for (k = 0; k < indxinfo->indnkeys; k++)
14332                         {
14333                                 int                     indkey = (int) indxinfo->indkeys[k];
14334                                 const char *attname;
14335
14336                                 if (indkey == InvalidAttrNumber)
14337                                         break;
14338                                 attname = getAttrName(indkey, tbinfo);
14339
14340                                 appendPQExpBuffer(q, "%s%s",
14341                                                                   (k == 0) ? "" : ", ",
14342                                                                   fmtId(attname));
14343                         }
14344
14345                         appendPQExpBufferChar(q, ')');
14346
14347                         if (indxinfo->options && strlen(indxinfo->options) > 0)
14348                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
14349
14350                         if (coninfo->condeferrable)
14351                         {
14352                                 appendPQExpBufferStr(q, " DEFERRABLE");
14353                                 if (coninfo->condeferred)
14354                                         appendPQExpBufferStr(q, " INITIALLY DEFERRED");
14355                         }
14356
14357                         appendPQExpBufferStr(q, ";\n");
14358                 }
14359
14360                 /* If the index is clustered, we need to record that. */
14361                 if (indxinfo->indisclustered)
14362                 {
14363                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
14364                                                           fmtId(tbinfo->dobj.name));
14365                         appendPQExpBuffer(q, " ON %s;\n",
14366                                                           fmtId(indxinfo->dobj.name));
14367                 }
14368
14369                 /*
14370                  * DROP must be fully qualified in case same name appears in
14371                  * pg_catalog
14372                  */
14373                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
14374                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
14375                 appendPQExpBuffer(delq, "%s ",
14376                                                   fmtId(tbinfo->dobj.name));
14377                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14378                                                   fmtId(coninfo->dobj.name));
14379
14380                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14381                                          coninfo->dobj.name,
14382                                          tbinfo->dobj.namespace->dobj.name,
14383                                          indxinfo->tablespace,
14384                                          tbinfo->rolname, false,
14385                                          "CONSTRAINT", SECTION_POST_DATA,
14386                                          q->data, delq->data, NULL,
14387                                          NULL, 0,
14388                                          NULL, NULL);
14389         }
14390         else if (coninfo->contype == 'f')
14391         {
14392                 /*
14393                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
14394                  * current table data is not processed
14395                  */
14396                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
14397                                                   fmtId(tbinfo->dobj.name));
14398                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14399                                                   fmtId(coninfo->dobj.name),
14400                                                   coninfo->condef);
14401
14402                 /*
14403                  * DROP must be fully qualified in case same name appears in
14404                  * pg_catalog
14405                  */
14406                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
14407                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
14408                 appendPQExpBuffer(delq, "%s ",
14409                                                   fmtId(tbinfo->dobj.name));
14410                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14411                                                   fmtId(coninfo->dobj.name));
14412
14413                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14414                                          coninfo->dobj.name,
14415                                          tbinfo->dobj.namespace->dobj.name,
14416                                          NULL,
14417                                          tbinfo->rolname, false,
14418                                          "FK CONSTRAINT", SECTION_POST_DATA,
14419                                          q->data, delq->data, NULL,
14420                                          NULL, 0,
14421                                          NULL, NULL);
14422         }
14423         else if (coninfo->contype == 'c' && tbinfo)
14424         {
14425                 /* CHECK constraint on a table */
14426
14427                 /* Ignore if not to be dumped separately */
14428                 if (coninfo->separate)
14429                 {
14430                         /* not ONLY since we want it to propagate to children */
14431                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
14432                                                           fmtId(tbinfo->dobj.name));
14433                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14434                                                           fmtId(coninfo->dobj.name),
14435                                                           coninfo->condef);
14436
14437                         /*
14438                          * DROP must be fully qualified in case same name appears in
14439                          * pg_catalog
14440                          */
14441                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
14442                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14443                         appendPQExpBuffer(delq, "%s ",
14444                                                           fmtId(tbinfo->dobj.name));
14445                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14446                                                           fmtId(coninfo->dobj.name));
14447
14448                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14449                                                  coninfo->dobj.name,
14450                                                  tbinfo->dobj.namespace->dobj.name,
14451                                                  NULL,
14452                                                  tbinfo->rolname, false,
14453                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
14454                                                  q->data, delq->data, NULL,
14455                                                  NULL, 0,
14456                                                  NULL, NULL);
14457                 }
14458         }
14459         else if (coninfo->contype == 'c' && tbinfo == NULL)
14460         {
14461                 /* CHECK constraint on a domain */
14462                 TypeInfo   *tyinfo = coninfo->condomain;
14463
14464                 /* Ignore if not to be dumped separately */
14465                 if (coninfo->separate)
14466                 {
14467                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
14468                                                           fmtId(tyinfo->dobj.name));
14469                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
14470                                                           fmtId(coninfo->dobj.name),
14471                                                           coninfo->condef);
14472
14473                         /*
14474                          * DROP must be fully qualified in case same name appears in
14475                          * pg_catalog
14476                          */
14477                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
14478                                                           fmtId(tyinfo->dobj.namespace->dobj.name));
14479                         appendPQExpBuffer(delq, "%s ",
14480                                                           fmtId(tyinfo->dobj.name));
14481                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
14482                                                           fmtId(coninfo->dobj.name));
14483
14484                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
14485                                                  coninfo->dobj.name,
14486                                                  tyinfo->dobj.namespace->dobj.name,
14487                                                  NULL,
14488                                                  tyinfo->rolname, false,
14489                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
14490                                                  q->data, delq->data, NULL,
14491                                                  NULL, 0,
14492                                                  NULL, NULL);
14493                 }
14494         }
14495         else
14496         {
14497                 exit_horribly(NULL, "unrecognized constraint type: %c\n",
14498                                           coninfo->contype);
14499         }
14500
14501         /* Dump Constraint Comments --- only works for table constraints */
14502         if (tbinfo && coninfo->separate)
14503                 dumpTableConstraintComment(fout, dopt, coninfo);
14504
14505         destroyPQExpBuffer(q);
14506         destroyPQExpBuffer(delq);
14507 }
14508
14509 /*
14510  * dumpTableConstraintComment --- dump a constraint's comment if any
14511  *
14512  * This is split out because we need the function in two different places
14513  * depending on whether the constraint is dumped as part of CREATE TABLE
14514  * or as a separate ALTER command.
14515  */
14516 static void
14517 dumpTableConstraintComment(Archive *fout, DumpOptions *dopt, ConstraintInfo *coninfo)
14518 {
14519         TableInfo  *tbinfo = coninfo->contable;
14520         PQExpBuffer labelq = createPQExpBuffer();
14521
14522         appendPQExpBuffer(labelq, "CONSTRAINT %s ",
14523                                           fmtId(coninfo->dobj.name));
14524         appendPQExpBuffer(labelq, "ON %s",
14525                                           fmtId(tbinfo->dobj.name));
14526         dumpComment(fout, dopt, labelq->data,
14527                                 tbinfo->dobj.namespace->dobj.name,
14528                                 tbinfo->rolname,
14529                                 coninfo->dobj.catId, 0,
14530                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
14531
14532         destroyPQExpBuffer(labelq);
14533 }
14534
14535 /*
14536  * findLastBuiltInOid -
14537  * find the last built in oid
14538  *
14539  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
14540  * pg_database entry for the current database
14541  */
14542 static Oid
14543 findLastBuiltinOid_V71(Archive *fout, const char *dbname)
14544 {
14545         PGresult   *res;
14546         Oid                     last_oid;
14547         PQExpBuffer query = createPQExpBuffer();
14548
14549         resetPQExpBuffer(query);
14550         appendPQExpBufferStr(query, "SELECT datlastsysoid from pg_database where datname = ");
14551         appendStringLiteralAH(query, dbname, fout);
14552
14553         res = ExecuteSqlQueryForSingleRow(fout, query->data);
14554         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
14555         PQclear(res);
14556         destroyPQExpBuffer(query);
14557         return last_oid;
14558 }
14559
14560 /*
14561  * findLastBuiltInOid -
14562  * find the last built in oid
14563  *
14564  * For 7.0, we do this by assuming that the last thing that initdb does is to
14565  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
14566  * initdb won't be changing anymore, it'll do.
14567  */
14568 static Oid
14569 findLastBuiltinOid_V70(Archive *fout)
14570 {
14571         PGresult   *res;
14572         int                     last_oid;
14573
14574         res = ExecuteSqlQueryForSingleRow(fout,
14575                                         "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
14576         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
14577         PQclear(res);
14578         return last_oid;
14579 }
14580
14581 /*
14582  * dumpSequence
14583  *        write the declaration (not data) of one user-defined sequence
14584  */
14585 static void
14586 dumpSequence(Archive *fout, DumpOptions *dopt, TableInfo *tbinfo)
14587 {
14588         PGresult   *res;
14589         char       *startv,
14590                            *incby,
14591                            *maxv = NULL,
14592                            *minv = NULL,
14593                            *cache;
14594         char            bufm[100],
14595                                 bufx[100];
14596         bool            cycled;
14597         PQExpBuffer query = createPQExpBuffer();
14598         PQExpBuffer delqry = createPQExpBuffer();
14599         PQExpBuffer labelq = createPQExpBuffer();
14600
14601         /* Make sure we are in proper schema */
14602         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14603
14604         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
14605         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
14606
14607         if (fout->remoteVersion >= 80400)
14608         {
14609                 appendPQExpBuffer(query,
14610                                                   "SELECT sequence_name, "
14611                                                   "start_value, increment_by, "
14612                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14613                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14614                                                   "     ELSE max_value "
14615                                                   "END AS max_value, "
14616                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14617                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14618                                                   "     ELSE min_value "
14619                                                   "END AS min_value, "
14620                                                   "cache_value, is_cycled FROM %s",
14621                                                   bufx, bufm,
14622                                                   fmtId(tbinfo->dobj.name));
14623         }
14624         else
14625         {
14626                 appendPQExpBuffer(query,
14627                                                   "SELECT sequence_name, "
14628                                                   "0 AS start_value, increment_by, "
14629                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
14630                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
14631                                                   "     ELSE max_value "
14632                                                   "END AS max_value, "
14633                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
14634                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
14635                                                   "     ELSE min_value "
14636                                                   "END AS min_value, "
14637                                                   "cache_value, is_cycled FROM %s",
14638                                                   bufx, bufm,
14639                                                   fmtId(tbinfo->dobj.name));
14640         }
14641
14642         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14643
14644         if (PQntuples(res) != 1)
14645         {
14646                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14647                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14648                                                                  PQntuples(res)),
14649                                   tbinfo->dobj.name, PQntuples(res));
14650                 exit_nicely(1);
14651         }
14652
14653         /* Disable this check: it fails if sequence has been renamed */
14654 #ifdef NOT_USED
14655         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
14656         {
14657                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
14658                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
14659                 exit_nicely(1);
14660         }
14661 #endif
14662
14663         startv = PQgetvalue(res, 0, 1);
14664         incby = PQgetvalue(res, 0, 2);
14665         if (!PQgetisnull(res, 0, 3))
14666                 maxv = PQgetvalue(res, 0, 3);
14667         if (!PQgetisnull(res, 0, 4))
14668                 minv = PQgetvalue(res, 0, 4);
14669         cache = PQgetvalue(res, 0, 5);
14670         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
14671
14672         /*
14673          * DROP must be fully qualified in case same name appears in pg_catalog
14674          */
14675         appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
14676                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14677         appendPQExpBuffer(delqry, "%s;\n",
14678                                           fmtId(tbinfo->dobj.name));
14679
14680         resetPQExpBuffer(query);
14681
14682         if (dopt->binary_upgrade)
14683         {
14684                 binary_upgrade_set_pg_class_oids(fout, query,
14685                                                                                  tbinfo->dobj.catId.oid, false);
14686                 binary_upgrade_set_type_oids_by_rel_oid(fout, query,
14687                                                                                                 tbinfo->dobj.catId.oid);
14688         }
14689
14690         appendPQExpBuffer(query,
14691                                           "CREATE SEQUENCE %s\n",
14692                                           fmtId(tbinfo->dobj.name));
14693
14694         if (fout->remoteVersion >= 80400)
14695                 appendPQExpBuffer(query, "    START WITH %s\n", startv);
14696
14697         appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
14698
14699         if (minv)
14700                 appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
14701         else
14702                 appendPQExpBufferStr(query, "    NO MINVALUE\n");
14703
14704         if (maxv)
14705                 appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
14706         else
14707                 appendPQExpBufferStr(query, "    NO MAXVALUE\n");
14708
14709         appendPQExpBuffer(query,
14710                                           "    CACHE %s%s",
14711                                           cache, (cycled ? "\n    CYCLE" : ""));
14712
14713         appendPQExpBufferStr(query, ";\n");
14714
14715         appendPQExpBuffer(labelq, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
14716
14717         /* binary_upgrade:      no need to clear TOAST table oid */
14718
14719         if (dopt->binary_upgrade)
14720                 binary_upgrade_extension_member(query, &tbinfo->dobj,
14721                                                                                 labelq->data);
14722
14723         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
14724                                  tbinfo->dobj.name,
14725                                  tbinfo->dobj.namespace->dobj.name,
14726                                  NULL,
14727                                  tbinfo->rolname,
14728                                  false, "SEQUENCE", SECTION_PRE_DATA,
14729                                  query->data, delqry->data, NULL,
14730                                  NULL, 0,
14731                                  NULL, NULL);
14732
14733         /*
14734          * If the sequence is owned by a table column, emit the ALTER for it as a
14735          * separate TOC entry immediately following the sequence's own entry. It's
14736          * OK to do this rather than using full sorting logic, because the
14737          * dependency that tells us it's owned will have forced the table to be
14738          * created first.  We can't just include the ALTER in the TOC entry
14739          * because it will fail if we haven't reassigned the sequence owner to
14740          * match the table's owner.
14741          *
14742          * We need not schema-qualify the table reference because both sequence
14743          * and table must be in the same schema.
14744          */
14745         if (OidIsValid(tbinfo->owning_tab))
14746         {
14747                 TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
14748
14749                 if (owning_tab && owning_tab->dobj.dump)
14750                 {
14751                         resetPQExpBuffer(query);
14752                         appendPQExpBuffer(query, "ALTER SEQUENCE %s",
14753                                                           fmtId(tbinfo->dobj.name));
14754                         appendPQExpBuffer(query, " OWNED BY %s",
14755                                                           fmtId(owning_tab->dobj.name));
14756                         appendPQExpBuffer(query, ".%s;\n",
14757                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
14758
14759                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14760                                                  tbinfo->dobj.name,
14761                                                  tbinfo->dobj.namespace->dobj.name,
14762                                                  NULL,
14763                                                  tbinfo->rolname,
14764                                                  false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
14765                                                  query->data, "", NULL,
14766                                                  &(tbinfo->dobj.dumpId), 1,
14767                                                  NULL, NULL);
14768                 }
14769         }
14770
14771         /* Dump Sequence Comments and Security Labels */
14772         dumpComment(fout, dopt, labelq->data,
14773                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14774                                 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14775         dumpSecLabel(fout, dopt, labelq->data,
14776                                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
14777                                  tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
14778
14779         PQclear(res);
14780
14781         destroyPQExpBuffer(query);
14782         destroyPQExpBuffer(delqry);
14783         destroyPQExpBuffer(labelq);
14784 }
14785
14786 /*
14787  * dumpSequenceData
14788  *        write the data of one user-defined sequence
14789  */
14790 static void
14791 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
14792 {
14793         TableInfo  *tbinfo = tdinfo->tdtable;
14794         PGresult   *res;
14795         char       *last;
14796         bool            called;
14797         PQExpBuffer query = createPQExpBuffer();
14798
14799         /* Make sure we are in proper schema */
14800         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
14801
14802         appendPQExpBuffer(query,
14803                                           "SELECT last_value, is_called FROM %s",
14804                                           fmtId(tbinfo->dobj.name));
14805
14806         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14807
14808         if (PQntuples(res) != 1)
14809         {
14810                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
14811                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
14812                                                                  PQntuples(res)),
14813                                   tbinfo->dobj.name, PQntuples(res));
14814                 exit_nicely(1);
14815         }
14816
14817         last = PQgetvalue(res, 0, 0);
14818         called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
14819
14820         resetPQExpBuffer(query);
14821         appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
14822         appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
14823         appendPQExpBuffer(query, ", %s, %s);\n",
14824                                           last, (called ? "true" : "false"));
14825
14826         ArchiveEntry(fout, nilCatalogId, createDumpId(),
14827                                  tbinfo->dobj.name,
14828                                  tbinfo->dobj.namespace->dobj.name,
14829                                  NULL,
14830                                  tbinfo->rolname,
14831                                  false, "SEQUENCE SET", SECTION_DATA,
14832                                  query->data, "", NULL,
14833                                  &(tbinfo->dobj.dumpId), 1,
14834                                  NULL, NULL);
14835
14836         PQclear(res);
14837
14838         destroyPQExpBuffer(query);
14839 }
14840
14841 /*
14842  * dumpTrigger
14843  *        write the declaration of one user-defined table trigger
14844  */
14845 static void
14846 dumpTrigger(Archive *fout, DumpOptions *dopt, TriggerInfo *tginfo)
14847 {
14848         TableInfo  *tbinfo = tginfo->tgtable;
14849         PQExpBuffer query;
14850         PQExpBuffer delqry;
14851         PQExpBuffer labelq;
14852         char       *tgargs;
14853         size_t          lentgargs;
14854         const char *p;
14855         int                     findx;
14856
14857         /*
14858          * we needn't check dobj.dump because TriggerInfo wouldn't have been
14859          * created in the first place for non-dumpable triggers
14860          */
14861         if (dopt->dataOnly)
14862                 return;
14863
14864         query = createPQExpBuffer();
14865         delqry = createPQExpBuffer();
14866         labelq = createPQExpBuffer();
14867
14868         /*
14869          * DROP must be fully qualified in case same name appears in pg_catalog
14870          */
14871         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
14872                                           fmtId(tginfo->dobj.name));
14873         appendPQExpBuffer(delqry, "ON %s.",
14874                                           fmtId(tbinfo->dobj.namespace->dobj.name));
14875         appendPQExpBuffer(delqry, "%s;\n",
14876                                           fmtId(tbinfo->dobj.name));
14877
14878         if (tginfo->tgdef)
14879         {
14880                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
14881         }
14882         else
14883         {
14884                 if (tginfo->tgisconstraint)
14885                 {
14886                         appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
14887                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
14888                 }
14889                 else
14890                 {
14891                         appendPQExpBufferStr(query, "CREATE TRIGGER ");
14892                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
14893                 }
14894                 appendPQExpBufferStr(query, "\n    ");
14895
14896                 /* Trigger type */
14897                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
14898                         appendPQExpBufferStr(query, "BEFORE");
14899                 else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
14900                         appendPQExpBufferStr(query, "AFTER");
14901                 else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
14902                         appendPQExpBufferStr(query, "INSTEAD OF");
14903                 else
14904                 {
14905                         write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
14906                         exit_nicely(1);
14907                 }
14908
14909                 findx = 0;
14910                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
14911                 {
14912                         appendPQExpBufferStr(query, " INSERT");
14913                         findx++;
14914                 }
14915                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
14916                 {
14917                         if (findx > 0)
14918                                 appendPQExpBufferStr(query, " OR DELETE");
14919                         else
14920                                 appendPQExpBufferStr(query, " DELETE");
14921                         findx++;
14922                 }
14923                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
14924                 {
14925                         if (findx > 0)
14926                                 appendPQExpBufferStr(query, " OR UPDATE");
14927                         else
14928                                 appendPQExpBufferStr(query, " UPDATE");
14929                         findx++;
14930                 }
14931                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
14932                 {
14933                         if (findx > 0)
14934                                 appendPQExpBufferStr(query, " OR TRUNCATE");
14935                         else
14936                                 appendPQExpBufferStr(query, " TRUNCATE");
14937                         findx++;
14938                 }
14939                 appendPQExpBuffer(query, " ON %s\n",
14940                                                   fmtId(tbinfo->dobj.name));
14941
14942                 if (tginfo->tgisconstraint)
14943                 {
14944                         if (OidIsValid(tginfo->tgconstrrelid))
14945                         {
14946                                 /* If we are using regclass, name is already quoted */
14947                                 if (fout->remoteVersion >= 70300)
14948                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14949                                                                           tginfo->tgconstrrelname);
14950                                 else
14951                                         appendPQExpBuffer(query, "    FROM %s\n    ",
14952                                                                           fmtId(tginfo->tgconstrrelname));
14953                         }
14954                         if (!tginfo->tgdeferrable)
14955                                 appendPQExpBufferStr(query, "NOT ");
14956                         appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
14957                         if (tginfo->tginitdeferred)
14958                                 appendPQExpBufferStr(query, "DEFERRED\n");
14959                         else
14960                                 appendPQExpBufferStr(query, "IMMEDIATE\n");
14961                 }
14962
14963                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
14964                         appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
14965                 else
14966                         appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
14967
14968                 /* In 7.3, result of regproc is already quoted */
14969                 if (fout->remoteVersion >= 70300)
14970                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14971                                                           tginfo->tgfname);
14972                 else
14973                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
14974                                                           fmtId(tginfo->tgfname));
14975
14976                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
14977                                                                                   &lentgargs);
14978                 p = tgargs;
14979                 for (findx = 0; findx < tginfo->tgnargs; findx++)
14980                 {
14981                         /* find the embedded null that terminates this trigger argument */
14982                         size_t          tlen = strlen(p);
14983
14984                         if (p + tlen >= tgargs + lentgargs)
14985                         {
14986                                 /* hm, not found before end of bytea value... */
14987                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
14988                                                   tginfo->tgargs,
14989                                                   tginfo->dobj.name,
14990                                                   tbinfo->dobj.name);
14991                                 exit_nicely(1);
14992                         }
14993
14994                         if (findx > 0)
14995                                 appendPQExpBufferStr(query, ", ");
14996                         appendStringLiteralAH(query, p, fout);
14997                         p += tlen + 1;
14998                 }
14999                 free(tgargs);
15000                 appendPQExpBufferStr(query, ");\n");
15001         }
15002
15003         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
15004         {
15005                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
15006                                                   fmtId(tbinfo->dobj.name));
15007                 switch (tginfo->tgenabled)
15008                 {
15009                         case 'D':
15010                         case 'f':
15011                                 appendPQExpBufferStr(query, "DISABLE");
15012                                 break;
15013                         case 'A':
15014                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
15015                                 break;
15016                         case 'R':
15017                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
15018                                 break;
15019                         default:
15020                                 appendPQExpBufferStr(query, "ENABLE");
15021                                 break;
15022                 }
15023                 appendPQExpBuffer(query, " TRIGGER %s;\n",
15024                                                   fmtId(tginfo->dobj.name));
15025         }
15026
15027         appendPQExpBuffer(labelq, "TRIGGER %s ",
15028                                           fmtId(tginfo->dobj.name));
15029         appendPQExpBuffer(labelq, "ON %s",
15030                                           fmtId(tbinfo->dobj.name));
15031
15032         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
15033                                  tginfo->dobj.name,
15034                                  tbinfo->dobj.namespace->dobj.name,
15035                                  NULL,
15036                                  tbinfo->rolname, false,
15037                                  "TRIGGER", SECTION_POST_DATA,
15038                                  query->data, delqry->data, NULL,
15039                                  NULL, 0,
15040                                  NULL, NULL);
15041
15042         dumpComment(fout, dopt, labelq->data,
15043                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15044                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
15045
15046         destroyPQExpBuffer(query);
15047         destroyPQExpBuffer(delqry);
15048         destroyPQExpBuffer(labelq);
15049 }
15050
15051 /*
15052  * dumpEventTrigger
15053  *        write the declaration of one user-defined event trigger
15054  */
15055 static void
15056 dumpEventTrigger(Archive *fout, DumpOptions *dopt, EventTriggerInfo *evtinfo)
15057 {
15058         PQExpBuffer query;
15059         PQExpBuffer labelq;
15060
15061         /* Skip if not to be dumped */
15062         if (!evtinfo->dobj.dump || dopt->dataOnly)
15063                 return;
15064
15065         query = createPQExpBuffer();
15066         labelq = createPQExpBuffer();
15067
15068         appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
15069         appendPQExpBufferStr(query, fmtId(evtinfo->dobj.name));
15070         appendPQExpBufferStr(query, " ON ");
15071         appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
15072         appendPQExpBufferStr(query, " ");
15073
15074         if (strcmp("", evtinfo->evttags) != 0)
15075         {
15076                 appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
15077                 appendPQExpBufferStr(query, evtinfo->evttags);
15078                 appendPQExpBufferStr(query, ") ");
15079         }
15080
15081         appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
15082         appendPQExpBufferStr(query, evtinfo->evtfname);
15083         appendPQExpBufferStr(query, "();\n");
15084
15085         if (evtinfo->evtenabled != 'O')
15086         {
15087                 appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
15088                                                   fmtId(evtinfo->dobj.name));
15089                 switch (evtinfo->evtenabled)
15090                 {
15091                         case 'D':
15092                                 appendPQExpBufferStr(query, "DISABLE");
15093                                 break;
15094                         case 'A':
15095                                 appendPQExpBufferStr(query, "ENABLE ALWAYS");
15096                                 break;
15097                         case 'R':
15098                                 appendPQExpBufferStr(query, "ENABLE REPLICA");
15099                                 break;
15100                         default:
15101                                 appendPQExpBufferStr(query, "ENABLE");
15102                                 break;
15103                 }
15104                 appendPQExpBufferStr(query, ";\n");
15105         }
15106         appendPQExpBuffer(labelq, "EVENT TRIGGER %s",
15107                                           fmtId(evtinfo->dobj.name));
15108
15109         ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
15110                                  evtinfo->dobj.name, NULL, NULL, evtinfo->evtowner, false,
15111                                  "EVENT TRIGGER", SECTION_POST_DATA,
15112                                  query->data, "", NULL, NULL, 0, NULL, NULL);
15113
15114         dumpComment(fout, dopt, labelq->data,
15115                                 NULL, evtinfo->evtowner,
15116                                 evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
15117
15118         destroyPQExpBuffer(query);
15119         destroyPQExpBuffer(labelq);
15120 }
15121
15122 /*
15123  * dumpRule
15124  *              Dump a rule
15125  */
15126 static void
15127 dumpRule(Archive *fout, DumpOptions *dopt, RuleInfo *rinfo)
15128 {
15129         TableInfo  *tbinfo = rinfo->ruletable;
15130         PQExpBuffer query;
15131         PQExpBuffer cmd;
15132         PQExpBuffer delcmd;
15133         PQExpBuffer labelq;
15134         PGresult   *res;
15135
15136         /* Skip if not to be dumped */
15137         if (!rinfo->dobj.dump || dopt->dataOnly)
15138                 return;
15139
15140         /*
15141          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
15142          * we do not want to dump it as a separate object.
15143          */
15144         if (!rinfo->separate)
15145                 return;
15146
15147         /*
15148          * Make sure we are in proper schema.
15149          */
15150         selectSourceSchema(fout, tbinfo->dobj.namespace->dobj.name);
15151
15152         query = createPQExpBuffer();
15153         cmd = createPQExpBuffer();
15154         delcmd = createPQExpBuffer();
15155         labelq = createPQExpBuffer();
15156
15157         if (fout->remoteVersion >= 70300)
15158         {
15159                 appendPQExpBuffer(query,
15160                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
15161                                                   rinfo->dobj.catId.oid);
15162         }
15163         else
15164         {
15165                 /* Rule name was unique before 7.3 ... */
15166                 appendPQExpBuffer(query,
15167                                                   "SELECT pg_get_ruledef('%s') AS definition",
15168                                                   rinfo->dobj.name);
15169         }
15170
15171         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15172
15173         if (PQntuples(res) != 1)
15174         {
15175                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
15176                                   rinfo->dobj.name, tbinfo->dobj.name);
15177                 exit_nicely(1);
15178         }
15179
15180         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
15181
15182         /*
15183          * Add the command to alter the rules replication firing semantics if it
15184          * differs from the default.
15185          */
15186         if (rinfo->ev_enabled != 'O')
15187         {
15188                 appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name));
15189                 switch (rinfo->ev_enabled)
15190                 {
15191                         case 'A':
15192                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
15193                                                                   fmtId(rinfo->dobj.name));
15194                                 break;
15195                         case 'R':
15196                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
15197                                                                   fmtId(rinfo->dobj.name));
15198                                 break;
15199                         case 'D':
15200                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
15201                                                                   fmtId(rinfo->dobj.name));
15202                                 break;
15203                 }
15204         }
15205
15206         /*
15207          * Apply view's reloptions when its ON SELECT rule is separate.
15208          */
15209         if (rinfo->reloptions && strlen(rinfo->reloptions) > 0)
15210         {
15211                 appendPQExpBuffer(cmd, "ALTER VIEW %s SET (%s);\n",
15212                                                   fmtId(tbinfo->dobj.name),
15213                                                   rinfo->reloptions);
15214         }
15215
15216         /*
15217          * DROP must be fully qualified in case same name appears in pg_catalog
15218          */
15219         appendPQExpBuffer(delcmd, "DROP RULE %s ",
15220                                           fmtId(rinfo->dobj.name));
15221         appendPQExpBuffer(delcmd, "ON %s.",
15222                                           fmtId(tbinfo->dobj.namespace->dobj.name));
15223         appendPQExpBuffer(delcmd, "%s;\n",
15224                                           fmtId(tbinfo->dobj.name));
15225
15226         appendPQExpBuffer(labelq, "RULE %s",
15227                                           fmtId(rinfo->dobj.name));
15228         appendPQExpBuffer(labelq, " ON %s",
15229                                           fmtId(tbinfo->dobj.name));
15230
15231         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
15232                                  rinfo->dobj.name,
15233                                  tbinfo->dobj.namespace->dobj.name,
15234                                  NULL,
15235                                  tbinfo->rolname, false,
15236                                  "RULE", SECTION_POST_DATA,
15237                                  cmd->data, delcmd->data, NULL,
15238                                  NULL, 0,
15239                                  NULL, NULL);
15240
15241         /* Dump rule comments */
15242         dumpComment(fout, dopt, labelq->data,
15243                                 tbinfo->dobj.namespace->dobj.name,
15244                                 tbinfo->rolname,
15245                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
15246
15247         PQclear(res);
15248
15249         destroyPQExpBuffer(query);
15250         destroyPQExpBuffer(cmd);
15251         destroyPQExpBuffer(delcmd);
15252         destroyPQExpBuffer(labelq);
15253 }
15254
15255 /*
15256  * getExtensionMembership --- obtain extension membership data
15257  */
15258 void
15259 getExtensionMembership(Archive *fout, DumpOptions *dopt, ExtensionInfo extinfo[],
15260                                            int numExtensions)
15261 {
15262         PQExpBuffer query;
15263         PGresult   *res;
15264         int                     ntups,
15265                                 i;
15266         int                     i_classid,
15267                                 i_objid,
15268                                 i_refclassid,
15269                                 i_refobjid;
15270         DumpableObject *dobj,
15271                            *refdobj;
15272
15273         /* Nothing to do if no extensions */
15274         if (numExtensions == 0)
15275                 return;
15276
15277         /* Make sure we are in proper schema */
15278         selectSourceSchema(fout, "pg_catalog");
15279
15280         query = createPQExpBuffer();
15281
15282         /* refclassid constraint is redundant but may speed the search */
15283         appendPQExpBufferStr(query, "SELECT "
15284                                                  "classid, objid, refclassid, refobjid "
15285                                                  "FROM pg_depend "
15286                                                  "WHERE refclassid = 'pg_extension'::regclass "
15287                                                  "AND deptype = 'e' "
15288                                                  "ORDER BY 3,4");
15289
15290         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15291
15292         ntups = PQntuples(res);
15293
15294         i_classid = PQfnumber(res, "classid");
15295         i_objid = PQfnumber(res, "objid");
15296         i_refclassid = PQfnumber(res, "refclassid");
15297         i_refobjid = PQfnumber(res, "refobjid");
15298
15299         /*
15300          * Since we ordered the SELECT by referenced ID, we can expect that
15301          * multiple entries for the same extension will appear together; this
15302          * saves on searches.
15303          */
15304         refdobj = NULL;
15305
15306         for (i = 0; i < ntups; i++)
15307         {
15308                 CatalogId       objId;
15309                 CatalogId       refobjId;
15310
15311                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
15312                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
15313                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
15314                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
15315
15316                 if (refdobj == NULL ||
15317                         refdobj->catId.tableoid != refobjId.tableoid ||
15318                         refdobj->catId.oid != refobjId.oid)
15319                         refdobj = findObjectByCatalogId(refobjId);
15320
15321                 /*
15322                  * Failure to find objects mentioned in pg_depend is not unexpected,
15323                  * since for example we don't collect info about TOAST tables.
15324                  */
15325                 if (refdobj == NULL)
15326                 {
15327 #ifdef NOT_USED
15328                         fprintf(stderr, "no referenced object %u %u\n",
15329                                         refobjId.tableoid, refobjId.oid);
15330 #endif
15331                         continue;
15332                 }
15333
15334                 dobj = findObjectByCatalogId(objId);
15335
15336                 if (dobj == NULL)
15337                 {
15338 #ifdef NOT_USED
15339                         fprintf(stderr, "no referencing object %u %u\n",
15340                                         objId.tableoid, objId.oid);
15341 #endif
15342                         continue;
15343                 }
15344
15345                 /* Record dependency so that getDependencies needn't repeat this */
15346                 addObjectDependency(dobj, refdobj->dumpId);
15347
15348                 dobj->ext_member = true;
15349
15350                 /*
15351                  * Normally, mark the member object as not to be dumped.  But in
15352                  * binary upgrades, we still dump the members individually, since the
15353                  * idea is to exactly reproduce the database contents rather than
15354                  * replace the extension contents with something different.
15355                  */
15356                 if (!dopt->binary_upgrade)
15357                         dobj->dump = false;
15358                 else
15359                         dobj->dump = refdobj->dump;
15360         }
15361
15362         PQclear(res);
15363
15364         /*
15365          * Now identify extension configuration tables and create TableDataInfo
15366          * objects for them, ensuring their data will be dumped even though the
15367          * tables themselves won't be.
15368          *
15369          * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
15370          * user data in a configuration table is treated like schema data. This
15371          * seems appropriate since system data in a config table would get
15372          * reloaded by CREATE EXTENSION.
15373          */
15374         for (i = 0; i < numExtensions; i++)
15375         {
15376                 ExtensionInfo *curext = &(extinfo[i]);
15377                 char       *extconfig = curext->extconfig;
15378                 char       *extcondition = curext->extcondition;
15379                 char      **extconfigarray = NULL;
15380                 char      **extconditionarray = NULL;
15381                 int                     nconfigitems;
15382                 int                     nconditionitems;
15383
15384                 if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
15385                   parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
15386                         nconfigitems == nconditionitems)
15387                 {
15388                         int                     j;
15389
15390                         for (j = 0; j < nconfigitems; j++)
15391                         {
15392                                 TableInfo  *configtbl;
15393                                 Oid                     configtbloid = atooid(extconfigarray[j]);
15394                                 bool            dumpobj = curext->dobj.dump;
15395
15396                                 configtbl = findTableByOid(configtbloid);
15397                                 if (configtbl == NULL)
15398                                         continue;
15399
15400                                 /*
15401                                  * Tables of not-to-be-dumped extensions shouldn't be dumped
15402                                  * unless the table or its schema is explicitly included
15403                                  */
15404                                 if (!curext->dobj.dump)
15405                                 {
15406                                         /* check table explicitly requested */
15407                                         if (table_include_oids.head != NULL &&
15408                                                 simple_oid_list_member(&table_include_oids,
15409                                                                                            configtbloid))
15410                                                 dumpobj = true;
15411
15412                                         /* check table's schema explicitly requested */
15413                                         if (configtbl->dobj.namespace->dobj.dump)
15414                                                 dumpobj = true;
15415                                 }
15416
15417                                 /* check table excluded by an exclusion switch */
15418                                 if (table_exclude_oids.head != NULL &&
15419                                         simple_oid_list_member(&table_exclude_oids,
15420                                                                                    configtbloid))
15421                                         dumpobj = false;
15422
15423                                 /* check schema excluded by an exclusion switch */
15424                                 if (simple_oid_list_member(&schema_exclude_oids,
15425                                                                   configtbl->dobj.namespace->dobj.catId.oid))
15426                                         dumpobj = false;
15427
15428                                 if (dumpobj)
15429                                 {
15430                                         /*
15431                                          * Note: config tables are dumped without OIDs regardless
15432                                          * of the --oids setting.  This is because row filtering
15433                                          * conditions aren't compatible with dumping OIDs.
15434                                          */
15435                                         makeTableDataInfo(dopt, configtbl, false);
15436                                         if (configtbl->dataObj != NULL)
15437                                         {
15438                                                 if (strlen(extconditionarray[j]) > 0)
15439                                                         configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
15440                                         }
15441                                 }
15442                         }
15443                 }
15444                 if (extconfigarray)
15445                         free(extconfigarray);
15446                 if (extconditionarray)
15447                         free(extconditionarray);
15448         }
15449
15450         destroyPQExpBuffer(query);
15451 }
15452
15453 /*
15454  * getDependencies --- obtain available dependency data
15455  */
15456 static void
15457 getDependencies(Archive *fout)
15458 {
15459         PQExpBuffer query;
15460         PGresult   *res;
15461         int                     ntups,
15462                                 i;
15463         int                     i_classid,
15464                                 i_objid,
15465                                 i_refclassid,
15466                                 i_refobjid,
15467                                 i_deptype;
15468         DumpableObject *dobj,
15469                            *refdobj;
15470
15471         /* No dependency info available before 7.3 */
15472         if (fout->remoteVersion < 70300)
15473                 return;
15474
15475         if (g_verbose)
15476                 write_msg(NULL, "reading dependency data\n");
15477
15478         /* Make sure we are in proper schema */
15479         selectSourceSchema(fout, "pg_catalog");
15480
15481         query = createPQExpBuffer();
15482
15483         /*
15484          * PIN dependencies aren't interesting, and EXTENSION dependencies were
15485          * already processed by getExtensionMembership.
15486          */
15487         appendPQExpBufferStr(query, "SELECT "
15488                                                  "classid, objid, refclassid, refobjid, deptype "
15489                                                  "FROM pg_depend "
15490                                                  "WHERE deptype != 'p' AND deptype != 'e' "
15491                                                  "ORDER BY 1,2");
15492
15493         res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15494
15495         ntups = PQntuples(res);
15496
15497         i_classid = PQfnumber(res, "classid");
15498         i_objid = PQfnumber(res, "objid");
15499         i_refclassid = PQfnumber(res, "refclassid");
15500         i_refobjid = PQfnumber(res, "refobjid");
15501         i_deptype = PQfnumber(res, "deptype");
15502
15503         /*
15504          * Since we ordered the SELECT by referencing ID, we can expect that
15505          * multiple entries for the same object will appear together; this saves
15506          * on searches.
15507          */
15508         dobj = NULL;
15509
15510         for (i = 0; i < ntups; i++)
15511         {
15512                 CatalogId       objId;
15513                 CatalogId       refobjId;
15514                 char            deptype;
15515
15516                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
15517                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
15518                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
15519                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
15520                 deptype = *(PQgetvalue(res, i, i_deptype));
15521
15522                 if (dobj == NULL ||
15523                         dobj->catId.tableoid != objId.tableoid ||
15524                         dobj->catId.oid != objId.oid)
15525                         dobj = findObjectByCatalogId(objId);
15526
15527                 /*
15528                  * Failure to find objects mentioned in pg_depend is not unexpected,
15529                  * since for example we don't collect info about TOAST tables.
15530                  */
15531                 if (dobj == NULL)
15532                 {
15533 #ifdef NOT_USED
15534                         fprintf(stderr, "no referencing object %u %u\n",
15535                                         objId.tableoid, objId.oid);
15536 #endif
15537                         continue;
15538                 }
15539
15540                 refdobj = findObjectByCatalogId(refobjId);
15541
15542                 if (refdobj == NULL)
15543                 {
15544 #ifdef NOT_USED
15545                         fprintf(stderr, "no referenced object %u %u\n",
15546                                         refobjId.tableoid, refobjId.oid);
15547 #endif
15548                         continue;
15549                 }
15550
15551                 /*
15552                  * Ordinarily, table rowtypes have implicit dependencies on their
15553                  * tables.  However, for a composite type the implicit dependency goes
15554                  * the other way in pg_depend; which is the right thing for DROP but
15555                  * it doesn't produce the dependency ordering we need. So in that one
15556                  * case, we reverse the direction of the dependency.
15557                  */
15558                 if (deptype == 'i' &&
15559                         dobj->objType == DO_TABLE &&
15560                         refdobj->objType == DO_TYPE)
15561                         addObjectDependency(refdobj, dobj->dumpId);
15562                 else
15563                         /* normal case */
15564                         addObjectDependency(dobj, refdobj->dumpId);
15565         }
15566
15567         PQclear(res);
15568
15569         destroyPQExpBuffer(query);
15570 }
15571
15572
15573 /*
15574  * createBoundaryObjects - create dummy DumpableObjects to represent
15575  * dump section boundaries.
15576  */
15577 static DumpableObject *
15578 createBoundaryObjects(void)
15579 {
15580         DumpableObject *dobjs;
15581
15582         dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
15583
15584         dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
15585         dobjs[0].catId = nilCatalogId;
15586         AssignDumpId(dobjs + 0);
15587         dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
15588
15589         dobjs[1].objType = DO_POST_DATA_BOUNDARY;
15590         dobjs[1].catId = nilCatalogId;
15591         AssignDumpId(dobjs + 1);
15592         dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
15593
15594         return dobjs;
15595 }
15596
15597 /*
15598  * addBoundaryDependencies - add dependencies as needed to enforce the dump
15599  * section boundaries.
15600  */
15601 static void
15602 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
15603                                                 DumpableObject *boundaryObjs)
15604 {
15605         DumpableObject *preDataBound = boundaryObjs + 0;
15606         DumpableObject *postDataBound = boundaryObjs + 1;
15607         int                     i;
15608
15609         for (i = 0; i < numObjs; i++)
15610         {
15611                 DumpableObject *dobj = dobjs[i];
15612
15613                 /*
15614                  * The classification of object types here must match the SECTION_xxx
15615                  * values assigned during subsequent ArchiveEntry calls!
15616                  */
15617                 switch (dobj->objType)
15618                 {
15619                         case DO_NAMESPACE:
15620                         case DO_EXTENSION:
15621                         case DO_TYPE:
15622                         case DO_SHELL_TYPE:
15623                         case DO_FUNC:
15624                         case DO_AGG:
15625                         case DO_OPERATOR:
15626                         case DO_OPCLASS:
15627                         case DO_OPFAMILY:
15628                         case DO_COLLATION:
15629                         case DO_CONVERSION:
15630                         case DO_TABLE:
15631                         case DO_ATTRDEF:
15632                         case DO_PROCLANG:
15633                         case DO_CAST:
15634                         case DO_DUMMY_TYPE:
15635                         case DO_TSPARSER:
15636                         case DO_TSDICT:
15637                         case DO_TSTEMPLATE:
15638                         case DO_TSCONFIG:
15639                         case DO_FDW:
15640                         case DO_FOREIGN_SERVER:
15641                         case DO_BLOB:
15642                                 /* Pre-data objects: must come before the pre-data boundary */
15643                                 addObjectDependency(preDataBound, dobj->dumpId);
15644                                 break;
15645                         case DO_TABLE_DATA:
15646                         case DO_BLOB_DATA:
15647                                 /* Data objects: must come between the boundaries */
15648                                 addObjectDependency(dobj, preDataBound->dumpId);
15649                                 addObjectDependency(postDataBound, dobj->dumpId);
15650                                 break;
15651                         case DO_INDEX:
15652                         case DO_REFRESH_MATVIEW:
15653                         case DO_TRIGGER:
15654                         case DO_EVENT_TRIGGER:
15655                         case DO_DEFAULT_ACL:
15656                         case DO_POLICY:
15657                                 /* Post-data objects: must come after the post-data boundary */
15658                                 addObjectDependency(dobj, postDataBound->dumpId);
15659                                 break;
15660                         case DO_RULE:
15661                                 /* Rules are post-data, but only if dumped separately */
15662                                 if (((RuleInfo *) dobj)->separate)
15663                                         addObjectDependency(dobj, postDataBound->dumpId);
15664                                 break;
15665                         case DO_CONSTRAINT:
15666                         case DO_FK_CONSTRAINT:
15667                                 /* Constraints are post-data, but only if dumped separately */
15668                                 if (((ConstraintInfo *) dobj)->separate)
15669                                         addObjectDependency(dobj, postDataBound->dumpId);
15670                                 break;
15671                         case DO_PRE_DATA_BOUNDARY:
15672                                 /* nothing to do */
15673                                 break;
15674                         case DO_POST_DATA_BOUNDARY:
15675                                 /* must come after the pre-data boundary */
15676                                 addObjectDependency(dobj, preDataBound->dumpId);
15677                                 break;
15678                 }
15679         }
15680 }
15681
15682
15683 /*
15684  * BuildArchiveDependencies - create dependency data for archive TOC entries
15685  *
15686  * The raw dependency data obtained by getDependencies() is not terribly
15687  * useful in an archive dump, because in many cases there are dependency
15688  * chains linking through objects that don't appear explicitly in the dump.
15689  * For example, a view will depend on its _RETURN rule while the _RETURN rule
15690  * will depend on other objects --- but the rule will not appear as a separate
15691  * object in the dump.  We need to adjust the view's dependencies to include
15692  * whatever the rule depends on that is included in the dump.
15693  *
15694  * Just to make things more complicated, there are also "special" dependencies
15695  * such as the dependency of a TABLE DATA item on its TABLE, which we must
15696  * not rearrange because pg_restore knows that TABLE DATA only depends on
15697  * its table.  In these cases we must leave the dependencies strictly as-is
15698  * even if they refer to not-to-be-dumped objects.
15699  *
15700  * To handle this, the convention is that "special" dependencies are created
15701  * during ArchiveEntry calls, and an archive TOC item that has any such
15702  * entries will not be touched here.  Otherwise, we recursively search the
15703  * DumpableObject data structures to build the correct dependencies for each
15704  * archive TOC item.
15705  */
15706 static void
15707 BuildArchiveDependencies(Archive *fout)
15708 {
15709         ArchiveHandle *AH = (ArchiveHandle *) fout;
15710         TocEntry   *te;
15711
15712         /* Scan all TOC entries in the archive */
15713         for (te = AH->toc->next; te != AH->toc; te = te->next)
15714         {
15715                 DumpableObject *dobj;
15716                 DumpId     *dependencies;
15717                 int                     nDeps;
15718                 int                     allocDeps;
15719
15720                 /* No need to process entries that will not be dumped */
15721                 if (te->reqs == 0)
15722                         continue;
15723                 /* Ignore entries that already have "special" dependencies */
15724                 if (te->nDeps > 0)
15725                         continue;
15726                 /* Otherwise, look up the item's original DumpableObject, if any */
15727                 dobj = findObjectByDumpId(te->dumpId);
15728                 if (dobj == NULL)
15729                         continue;
15730                 /* No work if it has no dependencies */
15731                 if (dobj->nDeps <= 0)
15732                         continue;
15733                 /* Set up work array */
15734                 allocDeps = 64;
15735                 dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
15736                 nDeps = 0;
15737                 /* Recursively find all dumpable dependencies */
15738                 findDumpableDependencies(AH, dobj,
15739                                                                  &dependencies, &nDeps, &allocDeps);
15740                 /* And save 'em ... */
15741                 if (nDeps > 0)
15742                 {
15743                         dependencies = (DumpId *) pg_realloc(dependencies,
15744                                                                                                  nDeps * sizeof(DumpId));
15745                         te->dependencies = dependencies;
15746                         te->nDeps = nDeps;
15747                 }
15748                 else
15749                         free(dependencies);
15750         }
15751 }
15752
15753 /* Recursive search subroutine for BuildArchiveDependencies */
15754 static void
15755 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
15756                                                  DumpId **dependencies, int *nDeps, int *allocDeps)
15757 {
15758         int                     i;
15759
15760         /*
15761          * Ignore section boundary objects: if we search through them, we'll
15762          * report lots of bogus dependencies.
15763          */
15764         if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
15765                 dobj->objType == DO_POST_DATA_BOUNDARY)
15766                 return;
15767
15768         for (i = 0; i < dobj->nDeps; i++)
15769         {
15770                 DumpId          depid = dobj->dependencies[i];
15771
15772                 if (TocIDRequired(AH, depid) != 0)
15773                 {
15774                         /* Object will be dumped, so just reference it as a dependency */
15775                         if (*nDeps >= *allocDeps)
15776                         {
15777                                 *allocDeps *= 2;
15778                                 *dependencies = (DumpId *) pg_realloc(*dependencies,
15779                                                                                                 *allocDeps * sizeof(DumpId));
15780                         }
15781                         (*dependencies)[*nDeps] = depid;
15782                         (*nDeps)++;
15783                 }
15784                 else
15785                 {
15786                         /*
15787                          * Object will not be dumped, so recursively consider its deps. We
15788                          * rely on the assumption that sortDumpableObjects already broke
15789                          * any dependency loops, else we might recurse infinitely.
15790                          */
15791                         DumpableObject *otherdobj = findObjectByDumpId(depid);
15792
15793                         if (otherdobj)
15794                                 findDumpableDependencies(AH, otherdobj,
15795                                                                                  dependencies, nDeps, allocDeps);
15796                 }
15797         }
15798 }
15799
15800
15801 /*
15802  * selectSourceSchema - make the specified schema the active search path
15803  * in the source database.
15804  *
15805  * NB: pg_catalog is explicitly searched after the specified schema;
15806  * so user names are only qualified if they are cross-schema references,
15807  * and system names are only qualified if they conflict with a user name
15808  * in the current schema.
15809  *
15810  * Whenever the selected schema is not pg_catalog, be careful to qualify
15811  * references to system catalogs and types in our emitted commands!
15812  *
15813  * This function is called only from selectSourceSchemaOnAH and
15814  * selectSourceSchema.
15815  */
15816 static void
15817 selectSourceSchema(Archive *fout, const char *schemaName)
15818 {
15819         PQExpBuffer query;
15820
15821         /* This is checked by the callers already */
15822         Assert(schemaName != NULL && *schemaName != '\0');
15823
15824         /* Not relevant if fetching from pre-7.3 DB */
15825         if (fout->remoteVersion < 70300)
15826                 return;
15827
15828         query = createPQExpBuffer();
15829         appendPQExpBuffer(query, "SET search_path = %s",
15830                                           fmtId(schemaName));
15831         if (strcmp(schemaName, "pg_catalog") != 0)
15832                 appendPQExpBufferStr(query, ", pg_catalog");
15833
15834         ExecuteSqlStatement(fout, query->data);
15835
15836         destroyPQExpBuffer(query);
15837 }
15838
15839 /*
15840  * getFormattedTypeName - retrieve a nicely-formatted type name for the
15841  * given type name.
15842  *
15843  * NB: in 7.3 and up the result may depend on the currently-selected
15844  * schema; this is why we don't try to cache the names.
15845  */
15846 static char *
15847 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
15848 {
15849         char       *result;
15850         PQExpBuffer query;
15851         PGresult   *res;
15852
15853         if (oid == 0)
15854         {
15855                 if ((opts & zeroAsOpaque) != 0)
15856                         return pg_strdup(g_opaque_type);
15857                 else if ((opts & zeroAsAny) != 0)
15858                         return pg_strdup("'any'");
15859                 else if ((opts & zeroAsStar) != 0)
15860                         return pg_strdup("*");
15861                 else if ((opts & zeroAsNone) != 0)
15862                         return pg_strdup("NONE");
15863         }
15864
15865         query = createPQExpBuffer();
15866         if (fout->remoteVersion >= 70300)
15867         {
15868                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
15869                                                   oid);
15870         }
15871         else if (fout->remoteVersion >= 70100)
15872         {
15873                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
15874                                                   oid);
15875         }
15876         else
15877         {
15878                 appendPQExpBuffer(query, "SELECT typname "
15879                                                   "FROM pg_type "
15880                                                   "WHERE oid = '%u'::oid",
15881                                                   oid);
15882         }
15883
15884         res = ExecuteSqlQueryForSingleRow(fout, query->data);
15885
15886         if (fout->remoteVersion >= 70100)
15887         {
15888                 /* already quoted */
15889                 result = pg_strdup(PQgetvalue(res, 0, 0));
15890         }
15891         else
15892         {
15893                 /* may need to quote it */
15894                 result = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
15895         }
15896
15897         PQclear(res);
15898         destroyPQExpBuffer(query);
15899
15900         return result;
15901 }
15902
15903 /*
15904  * myFormatType --- local implementation of format_type for use with 7.0.
15905  */
15906 static char *
15907 myFormatType(const char *typname, int32 typmod)
15908 {
15909         char       *result;
15910         bool            isarray = false;
15911         PQExpBuffer buf = createPQExpBuffer();
15912
15913         /* Handle array types */
15914         if (typname[0] == '_')
15915         {
15916                 isarray = true;
15917                 typname++;
15918         }
15919
15920         /* Show lengths on bpchar and varchar */
15921         if (strcmp(typname, "bpchar") == 0)
15922         {
15923                 int                     len = (typmod - VARHDRSZ);
15924
15925                 appendPQExpBufferStr(buf, "character");
15926                 if (len > 1)
15927                         appendPQExpBuffer(buf, "(%d)",
15928                                                           typmod - VARHDRSZ);
15929         }
15930         else if (strcmp(typname, "varchar") == 0)
15931         {
15932                 appendPQExpBufferStr(buf, "character varying");
15933                 if (typmod != -1)
15934                         appendPQExpBuffer(buf, "(%d)",
15935                                                           typmod - VARHDRSZ);
15936         }
15937         else if (strcmp(typname, "numeric") == 0)
15938         {
15939                 appendPQExpBufferStr(buf, "numeric");
15940                 if (typmod != -1)
15941                 {
15942                         int32           tmp_typmod;
15943                         int                     precision;
15944                         int                     scale;
15945
15946                         tmp_typmod = typmod - VARHDRSZ;
15947                         precision = (tmp_typmod >> 16) & 0xffff;
15948                         scale = tmp_typmod & 0xffff;
15949                         appendPQExpBuffer(buf, "(%d,%d)",
15950                                                           precision, scale);
15951                 }
15952         }
15953
15954         /*
15955          * char is an internal single-byte data type; Let's make sure we force it
15956          * through with quotes. - thomas 1998-12-13
15957          */
15958         else if (strcmp(typname, "char") == 0)
15959                 appendPQExpBufferStr(buf, "\"char\"");
15960         else
15961                 appendPQExpBufferStr(buf, fmtId(typname));
15962
15963         /* Append array qualifier for array types */
15964         if (isarray)
15965                 appendPQExpBufferStr(buf, "[]");
15966
15967         result = pg_strdup(buf->data);
15968         destroyPQExpBuffer(buf);
15969
15970         return result;
15971 }
15972
15973 /*
15974  * Return a column list clause for the given relation.
15975  *
15976  * Special case: if there are no undropped columns in the relation, return
15977  * "", not an invalid "()" column list.
15978  */
15979 static const char *
15980 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
15981 {
15982         int                     numatts = ti->numatts;
15983         char      **attnames = ti->attnames;
15984         bool       *attisdropped = ti->attisdropped;
15985         bool            needComma;
15986         int                     i;
15987
15988         appendPQExpBufferChar(buffer, '(');
15989         needComma = false;
15990         for (i = 0; i < numatts; i++)
15991         {
15992                 if (attisdropped[i])
15993                         continue;
15994                 if (needComma)
15995                         appendPQExpBufferStr(buffer, ", ");
15996                 appendPQExpBufferStr(buffer, fmtId(attnames[i]));
15997                 needComma = true;
15998         }
15999
16000         if (!needComma)
16001                 return "";                              /* no undropped columns */
16002
16003         appendPQExpBufferChar(buffer, ')');
16004         return buffer->data;
16005 }
16006
16007 /*
16008  * Execute an SQL query and verify that we got exactly one row back.
16009  */
16010 static PGresult *
16011 ExecuteSqlQueryForSingleRow(Archive *fout, char *query)
16012 {
16013         PGresult   *res;
16014         int                     ntups;
16015
16016         res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
16017
16018         /* Expecting a single result only */
16019         ntups = PQntuples(res);
16020         if (ntups != 1)
16021                 exit_horribly(NULL,
16022                                           ngettext("query returned %d row instead of one: %s\n",
16023                                                            "query returned %d rows instead of one: %s\n",
16024                                                            ntups),
16025                                           ntups, query);
16026
16027         return res;
16028 }