]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
In CREATE SEQUENCE dump, put MINVALUE before MAXVALUE so it reads better.
[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-2009, 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  * IDENTIFICATION
15  *        $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.559 2009/12/22 23:27:41 petere Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 #include "postgres_fe.h"
21
22 #include <unistd.h>
23 #include <ctype.h>
24 #ifdef ENABLE_NLS
25 #include <locale.h>
26 #endif
27 #ifdef HAVE_TERMIOS_H
28 #include <termios.h>
29 #endif
30
31 #include "getopt_long.h"
32
33 #include "access/attnum.h"
34 #include "access/sysattr.h"
35 #include "access/transam.h"
36 #include "catalog/pg_cast.h"
37 #include "catalog/pg_class.h"
38 #include "catalog/pg_default_acl.h"
39 #include "catalog/pg_largeobject.h"
40 #include "catalog/pg_proc.h"
41 #include "catalog/pg_trigger.h"
42 #include "catalog/pg_type.h"
43 #include "libpq/libpq-fs.h"
44
45 #include "pg_backup_archiver.h"
46 #include "dumputils.h"
47
48 extern char *optarg;
49 extern int      optind,
50                         opterr;
51
52
53 typedef struct
54 {
55         const char *descr;                      /* comment for an object */
56         Oid                     classoid;               /* object class (catalog OID) */
57         Oid                     objoid;                 /* object OID */
58         int                     objsubid;               /* subobject (table column #) */
59 } CommentItem;
60
61
62 /* global decls */
63 bool            g_verbose;                      /* User wants verbose narration of our
64                                                                  * activities. */
65 Archive    *g_fout;                             /* the script file */
66 PGconn     *g_conn;                             /* the database connection */
67
68 /* various user-settable parameters */
69 bool            schemaOnly;
70 bool            dataOnly;
71 bool            aclsSkip;
72 const char *lockWaitTimeout;
73
74 /* subquery used to convert user ID (eg, datdba) to user name */
75 static const char *username_subquery;
76
77 /* obsolete as of 7.3: */
78 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
79
80 /*
81  * Object inclusion/exclusion lists
82  *
83  * The string lists record the patterns given by command-line switches,
84  * which we then convert to lists of OIDs of matching objects.
85  */
86 static SimpleStringList schema_include_patterns = {NULL, NULL};
87 static SimpleOidList schema_include_oids = {NULL, NULL};
88 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
89 static SimpleOidList schema_exclude_oids = {NULL, NULL};
90
91 static SimpleStringList table_include_patterns = {NULL, NULL};
92 static SimpleOidList table_include_oids = {NULL, NULL};
93 static SimpleStringList table_exclude_patterns = {NULL, NULL};
94 static SimpleOidList table_exclude_oids = {NULL, NULL};
95
96 /* default, if no "inclusion" switches appear, is to dump everything */
97 static bool include_everything = true;
98
99 char            g_opaque_type[10];      /* name for the opaque type */
100
101 /* placeholders for the delimiters for comments */
102 char            g_comment_start[10];
103 char            g_comment_end[10];
104
105 static const CatalogId nilCatalogId = {0, 0};
106
107 /* these are to avoid passing around info for findNamespace() */
108 static NamespaceInfo *g_namespaces;
109 static int      g_numNamespaces;
110
111 /* flags for various command-line long options */
112 static int      binary_upgrade = 0;
113 static int      disable_dollar_quoting = 0;
114 static int      dump_inserts = 0;
115 static int      column_inserts = 0;
116
117
118 static void help(const char *progname);
119 static void expand_schema_name_patterns(SimpleStringList *patterns,
120                                                         SimpleOidList *oids);
121 static void expand_table_name_patterns(SimpleStringList *patterns,
122                                                    SimpleOidList *oids);
123 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
124 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
125 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
126 static void dumpComment(Archive *fout, const char *target,
127                         const char *namespace, const char *owner,
128                         CatalogId catalogId, int subid, DumpId dumpId);
129 static int findComments(Archive *fout, Oid classoid, Oid objoid,
130                          CommentItem **items);
131 static int      collectComments(Archive *fout, CommentItem **items);
132 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
133 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
134 static void dumpType(Archive *fout, TypeInfo *tinfo);
135 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
136 static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
137 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
138 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
139 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tinfo);
140 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
141 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
142 static void dumpFunc(Archive *fout, FuncInfo *finfo);
143 static void dumpCast(Archive *fout, CastInfo *cast);
144 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
145 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
146 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
147 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
148 static void dumpRule(Archive *fout, RuleInfo *rinfo);
149 static void dumpAgg(Archive *fout, AggInfo *agginfo);
150 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
151 static void dumpTable(Archive *fout, TableInfo *tbinfo);
152 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
153 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
154 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
155 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
156 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
157 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
158 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
159 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
160 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
161 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
162 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
163 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
164 static void dumpUserMappings(Archive *fout, const char *target,
165                                  const char *servername, const char *namespace,
166                                  const char *owner, CatalogId catalogId, DumpId dumpId);
167 static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
168
169 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
170                 const char *type, const char *name, const char *subname,
171                 const char *tag, const char *nspname, const char *owner,
172                 const char *acls);
173
174 static void getDependencies(void);
175 static void getDomainConstraints(TypeInfo *tinfo);
176 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
177 static void getTableDataFKConstraints(void);
178 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
179 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
180                                                           char **allargtypes,
181                                                           char **argmodes,
182                                                           char **argnames);
183 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
184 static const char *convertRegProcReference(const char *proc);
185 static const char *convertOperatorReference(const char *opr);
186 static const char *convertTSFunction(Oid funcOid);
187 static Oid      findLastBuiltinOid_V71(const char *);
188 static Oid      findLastBuiltinOid_V70(void);
189 static void selectSourceSchema(const char *schemaName);
190 static char *getFormattedTypeName(Oid oid, OidOptions opts);
191 static char *myFormatType(const char *typname, int32 typmod);
192 static const char *fmtQualifiedId(const char *schema, const char *id);
193 static bool hasBlobs(Archive *AH);
194 static int      dumpBlobs(Archive *AH, void *arg);
195 static int      dumpBlobComments(Archive *AH, void *arg);
196 static void dumpDatabase(Archive *AH);
197 static void dumpEncoding(Archive *AH);
198 static void dumpStdStrings(Archive *AH);
199 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
200 static const char *fmtCopyColumnList(const TableInfo *ti);
201 static void do_sql_command(PGconn *conn, const char *query);
202 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
203                                  ExecStatusType expected);
204
205
206 int
207 main(int argc, char **argv)
208 {
209         int                     c;
210         const char *filename = NULL;
211         const char *format = "p";
212         const char *dbname = NULL;
213         const char *pghost = NULL;
214         const char *pgport = NULL;
215         const char *username = NULL;
216         const char *dumpencoding = NULL;
217         const char *std_strings;
218         bool            oids = false;
219         TableInfo  *tblinfo;
220         int                     numTables;
221         DumpableObject **dobjs;
222         int                     numObjs;
223         int                     i;
224         enum trivalue prompt_password = TRI_DEFAULT;
225         int                     compressLevel = -1;
226         int                     plainText = 0;
227         int                     outputClean = 0;
228         int                     outputCreate = 0;
229         bool            outputBlobs = false;
230         int                     outputNoOwner = 0;
231         char       *outputSuperuser = NULL;
232         char       *use_role = NULL;
233         int                     my_version;
234         int                     optindex;
235         RestoreOptions *ropt;
236
237         static int      disable_triggers = 0;
238         static int      outputNoTablespaces = 0;
239         static int      use_setsessauth = 0;
240
241         static struct option long_options[] = {
242                 {"data-only", no_argument, NULL, 'a'},
243                 {"blobs", no_argument, NULL, 'b'},
244                 {"clean", no_argument, NULL, 'c'},
245                 {"create", no_argument, NULL, 'C'},
246                 {"file", required_argument, NULL, 'f'},
247                 {"format", required_argument, NULL, 'F'},
248                 {"host", required_argument, NULL, 'h'},
249                 {"ignore-version", no_argument, NULL, 'i'},
250                 {"no-reconnect", no_argument, NULL, 'R'},
251                 {"oids", no_argument, NULL, 'o'},
252                 {"no-owner", no_argument, NULL, 'O'},
253                 {"port", required_argument, NULL, 'p'},
254                 {"schema", required_argument, NULL, 'n'},
255                 {"exclude-schema", required_argument, NULL, 'N'},
256                 {"schema-only", no_argument, NULL, 's'},
257                 {"superuser", required_argument, NULL, 'S'},
258                 {"table", required_argument, NULL, 't'},
259                 {"exclude-table", required_argument, NULL, 'T'},
260                 {"no-password", no_argument, NULL, 'w'},
261                 {"password", no_argument, NULL, 'W'},
262                 {"username", required_argument, NULL, 'U'},
263                 {"verbose", no_argument, NULL, 'v'},
264                 {"no-privileges", no_argument, NULL, 'x'},
265                 {"no-acl", no_argument, NULL, 'x'},
266                 {"compress", required_argument, NULL, 'Z'},
267                 {"encoding", required_argument, NULL, 'E'},
268                 {"help", no_argument, NULL, '?'},
269                 {"version", no_argument, NULL, 'V'},
270
271                 /*
272                  * the following options don't have an equivalent short option letter
273                  */
274                 {"attribute-inserts", no_argument, &column_inserts, 1},
275                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
276                 {"column-inserts", no_argument, &column_inserts, 1},
277                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
278                 {"disable-triggers", no_argument, &disable_triggers, 1},
279                 {"inserts", no_argument, &dump_inserts, 1},
280                 {"lock-wait-timeout", required_argument, NULL, 2},
281                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
282                 {"role", required_argument, NULL, 3},
283                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
284
285                 {NULL, 0, NULL, 0}
286         };
287
288         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
289
290         g_verbose = false;
291
292         strcpy(g_comment_start, "-- ");
293         g_comment_end[0] = '\0';
294         strcpy(g_opaque_type, "opaque");
295
296         dataOnly = schemaOnly = false;
297         lockWaitTimeout = NULL;
298
299         progname = get_progname(argv[0]);
300
301         /* Set default options based on progname */
302         if (strcmp(progname, "pg_backup") == 0)
303                 format = "c";
304
305         if (argc > 1)
306         {
307                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
308                 {
309                         help(progname);
310                         exit(0);
311                 }
312                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
313                 {
314                         puts("pg_dump (PostgreSQL) " PG_VERSION);
315                         exit(0);
316                 }
317         }
318
319         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxX:Z:",
320                                                         long_options, &optindex)) != -1)
321         {
322                 switch (c)
323                 {
324                         case 'a':                       /* Dump data only */
325                                 dataOnly = true;
326                                 break;
327
328                         case 'b':                       /* Dump blobs */
329                                 outputBlobs = true;
330                                 break;
331
332                         case 'c':                       /* clean (i.e., drop) schema prior to create */
333                                 outputClean = 1;
334                                 break;
335
336                         case 'C':                       /* Create DB */
337                                 outputCreate = 1;
338                                 break;
339
340                         case 'E':                       /* Dump encoding */
341                                 dumpencoding = optarg;
342                                 break;
343
344                         case 'f':
345                                 filename = optarg;
346                                 break;
347
348                         case 'F':
349                                 format = optarg;
350                                 break;
351
352                         case 'h':                       /* server host */
353                                 pghost = optarg;
354                                 break;
355
356                         case 'i':
357                                 /* ignored, deprecated option */
358                                 break;
359
360                         case 'n':                       /* include schema(s) */
361                                 simple_string_list_append(&schema_include_patterns, optarg);
362                                 include_everything = false;
363                                 break;
364
365                         case 'N':                       /* exclude schema(s) */
366                                 simple_string_list_append(&schema_exclude_patterns, optarg);
367                                 break;
368
369                         case 'o':                       /* Dump oids */
370                                 oids = true;
371                                 break;
372
373                         case 'O':                       /* Don't reconnect to match owner */
374                                 outputNoOwner = 1;
375                                 break;
376
377                         case 'p':                       /* server port */
378                                 pgport = optarg;
379                                 break;
380
381                         case 'R':
382                                 /* no-op, still accepted for backwards compatibility */
383                                 break;
384
385                         case 's':                       /* dump schema only */
386                                 schemaOnly = true;
387                                 break;
388
389                         case 'S':                       /* Username for superuser in plain text output */
390                                 outputSuperuser = strdup(optarg);
391                                 break;
392
393                         case 't':                       /* include table(s) */
394                                 simple_string_list_append(&table_include_patterns, optarg);
395                                 include_everything = false;
396                                 break;
397
398                         case 'T':                       /* exclude table(s) */
399                                 simple_string_list_append(&table_exclude_patterns, optarg);
400                                 break;
401
402                         case 'U':
403                                 username = optarg;
404                                 break;
405
406                         case 'v':                       /* verbose */
407                                 g_verbose = true;
408                                 break;
409
410                         case 'w':
411                                 prompt_password = TRI_NO;
412                                 break;
413
414                         case 'W':
415                                 prompt_password = TRI_YES;
416                                 break;
417
418                         case 'x':                       /* skip ACL dump */
419                                 aclsSkip = true;
420                                 break;
421
422                         case 'X':
423                                 /* -X is a deprecated alternative to long options */
424                                 if (strcmp(optarg, "disable-dollar-quoting") == 0)
425                                         disable_dollar_quoting = 1;
426                                 else if (strcmp(optarg, "disable-triggers") == 0)
427                                         disable_triggers = 1;
428                                 else if (strcmp(optarg, "no-tablespaces") == 0)
429                                         outputNoTablespaces = 1;
430                                 else if (strcmp(optarg, "use-set-session-authorization") == 0)
431                                         use_setsessauth = 1;
432                                 else
433                                 {
434                                         fprintf(stderr,
435                                                         _("%s: invalid -X option -- %s\n"),
436                                                         progname, optarg);
437                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
438                                         exit(1);
439                                 }
440                                 break;
441
442                         case 'Z':                       /* Compression Level */
443                                 compressLevel = atoi(optarg);
444                                 break;
445
446                         case 0:
447                                 /* This covers the long options equivalent to -X xxx. */
448                                 break;
449
450                         case 2:                         /* lock-wait-timeout */
451                                 lockWaitTimeout = optarg;
452                                 break;
453
454                         case 3:                         /* SET ROLE */
455                                 use_role = optarg;
456                                 break;
457
458                         default:
459                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
460                                 exit(1);
461                 }
462         }
463
464         if (optind < (argc - 1))
465         {
466                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
467                                 progname, argv[optind + 1]);
468                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
469                                 progname);
470                 exit(1);
471         }
472
473         /* Get database name from command line */
474         if (optind < argc)
475                 dbname = argv[optind];
476
477         /* --column-inserts implies --inserts */
478         if (column_inserts)
479                 dump_inserts = 1;
480
481         if (dataOnly && schemaOnly)
482         {
483                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
484                 exit(1);
485         }
486
487         if (dataOnly && outputClean)
488         {
489                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
490                 exit(1);
491         }
492
493         if (dump_inserts && oids)
494         {
495                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
496                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
497                 exit(1);
498         }
499
500         /* open the output file */
501         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
502         {
503                 /* This is used by pg_dumpall, and is not documented */
504                 plainText = 1;
505                 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
506         }
507         else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
508                 g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
509         else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
510         {
511                 /*
512                  * Dump files into the current directory; for demonstration only, not
513                  * documented.
514                  */
515                 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
516         }
517         else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
518         {
519                 plainText = 1;
520                 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
521         }
522         else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
523                 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
524         else
525         {
526                 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
527                 exit(1);
528         }
529
530         if (g_fout == NULL)
531         {
532                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
533                 exit(1);
534         }
535
536         /* Let the archiver know how noisy to be */
537         g_fout->verbose = g_verbose;
538
539         my_version = parse_version(PG_VERSION);
540         if (my_version < 0)
541         {
542                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
543                 exit(1);
544         }
545
546         /*
547          * We allow the server to be back to 7.0, and up to any minor release of
548          * our own major version.  (See also version check in pg_dumpall.c.)
549          */
550         g_fout->minRemoteVersion = 70000;
551         g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
552
553         /*
554          * Open the database using the Archiver, so it knows about it. Errors mean
555          * death.
556          */
557         g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
558                                                          username, prompt_password);
559
560         /* Set the client encoding if requested */
561         if (dumpencoding)
562         {
563                 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
564                 {
565                         write_msg(NULL, "invalid client encoding \"%s\" specified\n",
566                                           dumpencoding);
567                         exit(1);
568                 }
569         }
570
571         /*
572          * Get the active encoding and the standard_conforming_strings setting, so
573          * we know how to escape strings.
574          */
575         g_fout->encoding = PQclientEncoding(g_conn);
576
577         std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
578         g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
579
580         /* Set the role if requested */
581         if (use_role && g_fout->remoteVersion >= 80100)
582         {
583                 PQExpBuffer query = createPQExpBuffer();
584
585                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
586                 do_sql_command(g_conn, query->data);
587                 destroyPQExpBuffer(query);
588         }
589
590         /* Set the datestyle to ISO to ensure the dump's portability */
591         do_sql_command(g_conn, "SET DATESTYLE = ISO");
592
593         /* Likewise, avoid using sql_standard intervalstyle */
594         if (g_fout->remoteVersion >= 80400)
595                 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
596
597         /*
598          * If supported, set extra_float_digits so that we can dump float data
599          * exactly (given correctly implemented float I/O code, anyway)
600          */
601         if (g_fout->remoteVersion >= 80500)
602                 do_sql_command(g_conn, "SET extra_float_digits TO 3");
603         else if (g_fout->remoteVersion >= 70400)
604                 do_sql_command(g_conn, "SET extra_float_digits TO 2");
605
606         /*
607          * If synchronized scanning is supported, disable it, to prevent
608          * unpredictable changes in row ordering across a dump and reload.
609          */
610         if (g_fout->remoteVersion >= 80300)
611                 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
612
613         /*
614          * Disable timeouts if supported.
615          */
616         if (g_fout->remoteVersion >= 70300)
617                 do_sql_command(g_conn, "SET statement_timeout = 0");
618
619         /*
620          * Start serializable transaction to dump consistent data.
621          */
622         do_sql_command(g_conn, "BEGIN");
623
624         do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
625
626         /* Select the appropriate subquery to convert user IDs to names */
627         if (g_fout->remoteVersion >= 80100)
628                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
629         else if (g_fout->remoteVersion >= 70300)
630                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
631         else
632                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
633
634         /* Find the last built-in OID, if needed */
635         if (g_fout->remoteVersion < 70300)
636         {
637                 if (g_fout->remoteVersion >= 70100)
638                         g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
639                 else
640                         g_last_builtin_oid = findLastBuiltinOid_V70();
641                 if (g_verbose)
642                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
643         }
644
645         /* Expand schema selection patterns into OID lists */
646         if (schema_include_patterns.head != NULL)
647         {
648                 expand_schema_name_patterns(&schema_include_patterns,
649                                                                         &schema_include_oids);
650                 if (schema_include_oids.head == NULL)
651                 {
652                         write_msg(NULL, "No matching schemas were found\n");
653                         exit_nicely();
654                 }
655         }
656         expand_schema_name_patterns(&schema_exclude_patterns,
657                                                                 &schema_exclude_oids);
658         /* non-matching exclusion patterns aren't an error */
659
660         /* Expand table selection patterns into OID lists */
661         if (table_include_patterns.head != NULL)
662         {
663                 expand_table_name_patterns(&table_include_patterns,
664                                                                    &table_include_oids);
665                 if (table_include_oids.head == NULL)
666                 {
667                         write_msg(NULL, "No matching tables were found\n");
668                         exit_nicely();
669                 }
670         }
671         expand_table_name_patterns(&table_exclude_patterns,
672                                                            &table_exclude_oids);
673         /* non-matching exclusion patterns aren't an error */
674
675         /*
676          * Dumping blobs is now default unless we saw an inclusion switch or -s
677          * ... but even if we did see one of these, -b turns it back on.
678          */
679         if (include_everything && !schemaOnly)
680                 outputBlobs = true;
681
682         /*
683          * Now scan the database and create DumpableObject structs for all the
684          * objects we intend to dump.
685          */
686         tblinfo = getSchemaData(&numTables);
687
688         if (g_fout->remoteVersion < 80400)
689                 guessConstraintInheritance(tblinfo, numTables);
690
691         if (!schemaOnly)
692         {
693                 getTableData(tblinfo, numTables, oids);
694                 if (dataOnly)
695                         getTableDataFKConstraints();
696         }
697
698         if (outputBlobs && hasBlobs(g_fout))
699         {
700                 /* Add placeholders to allow correct sorting of blobs */
701                 DumpableObject *blobobj;
702                 DumpableObject *blobcobj;
703
704                 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
705                 blobobj->objType = DO_BLOBS;
706                 blobobj->catId = nilCatalogId;
707                 AssignDumpId(blobobj);
708                 blobobj->name = strdup("BLOBS");
709
710                 blobcobj = (DumpableObject *) malloc(sizeof(DumpableObject));
711                 blobcobj->objType = DO_BLOB_COMMENTS;
712                 blobcobj->catId = nilCatalogId;
713                 AssignDumpId(blobcobj);
714                 blobcobj->name = strdup("BLOB COMMENTS");
715                 addObjectDependency(blobcobj, blobobj->dumpId);
716         }
717
718         /*
719          * Collect dependency data to assist in ordering the objects.
720          */
721         getDependencies();
722
723         /*
724          * Sort the objects into a safe dump order (no forward references).
725          *
726          * In 7.3 or later, we can rely on dependency information to help us
727          * determine a safe order, so the initial sort is mostly for cosmetic
728          * purposes: we sort by name to ensure that logically identical schemas
729          * will dump identically.  Before 7.3 we don't have dependencies and we
730          * use OID ordering as an (unreliable) guide to creation order.
731          */
732         getDumpableObjects(&dobjs, &numObjs);
733
734         if (g_fout->remoteVersion >= 70300)
735                 sortDumpableObjectsByTypeName(dobjs, numObjs);
736         else
737                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
738
739         sortDumpableObjects(dobjs, numObjs);
740
741         /*
742          * Create archive TOC entries for all the objects to be dumped, in a safe
743          * order.
744          */
745
746         /* First the special ENCODING and STDSTRINGS entries. */
747         dumpEncoding(g_fout);
748         dumpStdStrings(g_fout);
749
750         /* The database item is always next, unless we don't want it at all */
751         if (include_everything && !dataOnly)
752                 dumpDatabase(g_fout);
753
754         /* Now the rearrangeable objects. */
755         for (i = 0; i < numObjs; i++)
756                 dumpDumpableObject(g_fout, dobjs[i]);
757
758         /*
759          * And finally we can do the actual output.
760          */
761         if (plainText)
762         {
763                 ropt = NewRestoreOptions();
764                 ropt->filename = (char *) filename;
765                 ropt->dropSchema = outputClean;
766                 ropt->aclsSkip = aclsSkip;
767                 ropt->superuser = outputSuperuser;
768                 ropt->create = outputCreate;
769                 ropt->noOwner = outputNoOwner;
770                 ropt->noTablespace = outputNoTablespaces;
771                 ropt->disable_triggers = disable_triggers;
772                 ropt->use_setsessauth = use_setsessauth;
773                 ropt->dataOnly = dataOnly;
774
775                 if (compressLevel == -1)
776                         ropt->compression = 0;
777                 else
778                         ropt->compression = compressLevel;
779
780                 ropt->suppressDumpWarnings = true;              /* We've already shown them */
781
782                 RestoreArchive(g_fout, ropt);
783         }
784
785         CloseArchive(g_fout);
786
787         PQfinish(g_conn);
788
789         exit(0);
790 }
791
792
793 static void
794 help(const char *progname)
795 {
796         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
797         printf(_("Usage:\n"));
798         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
799
800         printf(_("\nGeneral options:\n"));
801         printf(_("  -f, --file=FILENAME         output file name\n"));
802         printf(_("  -F, --format=c|t|p          output file format (custom, tar, plain text)\n"));
803         printf(_("  -v, --verbose               verbose mode\n"));
804         printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
805         printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
806         printf(_("  --help                      show this help, then exit\n"));
807         printf(_("  --version                   output version information, then exit\n"));
808
809         printf(_("\nOptions controlling the output content:\n"));
810         printf(_("  -a, --data-only             dump only the data, not the schema\n"));
811         printf(_("  -b, --blobs                 include large objects in dump\n"));
812         printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
813         printf(_("  -C, --create                include commands to create database in dump\n"));
814         printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
815         printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
816         printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
817         printf(_("  -o, --oids                  include OIDs in dump\n"));
818         printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
819                          "                              plain-text format\n"));
820         printf(_("  -s, --schema-only           dump only the schema, no data\n"));
821         printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
822         printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
823         printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
824         printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
825         printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
826         printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
827         printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
828         printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
829         printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
830         printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
831         printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
832         printf(_("  --use-set-session-authorization\n"
833                          "                              use SET SESSION AUTHORIZATION commands instead of\n"
834         "                              ALTER OWNER commands to set ownership\n"));
835
836         printf(_("\nConnection options:\n"));
837         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
838         printf(_("  -p, --port=PORT          database server port number\n"));
839         printf(_("  -U, --username=NAME      connect as specified database user\n"));
840         printf(_("  -w, --no-password        never prompt for password\n"));
841         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
842
843         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
844                          "variable value is used.\n\n"));
845         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
846 }
847
848 void
849 exit_nicely(void)
850 {
851         PQfinish(g_conn);
852         if (g_verbose)
853                 write_msg(NULL, "*** aborted because of error\n");
854         exit(1);
855 }
856
857 /*
858  * Find the OIDs of all schemas matching the given list of patterns,
859  * and append them to the given OID list.
860  */
861 static void
862 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
863 {
864         PQExpBuffer query;
865         PGresult   *res;
866         SimpleStringListCell *cell;
867         int                     i;
868
869         if (patterns->head == NULL)
870                 return;                                 /* nothing to do */
871
872         if (g_fout->remoteVersion < 70300)
873         {
874                 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
875                 exit_nicely();
876         }
877
878         query = createPQExpBuffer();
879
880         /*
881          * We use UNION ALL rather than UNION; this might sometimes result in
882          * duplicate entries in the OID list, but we don't care.
883          */
884
885         for (cell = patterns->head; cell; cell = cell->next)
886         {
887                 if (cell != patterns->head)
888                         appendPQExpBuffer(query, "UNION ALL\n");
889                 appendPQExpBuffer(query,
890                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
891                 processSQLNamePattern(g_conn, query, cell->val, false, false,
892                                                           NULL, "n.nspname", NULL,
893                                                           NULL);
894         }
895
896         res = PQexec(g_conn, query->data);
897         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
898
899         for (i = 0; i < PQntuples(res); i++)
900         {
901                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
902         }
903
904         PQclear(res);
905         destroyPQExpBuffer(query);
906 }
907
908 /*
909  * Find the OIDs of all tables matching the given list of patterns,
910  * and append them to the given OID list.
911  */
912 static void
913 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
914 {
915         PQExpBuffer query;
916         PGresult   *res;
917         SimpleStringListCell *cell;
918         int                     i;
919
920         if (patterns->head == NULL)
921                 return;                                 /* nothing to do */
922
923         query = createPQExpBuffer();
924
925         /*
926          * We use UNION ALL rather than UNION; this might sometimes result in
927          * duplicate entries in the OID list, but we don't care.
928          */
929
930         for (cell = patterns->head; cell; cell = cell->next)
931         {
932                 if (cell != patterns->head)
933                         appendPQExpBuffer(query, "UNION ALL\n");
934                 appendPQExpBuffer(query,
935                                                   "SELECT c.oid"
936                                                   "\nFROM pg_catalog.pg_class c"
937                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
938                                                   "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
939                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
940                 processSQLNamePattern(g_conn, query, cell->val, true, false,
941                                                           "n.nspname", "c.relname", NULL,
942                                                           "pg_catalog.pg_table_is_visible(c.oid)");
943         }
944
945         res = PQexec(g_conn, query->data);
946         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
947
948         for (i = 0; i < PQntuples(res); i++)
949         {
950                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
951         }
952
953         PQclear(res);
954         destroyPQExpBuffer(query);
955 }
956
957 /*
958  * selectDumpableNamespace: policy-setting subroutine
959  *              Mark a namespace as to be dumped or not
960  */
961 static void
962 selectDumpableNamespace(NamespaceInfo *nsinfo)
963 {
964         /*
965          * If specific tables are being dumped, do not dump any complete
966          * namespaces. If specific namespaces are being dumped, dump just those
967          * namespaces. Otherwise, dump all non-system namespaces.
968          */
969         if (table_include_oids.head != NULL)
970                 nsinfo->dobj.dump = false;
971         else if (schema_include_oids.head != NULL)
972                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
973                                                                                                    nsinfo->dobj.catId.oid);
974         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
975                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
976                 nsinfo->dobj.dump = false;
977         else
978                 nsinfo->dobj.dump = true;
979
980         /*
981          * In any case, a namespace can be excluded by an exclusion switch
982          */
983         if (nsinfo->dobj.dump &&
984                 simple_oid_list_member(&schema_exclude_oids,
985                                                            nsinfo->dobj.catId.oid))
986                 nsinfo->dobj.dump = false;
987 }
988
989 /*
990  * selectDumpableTable: policy-setting subroutine
991  *              Mark a table as to be dumped or not
992  */
993 static void
994 selectDumpableTable(TableInfo *tbinfo)
995 {
996         /*
997          * If specific tables are being dumped, dump just those tables; else, dump
998          * according to the parent namespace's dump flag.
999          */
1000         if (table_include_oids.head != NULL)
1001                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1002                                                                                                    tbinfo->dobj.catId.oid);
1003         else
1004                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1005
1006         /*
1007          * In any case, a table can be excluded by an exclusion switch
1008          */
1009         if (tbinfo->dobj.dump &&
1010                 simple_oid_list_member(&table_exclude_oids,
1011                                                            tbinfo->dobj.catId.oid))
1012                 tbinfo->dobj.dump = false;
1013 }
1014
1015 /*
1016  * selectDumpableType: policy-setting subroutine
1017  *              Mark a type as to be dumped or not
1018  *
1019  * If it's a table's rowtype or an autogenerated array type, we also apply a
1020  * special type code to facilitate sorting into the desired order.      (We don't
1021  * want to consider those to be ordinary types because that would bring tables
1022  * up into the datatype part of the dump order.)  Those tests should be made
1023  * first to ensure the objType change is applied regardless of namespace etc.
1024  */
1025 static void
1026 selectDumpableType(TypeInfo *tinfo)
1027 {
1028         /* skip complex types, except for standalone composite types */
1029         if (OidIsValid(tinfo->typrelid) &&
1030                 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1031         {
1032                 tinfo->dobj.dump = false;
1033                 tinfo->dobj.objType = DO_DUMMY_TYPE;
1034         }
1035
1036         /* skip auto-generated array types */
1037         else if (tinfo->isArray)
1038         {
1039                 tinfo->dobj.dump = false;
1040                 tinfo->dobj.objType = DO_DUMMY_TYPE;
1041         }
1042
1043         /* dump only types in dumpable namespaces */
1044         else if (!tinfo->dobj.namespace->dobj.dump)
1045                 tinfo->dobj.dump = false;
1046
1047         /* skip undefined placeholder types */
1048         else if (!tinfo->isDefined)
1049                 tinfo->dobj.dump = false;
1050
1051         else
1052                 tinfo->dobj.dump = true;
1053 }
1054
1055 /*
1056  * selectDumpableDefaultACL: policy-setting subroutine
1057  *              Mark a default ACL as to be dumped or not
1058  *
1059  * For per-schema default ACLs, dump if the schema is to be dumped.
1060  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1061  * and aclsSkip are checked separately.
1062  */
1063 static void
1064 selectDumpableDefaultACL(DefaultACLInfo *dinfo)
1065 {
1066         if (dinfo->dobj.namespace)
1067                 dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
1068         else
1069                 dinfo->dobj.dump = include_everything;
1070 }
1071
1072 /*
1073  * selectDumpableObject: policy-setting subroutine
1074  *              Mark a generic dumpable object as to be dumped or not
1075  *
1076  * Use this only for object types without a special-case routine above.
1077  */
1078 static void
1079 selectDumpableObject(DumpableObject *dobj)
1080 {
1081         /*
1082          * Default policy is to dump if parent namespace is dumpable, or always
1083          * for non-namespace-associated items.
1084          */
1085         if (dobj->namespace)
1086                 dobj->dump = dobj->namespace->dobj.dump;
1087         else
1088                 dobj->dump = true;
1089 }
1090
1091 /*
1092  *      Dump a table's contents for loading using the COPY command
1093  *      - this routine is called by the Archiver when it wants the table
1094  *        to be dumped.
1095  */
1096
1097 static int
1098 dumpTableData_copy(Archive *fout, void *dcontext)
1099 {
1100         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1101         TableInfo  *tbinfo = tdinfo->tdtable;
1102         const char *classname = tbinfo->dobj.name;
1103         const bool      hasoids = tbinfo->hasoids;
1104         const bool      oids = tdinfo->oids;
1105         PQExpBuffer q = createPQExpBuffer();
1106         PGresult   *res;
1107         int                     ret;
1108         char       *copybuf;
1109         const char *column_list;
1110
1111         if (g_verbose)
1112                 write_msg(NULL, "dumping contents of table %s\n", classname);
1113
1114         /*
1115          * Make sure we are in proper schema.  We will qualify the table name
1116          * below anyway (in case its name conflicts with a pg_catalog table); but
1117          * this ensures reproducible results in case the table contains regproc,
1118          * regclass, etc columns.
1119          */
1120         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1121
1122         /*
1123          * If possible, specify the column list explicitly so that we have no
1124          * possibility of retrieving data in the wrong column order.  (The default
1125          * column ordering of COPY will not be what we want in certain corner
1126          * cases involving ADD COLUMN and inheritance.)
1127          */
1128         if (g_fout->remoteVersion >= 70300)
1129                 column_list = fmtCopyColumnList(tbinfo);
1130         else
1131                 column_list = "";               /* can't select columns in COPY */
1132
1133         if (oids && hasoids)
1134         {
1135                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1136                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1137                                                                                  classname),
1138                                                   column_list);
1139         }
1140         else
1141         {
1142                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1143                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1144                                                                                  classname),
1145                                                   column_list);
1146         }
1147         res = PQexec(g_conn, q->data);
1148         check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1149         PQclear(res);
1150
1151         for (;;)
1152         {
1153                 ret = PQgetCopyData(g_conn, &copybuf, 0);
1154
1155                 if (ret < 0)
1156                         break;                          /* done or error */
1157
1158                 if (copybuf)
1159                 {
1160                         WriteData(fout, copybuf, ret);
1161                         PQfreemem(copybuf);
1162                 }
1163
1164                 /* ----------
1165                  * THROTTLE:
1166                  *
1167                  * There was considerable discussion in late July, 2000 regarding
1168                  * slowing down pg_dump when backing up large tables. Users with both
1169                  * slow & fast (multi-processor) machines experienced performance
1170                  * degradation when doing a backup.
1171                  *
1172                  * Initial attempts based on sleeping for a number of ms for each ms
1173                  * of work were deemed too complex, then a simple 'sleep in each loop'
1174                  * implementation was suggested. The latter failed because the loop
1175                  * was too tight. Finally, the following was implemented:
1176                  *
1177                  * If throttle is non-zero, then
1178                  *              See how long since the last sleep.
1179                  *              Work out how long to sleep (based on ratio).
1180                  *              If sleep is more than 100ms, then
1181                  *                      sleep
1182                  *                      reset timer
1183                  *              EndIf
1184                  * EndIf
1185                  *
1186                  * where the throttle value was the number of ms to sleep per ms of
1187                  * work. The calculation was done in each loop.
1188                  *
1189                  * Most of the hard work is done in the backend, and this solution
1190                  * still did not work particularly well: on slow machines, the ratio
1191                  * was 50:1, and on medium paced machines, 1:1, and on fast
1192                  * multi-processor machines, it had little or no effect, for reasons
1193                  * that were unclear.
1194                  *
1195                  * Further discussion ensued, and the proposal was dropped.
1196                  *
1197                  * For those people who want this feature, it can be implemented using
1198                  * gettimeofday in each loop, calculating the time since last sleep,
1199                  * multiplying that by the sleep ratio, then if the result is more
1200                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1201                  * function to sleep for a subsecond period ie.
1202                  *
1203                  * select(0, NULL, NULL, NULL, &tvi);
1204                  *
1205                  * This will return after the interval specified in the structure tvi.
1206                  * Finally, call gettimeofday again to save the 'last sleep time'.
1207                  * ----------
1208                  */
1209         }
1210         archprintf(fout, "\\.\n\n\n");
1211
1212         if (ret == -2)
1213         {
1214                 /* copy data transfer failed */
1215                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1216                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1217                 write_msg(NULL, "The command was: %s\n", q->data);
1218                 exit_nicely();
1219         }
1220
1221         /* Check command status and return to normal libpq state */
1222         res = PQgetResult(g_conn);
1223         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1224         PQclear(res);
1225
1226         destroyPQExpBuffer(q);
1227         return 1;
1228 }
1229
1230 static int
1231 dumpTableData_insert(Archive *fout, void *dcontext)
1232 {
1233         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1234         TableInfo  *tbinfo = tdinfo->tdtable;
1235         const char *classname = tbinfo->dobj.name;
1236         PQExpBuffer q = createPQExpBuffer();
1237         PGresult   *res;
1238         int                     tuple;
1239         int                     nfields;
1240         int                     field;
1241
1242         /*
1243          * Make sure we are in proper schema.  We will qualify the table name
1244          * below anyway (in case its name conflicts with a pg_catalog table); but
1245          * this ensures reproducible results in case the table contains regproc,
1246          * regclass, etc columns.
1247          */
1248         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1249
1250         if (fout->remoteVersion >= 70100)
1251         {
1252                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1253                                                   "SELECT * FROM ONLY %s",
1254                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1255                                                                                  classname));
1256         }
1257         else
1258         {
1259                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1260                                                   "SELECT * FROM %s",
1261                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1262                                                                                  classname));
1263         }
1264
1265         res = PQexec(g_conn, q->data);
1266         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1267
1268         do
1269         {
1270                 PQclear(res);
1271
1272                 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1273                 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1274                                                  PGRES_TUPLES_OK);
1275                 nfields = PQnfields(res);
1276                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1277                 {
1278                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1279                         if (nfields == 0)
1280                         {
1281                                 /* corner case for zero-column table */
1282                                 archprintf(fout, "DEFAULT VALUES;\n");
1283                                 continue;
1284                         }
1285                         if (column_inserts)
1286                         {
1287                                 resetPQExpBuffer(q);
1288                                 appendPQExpBuffer(q, "(");
1289                                 for (field = 0; field < nfields; field++)
1290                                 {
1291                                         if (field > 0)
1292                                                 appendPQExpBuffer(q, ", ");
1293                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1294                                 }
1295                                 appendPQExpBuffer(q, ") ");
1296                                 archputs(q->data, fout);
1297                         }
1298                         archprintf(fout, "VALUES (");
1299                         for (field = 0; field < nfields; field++)
1300                         {
1301                                 if (field > 0)
1302                                         archprintf(fout, ", ");
1303                                 if (PQgetisnull(res, tuple, field))
1304                                 {
1305                                         archprintf(fout, "NULL");
1306                                         continue;
1307                                 }
1308
1309                                 /* XXX This code is partially duplicated in ruleutils.c */
1310                                 switch (PQftype(res, field))
1311                                 {
1312                                         case INT2OID:
1313                                         case INT4OID:
1314                                         case INT8OID:
1315                                         case OIDOID:
1316                                         case FLOAT4OID:
1317                                         case FLOAT8OID:
1318                                         case NUMERICOID:
1319                                                 {
1320                                                         /*
1321                                                          * These types are printed without quotes unless
1322                                                          * they contain values that aren't accepted by the
1323                                                          * scanner unquoted (e.g., 'NaN').      Note that
1324                                                          * strtod() and friends might accept NaN, so we
1325                                                          * can't use that to test.
1326                                                          *
1327                                                          * In reality we only need to defend against
1328                                                          * infinity and NaN, so we need not get too crazy
1329                                                          * about pattern matching here.
1330                                                          */
1331                                                         const char *s = PQgetvalue(res, tuple, field);
1332
1333                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1334                                                                 archprintf(fout, "%s", s);
1335                                                         else
1336                                                                 archprintf(fout, "'%s'", s);
1337                                                 }
1338                                                 break;
1339
1340                                         case BITOID:
1341                                         case VARBITOID:
1342                                                 archprintf(fout, "B'%s'",
1343                                                                    PQgetvalue(res, tuple, field));
1344                                                 break;
1345
1346                                         case BOOLOID:
1347                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1348                                                         archprintf(fout, "true");
1349                                                 else
1350                                                         archprintf(fout, "false");
1351                                                 break;
1352
1353                                         default:
1354                                                 /* All other types are printed as string literals. */
1355                                                 resetPQExpBuffer(q);
1356                                                 appendStringLiteralAH(q,
1357                                                                                           PQgetvalue(res, tuple, field),
1358                                                                                           fout);
1359                                                 archputs(q->data, fout);
1360                                                 break;
1361                                 }
1362                         }
1363                         archprintf(fout, ");\n");
1364                 }
1365         } while (PQntuples(res) > 0);
1366
1367         PQclear(res);
1368
1369         archprintf(fout, "\n\n");
1370
1371         do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1372
1373         destroyPQExpBuffer(q);
1374         return 1;
1375 }
1376
1377
1378 /*
1379  * dumpTableData -
1380  *        dump the contents of a single table
1381  *
1382  * Actually, this just makes an ArchiveEntry for the table contents.
1383  */
1384 static void
1385 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1386 {
1387         TableInfo  *tbinfo = tdinfo->tdtable;
1388         PQExpBuffer copyBuf = createPQExpBuffer();
1389         DataDumperPtr dumpFn;
1390         char       *copyStmt;
1391
1392         if (!dump_inserts)
1393         {
1394                 /* Dump/restore using COPY */
1395                 dumpFn = dumpTableData_copy;
1396                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1397                 appendPQExpBuffer(copyBuf, "COPY %s ",
1398                                                   fmtId(tbinfo->dobj.name));
1399                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1400                                                   fmtCopyColumnList(tbinfo),
1401                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1402                 copyStmt = copyBuf->data;
1403         }
1404         else
1405         {
1406                 /* Restore using INSERT */
1407                 dumpFn = dumpTableData_insert;
1408                 copyStmt = NULL;
1409         }
1410
1411         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1412                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1413                                  NULL, tbinfo->rolname,
1414                                  false, "TABLE DATA", SECTION_DATA,
1415                                  "", "", copyStmt,
1416                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1417                                  dumpFn, tdinfo);
1418
1419         destroyPQExpBuffer(copyBuf);
1420 }
1421
1422 /*
1423  * getTableData -
1424  *        set up dumpable objects representing the contents of tables
1425  */
1426 static void
1427 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1428 {
1429         int                     i;
1430
1431         for (i = 0; i < numTables; i++)
1432         {
1433                 /* Skip VIEWs (no data to dump) */
1434                 if (tblinfo[i].relkind == RELKIND_VIEW)
1435                         continue;
1436                 /* Skip SEQUENCEs (handled elsewhere) */
1437                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1438                         continue;
1439
1440                 if (tblinfo[i].dobj.dump)
1441                 {
1442                         TableDataInfo *tdinfo;
1443
1444                         tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1445
1446                         tdinfo->dobj.objType = DO_TABLE_DATA;
1447
1448                         /*
1449                          * Note: use tableoid 0 so that this object won't be mistaken for
1450                          * something that pg_depend entries apply to.
1451                          */
1452                         tdinfo->dobj.catId.tableoid = 0;
1453                         tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1454                         AssignDumpId(&tdinfo->dobj);
1455                         tdinfo->dobj.name = tblinfo[i].dobj.name;
1456                         tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1457                         tdinfo->tdtable = &(tblinfo[i]);
1458                         tdinfo->oids = oids;
1459                         addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1460
1461                         tblinfo[i].dataObj = tdinfo;
1462                 }
1463         }
1464 }
1465
1466 /*
1467  * getTableDataFKConstraints -
1468  *        add dump-order dependencies reflecting foreign key constraints
1469  *
1470  * This code is executed only in a data-only dump --- in schema+data dumps
1471  * we handle foreign key issues by not creating the FK constraints until
1472  * after the data is loaded.  In a data-only dump, however, we want to
1473  * order the table data objects in such a way that a table's referenced
1474  * tables are restored first.  (In the presence of circular references or
1475  * self-references this may be impossible; we'll detect and complain about
1476  * that during the dependency sorting step.)
1477  */
1478 static void
1479 getTableDataFKConstraints(void)
1480 {
1481         DumpableObject **dobjs;
1482         int                     numObjs;
1483         int                     i;
1484
1485         /* Search through all the dumpable objects for FK constraints */
1486         getDumpableObjects(&dobjs, &numObjs);
1487         for (i = 0; i < numObjs; i++)
1488         {
1489                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1490                 {
1491                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1492                         TableInfo  *ftable;
1493
1494                         /* Not interesting unless both tables are to be dumped */
1495                         if (cinfo->contable == NULL ||
1496                                 cinfo->contable->dataObj == NULL)
1497                                 continue;
1498                         ftable = findTableByOid(cinfo->confrelid);
1499                         if (ftable == NULL ||
1500                                 ftable->dataObj == NULL)
1501                                 continue;
1502
1503                         /*
1504                          * Okay, make referencing table's TABLE_DATA object depend on the
1505                          * referenced table's TABLE_DATA object.
1506                          */
1507                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1508                                                                 ftable->dataObj->dobj.dumpId);
1509                 }
1510         }
1511         free(dobjs);
1512 }
1513
1514
1515 /*
1516  * guessConstraintInheritance:
1517  *      In pre-8.4 databases, we can't tell for certain which constraints
1518  *      are inherited.  We assume a CHECK constraint is inherited if its name
1519  *      matches the name of any constraint in the parent.  Originally this code
1520  *      tried to compare the expression texts, but that can fail for various
1521  *      reasons --- for example, if the parent and child tables are in different
1522  *      schemas, reverse-listing of function calls may produce different text
1523  *      (schema-qualified or not) depending on search path.
1524  *
1525  *      In 8.4 and up we can rely on the conislocal field to decide which
1526  *      constraints must be dumped; much safer.
1527  *
1528  *      This function assumes all conislocal flags were initialized to TRUE.
1529  *      It clears the flag on anything that seems to be inherited.
1530  */
1531 static void
1532 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1533 {
1534         int                     i,
1535                                 j,
1536                                 k;
1537
1538         for (i = 0; i < numTables; i++)
1539         {
1540                 TableInfo  *tbinfo = &(tblinfo[i]);
1541                 int                     numParents;
1542                 TableInfo **parents;
1543                 TableInfo  *parent;
1544
1545                 /* Sequences and views never have parents */
1546                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1547                         tbinfo->relkind == RELKIND_VIEW)
1548                         continue;
1549
1550                 /* Don't bother computing anything for non-target tables, either */
1551                 if (!tbinfo->dobj.dump)
1552                         continue;
1553
1554                 numParents = tbinfo->numParents;
1555                 parents = tbinfo->parents;
1556
1557                 if (numParents == 0)
1558                         continue;                       /* nothing to see here, move along */
1559
1560                 /* scan for inherited CHECK constraints */
1561                 for (j = 0; j < tbinfo->ncheck; j++)
1562                 {
1563                         ConstraintInfo *constr;
1564
1565                         constr = &(tbinfo->checkexprs[j]);
1566
1567                         for (k = 0; k < numParents; k++)
1568                         {
1569                                 int                     l;
1570
1571                                 parent = parents[k];
1572                                 for (l = 0; l < parent->ncheck; l++)
1573                                 {
1574                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1575
1576                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1577                                         {
1578                                                 constr->conislocal = false;
1579                                                 break;
1580                                         }
1581                                 }
1582                                 if (!constr->conislocal)
1583                                         break;
1584                         }
1585                 }
1586         }
1587 }
1588
1589
1590 /*
1591  * dumpDatabase:
1592  *      dump the database definition
1593  */
1594 static void
1595 dumpDatabase(Archive *AH)
1596 {
1597         PQExpBuffer dbQry = createPQExpBuffer();
1598         PQExpBuffer delQry = createPQExpBuffer();
1599         PQExpBuffer creaQry = createPQExpBuffer();
1600         PGresult   *res;
1601         int                     ntups;
1602         int                     i_tableoid,
1603                                 i_oid,
1604                                 i_dba,
1605                                 i_encoding,
1606                                 i_collate,
1607                                 i_ctype,
1608                                 i_frozenxid,
1609                                 i_tablespace;
1610         CatalogId       dbCatId;
1611         DumpId          dbDumpId;
1612         const char *datname,
1613                            *dba,
1614                            *encoding,
1615                            *collate,
1616                            *ctype,
1617                            *tablespace;
1618         uint32          frozenxid;
1619
1620         datname = PQdb(g_conn);
1621
1622         if (g_verbose)
1623                 write_msg(NULL, "saving database definition\n");
1624
1625         /* Make sure we are in proper schema */
1626         selectSourceSchema("pg_catalog");
1627
1628         /* Get the database owner and parameters from pg_database */
1629         if (g_fout->remoteVersion >= 80400)
1630         {
1631                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1632                                                   "(%s datdba) AS dba, "
1633                                                   "pg_encoding_to_char(encoding) AS encoding, "
1634                                                   "datcollate, datctype, datfrozenxid, "
1635                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1636                                           "shobj_description(oid, 'pg_database') AS description "
1637
1638                                                   "FROM pg_database "
1639                                                   "WHERE datname = ",
1640                                                   username_subquery);
1641                 appendStringLiteralAH(dbQry, datname, AH);
1642         }
1643         else if (g_fout->remoteVersion >= 80200)
1644         {
1645                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1646                                                   "(%s datdba) AS dba, "
1647                                                   "pg_encoding_to_char(encoding) AS encoding, "
1648                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1649                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1650                                           "shobj_description(oid, 'pg_database') AS description "
1651
1652                                                   "FROM pg_database "
1653                                                   "WHERE datname = ",
1654                                                   username_subquery);
1655                 appendStringLiteralAH(dbQry, datname, AH);
1656         }
1657         else if (g_fout->remoteVersion >= 80000)
1658         {
1659                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1660                                                   "(%s datdba) AS dba, "
1661                                                   "pg_encoding_to_char(encoding) AS encoding, "
1662                                            "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1663                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1664                                                   "FROM pg_database "
1665                                                   "WHERE datname = ",
1666                                                   username_subquery);
1667                 appendStringLiteralAH(dbQry, datname, AH);
1668         }
1669         else if (g_fout->remoteVersion >= 70100)
1670         {
1671                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1672                                                   "(%s datdba) AS dba, "
1673                                                   "pg_encoding_to_char(encoding) AS encoding, "
1674                                                   "NULL AS datcollate, NULL AS datctype, "
1675                                                   "0 AS datfrozenxid, "
1676                                                   "NULL AS tablespace "
1677                                                   "FROM pg_database "
1678                                                   "WHERE datname = ",
1679                                                   username_subquery);
1680                 appendStringLiteralAH(dbQry, datname, AH);
1681         }
1682         else
1683         {
1684                 appendPQExpBuffer(dbQry, "SELECT "
1685                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1686                                                   "oid, "
1687                                                   "(%s datdba) AS dba, "
1688                                                   "pg_encoding_to_char(encoding) AS encoding, "
1689                                                   "NULL AS datcollate, NULL AS datctype, "
1690                                                   "0 AS datfrozenxid, "
1691                                                   "NULL AS tablespace "
1692                                                   "FROM pg_database "
1693                                                   "WHERE datname = ",
1694                                                   username_subquery);
1695                 appendStringLiteralAH(dbQry, datname, AH);
1696         }
1697
1698         res = PQexec(g_conn, dbQry->data);
1699         check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1700
1701         ntups = PQntuples(res);
1702
1703         if (ntups <= 0)
1704         {
1705                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1706                                   datname);
1707                 exit_nicely();
1708         }
1709
1710         if (ntups != 1)
1711         {
1712                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1713                                   ntups, datname);
1714                 exit_nicely();
1715         }
1716
1717         i_tableoid = PQfnumber(res, "tableoid");
1718         i_oid = PQfnumber(res, "oid");
1719         i_dba = PQfnumber(res, "dba");
1720         i_encoding = PQfnumber(res, "encoding");
1721         i_collate = PQfnumber(res, "datcollate");
1722         i_ctype = PQfnumber(res, "datctype");
1723         i_frozenxid = PQfnumber(res, "datfrozenxid");
1724         i_tablespace = PQfnumber(res, "tablespace");
1725
1726         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1727         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1728         dba = PQgetvalue(res, 0, i_dba);
1729         encoding = PQgetvalue(res, 0, i_encoding);
1730         collate = PQgetvalue(res, 0, i_collate);
1731         ctype = PQgetvalue(res, 0, i_ctype);
1732         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1733         tablespace = PQgetvalue(res, 0, i_tablespace);
1734
1735         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1736                                           fmtId(datname));
1737         if (strlen(encoding) > 0)
1738         {
1739                 appendPQExpBuffer(creaQry, " ENCODING = ");
1740                 appendStringLiteralAH(creaQry, encoding, AH);
1741         }
1742         if (strlen(collate) > 0)
1743         {
1744                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1745                 appendStringLiteralAH(creaQry, collate, AH);
1746         }
1747         if (strlen(ctype) > 0)
1748         {
1749                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1750                 appendStringLiteralAH(creaQry, ctype, AH);
1751         }
1752         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1753                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1754                                                   fmtId(tablespace));
1755         appendPQExpBuffer(creaQry, ";\n");
1756
1757         if (binary_upgrade)
1758         {
1759                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1760                 appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
1761                                                   "SET datfrozenxid = '%u'\n"
1762                                                   "WHERE        datname = ",
1763                                                   frozenxid);
1764                 appendStringLiteralAH(creaQry, datname, AH);
1765                 appendPQExpBuffer(creaQry, ";\n");
1766
1767         }
1768
1769         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1770                                           fmtId(datname));
1771
1772         dbDumpId = createDumpId();
1773
1774         ArchiveEntry(AH,
1775                                  dbCatId,               /* catalog ID */
1776                                  dbDumpId,              /* dump ID */
1777                                  datname,               /* Name */
1778                                  NULL,                  /* Namespace */
1779                                  NULL,                  /* Tablespace */
1780                                  dba,                   /* Owner */
1781                                  false,                 /* with oids */
1782                                  "DATABASE",    /* Desc */
1783                                  SECTION_PRE_DATA,              /* Section */
1784                                  creaQry->data, /* Create */
1785                                  delQry->data,  /* Del */
1786                                  NULL,                  /* Copy */
1787                                  NULL,                  /* Deps */
1788                                  0,                             /* # Deps */
1789                                  NULL,                  /* Dumper */
1790                                  NULL);                 /* Dumper Arg */
1791
1792         /*
1793          *      pg_largeobject comes from the old system intact, so set
1794          *      its relfrozenxid.
1795          */
1796         if (binary_upgrade)
1797         {
1798                 PGresult   *lo_res;
1799                 PQExpBuffer loFrozenQry = createPQExpBuffer();
1800                 PQExpBuffer loOutQry = createPQExpBuffer();
1801                 int                     i_relfrozenxid;
1802
1803                 appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
1804                                                         "FROM pg_catalog.pg_class\n"
1805                                                         "WHERE oid = %d;\n",
1806                                                         LargeObjectRelationId);
1807
1808                 lo_res = PQexec(g_conn, loFrozenQry->data);
1809                 check_sql_result(lo_res, g_conn, loFrozenQry->data, PGRES_TUPLES_OK);
1810
1811                 if (PQntuples(lo_res) != 1)
1812                 {
1813                         write_msg(NULL, "dumpDatabase(): could not find pg_largeobject.relfrozenxid\n");
1814                         exit_nicely();
1815                 }
1816
1817                 i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
1818
1819                 appendPQExpBuffer(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid.\n");
1820                 appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
1821                                                   "SET relfrozenxid = '%u'\n"
1822                                                   "WHERE oid = %d;\n",
1823                                                   atoi(PQgetvalue(lo_res, 0, i_relfrozenxid)),
1824                                                   LargeObjectRelationId);
1825                 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1826                                          "pg_largeobject", NULL, NULL, "",
1827                                          false, "pg_largeobject", SECTION_PRE_DATA,
1828                                          loOutQry->data, "", NULL,
1829                                          NULL, 0,
1830                                          NULL, NULL);
1831
1832                 PQclear(lo_res);
1833                 destroyPQExpBuffer(loFrozenQry);
1834                 destroyPQExpBuffer(loOutQry);
1835         }
1836
1837         /* Dump DB comment if any */
1838         if (g_fout->remoteVersion >= 80200)
1839         {
1840                 /*
1841                  * 8.2 keeps comments on shared objects in a shared table, so we
1842                  * cannot use the dumpComment used for other database objects.
1843                  */
1844                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1845
1846                 if (comment && strlen(comment))
1847                 {
1848                         resetPQExpBuffer(dbQry);
1849
1850                         /*
1851                          * Generates warning when loaded into a differently-named
1852                          * database.
1853                          */
1854                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
1855                         appendStringLiteralAH(dbQry, comment, AH);
1856                         appendPQExpBuffer(dbQry, ";\n");
1857
1858                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1859                                                  dba, false, "COMMENT", SECTION_NONE,
1860                                                  dbQry->data, "", NULL,
1861                                                  &dbDumpId, 1, NULL, NULL);
1862                 }
1863         }
1864         else
1865         {
1866                 resetPQExpBuffer(dbQry);
1867                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1868                 dumpComment(AH, dbQry->data, NULL, "",
1869                                         dbCatId, 0, dbDumpId);
1870         }
1871
1872         PQclear(res);
1873
1874         destroyPQExpBuffer(dbQry);
1875         destroyPQExpBuffer(delQry);
1876         destroyPQExpBuffer(creaQry);
1877 }
1878
1879
1880 /*
1881  * dumpEncoding: put the correct encoding into the archive
1882  */
1883 static void
1884 dumpEncoding(Archive *AH)
1885 {
1886         const char *encname = pg_encoding_to_char(AH->encoding);
1887         PQExpBuffer qry = createPQExpBuffer();
1888
1889         if (g_verbose)
1890                 write_msg(NULL, "saving encoding = %s\n", encname);
1891
1892         appendPQExpBuffer(qry, "SET client_encoding = ");
1893         appendStringLiteralAH(qry, encname, AH);
1894         appendPQExpBuffer(qry, ";\n");
1895
1896         ArchiveEntry(AH, nilCatalogId, createDumpId(),
1897                                  "ENCODING", NULL, NULL, "",
1898                                  false, "ENCODING", SECTION_PRE_DATA,
1899                                  qry->data, "", NULL,
1900                                  NULL, 0,
1901                                  NULL, NULL);
1902
1903         destroyPQExpBuffer(qry);
1904 }
1905
1906
1907 /*
1908  * dumpStdStrings: put the correct escape string behavior into the archive
1909  */
1910 static void
1911 dumpStdStrings(Archive *AH)
1912 {
1913         const char *stdstrings = AH->std_strings ? "on" : "off";
1914         PQExpBuffer qry = createPQExpBuffer();
1915
1916         if (g_verbose)
1917                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1918                                   stdstrings);
1919
1920         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1921                                           stdstrings);
1922
1923         ArchiveEntry(AH, nilCatalogId, createDumpId(),
1924                                  "STDSTRINGS", NULL, NULL, "",
1925                                  false, "STDSTRINGS", SECTION_PRE_DATA,
1926                                  qry->data, "", NULL,
1927                                  NULL, 0,
1928                                  NULL, NULL);
1929
1930         destroyPQExpBuffer(qry);
1931 }
1932
1933
1934 /*
1935  * hasBlobs:
1936  *      Test whether database contains any large objects
1937  */
1938 static bool
1939 hasBlobs(Archive *AH)
1940 {
1941         bool            result;
1942         const char *blobQry;
1943         PGresult   *res;
1944
1945         /* Make sure we are in proper schema */
1946         selectSourceSchema("pg_catalog");
1947
1948         /* Check for BLOB OIDs */
1949         if (AH->remoteVersion >= 80500)
1950                 blobQry = "SELECT oid FROM pg_largeobject_metadata LIMIT 1";
1951         else if (AH->remoteVersion >= 70100)
1952                 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1953         else
1954                 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1955
1956         res = PQexec(g_conn, blobQry);
1957         check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1958
1959         result = PQntuples(res) > 0;
1960
1961         PQclear(res);
1962
1963         return result;
1964 }
1965
1966 /*
1967  * dumpBlobs:
1968  *      dump all blobs
1969  */
1970 static int
1971 dumpBlobs(Archive *AH, void *arg)
1972 {
1973         const char *blobQry;
1974         const char *blobFetchQry;
1975         PGresult   *res;
1976         char            buf[LOBBUFSIZE];
1977         int                     i;
1978         int                     cnt;
1979
1980         if (g_verbose)
1981                 write_msg(NULL, "saving large objects\n");
1982
1983         /* Make sure we are in proper schema */
1984         selectSourceSchema("pg_catalog");
1985
1986         /* Cursor to get all BLOB OIDs */
1987         if (AH->remoteVersion >= 80500)
1988                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
1989         else if (AH->remoteVersion >= 70100)
1990                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1991         else
1992                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1993
1994         res = PQexec(g_conn, blobQry);
1995         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1996
1997         /* Command to fetch from cursor */
1998         blobFetchQry = "FETCH 1000 IN bloboid";
1999
2000         do
2001         {
2002                 PQclear(res);
2003
2004                 /* Do a fetch */
2005                 res = PQexec(g_conn, blobFetchQry);
2006                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2007
2008                 /* Process the tuples, if any */
2009                 for (i = 0; i < PQntuples(res); i++)
2010                 {
2011                         Oid                     blobOid;
2012                         int                     loFd;
2013
2014                         blobOid = atooid(PQgetvalue(res, i, 0));
2015                         /* Open the BLOB */
2016                         loFd = lo_open(g_conn, blobOid, INV_READ);
2017                         if (loFd == -1)
2018                         {
2019                                 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
2020                                                   PQerrorMessage(g_conn));
2021                                 exit_nicely();
2022                         }
2023
2024                         StartBlob(AH, blobOid);
2025
2026                         /* Now read it in chunks, sending data to archive */
2027                         do
2028                         {
2029                                 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
2030                                 if (cnt < 0)
2031                                 {
2032                                         write_msg(NULL, "dumpBlobs(): error reading large object: %s",
2033                                                           PQerrorMessage(g_conn));
2034                                         exit_nicely();
2035                                 }
2036
2037                                 WriteData(AH, buf, cnt);
2038                         } while (cnt > 0);
2039
2040                         lo_close(g_conn, loFd);
2041
2042                         EndBlob(AH, blobOid);
2043                 }
2044         } while (PQntuples(res) > 0);
2045
2046         PQclear(res);
2047
2048         return 1;
2049 }
2050
2051 /*
2052  * dumpBlobComments
2053  *      dump all blob properties.
2054  *  It has "BLOB COMMENTS" tag due to the historical reason, but note
2055  *  that it is the routine to dump all the properties of blobs.
2056  *
2057  * Since we don't provide any way to be selective about dumping blobs,
2058  * there's no need to be selective about their comments either.  We put
2059  * all the comments into one big TOC entry.
2060  */
2061 static int
2062 dumpBlobComments(Archive *AH, void *arg)
2063 {
2064         const char *blobQry;
2065         const char *blobFetchQry;
2066         PQExpBuffer cmdQry = createPQExpBuffer();
2067         PGresult   *res;
2068         int                     i;
2069
2070         if (g_verbose)
2071                 write_msg(NULL, "saving large object properties\n");
2072
2073         /* Make sure we are in proper schema */
2074         selectSourceSchema("pg_catalog");
2075
2076         /* Cursor to get all BLOB comments */
2077         if (AH->remoteVersion >= 80500)
2078                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2079                         "obj_description(oid, 'pg_largeobject'), "
2080                         "pg_get_userbyid(lomowner), lomacl "
2081                         "FROM pg_largeobject_metadata";
2082         else if (AH->remoteVersion >= 70300)
2083                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2084                         "obj_description(loid, 'pg_largeobject'), NULL, NULL "
2085                         "FROM (SELECT DISTINCT loid FROM "
2086                         "pg_description d JOIN pg_largeobject l ON (objoid = loid) "
2087                         "WHERE classoid = 'pg_largeobject'::regclass) ss";
2088         else if (AH->remoteVersion >= 70200)
2089                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2090                         "obj_description(loid, 'pg_largeobject'), NULL, NULL "
2091                         "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2092         else if (AH->remoteVersion >= 70100)
2093                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2094                         "obj_description(loid), NULL, NULL "
2095                         "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2096         else
2097                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2098                         "       ( "
2099                         "               SELECT description "
2100                         "               FROM pg_description pd "
2101                         "               WHERE pd.objoid=pc.oid "
2102                         "       ), NULL, NULL "
2103                         "FROM pg_class pc WHERE relkind = 'l'";
2104
2105         res = PQexec(g_conn, blobQry);
2106         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2107
2108         /* Command to fetch from cursor */
2109         blobFetchQry = "FETCH 100 IN blobcmt";
2110
2111         do
2112         {
2113                 PQclear(res);
2114
2115                 /* Do a fetch */
2116                 res = PQexec(g_conn, blobFetchQry);
2117                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2118
2119                 /* Process the tuples, if any */
2120                 for (i = 0; i < PQntuples(res); i++)
2121                 {
2122                         Oid                     blobOid = atooid(PQgetvalue(res, i, 0));
2123                         char       *lo_comment = PQgetvalue(res, i, 1);
2124                         char       *lo_owner = PQgetvalue(res, i, 2);
2125                         char       *lo_acl = PQgetvalue(res, i, 3);
2126                         char            lo_name[32];
2127
2128                         resetPQExpBuffer(cmdQry);
2129
2130                         /* comment on the blob */
2131                         if (!PQgetisnull(res, i, 1))
2132                         {
2133                                 appendPQExpBuffer(cmdQry,
2134                                                                   "COMMENT ON LARGE OBJECT %u IS ", blobOid);
2135                                 appendStringLiteralAH(cmdQry, lo_comment, AH);
2136                                 appendPQExpBuffer(cmdQry, ";\n");
2137                         }
2138
2139                         /* dump blob ownership, if necessary */
2140                         if (!PQgetisnull(res, i, 2))
2141                         {
2142                                 appendPQExpBuffer(cmdQry,
2143                                                                   "ALTER LARGE OBJECT %u OWNER TO %s;\n",
2144                                                                   blobOid, lo_owner);
2145                         }
2146
2147                         /* dump blob privileges, if necessary */
2148                         if (!PQgetisnull(res, i, 3) &&
2149                                 !dataOnly && !aclsSkip)
2150                         {
2151                                 snprintf(lo_name, sizeof(lo_name), "%u", blobOid);
2152                                 if (!buildACLCommands(lo_name, NULL, "LARGE OBJECT",
2153                                                                           lo_acl, lo_owner, "",
2154                                                                           AH->remoteVersion, cmdQry))
2155                                 {
2156                                         write_msg(NULL, "could not parse ACL (%s) for "
2157                                                           "large object %u", lo_acl, blobOid);
2158                                         exit_nicely();
2159                                 }
2160                         }
2161
2162                         if (cmdQry->len > 0)
2163                         {
2164                                 appendPQExpBuffer(cmdQry, "\n");
2165                                 archputs(cmdQry->data, AH);
2166                         }
2167                 }
2168         } while (PQntuples(res) > 0);
2169
2170         PQclear(res);
2171
2172         archputs("\n", AH);
2173
2174         destroyPQExpBuffer(cmdQry);
2175
2176         return 1;
2177 }
2178
2179 /*
2180  * getNamespaces:
2181  *        read all namespaces in the system catalogs and return them in the
2182  * NamespaceInfo* structure
2183  *
2184  *      numNamespaces is set to the number of namespaces read in
2185  */
2186 NamespaceInfo *
2187 getNamespaces(int *numNamespaces)
2188 {
2189         PGresult   *res;
2190         int                     ntups;
2191         int                     i;
2192         PQExpBuffer query;
2193         NamespaceInfo *nsinfo;
2194         int                     i_tableoid;
2195         int                     i_oid;
2196         int                     i_nspname;
2197         int                     i_rolname;
2198         int                     i_nspacl;
2199
2200         /*
2201          * Before 7.3, there are no real namespaces; create two dummy entries, one
2202          * for user stuff and one for system stuff.
2203          */
2204         if (g_fout->remoteVersion < 70300)
2205         {
2206                 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
2207
2208                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2209                 nsinfo[0].dobj.catId.tableoid = 0;
2210                 nsinfo[0].dobj.catId.oid = 0;
2211                 AssignDumpId(&nsinfo[0].dobj);
2212                 nsinfo[0].dobj.name = strdup("public");
2213                 nsinfo[0].rolname = strdup("");
2214                 nsinfo[0].nspacl = strdup("");
2215
2216                 selectDumpableNamespace(&nsinfo[0]);
2217
2218                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2219                 nsinfo[1].dobj.catId.tableoid = 0;
2220                 nsinfo[1].dobj.catId.oid = 1;
2221                 AssignDumpId(&nsinfo[1].dobj);
2222                 nsinfo[1].dobj.name = strdup("pg_catalog");
2223                 nsinfo[1].rolname = strdup("");
2224                 nsinfo[1].nspacl = strdup("");
2225
2226                 selectDumpableNamespace(&nsinfo[1]);
2227
2228                 g_namespaces = nsinfo;
2229                 g_numNamespaces = *numNamespaces = 2;
2230
2231                 return nsinfo;
2232         }
2233
2234         query = createPQExpBuffer();
2235
2236         /* Make sure we are in proper schema */
2237         selectSourceSchema("pg_catalog");
2238
2239         /*
2240          * we fetch all namespaces including system ones, so that every object we
2241          * read in can be linked to a containing namespace.
2242          */
2243         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2244                                           "(%s nspowner) AS rolname, "
2245                                           "nspacl FROM pg_namespace",
2246                                           username_subquery);
2247
2248         res = PQexec(g_conn, query->data);
2249         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2250
2251         ntups = PQntuples(res);
2252
2253         nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
2254
2255         i_tableoid = PQfnumber(res, "tableoid");
2256         i_oid = PQfnumber(res, "oid");
2257         i_nspname = PQfnumber(res, "nspname");
2258         i_rolname = PQfnumber(res, "rolname");
2259         i_nspacl = PQfnumber(res, "nspacl");
2260
2261         for (i = 0; i < ntups; i++)
2262         {
2263                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2264                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2265                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2266                 AssignDumpId(&nsinfo[i].dobj);
2267                 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
2268                 nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2269                 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
2270
2271                 /* Decide whether to dump this namespace */
2272                 selectDumpableNamespace(&nsinfo[i]);
2273
2274                 if (strlen(nsinfo[i].rolname) == 0)
2275                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2276                                           nsinfo[i].dobj.name);
2277         }
2278
2279         PQclear(res);
2280         destroyPQExpBuffer(query);
2281
2282         g_namespaces = nsinfo;
2283         g_numNamespaces = *numNamespaces = ntups;
2284
2285         return nsinfo;
2286 }
2287
2288 /*
2289  * findNamespace:
2290  *              given a namespace OID and an object OID, look up the info read by
2291  *              getNamespaces
2292  *
2293  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2294  * a system object or not.      In 7.3 and later there is no guessing.
2295  */
2296 static NamespaceInfo *
2297 findNamespace(Oid nsoid, Oid objoid)
2298 {
2299         int                     i;
2300
2301         if (g_fout->remoteVersion >= 70300)
2302         {
2303                 for (i = 0; i < g_numNamespaces; i++)
2304                 {
2305                         NamespaceInfo *nsinfo = &g_namespaces[i];
2306
2307                         if (nsoid == nsinfo->dobj.catId.oid)
2308                                 return nsinfo;
2309                 }
2310                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2311                 exit_nicely();
2312         }
2313         else
2314         {
2315                 /* This code depends on the layout set up by getNamespaces. */
2316                 if (objoid > g_last_builtin_oid)
2317                         i = 0;                          /* user object */
2318                 else
2319                         i = 1;                          /* system object */
2320                 return &g_namespaces[i];
2321         }
2322
2323         return NULL;                            /* keep compiler quiet */
2324 }
2325
2326 /*
2327  * getTypes:
2328  *        read all types in the system catalogs and return them in the
2329  * TypeInfo* structure
2330  *
2331  *      numTypes is set to the number of types read in
2332  *
2333  * NB: this must run after getFuncs() because we assume we can do
2334  * findFuncByOid().
2335  */
2336 TypeInfo *
2337 getTypes(int *numTypes)
2338 {
2339         PGresult   *res;
2340         int                     ntups;
2341         int                     i;
2342         PQExpBuffer query = createPQExpBuffer();
2343         TypeInfo   *tinfo;
2344         ShellTypeInfo *stinfo;
2345         int                     i_tableoid;
2346         int                     i_oid;
2347         int                     i_typname;
2348         int                     i_typnamespace;
2349         int                     i_rolname;
2350         int                     i_typinput;
2351         int                     i_typoutput;
2352         int                     i_typelem;
2353         int                     i_typrelid;
2354         int                     i_typrelkind;
2355         int                     i_typtype;
2356         int                     i_typisdefined;
2357         int                     i_isarray;
2358
2359         /*
2360          * we include even the built-in types because those may be used as array
2361          * elements by user-defined types
2362          *
2363          * we filter out the built-in types when we dump out the types
2364          *
2365          * same approach for undefined (shell) types and array types
2366          *
2367          * Note: as of 8.3 we can reliably detect whether a type is an
2368          * auto-generated array type by checking the element type's typarray.
2369          * (Before that the test is capable of generating false positives.) We
2370          * still check for name beginning with '_', though, so as to avoid the
2371          * cost of the subselect probe for all standard types.  This would have to
2372          * be revisited if the backend ever allows renaming of array types.
2373          */
2374
2375         /* Make sure we are in proper schema */
2376         selectSourceSchema("pg_catalog");
2377
2378         if (g_fout->remoteVersion >= 80300)
2379         {
2380                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2381                                                   "typnamespace, "
2382                                                   "(%s typowner) AS rolname, "
2383                                                   "typinput::oid AS typinput, "
2384                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2385                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2386                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2387                                                   "typtype, typisdefined, "
2388                                                   "typname[0] = '_' AND typelem != 0 AND "
2389                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2390                                                   "FROM pg_type",
2391                                                   username_subquery);
2392         }
2393         else if (g_fout->remoteVersion >= 70300)
2394         {
2395                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2396                                                   "typnamespace, "
2397                                                   "(%s typowner) AS rolname, "
2398                                                   "typinput::oid AS typinput, "
2399                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2400                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2401                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2402                                                   "typtype, typisdefined, "
2403                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2404                                                   "FROM pg_type",
2405                                                   username_subquery);
2406         }
2407         else if (g_fout->remoteVersion >= 70100)
2408         {
2409                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2410                                                   "0::oid AS typnamespace, "
2411                                                   "(%s typowner) AS rolname, "
2412                                                   "typinput::oid AS typinput, "
2413                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2414                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2415                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2416                                                   "typtype, typisdefined, "
2417                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2418                                                   "FROM pg_type",
2419                                                   username_subquery);
2420         }
2421         else
2422         {
2423                 appendPQExpBuffer(query, "SELECT "
2424                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2425                                                   "oid, typname, "
2426                                                   "0::oid AS typnamespace, "
2427                                                   "(%s typowner) AS rolname, "
2428                                                   "typinput::oid AS typinput, "
2429                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2430                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2431                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2432                                                   "typtype, typisdefined, "
2433                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2434                                                   "FROM pg_type",
2435                                                   username_subquery);
2436         }
2437
2438         res = PQexec(g_conn, query->data);
2439         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2440
2441         ntups = PQntuples(res);
2442
2443         tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
2444
2445         i_tableoid = PQfnumber(res, "tableoid");
2446         i_oid = PQfnumber(res, "oid");
2447         i_typname = PQfnumber(res, "typname");
2448         i_typnamespace = PQfnumber(res, "typnamespace");
2449         i_rolname = PQfnumber(res, "rolname");
2450         i_typinput = PQfnumber(res, "typinput");
2451         i_typoutput = PQfnumber(res, "typoutput");
2452         i_typelem = PQfnumber(res, "typelem");
2453         i_typrelid = PQfnumber(res, "typrelid");
2454         i_typrelkind = PQfnumber(res, "typrelkind");
2455         i_typtype = PQfnumber(res, "typtype");
2456         i_typisdefined = PQfnumber(res, "typisdefined");
2457         i_isarray = PQfnumber(res, "isarray");
2458
2459         for (i = 0; i < ntups; i++)
2460         {
2461                 tinfo[i].dobj.objType = DO_TYPE;
2462                 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2463                 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2464                 AssignDumpId(&tinfo[i].dobj);
2465                 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
2466                 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2467                                                                                                 tinfo[i].dobj.catId.oid);
2468                 tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2469                 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2470                 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2471                 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2472                 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2473                 tinfo[i].shellType = NULL;
2474
2475                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2476                         tinfo[i].isDefined = true;
2477                 else
2478                         tinfo[i].isDefined = false;
2479
2480                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2481                         tinfo[i].isArray = true;
2482                 else
2483                         tinfo[i].isArray = false;
2484
2485                 /* Decide whether we want to dump it */
2486                 selectDumpableType(&tinfo[i]);
2487
2488                 /*
2489                  * If it's a domain, fetch info about its constraints, if any
2490                  */
2491                 tinfo[i].nDomChecks = 0;
2492                 tinfo[i].domChecks = NULL;
2493                 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
2494                         getDomainConstraints(&(tinfo[i]));
2495
2496                 /*
2497                  * If it's a base type, make a DumpableObject representing a shell
2498                  * definition of the type.      We will need to dump that ahead of the I/O
2499                  * functions for the type.
2500                  *
2501                  * Note: the shell type doesn't have a catId.  You might think it
2502                  * should copy the base type's catId, but then it might capture the
2503                  * pg_depend entries for the type, which we don't want.
2504                  */
2505                 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
2506                 {
2507                         stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
2508                         stinfo->dobj.objType = DO_SHELL_TYPE;
2509                         stinfo->dobj.catId = nilCatalogId;
2510                         AssignDumpId(&stinfo->dobj);
2511                         stinfo->dobj.name = strdup(tinfo[i].dobj.name);
2512                         stinfo->dobj.namespace = tinfo[i].dobj.namespace;
2513                         stinfo->baseType = &(tinfo[i]);
2514                         tinfo[i].shellType = stinfo;
2515
2516                         /*
2517                          * Initially mark the shell type as not to be dumped.  We'll only
2518                          * dump it if the I/O functions need to be dumped; this is taken
2519                          * care of while sorting dependencies.
2520                          */
2521                         stinfo->dobj.dump = false;
2522
2523                         /*
2524                          * However, if dumping from pre-7.3, there will be no dependency
2525                          * info so we have to fake it here.  We only need to worry about
2526                          * typinput and typoutput since the other functions only exist
2527                          * post-7.3.
2528                          */
2529                         if (g_fout->remoteVersion < 70300)
2530                         {
2531                                 Oid                     typinput;
2532                                 Oid                     typoutput;
2533                                 FuncInfo   *funcInfo;
2534
2535                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
2536                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2537
2538                                 funcInfo = findFuncByOid(typinput);
2539                                 if (funcInfo && funcInfo->dobj.dump)
2540                                 {
2541                                         /* base type depends on function */
2542                                         addObjectDependency(&tinfo[i].dobj,
2543                                                                                 funcInfo->dobj.dumpId);
2544                                         /* function depends on shell type */
2545                                         addObjectDependency(&funcInfo->dobj,
2546                                                                                 stinfo->dobj.dumpId);
2547                                         /* mark shell type as to be dumped */
2548                                         stinfo->dobj.dump = true;
2549                                 }
2550
2551                                 funcInfo = findFuncByOid(typoutput);
2552                                 if (funcInfo && funcInfo->dobj.dump)
2553                                 {
2554                                         /* base type depends on function */
2555                                         addObjectDependency(&tinfo[i].dobj,
2556                                                                                 funcInfo->dobj.dumpId);
2557                                         /* function depends on shell type */
2558                                         addObjectDependency(&funcInfo->dobj,
2559                                                                                 stinfo->dobj.dumpId);
2560                                         /* mark shell type as to be dumped */
2561                                         stinfo->dobj.dump = true;
2562                                 }
2563                         }
2564                 }
2565
2566                 if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
2567                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2568                                           tinfo[i].dobj.name);
2569         }
2570
2571         *numTypes = ntups;
2572
2573         PQclear(res);
2574
2575         destroyPQExpBuffer(query);
2576
2577         return tinfo;
2578 }
2579
2580 /*
2581  * getOperators:
2582  *        read all operators in the system catalogs and return them in the
2583  * OprInfo* structure
2584  *
2585  *      numOprs is set to the number of operators read in
2586  */
2587 OprInfo *
2588 getOperators(int *numOprs)
2589 {
2590         PGresult   *res;
2591         int                     ntups;
2592         int                     i;
2593         PQExpBuffer query = createPQExpBuffer();
2594         OprInfo    *oprinfo;
2595         int                     i_tableoid;
2596         int                     i_oid;
2597         int                     i_oprname;
2598         int                     i_oprnamespace;
2599         int                     i_rolname;
2600         int                     i_oprcode;
2601
2602         /*
2603          * find all operators, including builtin operators; we filter out
2604          * system-defined operators at dump-out time.
2605          */
2606
2607         /* Make sure we are in proper schema */
2608         selectSourceSchema("pg_catalog");
2609
2610         if (g_fout->remoteVersion >= 70300)
2611         {
2612                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2613                                                   "oprnamespace, "
2614                                                   "(%s oprowner) AS rolname, "
2615                                                   "oprcode::oid AS oprcode "
2616                                                   "FROM pg_operator",
2617                                                   username_subquery);
2618         }
2619         else if (g_fout->remoteVersion >= 70100)
2620         {
2621                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2622                                                   "0::oid AS oprnamespace, "
2623                                                   "(%s oprowner) AS rolname, "
2624                                                   "oprcode::oid AS oprcode "
2625                                                   "FROM pg_operator",
2626                                                   username_subquery);
2627         }
2628         else
2629         {
2630                 appendPQExpBuffer(query, "SELECT "
2631                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2632                                                   "oid, oprname, "
2633                                                   "0::oid AS oprnamespace, "
2634                                                   "(%s oprowner) AS rolname, "
2635                                                   "oprcode::oid AS oprcode "
2636                                                   "FROM pg_operator",
2637                                                   username_subquery);
2638         }
2639
2640         res = PQexec(g_conn, query->data);
2641         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2642
2643         ntups = PQntuples(res);
2644         *numOprs = ntups;
2645
2646         oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
2647
2648         i_tableoid = PQfnumber(res, "tableoid");
2649         i_oid = PQfnumber(res, "oid");
2650         i_oprname = PQfnumber(res, "oprname");
2651         i_oprnamespace = PQfnumber(res, "oprnamespace");
2652         i_rolname = PQfnumber(res, "rolname");
2653         i_oprcode = PQfnumber(res, "oprcode");
2654
2655         for (i = 0; i < ntups; i++)
2656         {
2657                 oprinfo[i].dobj.objType = DO_OPERATOR;
2658                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2659                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2660                 AssignDumpId(&oprinfo[i].dobj);
2661                 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
2662                 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
2663                                                                                                   oprinfo[i].dobj.catId.oid);
2664                 oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2665                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
2666
2667                 /* Decide whether we want to dump it */
2668                 selectDumpableObject(&(oprinfo[i].dobj));
2669
2670                 if (strlen(oprinfo[i].rolname) == 0)
2671                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2672                                           oprinfo[i].dobj.name);
2673         }
2674
2675         PQclear(res);
2676
2677         destroyPQExpBuffer(query);
2678
2679         return oprinfo;
2680 }
2681
2682 /*
2683  * getConversions:
2684  *        read all conversions in the system catalogs and return them in the
2685  * ConvInfo* structure
2686  *
2687  *      numConversions is set to the number of conversions read in
2688  */
2689 ConvInfo *
2690 getConversions(int *numConversions)
2691 {
2692         PGresult   *res;
2693         int                     ntups;
2694         int                     i;
2695         PQExpBuffer query = createPQExpBuffer();
2696         ConvInfo   *convinfo;
2697         int                     i_tableoid;
2698         int                     i_oid;
2699         int                     i_conname;
2700         int                     i_connamespace;
2701         int                     i_rolname;
2702
2703         /* Conversions didn't exist pre-7.3 */
2704         if (g_fout->remoteVersion < 70300)
2705         {
2706                 *numConversions = 0;
2707                 return NULL;
2708         }
2709
2710         /*
2711          * find all conversions, including builtin conversions; we filter out
2712          * system-defined conversions at dump-out time.
2713          */
2714
2715         /* Make sure we are in proper schema */
2716         selectSourceSchema("pg_catalog");
2717
2718         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2719                                           "connamespace, "
2720                                           "(%s conowner) AS rolname "
2721                                           "FROM pg_conversion",
2722                                           username_subquery);
2723
2724         res = PQexec(g_conn, query->data);
2725         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2726
2727         ntups = PQntuples(res);
2728         *numConversions = ntups;
2729
2730         convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
2731
2732         i_tableoid = PQfnumber(res, "tableoid");
2733         i_oid = PQfnumber(res, "oid");
2734         i_conname = PQfnumber(res, "conname");
2735         i_connamespace = PQfnumber(res, "connamespace");
2736         i_rolname = PQfnumber(res, "rolname");
2737
2738         for (i = 0; i < ntups; i++)
2739         {
2740                 convinfo[i].dobj.objType = DO_CONVERSION;
2741                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2742                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2743                 AssignDumpId(&convinfo[i].dobj);
2744                 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2745                 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
2746                                                                                                  convinfo[i].dobj.catId.oid);
2747                 convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2748
2749                 /* Decide whether we want to dump it */
2750                 selectDumpableObject(&(convinfo[i].dobj));
2751         }
2752
2753         PQclear(res);
2754
2755         destroyPQExpBuffer(query);
2756
2757         return convinfo;
2758 }
2759
2760 /*
2761  * getOpclasses:
2762  *        read all opclasses in the system catalogs and return them in the
2763  * OpclassInfo* structure
2764  *
2765  *      numOpclasses is set to the number of opclasses read in
2766  */
2767 OpclassInfo *
2768 getOpclasses(int *numOpclasses)
2769 {
2770         PGresult   *res;
2771         int                     ntups;
2772         int                     i;
2773         PQExpBuffer query = createPQExpBuffer();
2774         OpclassInfo *opcinfo;
2775         int                     i_tableoid;
2776         int                     i_oid;
2777         int                     i_opcname;
2778         int                     i_opcnamespace;
2779         int                     i_rolname;
2780
2781         /*
2782          * find all opclasses, including builtin opclasses; we filter out
2783          * system-defined opclasses at dump-out time.
2784          */
2785
2786         /* Make sure we are in proper schema */
2787         selectSourceSchema("pg_catalog");
2788
2789         if (g_fout->remoteVersion >= 70300)
2790         {
2791                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2792                                                   "opcnamespace, "
2793                                                   "(%s opcowner) AS rolname "
2794                                                   "FROM pg_opclass",
2795                                                   username_subquery);
2796         }
2797         else if (g_fout->remoteVersion >= 70100)
2798         {
2799                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2800                                                   "0::oid AS opcnamespace, "
2801                                                   "''::name AS rolname "
2802                                                   "FROM pg_opclass");
2803         }
2804         else
2805         {
2806                 appendPQExpBuffer(query, "SELECT "
2807                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2808                                                   "oid, opcname, "
2809                                                   "0::oid AS opcnamespace, "
2810                                                   "''::name AS rolname "
2811                                                   "FROM pg_opclass");
2812         }
2813
2814         res = PQexec(g_conn, query->data);
2815         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2816
2817         ntups = PQntuples(res);
2818         *numOpclasses = ntups;
2819
2820         opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
2821
2822         i_tableoid = PQfnumber(res, "tableoid");
2823         i_oid = PQfnumber(res, "oid");
2824         i_opcname = PQfnumber(res, "opcname");
2825         i_opcnamespace = PQfnumber(res, "opcnamespace");
2826         i_rolname = PQfnumber(res, "rolname");
2827
2828         for (i = 0; i < ntups; i++)
2829         {
2830                 opcinfo[i].dobj.objType = DO_OPCLASS;
2831                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2832                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2833                 AssignDumpId(&opcinfo[i].dobj);
2834                 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2835                 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2836                                                                                                   opcinfo[i].dobj.catId.oid);
2837                 opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2838
2839                 /* Decide whether we want to dump it */
2840                 selectDumpableObject(&(opcinfo[i].dobj));
2841
2842                 if (g_fout->remoteVersion >= 70300)
2843                 {
2844                         if (strlen(opcinfo[i].rolname) == 0)
2845                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2846                                                   opcinfo[i].dobj.name);
2847                 }
2848         }
2849
2850         PQclear(res);
2851
2852         destroyPQExpBuffer(query);
2853
2854         return opcinfo;
2855 }
2856
2857 /*
2858  * getOpfamilies:
2859  *        read all opfamilies in the system catalogs and return them in the
2860  * OpfamilyInfo* structure
2861  *
2862  *      numOpfamilies is set to the number of opfamilies read in
2863  */
2864 OpfamilyInfo *
2865 getOpfamilies(int *numOpfamilies)
2866 {
2867         PGresult   *res;
2868         int                     ntups;
2869         int                     i;
2870         PQExpBuffer query;
2871         OpfamilyInfo *opfinfo;
2872         int                     i_tableoid;
2873         int                     i_oid;
2874         int                     i_opfname;
2875         int                     i_opfnamespace;
2876         int                     i_rolname;
2877
2878         /* Before 8.3, there is no separate concept of opfamilies */
2879         if (g_fout->remoteVersion < 80300)
2880         {
2881                 *numOpfamilies = 0;
2882                 return NULL;
2883         }
2884
2885         query = createPQExpBuffer();
2886
2887         /*
2888          * find all opfamilies, including builtin opfamilies; we filter out
2889          * system-defined opfamilies at dump-out time.
2890          */
2891
2892         /* Make sure we are in proper schema */
2893         selectSourceSchema("pg_catalog");
2894
2895         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2896                                           "opfnamespace, "
2897                                           "(%s opfowner) AS rolname "
2898                                           "FROM pg_opfamily",
2899                                           username_subquery);
2900
2901         res = PQexec(g_conn, query->data);
2902         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2903
2904         ntups = PQntuples(res);
2905         *numOpfamilies = ntups;
2906
2907         opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
2908
2909         i_tableoid = PQfnumber(res, "tableoid");
2910         i_oid = PQfnumber(res, "oid");
2911         i_opfname = PQfnumber(res, "opfname");
2912         i_opfnamespace = PQfnumber(res, "opfnamespace");
2913         i_rolname = PQfnumber(res, "rolname");
2914
2915         for (i = 0; i < ntups; i++)
2916         {
2917                 opfinfo[i].dobj.objType = DO_OPFAMILY;
2918                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2919                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2920                 AssignDumpId(&opfinfo[i].dobj);
2921                 opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
2922                 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
2923                                                                                                   opfinfo[i].dobj.catId.oid);
2924                 opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2925
2926                 /* Decide whether we want to dump it */
2927                 selectDumpableObject(&(opfinfo[i].dobj));
2928
2929                 if (g_fout->remoteVersion >= 70300)
2930                 {
2931                         if (strlen(opfinfo[i].rolname) == 0)
2932                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2933                                                   opfinfo[i].dobj.name);
2934                 }
2935         }
2936
2937         PQclear(res);
2938
2939         destroyPQExpBuffer(query);
2940
2941         return opfinfo;
2942 }
2943
2944 /*
2945  * getAggregates:
2946  *        read all the user-defined aggregates in the system catalogs and
2947  * return them in the AggInfo* structure
2948  *
2949  * numAggs is set to the number of aggregates read in
2950  */
2951 AggInfo *
2952 getAggregates(int *numAggs)
2953 {
2954         PGresult   *res;
2955         int                     ntups;
2956         int                     i;
2957         PQExpBuffer query = createPQExpBuffer();
2958         AggInfo    *agginfo;
2959         int                     i_tableoid;
2960         int                     i_oid;
2961         int                     i_aggname;
2962         int                     i_aggnamespace;
2963         int                     i_pronargs;
2964         int                     i_proargtypes;
2965         int                     i_rolname;
2966         int                     i_aggacl;
2967
2968         /* Make sure we are in proper schema */
2969         selectSourceSchema("pg_catalog");
2970
2971         /* find all user-defined aggregates */
2972
2973         if (g_fout->remoteVersion >= 80200)
2974         {
2975                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2976                                                   "pronamespace AS aggnamespace, "
2977                                                   "pronargs, proargtypes, "
2978                                                   "(%s proowner) AS rolname, "
2979                                                   "proacl AS aggacl "
2980                                                   "FROM pg_proc "
2981                                                   "WHERE proisagg "
2982                                                   "AND pronamespace != "
2983                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2984                                                   username_subquery);
2985         }
2986         else if (g_fout->remoteVersion >= 70300)
2987         {
2988                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2989                                                   "pronamespace AS aggnamespace, "
2990                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
2991                                                   "proargtypes, "
2992                                                   "(%s proowner) AS rolname, "
2993                                                   "proacl AS aggacl "
2994                                                   "FROM pg_proc "
2995                                                   "WHERE proisagg "
2996                                                   "AND pronamespace != "
2997                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2998                                                   username_subquery);
2999         }
3000         else if (g_fout->remoteVersion >= 70100)
3001         {
3002                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
3003                                                   "0::oid AS aggnamespace, "
3004                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3005                                                   "aggbasetype AS proargtypes, "
3006                                                   "(%s aggowner) AS rolname, "
3007                                                   "'{=X}' AS aggacl "
3008                                                   "FROM pg_aggregate "
3009                                                   "where oid > '%u'::oid",
3010                                                   username_subquery,
3011                                                   g_last_builtin_oid);
3012         }
3013         else
3014         {
3015                 appendPQExpBuffer(query, "SELECT "
3016                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
3017                                                   "oid, aggname, "
3018                                                   "0::oid AS aggnamespace, "
3019                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
3020                                                   "aggbasetype AS proargtypes, "
3021                                                   "(%s aggowner) AS rolname, "
3022                                                   "'{=X}' AS aggacl "
3023                                                   "FROM pg_aggregate "
3024                                                   "where oid > '%u'::oid",
3025                                                   username_subquery,
3026                                                   g_last_builtin_oid);
3027         }
3028
3029         res = PQexec(g_conn, query->data);
3030         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3031
3032         ntups = PQntuples(res);
3033         *numAggs = ntups;
3034
3035         agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
3036
3037         i_tableoid = PQfnumber(res, "tableoid");
3038         i_oid = PQfnumber(res, "oid");
3039         i_aggname = PQfnumber(res, "aggname");
3040         i_aggnamespace = PQfnumber(res, "aggnamespace");
3041         i_pronargs = PQfnumber(res, "pronargs");
3042         i_proargtypes = PQfnumber(res, "proargtypes");
3043         i_rolname = PQfnumber(res, "rolname");
3044         i_aggacl = PQfnumber(res, "aggacl");
3045
3046         for (i = 0; i < ntups; i++)
3047         {
3048                 agginfo[i].aggfn.dobj.objType = DO_AGG;
3049                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3050                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3051                 AssignDumpId(&agginfo[i].aggfn.dobj);
3052                 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
3053                 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
3054                                                                                         agginfo[i].aggfn.dobj.catId.oid);
3055                 agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
3056                 if (strlen(agginfo[i].aggfn.rolname) == 0)
3057                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
3058                                           agginfo[i].aggfn.dobj.name);
3059                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
3060                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
3061                 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
3062                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
3063                 if (agginfo[i].aggfn.nargs == 0)
3064                         agginfo[i].aggfn.argtypes = NULL;
3065                 else
3066                 {
3067                         agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
3068                         if (g_fout->remoteVersion >= 70300)
3069                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
3070                                                           agginfo[i].aggfn.argtypes,
3071                                                           agginfo[i].aggfn.nargs);
3072                         else
3073                                 /* it's just aggbasetype */
3074                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
3075                 }
3076
3077                 /* Decide whether we want to dump it */
3078                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
3079         }
3080
3081         PQclear(res);
3082
3083         destroyPQExpBuffer(query);
3084
3085         return agginfo;
3086 }
3087
3088 /*
3089  * getFuncs:
3090  *        read all the user-defined functions in the system catalogs and
3091  * return them in the FuncInfo* structure
3092  *
3093  * numFuncs is set to the number of functions read in
3094  */
3095 FuncInfo *
3096 getFuncs(int *numFuncs)
3097 {
3098         PGresult   *res;
3099         int                     ntups;
3100         int                     i;
3101         PQExpBuffer query = createPQExpBuffer();
3102         FuncInfo   *finfo;
3103         int                     i_tableoid;
3104         int                     i_oid;
3105         int                     i_proname;
3106         int                     i_pronamespace;
3107         int                     i_rolname;
3108         int                     i_prolang;
3109         int                     i_pronargs;
3110         int                     i_proargtypes;
3111         int                     i_prorettype;
3112         int                     i_proacl;
3113
3114         /* Make sure we are in proper schema */
3115         selectSourceSchema("pg_catalog");
3116
3117         /* find all user-defined funcs */
3118
3119         if (g_fout->remoteVersion >= 70300)
3120         {
3121                 appendPQExpBuffer(query,
3122                                                   "SELECT tableoid, oid, proname, prolang, "
3123                                                   "pronargs, proargtypes, prorettype, proacl, "
3124                                                   "pronamespace, "
3125                                                   "(%s proowner) AS rolname "
3126                                                   "FROM pg_proc "
3127                                                   "WHERE NOT proisagg "
3128                                                   "AND pronamespace != "
3129                                                   "(SELECT oid FROM pg_namespace "
3130                                                   "WHERE nspname = 'pg_catalog')",
3131                                                   username_subquery);
3132         }
3133         else if (g_fout->remoteVersion >= 70100)
3134         {
3135                 appendPQExpBuffer(query,
3136                                                   "SELECT tableoid, oid, proname, prolang, "
3137                                                   "pronargs, proargtypes, prorettype, "
3138                                                   "'{=X}' AS proacl, "
3139                                                   "0::oid AS pronamespace, "
3140                                                   "(%s proowner) AS rolname "
3141                                                   "FROM pg_proc "
3142                                                   "WHERE pg_proc.oid > '%u'::oid",
3143                                                   username_subquery,
3144                                                   g_last_builtin_oid);
3145         }
3146         else
3147         {
3148                 appendPQExpBuffer(query,
3149                                                   "SELECT "
3150                                                   "(SELECT oid FROM pg_class "
3151                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3152                                                   "oid, proname, prolang, "
3153                                                   "pronargs, proargtypes, prorettype, "
3154                                                   "'{=X}' AS proacl, "
3155                                                   "0::oid AS pronamespace, "
3156                                                   "(%s proowner) AS rolname "
3157                                                   "FROM pg_proc "
3158                                                   "where pg_proc.oid > '%u'::oid",
3159                                                   username_subquery,
3160                                                   g_last_builtin_oid);
3161         }
3162
3163         res = PQexec(g_conn, query->data);
3164         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3165
3166         ntups = PQntuples(res);
3167
3168         *numFuncs = ntups;
3169
3170         finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
3171
3172         i_tableoid = PQfnumber(res, "tableoid");
3173         i_oid = PQfnumber(res, "oid");
3174         i_proname = PQfnumber(res, "proname");
3175         i_pronamespace = PQfnumber(res, "pronamespace");
3176         i_rolname = PQfnumber(res, "rolname");
3177         i_prolang = PQfnumber(res, "prolang");
3178         i_pronargs = PQfnumber(res, "pronargs");
3179         i_proargtypes = PQfnumber(res, "proargtypes");
3180         i_prorettype = PQfnumber(res, "prorettype");
3181         i_proacl = PQfnumber(res, "proacl");
3182
3183         for (i = 0; i < ntups; i++)
3184         {
3185                 finfo[i].dobj.objType = DO_FUNC;
3186                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3187                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3188                 AssignDumpId(&finfo[i].dobj);
3189                 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
3190                 finfo[i].dobj.namespace =
3191                         findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3192                                                   finfo[i].dobj.catId.oid);
3193                 finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3194                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3195                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3196                 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
3197                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3198                 if (finfo[i].nargs == 0)
3199                         finfo[i].argtypes = NULL;
3200                 else
3201                 {
3202                         finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
3203                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3204                                                   finfo[i].argtypes, finfo[i].nargs);
3205                 }
3206
3207                 /* Decide whether we want to dump it */
3208                 selectDumpableObject(&(finfo[i].dobj));
3209
3210                 if (strlen(finfo[i].rolname) == 0)
3211                         write_msg(NULL,
3212                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3213                                           finfo[i].dobj.name);
3214         }
3215
3216         PQclear(res);
3217
3218         destroyPQExpBuffer(query);
3219
3220         return finfo;
3221 }
3222
3223 /*
3224  * getTables
3225  *        read all the user-defined tables (no indexes, no catalogs)
3226  * in the system catalogs return them in the TableInfo* structure
3227  *
3228  * numTables is set to the number of tables read in
3229  */
3230 TableInfo *
3231 getTables(int *numTables)
3232 {
3233         PGresult   *res;
3234         int                     ntups;
3235         int                     i;
3236         PQExpBuffer query = createPQExpBuffer();
3237         TableInfo  *tblinfo;
3238         int                     i_reltableoid;
3239         int                     i_reloid;
3240         int                     i_relname;
3241         int                     i_relnamespace;
3242         int                     i_relkind;
3243         int                     i_relacl;
3244         int                     i_rolname;
3245         int                     i_relchecks;
3246         int                     i_relhastriggers;
3247         int                     i_relhasindex;
3248         int                     i_relhasrules;
3249         int                     i_relhasoids;
3250         int                     i_relfrozenxid;
3251         int                     i_owning_tab;
3252         int                     i_owning_col;
3253         int                     i_reltablespace;
3254         int                     i_reloptions;
3255         int                     i_toastreloptions;
3256
3257         /* Make sure we are in proper schema */
3258         selectSourceSchema("pg_catalog");
3259
3260         /*
3261          * Find all the tables (including views and sequences).
3262          *
3263          * We include system catalogs, so that we can work if a user table is
3264          * defined to inherit from a system catalog (pretty weird, but...)
3265          *
3266          * We ignore tables that are not type 'r' (ordinary relation), 'S'
3267          * (sequence), 'v' (view), or 'c' (composite type).
3268          *
3269          * Composite-type table entries won't be dumped as such, but we have to
3270          * make a DumpableObject for them so that we can track dependencies of the
3271          * composite type (pg_depend entries for columns of the composite type
3272          * link to the pg_class entry not the pg_type entry).
3273          *
3274          * Note: in this phase we should collect only a minimal amount of
3275          * information about each table, basically just enough to decide if it is
3276          * interesting. We must fetch all tables in this phase because otherwise
3277          * we cannot correctly identify inherited columns, owned sequences, etc.
3278          */
3279
3280         if (g_fout->remoteVersion >= 80400)
3281         {
3282                 /*
3283                  * Left join to pick up dependency info linking sequences to their
3284                  * owning column, if any (note this dependency is AUTO as of 8.2)
3285                  */
3286                 appendPQExpBuffer(query,
3287                                                   "SELECT c.tableoid, c.oid, c.relname, "
3288                                                   "c.relacl, c.relkind, c.relnamespace, "
3289                                                   "(%s c.relowner) AS rolname, "
3290                                                   "c.relchecks, c.relhastriggers, "
3291                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3292                                                   "c.relfrozenxid, "
3293                                                   "d.refobjid AS owning_tab, "
3294                                                   "d.refobjsubid AS owning_col, "
3295                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3296                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3297                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3298                                                   "FROM pg_class c "
3299                                                   "LEFT JOIN pg_depend d ON "
3300                                                   "(c.relkind = '%c' AND "
3301                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3302                                                   "d.objsubid = 0 AND "
3303                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3304                                            "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3305                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3306                                                   "ORDER BY c.oid",
3307                                                   username_subquery,
3308                                                   RELKIND_SEQUENCE,
3309                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3310                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3311         }
3312         else if (g_fout->remoteVersion >= 80200)
3313         {
3314                 /*
3315                  * Left join to pick up dependency info linking sequences to their
3316                  * owning column, if any (note this dependency is AUTO as of 8.2)
3317                  */
3318                 appendPQExpBuffer(query,
3319                                                   "SELECT c.tableoid, c.oid, relname, "
3320                                                   "relacl, relkind, relnamespace, "
3321                                                   "(%s relowner) AS rolname, "
3322                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3323                                                   "relhasindex, relhasrules, relhasoids, "
3324                                                   "relfrozenxid, "
3325                                                   "d.refobjid AS owning_tab, "
3326                                                   "d.refobjsubid AS owning_col, "
3327                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3328                                                 "array_to_string(c.reloptions, ', ') AS reloptions, "
3329                                                   "NULL AS toast_reloptions "
3330                                                   "FROM pg_class c "
3331                                                   "LEFT JOIN pg_depend d ON "
3332                                                   "(c.relkind = '%c' AND "
3333                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3334                                                   "d.objsubid = 0 AND "
3335                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3336                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
3337                                                   "ORDER BY c.oid",
3338                                                   username_subquery,
3339                                                   RELKIND_SEQUENCE,
3340                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3341                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3342         }
3343         else if (g_fout->remoteVersion >= 80000)
3344         {
3345                 /*
3346                  * Left join to pick up dependency info linking sequences to their
3347                  * owning column, if any
3348                  */
3349                 appendPQExpBuffer(query,
3350                                                   "SELECT c.tableoid, c.oid, relname, "
3351                                                   "relacl, relkind, relnamespace, "
3352                                                   "(%s relowner) AS rolname, "
3353                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3354                                                   "relhasindex, relhasrules, relhasoids, "
3355                                                   "0 AS relfrozenxid, "
3356                                                   "d.refobjid AS owning_tab, "
3357                                                   "d.refobjsubid AS owning_col, "
3358                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3359                                                   "NULL AS reloptions, "
3360                                                   "NULL AS toast_reloptions "
3361                                                   "FROM pg_class c "
3362                                                   "LEFT JOIN pg_depend d ON "
3363                                                   "(c.relkind = '%c' AND "
3364                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3365                                                   "d.objsubid = 0 AND "
3366                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
3367                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
3368                                                   "ORDER BY c.oid",
3369                                                   username_subquery,
3370                                                   RELKIND_SEQUENCE,
3371                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3372                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3373         }
3374         else if (g_fout->remoteVersion >= 70300)
3375         {
3376                 /*
3377                  * Left join to pick up dependency info linking sequences to their
3378                  * owning column, if any
3379                  */
3380                 appendPQExpBuffer(query,
3381                                                   "SELECT c.tableoid, c.oid, relname, "
3382                                                   "relacl, relkind, relnamespace, "
3383                                                   "(%s relowner) AS rolname, "
3384                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3385                                                   "relhasindex, relhasrules, relhasoids, "
3386                                                   "0 AS relfrozenxid, "
3387                                                   "d.refobjid AS owning_tab, "
3388                                                   "d.refobjsubid AS owning_col, "
3389                                                   "NULL AS reltablespace, "
3390                                                   "NULL AS reloptions, "
3391                                                   "NULL AS toast_reloptions "
3392                                                   "FROM pg_class c "
3393                                                   "LEFT JOIN pg_depend d ON "
3394                                                   "(c.relkind = '%c' AND "
3395                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3396                                                   "d.objsubid = 0 AND "
3397                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
3398                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
3399                                                   "ORDER BY c.oid",
3400                                                   username_subquery,
3401                                                   RELKIND_SEQUENCE,
3402                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3403                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3404         }
3405         else if (g_fout->remoteVersion >= 70200)
3406         {
3407                 appendPQExpBuffer(query,
3408                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
3409                                                   "0::oid AS relnamespace, "
3410                                                   "(%s relowner) AS rolname, "
3411                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3412                                                   "relhasindex, relhasrules, relhasoids, "
3413                                                   "0 AS relfrozenxid, "
3414                                                   "NULL::oid AS owning_tab, "
3415                                                   "NULL::int4 AS owning_col, "
3416                                                   "NULL AS reltablespace, "
3417                                                   "NULL AS reloptions, "
3418                                                   "NULL AS toast_reloptions "
3419                                                   "FROM pg_class "
3420                                                   "WHERE relkind IN ('%c', '%c', '%c') "
3421                                                   "ORDER BY oid",
3422                                                   username_subquery,
3423                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3424         }
3425         else if (g_fout->remoteVersion >= 70100)
3426         {
3427                 /* all tables have oids in 7.1 */
3428                 appendPQExpBuffer(query,
3429                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
3430                                                   "0::oid AS relnamespace, "
3431                                                   "(%s relowner) AS rolname, "
3432                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3433                                                   "relhasindex, relhasrules, "
3434                                                   "'t'::bool AS relhasoids, "
3435                                                   "0 AS relfrozenxid, "
3436                                                   "NULL::oid AS owning_tab, "
3437                                                   "NULL::int4 AS owning_col, "
3438                                                   "NULL AS reltablespace, "
3439                                                   "NULL AS reloptions, "
3440                                                   "NULL AS toast_reloptions "
3441                                                   "FROM pg_class "
3442                                                   "WHERE relkind IN ('%c', '%c', '%c') "
3443                                                   "ORDER BY oid",
3444                                                   username_subquery,
3445                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3446         }
3447         else
3448         {
3449                 /*
3450                  * Before 7.1, view relkind was not set to 'v', so we must check if we
3451                  * have a view by looking for a rule in pg_rewrite.
3452                  */
3453                 appendPQExpBuffer(query,
3454                                                   "SELECT "
3455                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3456                                                   "oid, relname, relacl, "
3457                                                   "CASE WHEN relhasrules and relkind = 'r' "
3458                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3459                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
3460                                                   "THEN '%c'::\"char\" "
3461                                                   "ELSE relkind END AS relkind,"
3462                                                   "0::oid AS relnamespace, "
3463                                                   "(%s relowner) AS rolname, "
3464                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3465                                                   "relhasindex, relhasrules, "
3466                                                   "'t'::bool AS relhasoids, "
3467                                                   "0 as relfrozenxid, "
3468                                                   "NULL::oid AS owning_tab, "
3469                                                   "NULL::int4 AS owning_col, "
3470                                                   "NULL AS reltablespace, "
3471                                                   "NULL AS reloptions, "
3472                                                   "NULL AS toast_reloptions "
3473                                                   "FROM pg_class c "
3474                                                   "WHERE relkind IN ('%c', '%c') "
3475                                                   "ORDER BY oid",
3476                                                   RELKIND_VIEW,
3477                                                   username_subquery,
3478                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
3479         }
3480
3481         res = PQexec(g_conn, query->data);
3482         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3483
3484         ntups = PQntuples(res);
3485
3486         *numTables = ntups;
3487
3488         /*
3489          * Extract data from result and lock dumpable tables.  We do the locking
3490          * before anything else, to minimize the window wherein a table could
3491          * disappear under us.
3492          *
3493          * Note that we have to save info about all tables here, even when dumping
3494          * only one, because we don't yet know which tables might be inheritance
3495          * ancestors of the target table.
3496          */
3497         tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
3498
3499         i_reltableoid = PQfnumber(res, "tableoid");
3500         i_reloid = PQfnumber(res, "oid");
3501         i_relname = PQfnumber(res, "relname");
3502         i_relnamespace = PQfnumber(res, "relnamespace");
3503         i_relacl = PQfnumber(res, "relacl");
3504         i_relkind = PQfnumber(res, "relkind");
3505         i_rolname = PQfnumber(res, "rolname");
3506         i_relchecks = PQfnumber(res, "relchecks");
3507         i_relhastriggers = PQfnumber(res, "relhastriggers");
3508         i_relhasindex = PQfnumber(res, "relhasindex");
3509         i_relhasrules = PQfnumber(res, "relhasrules");
3510         i_relhasoids = PQfnumber(res, "relhasoids");
3511         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
3512         i_owning_tab = PQfnumber(res, "owning_tab");
3513         i_owning_col = PQfnumber(res, "owning_col");
3514         i_reltablespace = PQfnumber(res, "reltablespace");
3515         i_reloptions = PQfnumber(res, "reloptions");
3516         i_toastreloptions = PQfnumber(res, "toast_reloptions");
3517
3518         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3519         {
3520                 /*
3521                  * Arrange to fail instead of waiting forever for a table lock.
3522                  *
3523                  * NB: this coding assumes that the only queries issued within the
3524                  * following loop are LOCK TABLEs; else the timeout may be undesirably
3525                  * applied to other things too.
3526                  */
3527                 resetPQExpBuffer(query);
3528                 appendPQExpBuffer(query, "SET statement_timeout = ");
3529                 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3530                 do_sql_command(g_conn, query->data);
3531         }
3532
3533         for (i = 0; i < ntups; i++)
3534         {
3535                 tblinfo[i].dobj.objType = DO_TABLE;
3536                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
3537                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
3538                 AssignDumpId(&tblinfo[i].dobj);
3539                 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
3540                 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
3541                                                                                                   tblinfo[i].dobj.catId.oid);
3542                 tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3543                 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
3544                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
3545                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
3546                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
3547                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
3548                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
3549                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
3550                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
3551                 if (PQgetisnull(res, i, i_owning_tab))
3552                 {
3553                         tblinfo[i].owning_tab = InvalidOid;
3554                         tblinfo[i].owning_col = 0;
3555                 }
3556                 else
3557                 {
3558                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3559                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
3560                 }
3561                 tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
3562                 tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
3563                 tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
3564
3565                 /* other fields were zeroed above */
3566
3567                 /*
3568                  * Decide whether we want to dump this table.
3569                  */
3570                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3571                         tblinfo[i].dobj.dump = false;
3572                 else
3573                         selectDumpableTable(&tblinfo[i]);
3574                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3575
3576                 /*
3577                  * Read-lock target tables to make sure they aren't DROPPED or altered
3578                  * in schema before we get around to dumping them.
3579                  *
3580                  * Note that we don't explicitly lock parents of the target tables; we
3581                  * assume our lock on the child is enough to prevent schema
3582                  * alterations to parent tables.
3583                  *
3584                  * NOTE: it'd be kinda nice to lock views and sequences too, not only
3585                  * plain tables, but the backend doesn't presently allow that.
3586                  */
3587                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
3588                 {
3589                         resetPQExpBuffer(query);
3590                         appendPQExpBuffer(query,
3591                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
3592                                                  fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
3593                                                                                 tblinfo[i].dobj.name));
3594                         do_sql_command(g_conn, query->data);
3595                 }
3596
3597                 /* Emit notice if join for owner failed */
3598                 if (strlen(tblinfo[i].rolname) == 0)
3599                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
3600                                           tblinfo[i].dobj.name);
3601         }
3602
3603         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3604         {
3605                 do_sql_command(g_conn, "SET statement_timeout = 0");
3606         }
3607
3608         PQclear(res);
3609
3610         /*
3611          * Force sequences that are "owned" by table columns to be dumped whenever
3612          * their owning table is being dumped.
3613          */
3614         for (i = 0; i < ntups; i++)
3615         {
3616                 TableInfo  *seqinfo = &tblinfo[i];
3617                 int                     j;
3618
3619                 if (!OidIsValid(seqinfo->owning_tab))
3620                         continue;                       /* not an owned sequence */
3621                 if (seqinfo->dobj.dump)
3622                         continue;                       /* no need to search */
3623
3624                 /* can't use findTableByOid yet, unfortunately */
3625                 for (j = 0; j < ntups; j++)
3626                 {
3627                         if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3628                         {
3629                                 if (tblinfo[j].dobj.dump)
3630                                 {
3631                                         seqinfo->interesting = true;
3632                                         seqinfo->dobj.dump = true;
3633                                 }
3634                                 break;
3635                         }
3636                 }
3637         }
3638
3639         destroyPQExpBuffer(query);
3640
3641         return tblinfo;
3642 }
3643
3644 /*
3645  * getInherits
3646  *        read all the inheritance information
3647  * from the system catalogs return them in the InhInfo* structure
3648  *
3649  * numInherits is set to the number of pairs read in
3650  */
3651 InhInfo *
3652 getInherits(int *numInherits)
3653 {
3654         PGresult   *res;
3655         int                     ntups;
3656         int                     i;
3657         PQExpBuffer query = createPQExpBuffer();
3658         InhInfo    *inhinfo;
3659
3660         int                     i_inhrelid;
3661         int                     i_inhparent;
3662
3663         /* Make sure we are in proper schema */
3664         selectSourceSchema("pg_catalog");
3665
3666         /* find all the inheritance information */
3667
3668         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
3669
3670         res = PQexec(g_conn, query->data);
3671         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3672
3673         ntups = PQntuples(res);
3674
3675         *numInherits = ntups;
3676
3677         inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3678
3679         i_inhrelid = PQfnumber(res, "inhrelid");
3680         i_inhparent = PQfnumber(res, "inhparent");
3681
3682         for (i = 0; i < ntups; i++)
3683         {
3684                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3685                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3686         }
3687
3688         PQclear(res);
3689
3690         destroyPQExpBuffer(query);
3691
3692         return inhinfo;
3693 }
3694
3695 /*
3696  * getIndexes
3697  *        get information about every index on a dumpable table
3698  *
3699  * Note: index data is not returned directly to the caller, but it
3700  * does get entered into the DumpableObject tables.
3701  */
3702 void
3703 getIndexes(TableInfo tblinfo[], int numTables)
3704 {
3705         int                     i,
3706                                 j;
3707         PQExpBuffer query = createPQExpBuffer();
3708         PGresult   *res;
3709         IndxInfo   *indxinfo;
3710         ConstraintInfo *constrinfo;
3711         int                     i_tableoid,
3712                                 i_oid,
3713                                 i_indexname,
3714                                 i_indexdef,
3715                                 i_indnkeys,
3716                                 i_indkey,
3717                                 i_indisclustered,
3718                                 i_contype,
3719                                 i_conname,
3720                                 i_condeferrable,
3721                                 i_condeferred,
3722                                 i_contableoid,
3723                                 i_conoid,
3724                                 i_condef,
3725                                 i_tablespace,
3726                                 i_options;
3727         int                     ntups;
3728
3729         for (i = 0; i < numTables; i++)
3730         {
3731                 TableInfo  *tbinfo = &tblinfo[i];
3732
3733                 /* Only plain tables have indexes */
3734                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3735                         continue;
3736
3737                 /* Ignore indexes of tables not to be dumped */
3738                 if (!tbinfo->dobj.dump)
3739                         continue;
3740
3741                 if (g_verbose)
3742                         write_msg(NULL, "reading indexes for table \"%s\"\n",
3743                                           tbinfo->dobj.name);
3744
3745                 /* Make sure we are in proper schema so indexdef is right */
3746                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3747
3748                 /*
3749                  * The point of the messy-looking outer join is to find a constraint
3750                  * that is related by an internal dependency link to the index. If we
3751                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
3752                  * assume an index won't have more than one internal dependency.
3753                  */
3754                 resetPQExpBuffer(query);
3755                 if (g_fout->remoteVersion >= 80500)
3756                 {
3757                         appendPQExpBuffer(query,
3758                                                           "SELECT t.tableoid, t.oid, "
3759                                                           "t.relname AS indexname, "
3760                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3761                                                           "t.relnatts AS indnkeys, "
3762                                                           "i.indkey, i.indisclustered, "
3763                                                           "c.contype, c.conname, "
3764                                                           "c.condeferrable, c.condeferred, "
3765                                                           "c.tableoid AS contableoid, "
3766                                                           "c.oid AS conoid, "
3767                                                           "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
3768                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3769                                                         "array_to_string(t.reloptions, ', ') AS options "
3770                                                           "FROM pg_catalog.pg_index i "
3771                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3772                                                           "LEFT JOIN pg_catalog.pg_depend d "
3773                                                           "ON (d.classid = t.tableoid "
3774                                                           "AND d.objid = t.oid "
3775                                                           "AND d.deptype = 'i') "
3776                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3777                                                           "ON (d.refclassid = c.tableoid "
3778                                                           "AND d.refobjid = c.oid) "
3779                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3780                                                           "ORDER BY indexname",
3781                                                           tbinfo->dobj.catId.oid);
3782                 }
3783                 else if (g_fout->remoteVersion >= 80200)
3784                 {
3785                         appendPQExpBuffer(query,
3786                                                           "SELECT t.tableoid, t.oid, "
3787                                                           "t.relname AS indexname, "
3788                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3789                                                           "t.relnatts AS indnkeys, "
3790                                                           "i.indkey, i.indisclustered, "
3791                                                           "c.contype, c.conname, "
3792                                                           "c.condeferrable, c.condeferred, "
3793                                                           "c.tableoid AS contableoid, "
3794                                                           "c.oid AS conoid, "
3795                                                           "null AS condef, "
3796                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3797                                                         "array_to_string(t.reloptions, ', ') AS options "
3798                                                           "FROM pg_catalog.pg_index i "
3799                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3800                                                           "LEFT JOIN pg_catalog.pg_depend d "
3801                                                           "ON (d.classid = t.tableoid "
3802                                                           "AND d.objid = t.oid "
3803                                                           "AND d.deptype = 'i') "
3804                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3805                                                           "ON (d.refclassid = c.tableoid "
3806                                                           "AND d.refobjid = c.oid) "
3807                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3808                                                           "ORDER BY indexname",
3809                                                           tbinfo->dobj.catId.oid);
3810                 }
3811                 else if (g_fout->remoteVersion >= 80000)
3812                 {
3813                         appendPQExpBuffer(query,
3814                                                           "SELECT t.tableoid, t.oid, "
3815                                                           "t.relname AS indexname, "
3816                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3817                                                           "t.relnatts AS indnkeys, "
3818                                                           "i.indkey, i.indisclustered, "
3819                                                           "c.contype, c.conname, "
3820                                                           "c.condeferrable, c.condeferred, "
3821                                                           "c.tableoid AS contableoid, "
3822                                                           "c.oid AS conoid, "
3823                                                           "null AS condef, "
3824                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3825                                                           "null AS options "
3826                                                           "FROM pg_catalog.pg_index i "
3827                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3828                                                           "LEFT JOIN pg_catalog.pg_depend d "
3829                                                           "ON (d.classid = t.tableoid "
3830                                                           "AND d.objid = t.oid "
3831                                                           "AND d.deptype = 'i') "
3832                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3833                                                           "ON (d.refclassid = c.tableoid "
3834                                                           "AND d.refobjid = c.oid) "
3835                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3836                                                           "ORDER BY indexname",
3837                                                           tbinfo->dobj.catId.oid);
3838                 }
3839                 else if (g_fout->remoteVersion >= 70300)
3840                 {
3841                         appendPQExpBuffer(query,
3842                                                           "SELECT t.tableoid, t.oid, "
3843                                                           "t.relname AS indexname, "
3844                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3845                                                           "t.relnatts AS indnkeys, "
3846                                                           "i.indkey, i.indisclustered, "
3847                                                           "c.contype, c.conname, "
3848                                                           "c.condeferrable, c.condeferred, "
3849                                                           "c.tableoid AS contableoid, "
3850                                                           "c.oid AS conoid, "
3851                                                           "null AS condef, "
3852                                                           "NULL AS tablespace, "
3853                                                           "null AS options "
3854                                                           "FROM pg_catalog.pg_index i "
3855                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3856                                                           "LEFT JOIN pg_catalog.pg_depend d "
3857                                                           "ON (d.classid = t.tableoid "
3858                                                           "AND d.objid = t.oid "
3859                                                           "AND d.deptype = 'i') "
3860                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3861                                                           "ON (d.refclassid = c.tableoid "
3862                                                           "AND d.refobjid = c.oid) "
3863                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3864                                                           "ORDER BY indexname",
3865                                                           tbinfo->dobj.catId.oid);
3866                 }
3867                 else if (g_fout->remoteVersion >= 70100)
3868                 {
3869                         appendPQExpBuffer(query,
3870                                                           "SELECT t.tableoid, t.oid, "
3871                                                           "t.relname AS indexname, "
3872                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
3873                                                           "t.relnatts AS indnkeys, "
3874                                                           "i.indkey, false AS indisclustered, "
3875                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
3876                                                           "ELSE '0'::char END AS contype, "
3877                                                           "t.relname AS conname, "
3878                                                           "false AS condeferrable, "
3879                                                           "false AS condeferred, "
3880                                                           "0::oid AS contableoid, "
3881                                                           "t.oid AS conoid, "
3882                                                           "null AS condef, "
3883                                                           "NULL AS tablespace, "
3884                                                           "null AS options "
3885                                                           "FROM pg_index i, pg_class t "
3886                                                           "WHERE t.oid = i.indexrelid "
3887                                                           "AND i.indrelid = '%u'::oid "
3888                                                           "ORDER BY indexname",
3889                                                           tbinfo->dobj.catId.oid);
3890                 }
3891                 else
3892                 {
3893                         appendPQExpBuffer(query,
3894                                                           "SELECT "
3895                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3896                                                           "t.oid, "
3897                                                           "t.relname AS indexname, "
3898                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
3899                                                           "t.relnatts AS indnkeys, "
3900                                                           "i.indkey, false AS indisclustered, "
3901                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
3902                                                           "ELSE '0'::char END AS contype, "
3903                                                           "t.relname AS conname, "
3904                                                           "false AS condeferrable, "
3905                                                           "false AS condeferred, "
3906                                                           "0::oid AS contableoid, "
3907                                                           "t.oid AS conoid, "
3908                                                           "null AS condef, "
3909                                                           "NULL AS tablespace, "
3910                                                           "null AS options "
3911                                                           "FROM pg_index i, pg_class t "
3912                                                           "WHERE t.oid = i.indexrelid "
3913                                                           "AND i.indrelid = '%u'::oid "
3914                                                           "ORDER BY indexname",
3915                                                           tbinfo->dobj.catId.oid);
3916                 }
3917
3918                 res = PQexec(g_conn, query->data);
3919                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3920
3921                 ntups = PQntuples(res);
3922
3923                 i_tableoid = PQfnumber(res, "tableoid");
3924                 i_oid = PQfnumber(res, "oid");
3925                 i_indexname = PQfnumber(res, "indexname");
3926                 i_indexdef = PQfnumber(res, "indexdef");
3927                 i_indnkeys = PQfnumber(res, "indnkeys");
3928                 i_indkey = PQfnumber(res, "indkey");
3929                 i_indisclustered = PQfnumber(res, "indisclustered");
3930                 i_contype = PQfnumber(res, "contype");
3931                 i_conname = PQfnumber(res, "conname");
3932                 i_condeferrable = PQfnumber(res, "condeferrable");
3933                 i_condeferred = PQfnumber(res, "condeferred");
3934                 i_contableoid = PQfnumber(res, "contableoid");
3935                 i_conoid = PQfnumber(res, "conoid");
3936                 i_condef = PQfnumber(res, "condef");
3937                 i_tablespace = PQfnumber(res, "tablespace");
3938                 i_options = PQfnumber(res, "options");
3939
3940                 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3941                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3942
3943                 for (j = 0; j < ntups; j++)
3944                 {
3945                         char            contype;
3946
3947                         indxinfo[j].dobj.objType = DO_INDEX;
3948                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3949                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3950                         AssignDumpId(&indxinfo[j].dobj);
3951                         indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
3952                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3953                         indxinfo[j].indextable = tbinfo;
3954                         indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
3955                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
3956                         indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
3957                         indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
3958
3959                         /*
3960                          * In pre-7.4 releases, indkeys may contain more entries than
3961                          * indnkeys says (since indnkeys will be 1 for a functional
3962                          * index).      We don't actually care about this case since we don't
3963                          * examine indkeys except for indexes associated with PRIMARY and
3964                          * UNIQUE constraints, which are never functional indexes. But we
3965                          * have to allocate enough space to keep parseOidArray from
3966                          * complaining.
3967                          */
3968                         indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
3969                         parseOidArray(PQgetvalue(res, j, i_indkey),
3970                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
3971                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3972                         contype = *(PQgetvalue(res, j, i_contype));
3973
3974                         if (contype == 'p' || contype == 'u' || contype == 'x')
3975                         {
3976                                 /*
3977                                  * If we found a constraint matching the index, create an
3978                                  * entry for it.
3979                                  *
3980                                  * In a pre-7.3 database, we take this path iff the index was
3981                                  * marked indisprimary.
3982                                  */
3983                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
3984                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3985                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3986                                 AssignDumpId(&constrinfo[j].dobj);
3987                                 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3988                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3989                                 constrinfo[j].contable = tbinfo;
3990                                 constrinfo[j].condomain = NULL;
3991                                 constrinfo[j].contype = contype;
3992                                 if (contype == 'x')
3993                                         constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
3994                                 else
3995                                         constrinfo[j].condef = NULL;
3996                                 constrinfo[j].confrelid = InvalidOid;
3997                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
3998                                 constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
3999                                 constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
4000                                 constrinfo[j].conislocal = true;
4001                                 constrinfo[j].separate = true;
4002
4003                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
4004
4005                                 /* If pre-7.3 DB, better make sure table comes first */
4006                                 addObjectDependency(&constrinfo[j].dobj,
4007                                                                         tbinfo->dobj.dumpId);
4008                         }
4009                         else
4010                         {
4011                                 /* Plain secondary index */
4012                                 indxinfo[j].indexconstraint = 0;
4013                         }
4014                 }
4015
4016                 PQclear(res);
4017         }
4018
4019         destroyPQExpBuffer(query);
4020 }
4021
4022 /*
4023  * getConstraints
4024  *
4025  * Get info about constraints on dumpable tables.
4026  *
4027  * Currently handles foreign keys only.
4028  * Unique and primary key constraints are handled with indexes,
4029  * while check constraints are processed in getTableAttrs().
4030  */
4031 void
4032 getConstraints(TableInfo tblinfo[], int numTables)
4033 {
4034         int                     i,
4035                                 j;
4036         ConstraintInfo *constrinfo;
4037         PQExpBuffer query;
4038         PGresult   *res;
4039         int                     i_contableoid,
4040                                 i_conoid,
4041                                 i_conname,
4042                                 i_confrelid,
4043                                 i_condef;
4044         int                     ntups;
4045
4046         /* pg_constraint was created in 7.3, so nothing to do if older */
4047         if (g_fout->remoteVersion < 70300)
4048                 return;
4049
4050         query = createPQExpBuffer();
4051
4052         for (i = 0; i < numTables; i++)
4053         {
4054                 TableInfo  *tbinfo = &tblinfo[i];
4055
4056                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4057                         continue;
4058
4059                 if (g_verbose)
4060                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
4061                                           tbinfo->dobj.name);
4062
4063                 /*
4064                  * select table schema to ensure constraint expr is qualified if
4065                  * needed
4066                  */
4067                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4068
4069                 resetPQExpBuffer(query);
4070                 appendPQExpBuffer(query,
4071                                                   "SELECT tableoid, oid, conname, confrelid, "
4072                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
4073                                                   "FROM pg_catalog.pg_constraint "
4074                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4075                                                   "AND contype = 'f'",
4076                                                   tbinfo->dobj.catId.oid);
4077                 res = PQexec(g_conn, query->data);
4078                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4079
4080                 ntups = PQntuples(res);
4081
4082                 i_contableoid = PQfnumber(res, "tableoid");
4083                 i_conoid = PQfnumber(res, "oid");
4084                 i_conname = PQfnumber(res, "conname");
4085                 i_confrelid = PQfnumber(res, "confrelid");
4086                 i_condef = PQfnumber(res, "condef");
4087
4088                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4089
4090                 for (j = 0; j < ntups; j++)
4091                 {
4092                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
4093                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
4094                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
4095                         AssignDumpId(&constrinfo[j].dobj);
4096                         constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
4097                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
4098                         constrinfo[j].contable = tbinfo;
4099                         constrinfo[j].condomain = NULL;
4100                         constrinfo[j].contype = 'f';
4101                         constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
4102                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
4103                         constrinfo[j].conindex = 0;
4104                         constrinfo[j].condeferrable = false;
4105                         constrinfo[j].condeferred = false;
4106                         constrinfo[j].conislocal = true;
4107                         constrinfo[j].separate = true;
4108                 }
4109
4110                 PQclear(res);
4111         }
4112
4113         destroyPQExpBuffer(query);
4114 }
4115
4116 /*
4117  * getDomainConstraints
4118  *
4119  * Get info about constraints on a domain.
4120  */
4121 static void
4122 getDomainConstraints(TypeInfo *tinfo)
4123 {
4124         int                     i;
4125         ConstraintInfo *constrinfo;
4126         PQExpBuffer query;
4127         PGresult   *res;
4128         int                     i_tableoid,
4129                                 i_oid,
4130                                 i_conname,
4131                                 i_consrc;
4132         int                     ntups;
4133
4134         /* pg_constraint was created in 7.3, so nothing to do if older */
4135         if (g_fout->remoteVersion < 70300)
4136                 return;
4137
4138         /*
4139          * select appropriate schema to ensure names in constraint are properly
4140          * qualified
4141          */
4142         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
4143
4144         query = createPQExpBuffer();
4145
4146         if (g_fout->remoteVersion >= 70400)
4147                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4148                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc "
4149                                                   "FROM pg_catalog.pg_constraint "
4150                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4151                                                   "ORDER BY conname",
4152                                                   tinfo->dobj.catId.oid);
4153         else
4154                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
4155                                                   "'CHECK (' || consrc || ')' AS consrc "
4156                                                   "FROM pg_catalog.pg_constraint "
4157                                                   "WHERE contypid = '%u'::pg_catalog.oid "
4158                                                   "ORDER BY conname",
4159                                                   tinfo->dobj.catId.oid);
4160
4161         res = PQexec(g_conn, query->data);
4162         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4163
4164         ntups = PQntuples(res);
4165
4166         i_tableoid = PQfnumber(res, "tableoid");
4167         i_oid = PQfnumber(res, "oid");
4168         i_conname = PQfnumber(res, "conname");
4169         i_consrc = PQfnumber(res, "consrc");
4170
4171         constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4172
4173         tinfo->nDomChecks = ntups;
4174         tinfo->domChecks = constrinfo;
4175
4176         for (i = 0; i < ntups; i++)
4177         {
4178                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4179                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4180                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4181                 AssignDumpId(&constrinfo[i].dobj);
4182                 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
4183                 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
4184                 constrinfo[i].contable = NULL;
4185                 constrinfo[i].condomain = tinfo;
4186                 constrinfo[i].contype = 'c';
4187                 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
4188                 constrinfo[i].confrelid = InvalidOid;
4189                 constrinfo[i].conindex = 0;
4190                 constrinfo[i].condeferrable = false;
4191                 constrinfo[i].condeferred = false;
4192                 constrinfo[i].conislocal = true;
4193                 constrinfo[i].separate = false;
4194
4195                 /*
4196                  * Make the domain depend on the constraint, ensuring it won't be
4197                  * output till any constraint dependencies are OK.
4198                  */
4199                 addObjectDependency(&tinfo->dobj,
4200                                                         constrinfo[i].dobj.dumpId);
4201         }
4202
4203         PQclear(res);
4204
4205         destroyPQExpBuffer(query);
4206 }
4207
4208 /*
4209  * getRules
4210  *        get basic information about every rule in the system
4211  *
4212  * numRules is set to the number of rules read in
4213  */
4214 RuleInfo *
4215 getRules(int *numRules)
4216 {
4217         PGresult   *res;
4218         int                     ntups;
4219         int                     i;
4220         PQExpBuffer query = createPQExpBuffer();
4221         RuleInfo   *ruleinfo;
4222         int                     i_tableoid;
4223         int                     i_oid;
4224         int                     i_rulename;
4225         int                     i_ruletable;
4226         int                     i_ev_type;
4227         int                     i_is_instead;
4228         int                     i_ev_enabled;
4229
4230         /* Make sure we are in proper schema */
4231         selectSourceSchema("pg_catalog");
4232
4233         if (g_fout->remoteVersion >= 80300)
4234         {
4235                 appendPQExpBuffer(query, "SELECT "
4236                                                   "tableoid, oid, rulename, "
4237                                                   "ev_class AS ruletable, ev_type, is_instead, "
4238                                                   "ev_enabled "
4239                                                   "FROM pg_rewrite "
4240                                                   "ORDER BY oid");
4241         }
4242         else if (g_fout->remoteVersion >= 70100)
4243         {
4244                 appendPQExpBuffer(query, "SELECT "
4245                                                   "tableoid, oid, rulename, "
4246                                                   "ev_class AS ruletable, ev_type, is_instead, "
4247                                                   "'O'::char AS ev_enabled "
4248                                                   "FROM pg_rewrite "
4249                                                   "ORDER BY oid");
4250         }
4251         else
4252         {
4253                 appendPQExpBuffer(query, "SELECT "
4254                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4255                                                   "oid, rulename, "
4256                                                   "ev_class AS ruletable, ev_type, is_instead, "
4257                                                   "'O'::char AS ev_enabled "
4258                                                   "FROM pg_rewrite "
4259                                                   "ORDER BY oid");
4260         }
4261
4262         res = PQexec(g_conn, query->data);
4263         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4264
4265         ntups = PQntuples(res);
4266
4267         *numRules = ntups;
4268
4269         ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
4270
4271         i_tableoid = PQfnumber(res, "tableoid");
4272         i_oid = PQfnumber(res, "oid");
4273         i_rulename = PQfnumber(res, "rulename");
4274         i_ruletable = PQfnumber(res, "ruletable");
4275         i_ev_type = PQfnumber(res, "ev_type");
4276         i_is_instead = PQfnumber(res, "is_instead");
4277         i_ev_enabled = PQfnumber(res, "ev_enabled");
4278
4279         for (i = 0; i < ntups; i++)
4280         {
4281                 Oid                     ruletableoid;
4282
4283                 ruleinfo[i].dobj.objType = DO_RULE;
4284                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4285                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4286                 AssignDumpId(&ruleinfo[i].dobj);
4287                 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
4288                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
4289                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
4290                 if (ruleinfo[i].ruletable == NULL)
4291                 {
4292                         write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4293                                           ruletableoid,
4294                                           ruleinfo[i].dobj.catId.oid);
4295                         exit_nicely();
4296                 }
4297                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
4298                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
4299                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
4300                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
4301                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
4302                 if (ruleinfo[i].ruletable)
4303                 {
4304                         /*
4305                          * If the table is a view, force its ON SELECT rule to be sorted
4306                          * before the view itself --- this ensures that any dependencies
4307                          * for the rule affect the table's positioning. Other rules are
4308                          * forced to appear after their table.
4309                          */
4310                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4311                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
4312                         {
4313                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
4314                                                                         ruleinfo[i].dobj.dumpId);
4315                                 /* We'll merge the rule into CREATE VIEW, if possible */
4316                                 ruleinfo[i].separate = false;
4317                         }
4318                         else
4319                         {
4320                                 addObjectDependency(&ruleinfo[i].dobj,
4321                                                                         ruleinfo[i].ruletable->dobj.dumpId);
4322                                 ruleinfo[i].separate = true;
4323                         }
4324                 }
4325                 else
4326                         ruleinfo[i].separate = true;
4327         }
4328
4329         PQclear(res);
4330
4331         destroyPQExpBuffer(query);
4332
4333         return ruleinfo;
4334 }
4335
4336 /*
4337  * getTriggers
4338  *        get information about every trigger on a dumpable table
4339  *
4340  * Note: trigger data is not returned directly to the caller, but it
4341  * does get entered into the DumpableObject tables.
4342  */
4343 void
4344 getTriggers(TableInfo tblinfo[], int numTables)
4345 {
4346         int                     i,
4347                                 j;
4348         PQExpBuffer query = createPQExpBuffer();
4349         PGresult   *res;
4350         TriggerInfo *tginfo;
4351         int                     i_tableoid,
4352                                 i_oid,
4353                                 i_tgname,
4354                                 i_tgfname,
4355                                 i_tgtype,
4356                                 i_tgnargs,
4357                                 i_tgargs,
4358                                 i_tgisconstraint,
4359                                 i_tgconstrname,
4360                                 i_tgconstrrelid,
4361                                 i_tgconstrrelname,
4362                                 i_tgenabled,
4363                                 i_tgdeferrable,
4364                                 i_tginitdeferred,
4365                                 i_tgdef;
4366         int                     ntups;
4367
4368         for (i = 0; i < numTables; i++)
4369         {
4370                 TableInfo  *tbinfo = &tblinfo[i];
4371
4372                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4373                         continue;
4374
4375                 if (g_verbose)
4376                         write_msg(NULL, "reading triggers for table \"%s\"\n",
4377                                           tbinfo->dobj.name);
4378
4379                 /*
4380                  * select table schema to ensure regproc name is qualified if needed
4381                  */
4382                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4383
4384                 resetPQExpBuffer(query);
4385                 if (g_fout->remoteVersion >= 80500)
4386                 {
4387                         /*
4388                          * NB: think not to use pretty=true in pg_get_triggerdef.  It
4389                          * could result in non-forward-compatible dumps of WHEN clauses
4390                          * due to under-parenthesization.
4391                          */
4392                         appendPQExpBuffer(query,
4393                                                           "SELECT tgname, "
4394                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
4395                                                           "pg_catalog.pg_get_triggerdef(oid, false) AS tgdef, "
4396                                                           "tgenabled, tableoid, oid "
4397                                                           "FROM pg_catalog.pg_trigger t "
4398                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
4399                                                           "AND tgconstraint = 0",
4400                                                           tbinfo->dobj.catId.oid);
4401                 }
4402                 else if (g_fout->remoteVersion >= 80300)
4403                 {
4404                         /*
4405                          * We ignore triggers that are tied to a foreign-key constraint
4406                          */
4407                         appendPQExpBuffer(query,
4408                                                           "SELECT tgname, "
4409                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
4410                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4411                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4412                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4413                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4414                                                           "FROM pg_catalog.pg_trigger t "
4415                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
4416                                                           "AND tgconstraint = 0",
4417                                                           tbinfo->dobj.catId.oid);
4418                 }
4419                 else if (g_fout->remoteVersion >= 70300)
4420                 {
4421                         /*
4422                          * We ignore triggers that are tied to a foreign-key constraint,
4423                          * but in these versions we have to grovel through pg_constraint
4424                          * to find out
4425                          */
4426                         appendPQExpBuffer(query,
4427                                                           "SELECT tgname, "
4428                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
4429                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4430                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4431                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4432                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4433                                                           "FROM pg_catalog.pg_trigger t "
4434                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
4435                                                           "AND (NOT tgisconstraint "
4436                                                           " OR NOT EXISTS"
4437                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
4438                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4439                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4440                                                           tbinfo->dobj.catId.oid);
4441                 }
4442                 else if (g_fout->remoteVersion >= 70100)
4443                 {
4444                         appendPQExpBuffer(query,
4445                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
4446                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4447                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4448                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4449                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4450                                                           "             AS tgconstrrelname "
4451                                                           "FROM pg_trigger "
4452                                                           "WHERE tgrelid = '%u'::oid",
4453                                                           tbinfo->dobj.catId.oid);
4454                 }
4455                 else
4456                 {
4457                         appendPQExpBuffer(query,
4458                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
4459                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4460                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4461                                                           "tgconstrrelid, tginitdeferred, "
4462                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4463                                                           "oid, "
4464                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4465                                                           "             AS tgconstrrelname "
4466                                                           "FROM pg_trigger "
4467                                                           "WHERE tgrelid = '%u'::oid",
4468                                                           tbinfo->dobj.catId.oid);
4469                 }
4470                 res = PQexec(g_conn, query->data);
4471                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4472
4473                 ntups = PQntuples(res);
4474
4475                 i_tableoid = PQfnumber(res, "tableoid");
4476                 i_oid = PQfnumber(res, "oid");
4477                 i_tgname = PQfnumber(res, "tgname");
4478                 i_tgfname = PQfnumber(res, "tgfname");
4479                 i_tgtype = PQfnumber(res, "tgtype");
4480                 i_tgnargs = PQfnumber(res, "tgnargs");
4481                 i_tgargs = PQfnumber(res, "tgargs");
4482                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
4483                 i_tgconstrname = PQfnumber(res, "tgconstrname");
4484                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
4485                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
4486                 i_tgenabled = PQfnumber(res, "tgenabled");
4487                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
4488                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
4489                 i_tgdef = PQfnumber(res, "tgdef");
4490
4491                 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4492
4493                 for (j = 0; j < ntups; j++)
4494                 {
4495                         tginfo[j].dobj.objType = DO_TRIGGER;
4496                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4497                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4498                         AssignDumpId(&tginfo[j].dobj);
4499                         tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
4500                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
4501                         tginfo[j].tgtable = tbinfo;
4502                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
4503                         if (i_tgdef >= 0)
4504                         {
4505                                 tginfo[j].tgdef = strdup(PQgetvalue(res, j, i_tgdef));
4506
4507                                 /* remaining fields are not valid if we have tgdef */
4508                                 tginfo[j].tgfname = NULL;
4509                                 tginfo[j].tgtype = 0;
4510                                 tginfo[j].tgnargs = 0;
4511                                 tginfo[j].tgargs = NULL;
4512                                 tginfo[j].tgisconstraint = false;
4513                                 tginfo[j].tgdeferrable = false;
4514                                 tginfo[j].tginitdeferred = false;
4515                                 tginfo[j].tgconstrname = NULL;
4516                                 tginfo[j].tgconstrrelid = InvalidOid;
4517                                 tginfo[j].tgconstrrelname = NULL;
4518                         }
4519                         else
4520                         {
4521                                 tginfo[j].tgdef = NULL;
4522
4523                                 tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
4524                                 tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4525                                 tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4526                                 tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
4527                                 tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
4528                                 tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
4529                                 tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
4530
4531                                 if (tginfo[j].tgisconstraint)
4532                                 {
4533                                         tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
4534                                         tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
4535                                         if (OidIsValid(tginfo[j].tgconstrrelid))
4536                                         {
4537                                                 if (PQgetisnull(res, j, i_tgconstrrelname))
4538                                                 {
4539                                                         write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4540                                                                           tginfo[j].dobj.name, tbinfo->dobj.name,
4541                                                                           tginfo[j].tgconstrrelid);
4542                                                         exit_nicely();
4543                                                 }
4544                                                 tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4545                                         }
4546                                         else
4547                                                 tginfo[j].tgconstrrelname = NULL;
4548                                 }
4549                                 else
4550                                 {
4551                                         tginfo[j].tgconstrname = NULL;
4552                                         tginfo[j].tgconstrrelid = InvalidOid;
4553                                         tginfo[j].tgconstrrelname = NULL;
4554                                 }
4555                         }
4556                 }
4557
4558                 PQclear(res);
4559         }
4560
4561         destroyPQExpBuffer(query);
4562 }
4563
4564 /*
4565  * getProcLangs
4566  *        get basic information about every procedural language in the system
4567  *
4568  * numProcLangs is set to the number of langs read in
4569  *
4570  * NB: this must run after getFuncs() because we assume we can do
4571  * findFuncByOid().
4572  */
4573 ProcLangInfo *
4574 getProcLangs(int *numProcLangs)
4575 {
4576         PGresult   *res;
4577         int                     ntups;
4578         int                     i;
4579         PQExpBuffer query = createPQExpBuffer();
4580         ProcLangInfo *planginfo;
4581         int                     i_tableoid;
4582         int                     i_oid;
4583         int                     i_lanname;
4584         int                     i_lanpltrusted;
4585         int                     i_lanplcallfoid;
4586         int                     i_laninline;
4587         int                     i_lanvalidator;
4588         int                     i_lanacl;
4589         int                     i_lanowner;
4590
4591         /* Make sure we are in proper schema */
4592         selectSourceSchema("pg_catalog");
4593
4594         if (g_fout->remoteVersion >= 80500)
4595         {
4596                 /* pg_language has a laninline column */
4597                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4598                                                   "lanname, lanpltrusted, lanplcallfoid, "
4599                                                   "laninline, lanvalidator,  lanacl, "
4600                                                   "(%s lanowner) AS lanowner "
4601                                                   "FROM pg_language "
4602                                                   "WHERE lanispl "
4603                                                   /* do not dump initdb-installed languages */
4604                                                   "AND oid >= %u "
4605                                                   "ORDER BY oid",
4606                                                   username_subquery, FirstNormalObjectId);
4607         }
4608         else if (g_fout->remoteVersion >= 80300)
4609         {
4610                 /* pg_language has a lanowner column */
4611                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4612                                                   "lanname, lanpltrusted, lanplcallfoid, "
4613                                                   "lanvalidator,  lanacl, "
4614                                                   "(%s lanowner) AS lanowner "
4615                                                   "FROM pg_language "
4616                                                   "WHERE lanispl%s "
4617                                                   "ORDER BY oid",
4618                                                   username_subquery,
4619                                                   binary_upgrade ? "\nAND lanname != 'plpgsql'" : "");
4620         }
4621         else if (g_fout->remoteVersion >= 80100)
4622         {
4623                 /* Languages are owned by the bootstrap superuser, OID 10 */
4624                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4625                                                   "(%s '10') AS lanowner "
4626                                                   "FROM pg_language "
4627                                                   "WHERE lanispl "
4628                                                   "ORDER BY oid",
4629                                                   username_subquery);
4630         }
4631         else if (g_fout->remoteVersion >= 70400)
4632         {
4633                 /* Languages are owned by the bootstrap superuser, sysid 1 */
4634                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4635                                                   "(%s '1') AS lanowner "
4636                                                   "FROM pg_language "
4637                                                   "WHERE lanispl "
4638                                                   "ORDER BY oid",
4639                                                   username_subquery);
4640         }
4641         else if (g_fout->remoteVersion >= 70100)
4642         {
4643                 /* No clear notion of an owner at all before 7.4 ... */
4644                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4645                                                   "WHERE lanispl "
4646                                                   "ORDER BY oid");
4647         }
4648         else
4649         {
4650                 appendPQExpBuffer(query, "SELECT "
4651                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4652                                                   "oid, * FROM pg_language "
4653                                                   "WHERE lanispl "
4654                                                   "ORDER BY oid");
4655         }
4656
4657         res = PQexec(g_conn, query->data);
4658         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4659
4660         ntups = PQntuples(res);
4661
4662         *numProcLangs = ntups;
4663
4664         planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
4665
4666         i_tableoid = PQfnumber(res, "tableoid");
4667         i_oid = PQfnumber(res, "oid");
4668         i_lanname = PQfnumber(res, "lanname");
4669         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
4670         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
4671         /* these may fail and return -1: */
4672         i_laninline = PQfnumber(res, "laninline");
4673         i_lanvalidator = PQfnumber(res, "lanvalidator");
4674         i_lanacl = PQfnumber(res, "lanacl");
4675         i_lanowner = PQfnumber(res, "lanowner");
4676
4677         for (i = 0; i < ntups; i++)
4678         {
4679                 planginfo[i].dobj.objType = DO_PROCLANG;
4680                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4681                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4682                 AssignDumpId(&planginfo[i].dobj);
4683
4684                 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
4685                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
4686                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
4687                 if (i_laninline >= 0)
4688                         planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
4689                 else
4690                         planginfo[i].laninline = InvalidOid;
4691                 if (i_lanvalidator >= 0)
4692                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
4693                 else
4694                         planginfo[i].lanvalidator = InvalidOid;
4695                 if (i_lanacl >= 0)
4696                         planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4697                 else
4698                         planginfo[i].lanacl = strdup("{=U}");
4699                 if (i_lanowner >= 0)
4700                         planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4701                 else
4702                         planginfo[i].lanowner = strdup("");
4703
4704                 if (g_fout->remoteVersion < 70300)
4705                 {
4706                         /*
4707                          * We need to make a dependency to ensure the function will be
4708                          * dumped first.  (In 7.3 and later the regular dependency
4709                          * mechanism will handle this for us.)
4710                          */
4711                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4712
4713                         if (funcInfo)
4714                                 addObjectDependency(&planginfo[i].dobj,
4715                                                                         funcInfo->dobj.dumpId);
4716                 }
4717         }
4718
4719         PQclear(res);
4720
4721         destroyPQExpBuffer(query);
4722
4723         return planginfo;
4724 }
4725
4726 /*
4727  * getCasts
4728  *        get basic information about every cast in the system
4729  *
4730  * numCasts is set to the number of casts read in
4731  */
4732 CastInfo *
4733 getCasts(int *numCasts)
4734 {
4735         PGresult   *res;
4736         int                     ntups;
4737         int                     i;
4738         PQExpBuffer query = createPQExpBuffer();
4739         CastInfo   *castinfo;
4740         int                     i_tableoid;
4741         int                     i_oid;
4742         int                     i_castsource;
4743         int                     i_casttarget;
4744         int                     i_castfunc;
4745         int                     i_castcontext;
4746         int                     i_castmethod;
4747
4748         /* Make sure we are in proper schema */
4749         selectSourceSchema("pg_catalog");
4750
4751         if (g_fout->remoteVersion >= 80400)
4752         {
4753                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4754                                                   "castsource, casttarget, castfunc, castcontext, "
4755                                                   "castmethod "
4756                                                   "FROM pg_cast ORDER BY 3,4");
4757         }
4758         else if (g_fout->remoteVersion >= 70300)
4759         {
4760                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4761                                                   "castsource, casttarget, castfunc, castcontext, "
4762                                 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
4763                                                   "FROM pg_cast ORDER BY 3,4");
4764         }
4765         else
4766         {
4767                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
4768                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
4769                                                   "p.oid AS castfunc, 'e' AS castcontext, "
4770                                                   "'f' AS castmethod "
4771                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
4772                                                   "WHERE p.pronargs = 1 AND "
4773                                                   "p.proargtypes[0] = t1.oid AND "
4774                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
4775                                                   "ORDER BY 3,4");
4776         }
4777
4778         res = PQexec(g_conn, query->data);
4779         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4780
4781         ntups = PQntuples(res);
4782
4783         *numCasts = ntups;
4784
4785         castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
4786
4787         i_tableoid = PQfnumber(res, "tableoid");
4788         i_oid = PQfnumber(res, "oid");
4789         i_castsource = PQfnumber(res, "castsource");
4790         i_casttarget = PQfnumber(res, "casttarget");
4791         i_castfunc = PQfnumber(res, "castfunc");
4792         i_castcontext = PQfnumber(res, "castcontext");
4793         i_castmethod = PQfnumber(res, "castmethod");
4794
4795         for (i = 0; i < ntups; i++)
4796         {
4797                 PQExpBufferData namebuf;
4798                 TypeInfo   *sTypeInfo;
4799                 TypeInfo   *tTypeInfo;
4800
4801                 castinfo[i].dobj.objType = DO_CAST;
4802                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4803                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4804                 AssignDumpId(&castinfo[i].dobj);
4805                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
4806                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
4807                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
4808                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4809                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
4810
4811                 /*
4812                  * Try to name cast as concatenation of typnames.  This is only used
4813                  * for purposes of sorting.  If we fail to find either type, the name
4814                  * will be an empty string.
4815                  */
4816                 initPQExpBuffer(&namebuf);
4817                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
4818                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
4819                 if (sTypeInfo && tTypeInfo)
4820                         appendPQExpBuffer(&namebuf, "%s %s",
4821                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
4822                 castinfo[i].dobj.name = namebuf.data;
4823
4824                 if (OidIsValid(castinfo[i].castfunc))
4825                 {
4826                         /*
4827                          * We need to make a dependency to ensure the function will be
4828                          * dumped first.  (In 7.3 and later the regular dependency
4829                          * mechanism will handle this for us.)
4830                          */
4831                         FuncInfo   *funcInfo;
4832
4833                         funcInfo = findFuncByOid(castinfo[i].castfunc);
4834                         if (funcInfo)
4835                                 addObjectDependency(&castinfo[i].dobj,
4836                                                                         funcInfo->dobj.dumpId);
4837                 }
4838         }
4839
4840         PQclear(res);
4841
4842         destroyPQExpBuffer(query);
4843
4844         return castinfo;
4845 }
4846
4847 /*
4848  * getTableAttrs -
4849  *        for each interesting table, read info about its attributes
4850  *        (names, types, default values, CHECK constraints, etc)
4851  *
4852  * This is implemented in a very inefficient way right now, looping
4853  * through the tblinfo and doing a join per table to find the attrs and their
4854  * types.  However, because we want type names and so forth to be named
4855  * relative to the schema of each table, we couldn't do it in just one
4856  * query.  (Maybe one query per schema?)
4857  *
4858  *      modifies tblinfo
4859  */
4860 void
4861 getTableAttrs(TableInfo *tblinfo, int numTables)
4862 {
4863         int                     i,
4864                                 j;
4865         PQExpBuffer q = createPQExpBuffer();
4866         int                     i_attnum;
4867         int                     i_attname;
4868         int                     i_atttypname;
4869         int                     i_atttypmod;
4870         int                     i_attstattarget;
4871         int                     i_attdistinct;
4872         int                     i_attstorage;
4873         int                     i_typstorage;
4874         int                     i_attnotnull;
4875         int                     i_atthasdef;
4876         int                     i_attisdropped;
4877         int                     i_attlen;
4878         int                     i_attalign;
4879         int                     i_attislocal;
4880         PGresult   *res;
4881         int                     ntups;
4882         bool            hasdefaults;
4883
4884         for (i = 0; i < numTables; i++)
4885         {
4886                 TableInfo  *tbinfo = &tblinfo[i];
4887
4888                 /* Don't bother to collect info for sequences */
4889                 if (tbinfo->relkind == RELKIND_SEQUENCE)
4890                         continue;
4891
4892                 /* Don't bother with uninteresting tables, either */
4893                 if (!tbinfo->interesting)
4894                         continue;
4895
4896                 /*
4897                  * Make sure we are in proper schema for this table; this allows
4898                  * correct retrieval of formatted type names and default exprs
4899                  */
4900                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4901
4902                 /* find all the user attributes and their types */
4903
4904                 /*
4905                  * we must read the attribute names in attribute number order! because
4906                  * we will use the attnum to index into the attnames array later.  We
4907                  * actually ask to order by "attrelid, attnum" because (at least up to
4908                  * 7.3) the planner is not smart enough to realize it needn't re-sort
4909                  * the output of an indexscan on pg_attribute_relid_attnum_index.
4910                  */
4911                 if (g_verbose)
4912                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4913                                           tbinfo->dobj.name);
4914
4915                 resetPQExpBuffer(q);
4916
4917                 if (g_fout->remoteVersion >= 80500)
4918                 {
4919                         /* attdistinct is new in 8.5 */
4920                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4921                                                           "a.attstattarget, a.attdistinct, "
4922                                                           "a.attstorage, t.typstorage, "
4923                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
4924                                                           "a.attlen, a.attalign, a.attislocal, "
4925                                    "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4926                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4927                                                           "ON a.atttypid = t.oid "
4928                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
4929                                                           "AND a.attnum > 0::pg_catalog.int2 "
4930                                                           "ORDER BY a.attrelid, a.attnum",
4931                                                           tbinfo->dobj.catId.oid);
4932                 }
4933                 else if (g_fout->remoteVersion >= 70300)
4934                 {
4935                         /* need left join here to not fail on dropped columns ... */
4936                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4937                                                           "a.attstattarget, 0 AS attdistinct, "
4938                                                           "a.attstorage, t.typstorage, "
4939                                                           "a.attnotnull, a.atthasdef, a.attisdropped, "
4940                                                           "a.attlen, a.attalign, a.attislocal, "
4941                                    "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4942                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4943                                                           "ON a.atttypid = t.oid "
4944                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
4945                                                           "AND a.attnum > 0::pg_catalog.int2 "
4946                                                           "ORDER BY a.attrelid, a.attnum",
4947                                                           tbinfo->dobj.catId.oid);
4948                 }
4949                 else if (g_fout->remoteVersion >= 70100)
4950                 {
4951                         /*
4952                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
4953                          * we don't dump it because we can't tell whether it's been
4954                          * explicitly set or was just a default.
4955                          */
4956                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4957                                                           "-1 AS attstattarget, 0 AS attdistinct, "
4958                                                           "a.attstorage, "
4959                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
4960                                                           "false AS attisdropped, a.attlen, "
4961                                                           "a.attalign, false AS attislocal, "
4962                                                           "format_type(t.oid,a.atttypmod) AS atttypname "
4963                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
4964                                                           "ON a.atttypid = t.oid "
4965                                                           "WHERE a.attrelid = '%u'::oid "
4966                                                           "AND a.attnum > 0::int2 "
4967                                                           "ORDER BY a.attrelid, a.attnum",
4968                                                           tbinfo->dobj.catId.oid);
4969                 }
4970                 else
4971                 {
4972                         /* format_type not available before 7.1 */
4973                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
4974                                                           "-1 AS attstattarget, 0 AS attdistinct, "
4975                                                           "attstorage, attstorage AS typstorage, "
4976                                                           "attnotnull, atthasdef, false AS attisdropped, "
4977                                                           "attlen, attalign, "
4978                                                           "false AS attislocal, "
4979                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
4980                                                           "FROM pg_attribute a "
4981                                                           "WHERE attrelid = '%u'::oid "
4982                                                           "AND attnum > 0::int2 "
4983                                                           "ORDER BY attrelid, attnum",
4984                                                           tbinfo->dobj.catId.oid);
4985                 }
4986
4987                 res = PQexec(g_conn, q->data);
4988                 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4989
4990                 ntups = PQntuples(res);
4991
4992                 i_attnum = PQfnumber(res, "attnum");
4993                 i_attname = PQfnumber(res, "attname");
4994                 i_atttypname = PQfnumber(res, "atttypname");
4995                 i_atttypmod = PQfnumber(res, "atttypmod");
4996                 i_attstattarget = PQfnumber(res, "attstattarget");
4997                 i_attdistinct = PQfnumber(res, "attdistinct");
4998                 i_attstorage = PQfnumber(res, "attstorage");
4999                 i_typstorage = PQfnumber(res, "typstorage");
5000                 i_attnotnull = PQfnumber(res, "attnotnull");
5001                 i_atthasdef = PQfnumber(res, "atthasdef");
5002                 i_attisdropped = PQfnumber(res, "attisdropped");
5003                 i_attlen = PQfnumber(res, "attlen");
5004                 i_attalign = PQfnumber(res, "attalign");
5005                 i_attislocal = PQfnumber(res, "attislocal");
5006
5007                 tbinfo->numatts = ntups;
5008                 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
5009                 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
5010                 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
5011                 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
5012                 tbinfo->attdistinct = (float4 *) malloc(ntups * sizeof(float4));
5013                 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
5014                 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
5015                 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
5016                 tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
5017                 tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
5018                 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
5019                 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
5020                 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
5021                 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
5022                 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
5023                 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
5024                 hasdefaults = false;
5025
5026                 for (j = 0; j < ntups; j++)
5027                 {
5028                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
5029                         {
5030                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
5031                                                   tbinfo->dobj.name);
5032                                 exit_nicely();
5033                         }
5034                         tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
5035                         tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
5036                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
5037                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
5038                         tbinfo->attdistinct[j] = strtod(PQgetvalue(res, j, i_attdistinct),
5039                                                                                         (char **) NULL);
5040                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
5041                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
5042                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
5043                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
5044                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
5045                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
5046                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
5047                         tbinfo->attrdefs[j] = NULL; /* fix below */
5048                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
5049                                 hasdefaults = true;
5050                         /* these flags will be set in flagInhAttrs() */
5051                         tbinfo->inhAttrs[j] = false;
5052                         tbinfo->inhAttrDef[j] = false;
5053                         tbinfo->inhNotNull[j] = false;
5054                 }
5055
5056                 PQclear(res);
5057
5058                 /*
5059                  * Get info about column defaults
5060                  */
5061                 if (hasdefaults)
5062                 {
5063                         AttrDefInfo *attrdefs;
5064                         int                     numDefaults;
5065
5066                         if (g_verbose)
5067                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
5068                                                   tbinfo->dobj.name);
5069
5070                         resetPQExpBuffer(q);
5071                         if (g_fout->remoteVersion >= 70300)
5072                         {
5073                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
5074                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
5075                                                                   "FROM pg_catalog.pg_attrdef "
5076                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
5077                                                                   tbinfo->dobj.catId.oid);
5078                         }
5079                         else if (g_fout->remoteVersion >= 70200)
5080                         {
5081                                 /* 7.2 did not have OIDs in pg_attrdef */
5082                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
5083                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
5084                                                                   "FROM pg_attrdef "
5085                                                                   "WHERE adrelid = '%u'::oid",
5086                                                                   tbinfo->dobj.catId.oid);
5087                         }
5088                         else if (g_fout->remoteVersion >= 70100)
5089                         {
5090                                 /* no pg_get_expr, so must rely on adsrc */
5091                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
5092                                                                   "FROM pg_attrdef "
5093                                                                   "WHERE adrelid = '%u'::oid",
5094                                                                   tbinfo->dobj.catId.oid);
5095                         }
5096                         else
5097                         {
5098                                 /* no pg_get_expr, no tableoid either */
5099                                 appendPQExpBuffer(q, "SELECT "
5100                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
5101                                                                   "oid, adnum, adsrc "
5102                                                                   "FROM pg_attrdef "
5103                                                                   "WHERE adrelid = '%u'::oid",
5104                                                                   tbinfo->dobj.catId.oid);
5105                         }
5106                         res = PQexec(g_conn, q->data);
5107                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5108
5109                         numDefaults = PQntuples(res);
5110                         attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
5111
5112                         for (j = 0; j < numDefaults; j++)
5113                         {
5114                                 int                     adnum;
5115
5116                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
5117                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5118                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5119                                 AssignDumpId(&attrdefs[j].dobj);
5120                                 attrdefs[j].adtable = tbinfo;
5121                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
5122                                 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
5123
5124                                 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
5125                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
5126
5127                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
5128
5129                                 /*
5130                                  * Defaults on a VIEW must always be dumped as separate ALTER
5131                                  * TABLE commands.      Defaults on regular tables are dumped as
5132                                  * part of the CREATE TABLE if possible.  To check if it's
5133                                  * safe, we mark the default as needing to appear before the
5134                                  * CREATE.
5135                                  */
5136                                 if (tbinfo->relkind == RELKIND_VIEW)
5137                                 {
5138                                         attrdefs[j].separate = true;
5139                                         /* needed in case pre-7.3 DB: */
5140                                         addObjectDependency(&attrdefs[j].dobj,
5141                                                                                 tbinfo->dobj.dumpId);
5142                                 }
5143                                 else
5144                                 {
5145                                         attrdefs[j].separate = false;
5146                                         addObjectDependency(&tbinfo->dobj,
5147                                                                                 attrdefs[j].dobj.dumpId);
5148                                 }
5149
5150                                 if (adnum <= 0 || adnum > ntups)
5151                                 {
5152                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
5153                                                           adnum, tbinfo->dobj.name);
5154                                         exit_nicely();
5155                                 }
5156                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
5157                         }
5158                         PQclear(res);
5159                 }
5160
5161                 /*
5162                  * Get info about table CHECK constraints
5163                  */
5164                 if (tbinfo->ncheck > 0)
5165                 {
5166                         ConstraintInfo *constrs;
5167                         int                     numConstrs;
5168
5169                         if (g_verbose)
5170                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
5171                                                   tbinfo->dobj.name);
5172
5173                         resetPQExpBuffer(q);
5174                         if (g_fout->remoteVersion >= 80400)
5175                         {
5176                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5177                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5178                                                                   "conislocal "
5179                                                                   "FROM pg_catalog.pg_constraint "
5180                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5181                                                                   "   AND contype = 'c' "
5182                                                                   "ORDER BY conname",
5183                                                                   tbinfo->dobj.catId.oid);
5184                         }
5185                         else if (g_fout->remoteVersion >= 70400)
5186                         {
5187                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5188                                                    "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
5189                                                                   "true AS conislocal "
5190                                                                   "FROM pg_catalog.pg_constraint "
5191                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5192                                                                   "   AND contype = 'c' "
5193                                                                   "ORDER BY conname",
5194                                                                   tbinfo->dobj.catId.oid);
5195                         }
5196                         else if (g_fout->remoteVersion >= 70300)
5197                         {
5198                                 /* no pg_get_constraintdef, must use consrc */
5199                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
5200                                                                   "'CHECK (' || consrc || ')' AS consrc, "
5201                                                                   "true AS conislocal "
5202                                                                   "FROM pg_catalog.pg_constraint "
5203                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
5204                                                                   "   AND contype = 'c' "
5205                                                                   "ORDER BY conname",
5206                                                                   tbinfo->dobj.catId.oid);
5207                         }
5208                         else if (g_fout->remoteVersion >= 70200)
5209                         {
5210                                 /* 7.2 did not have OIDs in pg_relcheck */
5211                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
5212                                                                   "rcname AS conname, "
5213                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
5214                                                                   "true AS conislocal "
5215                                                                   "FROM pg_relcheck "
5216                                                                   "WHERE rcrelid = '%u'::oid "
5217                                                                   "ORDER BY rcname",
5218                                                                   tbinfo->dobj.catId.oid);
5219                         }
5220                         else if (g_fout->remoteVersion >= 70100)
5221                         {
5222                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
5223                                                                   "rcname AS conname, "
5224                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
5225                                                                   "true AS conislocal "
5226                                                                   "FROM pg_relcheck "
5227                                                                   "WHERE rcrelid = '%u'::oid "
5228                                                                   "ORDER BY rcname",
5229                                                                   tbinfo->dobj.catId.oid);
5230                         }
5231                         else
5232                         {
5233                                 /* no tableoid in 7.0 */
5234                                 appendPQExpBuffer(q, "SELECT "
5235                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
5236                                                                   "oid, rcname AS conname, "
5237                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
5238                                                                   "true AS conislocal "
5239                                                                   "FROM pg_relcheck "
5240                                                                   "WHERE rcrelid = '%u'::oid "
5241                                                                   "ORDER BY rcname",
5242                                                                   tbinfo->dobj.catId.oid);
5243                         }
5244                         res = PQexec(g_conn, q->data);
5245                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5246
5247                         numConstrs = PQntuples(res);
5248                         if (numConstrs != tbinfo->ncheck)
5249                         {
5250                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
5251                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
5252                                                                                  tbinfo->ncheck),
5253                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5254                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5255                                 exit_nicely();
5256                         }
5257
5258                         constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5259                         tbinfo->checkexprs = constrs;
5260
5261                         for (j = 0; j < numConstrs; j++)
5262                         {
5263                                 constrs[j].dobj.objType = DO_CONSTRAINT;
5264                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5265                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5266                                 AssignDumpId(&constrs[j].dobj);
5267                                 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
5268                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
5269                                 constrs[j].contable = tbinfo;
5270                                 constrs[j].condomain = NULL;
5271                                 constrs[j].contype = 'c';
5272                                 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
5273                                 constrs[j].confrelid = InvalidOid;
5274                                 constrs[j].conindex = 0;
5275                                 constrs[j].condeferrable = false;
5276                                 constrs[j].condeferred = false;
5277                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
5278                                 constrs[j].separate = false;
5279
5280                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
5281
5282                                 /*
5283                                  * Mark the constraint as needing to appear before the table
5284                                  * --- this is so that any other dependencies of the
5285                                  * constraint will be emitted before we try to create the
5286                                  * table.
5287                                  */
5288                                 addObjectDependency(&tbinfo->dobj,
5289                                                                         constrs[j].dobj.dumpId);
5290
5291                                 /*
5292                                  * If the constraint is inherited, this will be detected later
5293                                  * (in pre-8.4 databases).      We also detect later if the
5294                                  * constraint must be split out from the table definition.
5295                                  */
5296                         }
5297                         PQclear(res);
5298                 }
5299         }
5300
5301         destroyPQExpBuffer(q);
5302 }
5303
5304
5305 /*
5306  * getTSParsers:
5307  *        read all text search parsers in the system catalogs and return them
5308  *        in the TSParserInfo* structure
5309  *
5310  *      numTSParsers is set to the number of parsers read in
5311  */
5312 TSParserInfo *
5313 getTSParsers(int *numTSParsers)
5314 {
5315         PGresult   *res;
5316         int                     ntups;
5317         int                     i;
5318         PQExpBuffer query = createPQExpBuffer();
5319         TSParserInfo *prsinfo;
5320         int                     i_tableoid;
5321         int                     i_oid;
5322         int                     i_prsname;
5323         int                     i_prsnamespace;
5324         int                     i_prsstart;
5325         int                     i_prstoken;
5326         int                     i_prsend;
5327         int                     i_prsheadline;
5328         int                     i_prslextype;
5329
5330         /* Before 8.3, there is no built-in text search support */
5331         if (g_fout->remoteVersion < 80300)
5332         {
5333                 *numTSParsers = 0;
5334                 return NULL;
5335         }
5336
5337         /*
5338          * find all text search objects, including builtin ones; we filter out
5339          * system-defined objects at dump-out time.
5340          */
5341
5342         /* Make sure we are in proper schema */
5343         selectSourceSchema("pg_catalog");
5344
5345         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
5346                                           "prsstart::oid, prstoken::oid, "
5347                                           "prsend::oid, prsheadline::oid, prslextype::oid "
5348                                           "FROM pg_ts_parser");
5349
5350         res = PQexec(g_conn, query->data);
5351         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5352
5353         ntups = PQntuples(res);
5354         *numTSParsers = ntups;
5355
5356         prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
5357
5358         i_tableoid = PQfnumber(res, "tableoid");
5359         i_oid = PQfnumber(res, "oid");
5360         i_prsname = PQfnumber(res, "prsname");
5361         i_prsnamespace = PQfnumber(res, "prsnamespace");
5362         i_prsstart = PQfnumber(res, "prsstart");
5363         i_prstoken = PQfnumber(res, "prstoken");
5364         i_prsend = PQfnumber(res, "prsend");
5365         i_prsheadline = PQfnumber(res, "prsheadline");
5366         i_prslextype = PQfnumber(res, "prslextype");
5367
5368         for (i = 0; i < ntups; i++)
5369         {
5370                 prsinfo[i].dobj.objType = DO_TSPARSER;
5371                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5372                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5373                 AssignDumpId(&prsinfo[i].dobj);
5374                 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
5375                 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
5376                                                                                                   prsinfo[i].dobj.catId.oid);
5377                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
5378                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
5379                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
5380                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
5381                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
5382
5383                 /* Decide whether we want to dump it */
5384                 selectDumpableObject(&(prsinfo[i].dobj));
5385         }
5386
5387         PQclear(res);
5388
5389         destroyPQExpBuffer(query);
5390
5391         return prsinfo;
5392 }
5393
5394 /*
5395  * getTSDictionaries:
5396  *        read all text search dictionaries in the system catalogs and return them
5397  *        in the TSDictInfo* structure
5398  *
5399  *      numTSDicts is set to the number of dictionaries read in
5400  */
5401 TSDictInfo *
5402 getTSDictionaries(int *numTSDicts)
5403 {
5404         PGresult   *res;
5405         int                     ntups;
5406         int                     i;
5407         PQExpBuffer query = createPQExpBuffer();
5408         TSDictInfo *dictinfo;
5409         int                     i_tableoid;
5410         int                     i_oid;
5411         int                     i_dictname;
5412         int                     i_dictnamespace;
5413         int                     i_rolname;
5414         int                     i_dicttemplate;
5415         int                     i_dictinitoption;
5416
5417         /* Before 8.3, there is no built-in text search support */
5418         if (g_fout->remoteVersion < 80300)
5419         {
5420                 *numTSDicts = 0;
5421                 return NULL;
5422         }
5423
5424         /* Make sure we are in proper schema */
5425         selectSourceSchema("pg_catalog");
5426
5427         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5428                                           "dictnamespace, (%s dictowner) AS rolname, "
5429                                           "dicttemplate, dictinitoption "
5430                                           "FROM pg_ts_dict",
5431                                           username_subquery);
5432
5433         res = PQexec(g_conn, query->data);
5434         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5435
5436         ntups = PQntuples(res);
5437         *numTSDicts = ntups;
5438
5439         dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5440
5441         i_tableoid = PQfnumber(res, "tableoid");
5442         i_oid = PQfnumber(res, "oid");
5443         i_dictname = PQfnumber(res, "dictname");
5444         i_dictnamespace = PQfnumber(res, "dictnamespace");
5445         i_rolname = PQfnumber(res, "rolname");
5446         i_dictinitoption = PQfnumber(res, "dictinitoption");
5447         i_dicttemplate = PQfnumber(res, "dicttemplate");
5448
5449         for (i = 0; i < ntups; i++)
5450         {
5451                 dictinfo[i].dobj.objType = DO_TSDICT;
5452                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5453                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5454                 AssignDumpId(&dictinfo[i].dobj);
5455                 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5456                 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5457                                                                                                  dictinfo[i].dobj.catId.oid);
5458                 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5459                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5460                 if (PQgetisnull(res, i, i_dictinitoption))
5461                         dictinfo[i].dictinitoption = NULL;
5462                 else
5463                         dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5464
5465                 /* Decide whether we want to dump it */
5466                 selectDumpableObject(&(dictinfo[i].dobj));
5467         }
5468
5469         PQclear(res);
5470
5471         destroyPQExpBuffer(query);
5472
5473         return dictinfo;
5474 }
5475
5476 /*
5477  * getTSTemplates:
5478  *        read all text search templates in the system catalogs and return them
5479  *        in the TSTemplateInfo* structure
5480  *
5481  *      numTSTemplates is set to the number of templates read in
5482  */
5483 TSTemplateInfo *
5484 getTSTemplates(int *numTSTemplates)
5485 {
5486         PGresult   *res;
5487         int                     ntups;
5488         int                     i;
5489         PQExpBuffer query = createPQExpBuffer();
5490         TSTemplateInfo *tmplinfo;
5491         int                     i_tableoid;
5492         int                     i_oid;
5493         int                     i_tmplname;
5494         int                     i_tmplnamespace;
5495         int                     i_tmplinit;
5496         int                     i_tmpllexize;
5497
5498         /* Before 8.3, there is no built-in text search support */
5499         if (g_fout->remoteVersion < 80300)
5500         {
5501                 *numTSTemplates = 0;
5502                 return NULL;
5503         }
5504
5505         /* Make sure we are in proper schema */
5506         selectSourceSchema("pg_catalog");
5507
5508         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5509                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5510                                           "FROM pg_ts_template");
5511
5512         res = PQexec(g_conn, query->data);
5513         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5514
5515         ntups = PQntuples(res);
5516         *numTSTemplates = ntups;
5517
5518         tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5519
5520         i_tableoid = PQfnumber(res, "tableoid");
5521         i_oid = PQfnumber(res, "oid");
5522         i_tmplname = PQfnumber(res, "tmplname");
5523         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5524         i_tmplinit = PQfnumber(res, "tmplinit");
5525         i_tmpllexize = PQfnumber(res, "tmpllexize");
5526
5527         for (i = 0; i < ntups; i++)
5528         {
5529                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5530                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5531                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5532                 AssignDumpId(&tmplinfo[i].dobj);
5533                 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5534                 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5535                                                                                                  tmplinfo[i].dobj.catId.oid);
5536                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5537                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5538
5539                 /* Decide whether we want to dump it */
5540                 selectDumpableObject(&(tmplinfo[i].dobj));
5541         }
5542
5543         PQclear(res);
5544
5545         destroyPQExpBuffer(query);
5546
5547         return tmplinfo;
5548 }
5549
5550 /*
5551  * getTSConfigurations:
5552  *        read all text search configurations in the system catalogs and return
5553  *        them in the TSConfigInfo* structure
5554  *
5555  *      numTSConfigs is set to the number of configurations read in
5556  */
5557 TSConfigInfo *
5558 getTSConfigurations(int *numTSConfigs)
5559 {
5560         PGresult   *res;
5561         int                     ntups;
5562         int                     i;
5563         PQExpBuffer query = createPQExpBuffer();
5564         TSConfigInfo *cfginfo;
5565         int                     i_tableoid;
5566         int                     i_oid;
5567         int                     i_cfgname;
5568         int                     i_cfgnamespace;
5569         int                     i_rolname;
5570         int                     i_cfgparser;
5571
5572         /* Before 8.3, there is no built-in text search support */
5573         if (g_fout->remoteVersion < 80300)
5574         {
5575                 *numTSConfigs = 0;
5576                 return NULL;
5577         }
5578
5579         /* Make sure we are in proper schema */
5580         selectSourceSchema("pg_catalog");
5581
5582         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5583                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5584                                           "FROM pg_ts_config",
5585                                           username_subquery);
5586
5587         res = PQexec(g_conn, query->data);
5588         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5589
5590         ntups = PQntuples(res);
5591         *numTSConfigs = ntups;
5592
5593         cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5594
5595         i_tableoid = PQfnumber(res, "tableoid");
5596         i_oid = PQfnumber(res, "oid");
5597         i_cfgname = PQfnumber(res, "cfgname");
5598         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5599         i_rolname = PQfnumber(res, "rolname");
5600         i_cfgparser = PQfnumber(res, "cfgparser");
5601
5602         for (i = 0; i < ntups; i++)
5603         {
5604                 cfginfo[i].dobj.objType = DO_TSCONFIG;
5605                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5606                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5607                 AssignDumpId(&cfginfo[i].dobj);
5608                 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5609                 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5610                                                                                                   cfginfo[i].dobj.catId.oid);
5611                 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5612                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5613
5614                 /* Decide whether we want to dump it */
5615                 selectDumpableObject(&(cfginfo[i].dobj));
5616         }
5617
5618         PQclear(res);
5619
5620         destroyPQExpBuffer(query);
5621
5622         return cfginfo;
5623 }
5624
5625 /*
5626  * getForeignDataWrappers:
5627  *        read all foreign-data wrappers in the system catalogs and return
5628  *        them in the FdwInfo* structure
5629  *
5630  *      numForeignDataWrappers is set to the number of fdws read in
5631  */
5632 FdwInfo *
5633 getForeignDataWrappers(int *numForeignDataWrappers)
5634 {
5635         PGresult   *res;
5636         int                     ntups;
5637         int                     i;
5638         PQExpBuffer query = createPQExpBuffer();
5639         FdwInfo    *fdwinfo;
5640         int                     i_oid;
5641         int                     i_fdwname;
5642         int                     i_rolname;
5643         int                     i_fdwvalidator;
5644         int                     i_fdwacl;
5645         int                     i_fdwoptions;
5646
5647         /* Before 8.4, there are no foreign-data wrappers */
5648         if (g_fout->remoteVersion < 80400)
5649         {
5650                 *numForeignDataWrappers = 0;
5651                 return NULL;
5652         }
5653
5654         /* Make sure we are in proper schema */
5655         selectSourceSchema("pg_catalog");
5656
5657         appendPQExpBuffer(query, "SELECT oid, fdwname, "
5658                 "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5659                                           "array_to_string(ARRAY("
5660                  "              SELECT option_name || ' ' || quote_literal(option_value) "
5661            "            FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5662                                           "FROM pg_foreign_data_wrapper",
5663                                           username_subquery);
5664
5665         res = PQexec(g_conn, query->data);
5666         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5667
5668         ntups = PQntuples(res);
5669         *numForeignDataWrappers = ntups;
5670
5671         fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
5672
5673         i_oid = PQfnumber(res, "oid");
5674         i_fdwname = PQfnumber(res, "fdwname");
5675         i_rolname = PQfnumber(res, "rolname");
5676         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5677         i_fdwacl = PQfnumber(res, "fdwacl");
5678         i_fdwoptions = PQfnumber(res, "fdwoptions");
5679
5680         for (i = 0; i < ntups; i++)
5681         {
5682                 fdwinfo[i].dobj.objType = DO_FDW;
5683                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5684                 AssignDumpId(&fdwinfo[i].dobj);
5685                 fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
5686                 fdwinfo[i].dobj.namespace = NULL;
5687                 fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5688                 fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
5689                 fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
5690                 fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
5691
5692
5693                 /* Decide whether we want to dump it */
5694                 selectDumpableObject(&(fdwinfo[i].dobj));
5695         }
5696
5697         PQclear(res);
5698
5699         destroyPQExpBuffer(query);
5700
5701         return fdwinfo;
5702 }
5703
5704 /*
5705  * getForeignServers:
5706  *        read all foreign servers in the system catalogs and return
5707  *        them in the ForeignServerInfo * structure
5708  *
5709  *      numForeignServers is set to the number of servers read in
5710  */
5711 ForeignServerInfo *
5712 getForeignServers(int *numForeignServers)
5713 {
5714         PGresult   *res;
5715         int                     ntups;
5716         int                     i;
5717         PQExpBuffer query = createPQExpBuffer();
5718         ForeignServerInfo *srvinfo;
5719         int                     i_oid;
5720         int                     i_srvname;
5721         int                     i_rolname;
5722         int                     i_srvfdw;
5723         int                     i_srvtype;
5724         int                     i_srvversion;
5725         int                     i_srvacl;
5726         int                     i_srvoptions;
5727
5728         /* Before 8.4, there are no foreign servers */
5729         if (g_fout->remoteVersion < 80400)
5730         {
5731                 *numForeignServers = 0;
5732                 return NULL;
5733         }
5734
5735         /* Make sure we are in proper schema */
5736         selectSourceSchema("pg_catalog");
5737
5738         appendPQExpBuffer(query, "SELECT oid, srvname, "
5739                                           "(%s srvowner) AS rolname, "
5740                                           "srvfdw, srvtype, srvversion, srvacl,"
5741                                           "array_to_string(ARRAY("
5742                  "              SELECT option_name || ' ' || quote_literal(option_value) "
5743            "            FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5744                                           "FROM pg_foreign_server",
5745                                           username_subquery);
5746
5747         res = PQexec(g_conn, query->data);
5748         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5749
5750         ntups = PQntuples(res);
5751         *numForeignServers = ntups;
5752
5753         srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
5754
5755         i_oid = PQfnumber(res, "oid");
5756         i_srvname = PQfnumber(res, "srvname");
5757         i_rolname = PQfnumber(res, "rolname");
5758         i_srvfdw = PQfnumber(res, "srvfdw");
5759         i_srvtype = PQfnumber(res, "srvtype");
5760         i_srvversion = PQfnumber(res, "srvversion");
5761         i_srvacl = PQfnumber(res, "srvacl");
5762         i_srvoptions = PQfnumber(res, "srvoptions");
5763
5764         for (i = 0; i < ntups; i++)
5765         {
5766                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5767                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5768                 AssignDumpId(&srvinfo[i].dobj);
5769                 srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
5770                 srvinfo[i].dobj.namespace = NULL;
5771                 srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5772                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5773                 srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
5774                 srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
5775                 srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
5776                 srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
5777
5778                 /* Decide whether we want to dump it */
5779                 selectDumpableObject(&(srvinfo[i].dobj));
5780         }
5781
5782         PQclear(res);
5783
5784         destroyPQExpBuffer(query);
5785
5786         return srvinfo;
5787 }
5788
5789 /*
5790  * getDefaultACLs:
5791  *        read all default ACL information in the system catalogs and return
5792  *        them in the DefaultACLInfo structure
5793  *
5794  *      numDefaultACLs is set to the number of ACLs read in
5795  */
5796 DefaultACLInfo *
5797 getDefaultACLs(int *numDefaultACLs)
5798 {
5799         DefaultACLInfo *daclinfo;
5800         PQExpBuffer query;
5801         PGresult   *res;
5802         int                     i_oid;
5803         int                     i_tableoid;
5804         int                     i_defaclrole;
5805         int                     i_defaclnamespace;
5806         int                     i_defaclobjtype;
5807         int                     i_defaclacl;
5808         int                     i,
5809                                 ntups;
5810
5811         if (g_fout->remoteVersion < 80500)
5812         {
5813                 *numDefaultACLs = 0;
5814                 return NULL;
5815         }
5816
5817         query = createPQExpBuffer();
5818
5819         /* Make sure we are in proper schema */
5820         selectSourceSchema("pg_catalog");
5821
5822         appendPQExpBuffer(query, "SELECT oid, tableoid, "
5823                                           "(%s defaclrole) AS defaclrole, "
5824                                           "defaclnamespace, "
5825                                           "defaclobjtype, "
5826                                           "defaclacl "
5827                                           "FROM pg_default_acl",
5828                                           username_subquery);
5829
5830         res = PQexec(g_conn, query->data);
5831         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5832
5833         ntups = PQntuples(res);
5834         *numDefaultACLs = ntups;
5835
5836         daclinfo = (DefaultACLInfo *) malloc(ntups * sizeof(DefaultACLInfo));
5837
5838         i_oid = PQfnumber(res, "oid");
5839         i_tableoid = PQfnumber(res, "tableoid");
5840         i_defaclrole = PQfnumber(res, "defaclrole");
5841         i_defaclnamespace = PQfnumber(res, "defaclnamespace");
5842         i_defaclobjtype = PQfnumber(res, "defaclobjtype");
5843         i_defaclacl = PQfnumber(res, "defaclacl");
5844
5845         for (i = 0; i < ntups; i++)
5846         {
5847                 Oid             nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
5848
5849                 daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
5850                 daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5851                 daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5852                 AssignDumpId(&daclinfo[i].dobj);
5853                 /* cheesy ... is it worth coming up with a better object name? */
5854                 daclinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_defaclobjtype));
5855
5856                 if (nspid != InvalidOid)
5857                         daclinfo[i].dobj.namespace = findNamespace(nspid,
5858                                                                                                            daclinfo[i].dobj.catId.oid);
5859                 else
5860                         daclinfo[i].dobj.namespace = NULL;
5861
5862                 daclinfo[i].defaclrole = strdup(PQgetvalue(res, i, i_defaclrole));
5863                 daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
5864                 daclinfo[i].defaclacl = strdup(PQgetvalue(res, i, i_defaclacl));
5865
5866                 /* Decide whether we want to dump it */
5867                 selectDumpableDefaultACL(&(daclinfo[i]));
5868         }
5869
5870         PQclear(res);
5871
5872         destroyPQExpBuffer(query);
5873
5874         return daclinfo;
5875 }
5876
5877 /*
5878  * dumpComment --
5879  *
5880  * This routine is used to dump any comments associated with the
5881  * object handed to this routine. The routine takes a constant character
5882  * string for the target part of the comment-creation command, plus
5883  * the namespace and owner of the object (for labeling the ArchiveEntry),
5884  * plus catalog ID and subid which are the lookup key for pg_description,
5885  * plus the dump ID for the object (for setting a dependency).
5886  * If a matching pg_description entry is found, it is dumped.
5887  *
5888  * Note: although this routine takes a dumpId for dependency purposes,
5889  * that purpose is just to mark the dependency in the emitted dump file
5890  * for possible future use by pg_restore.  We do NOT use it for determining
5891  * ordering of the comment in the dump file, because this routine is called
5892  * after dependency sorting occurs.  This routine should be called just after
5893  * calling ArchiveEntry() for the specified object.
5894  */
5895 static void
5896 dumpComment(Archive *fout, const char *target,
5897                         const char *namespace, const char *owner,
5898                         CatalogId catalogId, int subid, DumpId dumpId)
5899 {
5900         CommentItem *comments;
5901         int                     ncomments;
5902
5903         /* Comments are SCHEMA not data */
5904         if (dataOnly)
5905                 return;
5906
5907         /* Search for comments associated with catalogId, using table */
5908         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5909                                                          &comments);
5910
5911         /* Is there one matching the subid? */
5912         while (ncomments > 0)
5913         {
5914                 if (comments->objsubid == subid)
5915                         break;
5916                 comments++;
5917                 ncomments--;
5918         }
5919
5920         /* If a comment exists, build COMMENT ON statement */
5921         if (ncomments > 0)
5922         {
5923                 PQExpBuffer query = createPQExpBuffer();
5924
5925                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5926                 appendStringLiteralAH(query, comments->descr, fout);
5927                 appendPQExpBuffer(query, ";\n");
5928
5929                 /*
5930                  * We mark comments as SECTION_NONE because they really belong in the
5931                  * same section as their parent, whether that is pre-data or
5932                  * post-data.
5933                  */
5934                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5935                                          target, namespace, NULL, owner,
5936                                          false, "COMMENT", SECTION_NONE,
5937                                          query->data, "", NULL,
5938                                          &(dumpId), 1,
5939                                          NULL, NULL);
5940
5941                 destroyPQExpBuffer(query);
5942         }
5943 }
5944
5945 /*
5946  * dumpTableComment --
5947  *
5948  * As above, but dump comments for both the specified table (or view)
5949  * and its columns.
5950  */
5951 static void
5952 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5953                                  const char *reltypename)
5954 {
5955         CommentItem *comments;
5956         int                     ncomments;
5957         PQExpBuffer query;
5958         PQExpBuffer target;
5959
5960         /* Comments are SCHEMA not data */
5961         if (dataOnly)
5962                 return;
5963
5964         /* Search for comments associated with relation, using table */
5965         ncomments = findComments(fout,
5966                                                          tbinfo->dobj.catId.tableoid,
5967                                                          tbinfo->dobj.catId.oid,
5968                                                          &comments);
5969
5970         /* If comments exist, build COMMENT ON statements */
5971         if (ncomments <= 0)
5972                 return;
5973
5974         query = createPQExpBuffer();
5975         target = createPQExpBuffer();
5976
5977         while (ncomments > 0)
5978         {
5979                 const char *descr = comments->descr;
5980                 int                     objsubid = comments->objsubid;
5981
5982                 if (objsubid == 0)
5983                 {
5984                         resetPQExpBuffer(target);
5985                         appendPQExpBuffer(target, "%s %s", reltypename,
5986                                                           fmtId(tbinfo->dobj.name));
5987
5988                         resetPQExpBuffer(query);
5989                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5990                         appendStringLiteralAH(query, descr, fout);
5991                         appendPQExpBuffer(query, ";\n");
5992
5993                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
5994                                                  target->data,
5995                                                  tbinfo->dobj.namespace->dobj.name,
5996                                                  NULL, tbinfo->rolname,
5997                                                  false, "COMMENT", SECTION_NONE,
5998                                                  query->data, "", NULL,
5999                                                  &(tbinfo->dobj.dumpId), 1,
6000                                                  NULL, NULL);
6001                 }
6002                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
6003                 {
6004                         resetPQExpBuffer(target);
6005                         appendPQExpBuffer(target, "COLUMN %s.",
6006                                                           fmtId(tbinfo->dobj.name));
6007                         appendPQExpBuffer(target, "%s",
6008                                                           fmtId(tbinfo->attnames[objsubid - 1]));
6009
6010                         resetPQExpBuffer(query);
6011                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
6012                         appendStringLiteralAH(query, descr, fout);
6013                         appendPQExpBuffer(query, ";\n");
6014
6015                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
6016                                                  target->data,
6017                                                  tbinfo->dobj.namespace->dobj.name,
6018                                                  NULL, tbinfo->rolname,
6019                                                  false, "COMMENT", SECTION_NONE,
6020                                                  query->data, "", NULL,
6021                                                  &(tbinfo->dobj.dumpId), 1,
6022                                                  NULL, NULL);
6023                 }
6024
6025                 comments++;
6026                 ncomments--;
6027         }
6028
6029         destroyPQExpBuffer(query);
6030         destroyPQExpBuffer(target);
6031 }
6032
6033 /*
6034  * findComments --
6035  *
6036  * Find the comment(s), if any, associated with the given object.  All the
6037  * objsubid values associated with the given classoid/objoid are found with
6038  * one search.
6039  */
6040 static int
6041 findComments(Archive *fout, Oid classoid, Oid objoid,
6042                          CommentItem **items)
6043 {
6044         /* static storage for table of comments */
6045         static CommentItem *comments = NULL;
6046         static int      ncomments = -1;
6047
6048         CommentItem *middle = NULL;
6049         CommentItem *low;
6050         CommentItem *high;
6051         int                     nmatch;
6052
6053         /* Get comments if we didn't already */
6054         if (ncomments < 0)
6055                 ncomments = collectComments(fout, &comments);
6056
6057         /*
6058          * Pre-7.2, pg_description does not contain classoid, so collectComments
6059          * just stores a zero.  If there's a collision on object OID, well, you
6060          * get duplicate comments.
6061          */
6062         if (fout->remoteVersion < 70200)
6063                 classoid = 0;
6064
6065         /*
6066          * Do binary search to find some item matching the object.
6067          */
6068         low = &comments[0];
6069         high = &comments[ncomments - 1];
6070         while (low <= high)
6071         {
6072                 middle = low + (high - low) / 2;
6073
6074                 if (classoid < middle->classoid)
6075                         high = middle - 1;
6076                 else if (classoid > middle->classoid)
6077                         low = middle + 1;
6078                 else if (objoid < middle->objoid)
6079                         high = middle - 1;
6080                 else if (objoid > middle->objoid)
6081                         low = middle + 1;
6082                 else
6083                         break;                          /* found a match */
6084         }
6085
6086         if (low > high)                         /* no matches */
6087         {
6088                 *items = NULL;
6089                 return 0;
6090         }
6091
6092         /*
6093          * Now determine how many items match the object.  The search loop
6094          * invariant still holds: only items between low and high inclusive could
6095          * match.
6096          */
6097         nmatch = 1;
6098         while (middle > low)
6099         {
6100                 if (classoid != middle[-1].classoid ||
6101                         objoid != middle[-1].objoid)
6102                         break;
6103                 middle--;
6104                 nmatch++;
6105         }
6106
6107         *items = middle;
6108
6109         middle += nmatch;
6110         while (middle <= high)
6111         {
6112                 if (classoid != middle->classoid ||
6113                         objoid != middle->objoid)
6114                         break;
6115                 middle++;
6116                 nmatch++;
6117         }
6118
6119         return nmatch;
6120 }
6121
6122 /*
6123  * collectComments --
6124  *
6125  * Construct a table of all comments available for database objects.
6126  * We used to do per-object queries for the comments, but it's much faster
6127  * to pull them all over at once, and on most databases the memory cost
6128  * isn't high.
6129  *
6130  * The table is sorted by classoid/objid/objsubid for speed in lookup.
6131  */
6132 static int
6133 collectComments(Archive *fout, CommentItem **items)
6134 {
6135         PGresult   *res;
6136         PQExpBuffer query;
6137         int                     i_description;
6138         int                     i_classoid;
6139         int                     i_objoid;
6140         int                     i_objsubid;
6141         int                     ntups;
6142         int                     i;
6143         CommentItem *comments;
6144
6145         /*
6146          * Note we do NOT change source schema here; preserve the caller's
6147          * setting, instead.
6148          */
6149
6150         query = createPQExpBuffer();
6151
6152         if (fout->remoteVersion >= 70300)
6153         {
6154                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
6155                                                   "FROM pg_catalog.pg_description "
6156                                                   "ORDER BY classoid, objoid, objsubid");
6157         }
6158         else if (fout->remoteVersion >= 70200)
6159         {
6160                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
6161                                                   "FROM pg_description "
6162                                                   "ORDER BY classoid, objoid, objsubid");
6163         }
6164         else
6165         {
6166                 /* Note: this will fail to find attribute comments in pre-7.2... */
6167                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
6168                                                   "FROM pg_description "
6169                                                   "ORDER BY objoid");
6170         }
6171
6172         res = PQexec(g_conn, query->data);
6173         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6174
6175         /* Construct lookup table containing OIDs in numeric form */
6176
6177         i_description = PQfnumber(res, "description");
6178         i_classoid = PQfnumber(res, "classoid");
6179         i_objoid = PQfnumber(res, "objoid");
6180         i_objsubid = PQfnumber(res, "objsubid");
6181
6182         ntups = PQntuples(res);
6183
6184         comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
6185
6186         for (i = 0; i < ntups; i++)
6187         {
6188                 comments[i].descr = PQgetvalue(res, i, i_description);
6189                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
6190                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
6191                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
6192         }
6193
6194         /* Do NOT free the PGresult since we are keeping pointers into it */
6195         destroyPQExpBuffer(query);
6196
6197         *items = comments;
6198         return ntups;
6199 }
6200
6201 /*
6202  * dumpDumpableObject
6203  *
6204  * This routine and its subsidiaries are responsible for creating
6205  * ArchiveEntries (TOC objects) for each object to be dumped.
6206  */
6207 static void
6208 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
6209 {
6210         switch (dobj->objType)
6211         {
6212                 case DO_NAMESPACE:
6213                         dumpNamespace(fout, (NamespaceInfo *) dobj);
6214                         break;
6215                 case DO_TYPE:
6216                         dumpType(fout, (TypeInfo *) dobj);
6217                         break;
6218                 case DO_SHELL_TYPE:
6219                         dumpShellType(fout, (ShellTypeInfo *) dobj);
6220                         break;
6221                 case DO_FUNC:
6222                         dumpFunc(fout, (FuncInfo *) dobj);
6223                         break;
6224                 case DO_AGG:
6225                         dumpAgg(fout, (AggInfo *) dobj);
6226                         break;
6227                 case DO_OPERATOR:
6228                         dumpOpr(fout, (OprInfo *) dobj);
6229                         break;
6230                 case DO_OPCLASS:
6231                         dumpOpclass(fout, (OpclassInfo *) dobj);
6232                         break;
6233                 case DO_OPFAMILY:
6234                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
6235                         break;
6236                 case DO_CONVERSION:
6237                         dumpConversion(fout, (ConvInfo *) dobj);
6238                         break;
6239                 case DO_TABLE:
6240                         dumpTable(fout, (TableInfo *) dobj);
6241                         break;
6242                 case DO_ATTRDEF:
6243                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
6244                         break;
6245                 case DO_INDEX:
6246                         dumpIndex(fout, (IndxInfo *) dobj);
6247                         break;
6248                 case DO_RULE:
6249                         dumpRule(fout, (RuleInfo *) dobj);
6250                         break;
6251                 case DO_TRIGGER:
6252                         dumpTrigger(fout, (TriggerInfo *) dobj);
6253                         break;
6254                 case DO_CONSTRAINT:
6255                         dumpConstraint(fout, (ConstraintInfo *) dobj);
6256                         break;
6257                 case DO_FK_CONSTRAINT:
6258                         dumpConstraint(fout, (ConstraintInfo *) dobj);
6259                         break;
6260                 case DO_PROCLANG:
6261                         dumpProcLang(fout, (ProcLangInfo *) dobj);
6262                         break;
6263                 case DO_CAST:
6264                         dumpCast(fout, (CastInfo *) dobj);
6265                         break;
6266                 case DO_TABLE_DATA:
6267                         dumpTableData(fout, (TableDataInfo *) dobj);
6268                         break;
6269                 case DO_DUMMY_TYPE:
6270                         /* table rowtypes and array types are never dumped separately */
6271                         break;
6272                 case DO_TSPARSER:
6273                         dumpTSParser(fout, (TSParserInfo *) dobj);
6274                         break;
6275                 case DO_TSDICT:
6276                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
6277                         break;
6278                 case DO_TSTEMPLATE:
6279                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
6280                         break;
6281                 case DO_TSCONFIG:
6282                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
6283                         break;
6284                 case DO_FDW:
6285                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
6286                         break;
6287                 case DO_FOREIGN_SERVER:
6288                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
6289                         break;
6290                 case DO_DEFAULT_ACL:
6291                         dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
6292                         break;
6293                 case DO_BLOBS:
6294                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
6295                                                  dobj->name, NULL, NULL, "",
6296                                                  false, "BLOBS", SECTION_DATA,
6297                                                  "", "", NULL,
6298                                                  dobj->dependencies, dobj->nDeps,
6299                                                  dumpBlobs, NULL);
6300                         break;
6301                 case DO_BLOB_COMMENTS:
6302                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
6303                                                  dobj->name, NULL, NULL, "",
6304                                                  false, "BLOB COMMENTS", SECTION_DATA,
6305                                                  "", "", NULL,
6306                                                  dobj->dependencies, dobj->nDeps,
6307                                                  dumpBlobComments, NULL);
6308                         break;
6309         }
6310 }
6311
6312 /*
6313  * dumpNamespace
6314  *        writes out to fout the queries to recreate a user-defined namespace
6315  */
6316 static void
6317 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
6318 {
6319         PQExpBuffer q;
6320         PQExpBuffer delq;
6321         char       *qnspname;
6322
6323         /* Skip if not to be dumped */
6324         if (!nspinfo->dobj.dump || dataOnly)
6325                 return;
6326
6327         /* don't dump dummy namespace from pre-7.3 source */
6328         if (strlen(nspinfo->dobj.name) == 0)
6329                 return;
6330
6331         q = createPQExpBuffer();
6332         delq = createPQExpBuffer();
6333
6334         qnspname = strdup(fmtId(nspinfo->dobj.name));
6335
6336         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
6337
6338         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
6339
6340         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
6341                                  nspinfo->dobj.name,
6342                                  NULL, NULL,
6343                                  nspinfo->rolname,
6344                                  false, "SCHEMA", SECTION_PRE_DATA,
6345                                  q->data, delq->data, NULL,
6346                                  nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
6347                                  NULL, NULL);
6348
6349         /* Dump Schema Comments */
6350         resetPQExpBuffer(q);
6351         appendPQExpBuffer(q, "SCHEMA %s", qnspname);
6352         dumpComment(fout, q->data,
6353                                 NULL, nspinfo->rolname,
6354                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
6355
6356         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6357                         qnspname, NULL, nspinfo->dobj.name, NULL,
6358                         nspinfo->rolname, nspinfo->nspacl);
6359
6360         free(qnspname);
6361
6362         destroyPQExpBuffer(q);
6363         destroyPQExpBuffer(delq);
6364 }
6365
6366 /*
6367  * dumpType
6368  *        writes out to fout the queries to recreate a user-defined type
6369  */
6370 static void
6371 dumpType(Archive *fout, TypeInfo *tinfo)
6372 {
6373         /* Skip if not to be dumped */
6374         if (!tinfo->dobj.dump || dataOnly)
6375                 return;
6376
6377         /* Dump out in proper style */
6378         if (tinfo->typtype == TYPTYPE_BASE)
6379                 dumpBaseType(fout, tinfo);
6380         else if (tinfo->typtype == TYPTYPE_DOMAIN)
6381                 dumpDomain(fout, tinfo);
6382         else if (tinfo->typtype == TYPTYPE_COMPOSITE)
6383                 dumpCompositeType(fout, tinfo);
6384         else if (tinfo->typtype == TYPTYPE_ENUM)
6385                 dumpEnumType(fout, tinfo);
6386 }
6387
6388 /*
6389  * dumpEnumType
6390  *        writes out to fout the queries to recreate a user-defined enum type
6391  */
6392 static void
6393 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6394 {
6395         PQExpBuffer q = createPQExpBuffer();
6396         PQExpBuffer delq = createPQExpBuffer();
6397         PQExpBuffer query = createPQExpBuffer();
6398         PGresult   *res;
6399         int                     num,
6400                                 i;
6401         char       *label;
6402
6403         /* Set proper schema search path so regproc references list correctly */
6404         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6405
6406         appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6407                                           "WHERE enumtypid = '%u'"
6408                                           "ORDER BY oid",
6409                                           tinfo->dobj.catId.oid);
6410
6411         res = PQexec(g_conn, query->data);
6412         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6413
6414         num = PQntuples(res);
6415         /* should be at least 1 value */
6416         if (num == 0)
6417         {
6418                 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
6419                 exit_nicely();
6420         }
6421
6422         /*
6423          * DROP must be fully qualified in case same name appears in pg_catalog.
6424          * CASCADE shouldn't be required here as for normal types since the I/O
6425          * functions are generic and do not get dropped.
6426          */
6427         appendPQExpBuffer(delq, "DROP TYPE %s.",
6428                                           fmtId(tinfo->dobj.namespace->dobj.name));
6429         appendPQExpBuffer(delq, "%s;\n",
6430                                           fmtId(tinfo->dobj.name));
6431         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
6432                                           fmtId(tinfo->dobj.name));
6433         for (i = 0; i < num; i++)
6434         {
6435                 label = PQgetvalue(res, i, 0);
6436                 if (i > 0)
6437                         appendPQExpBuffer(q, ",\n");
6438                 appendPQExpBuffer(q, "    ");
6439                 appendStringLiteralAH(q, label, fout);
6440         }
6441         appendPQExpBuffer(q, "\n);\n");
6442
6443         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6444                                  tinfo->dobj.name,
6445                                  tinfo->dobj.namespace->dobj.name,
6446                                  NULL,
6447                                  tinfo->rolname, false,
6448                                  "TYPE", SECTION_PRE_DATA,
6449                                  q->data, delq->data, NULL,
6450                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6451                                  NULL, NULL);
6452
6453         /* Dump Type Comments */
6454         resetPQExpBuffer(q);
6455
6456         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6457         dumpComment(fout, q->data,
6458                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6459                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6460
6461         PQclear(res);
6462         destroyPQExpBuffer(q);
6463         destroyPQExpBuffer(delq);
6464         destroyPQExpBuffer(query);
6465 }
6466
6467 /*
6468  * dumpBaseType
6469  *        writes out to fout the queries to recreate a user-defined base type
6470  */
6471 static void
6472 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6473 {
6474         PQExpBuffer q = createPQExpBuffer();
6475         PQExpBuffer delq = createPQExpBuffer();
6476         PQExpBuffer query = createPQExpBuffer();
6477         PGresult   *res;
6478         int                     ntups;
6479         char       *typlen;
6480         char       *typinput;
6481         char       *typoutput;
6482         char       *typreceive;
6483         char       *typsend;
6484         char       *typmodin;
6485         char       *typmodout;
6486         char       *typanalyze;
6487         Oid                     typinputoid;
6488         Oid                     typoutputoid;
6489         Oid                     typreceiveoid;
6490         Oid                     typsendoid;
6491         Oid                     typmodinoid;
6492         Oid                     typmodoutoid;
6493         Oid                     typanalyzeoid;
6494         char       *typcategory;
6495         char       *typispreferred;
6496         char       *typdelim;
6497         char       *typbyval;
6498         char       *typalign;
6499         char       *typstorage;
6500         char       *typdefault;
6501         bool            typdefault_is_literal = false;
6502
6503         /* Set proper schema search path so regproc references list correctly */
6504         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6505
6506         /* Fetch type-specific details */
6507         if (fout->remoteVersion >= 80400)
6508         {
6509                 appendPQExpBuffer(query, "SELECT typlen, "
6510                                                   "typinput, typoutput, typreceive, typsend, "
6511                                                   "typmodin, typmodout, typanalyze, "
6512                                                   "typinput::pg_catalog.oid AS typinputoid, "
6513                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6514                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6515                                                   "typsend::pg_catalog.oid AS typsendoid, "
6516                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
6517                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
6518                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6519                                                   "typcategory, typispreferred, "
6520                                                   "typdelim, typbyval, typalign, typstorage, "
6521                                                   "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
6522                                                   "FROM pg_catalog.pg_type "
6523                                                   "WHERE oid = '%u'::pg_catalog.oid",
6524                                                   tinfo->dobj.catId.oid);
6525         }
6526         else if (fout->remoteVersion >= 80300)
6527         {
6528                 /* Before 8.4, pg_get_expr does not allow 0 for its second arg */
6529                 appendPQExpBuffer(query, "SELECT typlen, "
6530                                                   "typinput, typoutput, typreceive, typsend, "
6531                                                   "typmodin, typmodout, typanalyze, "
6532                                                   "typinput::pg_catalog.oid AS typinputoid, "
6533                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6534                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6535                                                   "typsend::pg_catalog.oid AS typsendoid, "
6536                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
6537                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
6538                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6539                                                   "'U' AS typcategory, false AS typispreferred, "
6540                                                   "typdelim, typbyval, typalign, typstorage, "
6541                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6542                                                   "FROM pg_catalog.pg_type "
6543                                                   "WHERE oid = '%u'::pg_catalog.oid",
6544                                                   tinfo->dobj.catId.oid);
6545         }
6546         else if (fout->remoteVersion >= 80000)
6547         {
6548                 appendPQExpBuffer(query, "SELECT typlen, "
6549                                                   "typinput, typoutput, typreceive, typsend, "
6550                                                   "'-' AS typmodin, '-' AS typmodout, "
6551                                                   "typanalyze, "
6552                                                   "typinput::pg_catalog.oid AS typinputoid, "
6553                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6554                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6555                                                   "typsend::pg_catalog.oid AS typsendoid, "
6556                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6557                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6558                                                   "'U' AS typcategory, false AS typispreferred, "
6559                                                   "typdelim, typbyval, typalign, typstorage, "
6560                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6561                                                   "FROM pg_catalog.pg_type "
6562                                                   "WHERE oid = '%u'::pg_catalog.oid",
6563                                                   tinfo->dobj.catId.oid);
6564         }
6565         else if (fout->remoteVersion >= 70400)
6566         {
6567                 appendPQExpBuffer(query, "SELECT typlen, "
6568                                                   "typinput, typoutput, typreceive, typsend, "
6569                                                   "'-' AS typmodin, '-' AS typmodout, "
6570                                                   "'-' AS typanalyze, "
6571                                                   "typinput::pg_catalog.oid AS typinputoid, "
6572                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6573                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6574                                                   "typsend::pg_catalog.oid AS typsendoid, "
6575                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6576                                                   "0 AS typanalyzeoid, "
6577                                                   "'U' AS typcategory, false AS typispreferred, "
6578                                                   "typdelim, typbyval, typalign, typstorage, "
6579                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6580                                                   "FROM pg_catalog.pg_type "
6581                                                   "WHERE oid = '%u'::pg_catalog.oid",
6582                                                   tinfo->dobj.catId.oid);
6583         }
6584         else if (fout->remoteVersion >= 70300)
6585         {
6586                 appendPQExpBuffer(query, "SELECT typlen, "
6587                                                   "typinput, typoutput, "
6588                                                   "'-' AS typreceive, '-' AS typsend, "
6589                                                   "'-' AS typmodin, '-' AS typmodout, "
6590                                                   "'-' AS typanalyze, "
6591                                                   "typinput::pg_catalog.oid AS typinputoid, "
6592                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6593                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6594                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6595                                                   "0 AS typanalyzeoid, "
6596                                                   "'U' AS typcategory, false AS typispreferred, "
6597                                                   "typdelim, typbyval, typalign, typstorage, "
6598                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6599                                                   "FROM pg_catalog.pg_type "
6600                                                   "WHERE oid = '%u'::pg_catalog.oid",
6601                                                   tinfo->dobj.catId.oid);
6602         }
6603         else if (fout->remoteVersion >= 70200)
6604         {
6605                 /*
6606                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
6607                  * ignore them because they are not right.
6608                  */
6609                 appendPQExpBuffer(query, "SELECT typlen, "
6610                                                   "typinput, typoutput, "
6611                                                   "'-' AS typreceive, '-' AS typsend, "
6612                                                   "'-' AS typmodin, '-' AS typmodout, "
6613                                                   "'-' AS typanalyze, "
6614                                                   "typinput::oid AS typinputoid, "
6615                                                   "typoutput::oid AS typoutputoid, "
6616                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6617                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6618                                                   "0 AS typanalyzeoid, "
6619                                                   "'U' AS typcategory, false AS typispreferred, "
6620                                                   "typdelim, typbyval, typalign, typstorage, "
6621                                                   "NULL AS typdefaultbin, typdefault "
6622                                                   "FROM pg_type "
6623                                                   "WHERE oid = '%u'::oid",
6624                                                   tinfo->dobj.catId.oid);
6625         }
6626         else if (fout->remoteVersion >= 70100)
6627         {
6628                 /*
6629                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
6630                  * representation.
6631                  */
6632                 appendPQExpBuffer(query, "SELECT typlen, "
6633                                                   "typinput, typoutput, "
6634                                                   "'-' AS typreceive, '-' AS typsend, "
6635                                                   "'-' AS typmodin, '-' AS typmodout, "
6636                                                   "'-' AS typanalyze, "
6637                                                   "typinput::oid AS typinputoid, "
6638                                                   "typoutput::oid AS typoutputoid, "
6639                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6640                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6641                                                   "0 AS typanalyzeoid, "
6642                                                   "'U' AS typcategory, false AS typispreferred, "
6643                                                   "typdelim, typbyval, typalign, typstorage, "
6644                                                   "NULL AS typdefaultbin, NULL AS typdefault "
6645                                                   "FROM pg_type "
6646                                                   "WHERE oid = '%u'::oid",
6647                                                   tinfo->dobj.catId.oid);
6648         }
6649         else
6650         {
6651                 appendPQExpBuffer(query, "SELECT typlen, "
6652                                                   "typinput, typoutput, "
6653                                                   "'-' AS typreceive, '-' AS typsend, "
6654                                                   "'-' AS typmodin, '-' AS typmodout, "
6655                                                   "'-' AS typanalyze, "
6656                                                   "typinput::oid AS typinputoid, "
6657                                                   "typoutput::oid AS typoutputoid, "
6658                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6659                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6660                                                   "0 AS typanalyzeoid, "
6661                                                   "'U' AS typcategory, false AS typispreferred, "
6662                                                   "typdelim, typbyval, typalign, "
6663                                                   "'p'::char AS typstorage, "
6664                                                   "NULL AS typdefaultbin, NULL AS typdefault "
6665                                                   "FROM pg_type "
6666                                                   "WHERE oid = '%u'::oid",
6667                                                   tinfo->dobj.catId.oid);
6668         }
6669
6670         res = PQexec(g_conn, query->data);
6671         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6672
6673         /* Expecting a single result only */
6674         ntups = PQntuples(res);
6675         if (ntups != 1)
6676         {
6677                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6678                                                            "query returned %d rows instead of one: %s\n",
6679                                                                  ntups),
6680                                   ntups, query->data);
6681                 exit_nicely();
6682         }
6683
6684         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6685         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6686         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6687         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6688         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6689         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6690         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6691         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6692         typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6693         typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6694         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6695         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6696         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6697         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6698         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6699         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6700         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6701         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6702         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6703         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6704         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6705         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6706                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6707         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6708         {
6709                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6710                 typdefault_is_literal = true;   /* it needs quotes */
6711         }
6712         else
6713                 typdefault = NULL;
6714
6715         /*
6716          * DROP must be fully qualified in case same name appears in pg_catalog.
6717          * The reason we include CASCADE is that the circular dependency between
6718          * the type and its I/O functions makes it impossible to drop the type any
6719          * other way.
6720          */
6721         appendPQExpBuffer(delq, "DROP TYPE %s.",
6722                                           fmtId(tinfo->dobj.namespace->dobj.name));
6723         appendPQExpBuffer(delq, "%s CASCADE;\n",
6724                                           fmtId(tinfo->dobj.name));
6725
6726         appendPQExpBuffer(q,
6727                                           "CREATE TYPE %s (\n"
6728                                           "    INTERNALLENGTH = %s",
6729                                           fmtId(tinfo->dobj.name),
6730                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6731
6732         if (fout->remoteVersion >= 70300)
6733         {
6734                 /* regproc result is correctly quoted as of 7.3 */
6735                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
6736                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
6737                 if (OidIsValid(typreceiveoid))
6738                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
6739                 if (OidIsValid(typsendoid))
6740                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
6741                 if (OidIsValid(typmodinoid))
6742                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
6743                 if (OidIsValid(typmodoutoid))
6744                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
6745                 if (OidIsValid(typanalyzeoid))
6746                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
6747         }
6748         else
6749         {
6750                 /* regproc delivers an unquoted name before 7.3 */
6751                 /* cannot combine these because fmtId uses static result area */
6752                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
6753                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
6754                 /* receive/send/typmodin/typmodout/analyze need not be printed */
6755         }
6756
6757         if (typdefault != NULL)
6758         {
6759                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
6760                 if (typdefault_is_literal)
6761                         appendStringLiteralAH(q, typdefault, fout);
6762                 else
6763                         appendPQExpBufferStr(q, typdefault);
6764         }
6765
6766         if (OidIsValid(tinfo->typelem))
6767         {
6768                 char       *elemType;
6769
6770                 /* reselect schema in case changed by function dump */
6771                 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6772                 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6773                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
6774                 free(elemType);
6775         }
6776
6777         if (strcmp(typcategory, "U") != 0)
6778         {
6779                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
6780                 appendStringLiteralAH(q, typcategory, fout);
6781         }
6782
6783         if (strcmp(typispreferred, "t") == 0)
6784                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
6785
6786         if (typdelim && strcmp(typdelim, ",") != 0)
6787         {
6788                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
6789                 appendStringLiteralAH(q, typdelim, fout);
6790         }
6791
6792         if (strcmp(typalign, "c") == 0)
6793                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
6794         else if (strcmp(typalign, "s") == 0)
6795                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
6796         else if (strcmp(typalign, "i") == 0)
6797                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
6798         else if (strcmp(typalign, "d") == 0)
6799                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
6800
6801         if (strcmp(typstorage, "p") == 0)
6802                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
6803         else if (strcmp(typstorage, "e") == 0)
6804                 appendPQExpBuffer(q, ",\n    STORAGE = external");
6805         else if (strcmp(typstorage, "x") == 0)
6806                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
6807         else if (strcmp(typstorage, "m") == 0)
6808                 appendPQExpBuffer(q, ",\n    STORAGE = main");
6809
6810         if (strcmp(typbyval, "t") == 0)
6811                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
6812
6813         appendPQExpBuffer(q, "\n);\n");
6814
6815         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6816                                  tinfo->dobj.name,
6817                                  tinfo->dobj.namespace->dobj.name,
6818                                  NULL,
6819                                  tinfo->rolname, false,
6820                                  "TYPE", SECTION_PRE_DATA,
6821                                  q->data, delq->data, NULL,
6822                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6823                                  NULL, NULL);
6824
6825         /* Dump Type Comments */
6826         resetPQExpBuffer(q);
6827
6828         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6829         dumpComment(fout, q->data,
6830                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6831                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6832
6833         PQclear(res);
6834         destroyPQExpBuffer(q);
6835         destroyPQExpBuffer(delq);
6836         destroyPQExpBuffer(query);
6837 }
6838
6839 /*
6840  * dumpDomain
6841  *        writes out to fout the queries to recreate a user-defined domain
6842  */
6843 static void
6844 dumpDomain(Archive *fout, TypeInfo *tinfo)
6845 {
6846         PQExpBuffer q = createPQExpBuffer();
6847         PQExpBuffer delq = createPQExpBuffer();
6848         PQExpBuffer query = createPQExpBuffer();
6849         PGresult   *res;
6850         int                     ntups;
6851         int                     i;
6852         char       *typnotnull;
6853         char       *typdefn;
6854         char       *typdefault;
6855         bool            typdefault_is_literal = false;
6856
6857         /* Set proper schema search path so type references list correctly */
6858         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6859
6860         /* Fetch domain specific details */
6861         /* We assume here that remoteVersion must be at least 70300 */
6862         appendPQExpBuffer(query, "SELECT typnotnull, "
6863                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6864                                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6865                                           "FROM pg_catalog.pg_type "
6866                                           "WHERE oid = '%u'::pg_catalog.oid",
6867                                           tinfo->dobj.catId.oid);
6868
6869         res = PQexec(g_conn, query->data);
6870         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6871
6872         /* Expecting a single result only */
6873         ntups = PQntuples(res);
6874         if (ntups != 1)
6875         {
6876                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6877                                                            "query returned %d rows instead of one: %s\n",
6878                                                                  ntups),
6879                                   ntups, query->data);
6880                 exit_nicely();
6881         }
6882
6883         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6884         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6885         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6886                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6887         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6888         {
6889                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6890                 typdefault_is_literal = true;   /* it needs quotes */
6891         }
6892         else
6893                 typdefault = NULL;
6894
6895         appendPQExpBuffer(q,
6896                                           "CREATE DOMAIN %s AS %s",
6897                                           fmtId(tinfo->dobj.name),
6898                                           typdefn);
6899
6900         if (typnotnull[0] == 't')
6901                 appendPQExpBuffer(q, " NOT NULL");
6902
6903         if (typdefault != NULL)
6904         {
6905                 appendPQExpBuffer(q, " DEFAULT ");
6906                 if (typdefault_is_literal)
6907                         appendStringLiteralAH(q, typdefault, fout);
6908                 else
6909                         appendPQExpBufferStr(q, typdefault);
6910         }
6911
6912         PQclear(res);
6913
6914         /*
6915          * Add any CHECK constraints for the domain
6916          */
6917         for (i = 0; i < tinfo->nDomChecks; i++)
6918         {
6919                 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6920
6921                 if (!domcheck->separate)
6922                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6923                                                           fmtId(domcheck->dobj.name), domcheck->condef);
6924         }
6925
6926         appendPQExpBuffer(q, ";\n");
6927
6928         /*
6929          * DROP must be fully qualified in case same name appears in pg_catalog
6930          */
6931         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6932                                           fmtId(tinfo->dobj.namespace->dobj.name));
6933         appendPQExpBuffer(delq, "%s;\n",
6934                                           fmtId(tinfo->dobj.name));
6935
6936         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6937                                  tinfo->dobj.name,
6938                                  tinfo->dobj.namespace->dobj.name,
6939                                  NULL,
6940                                  tinfo->rolname, false,
6941                                  "DOMAIN", SECTION_PRE_DATA,
6942                                  q->data, delq->data, NULL,
6943                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6944                                  NULL, NULL);
6945
6946         /* Dump Domain Comments */
6947         resetPQExpBuffer(q);
6948
6949         appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6950         dumpComment(fout, q->data,
6951                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6952                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6953
6954         destroyPQExpBuffer(q);
6955         destroyPQExpBuffer(delq);
6956         destroyPQExpBuffer(query);
6957 }
6958
6959 /*
6960  * dumpCompositeType
6961  *        writes out to fout the queries to recreate a user-defined stand-alone
6962  *        composite type
6963  */
6964 static void
6965 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6966 {
6967         PQExpBuffer q = createPQExpBuffer();
6968         PQExpBuffer delq = createPQExpBuffer();
6969         PQExpBuffer query = createPQExpBuffer();
6970         PGresult   *res;
6971         int                     ntups;
6972         int                     i_attname;
6973         int                     i_atttypdefn;
6974         int                     i;
6975
6976         /* Set proper schema search path so type references list correctly */
6977         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6978
6979         /* Fetch type specific details */
6980         /* We assume here that remoteVersion must be at least 70300 */
6981
6982         appendPQExpBuffer(query, "SELECT a.attname, "
6983                          "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6984                                           "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6985                                           "WHERE t.oid = '%u'::pg_catalog.oid "
6986                                           "AND a.attrelid = t.typrelid "
6987                                           "AND NOT a.attisdropped "
6988                                           "ORDER BY a.attnum ",
6989                                           tinfo->dobj.catId.oid);
6990
6991         res = PQexec(g_conn, query->data);
6992         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6993
6994         /* Expecting at least a single result */
6995         ntups = PQntuples(res);
6996         if (ntups < 1)
6997         {
6998                 write_msg(NULL, "query returned no rows: %s\n", query->data);
6999                 exit_nicely();
7000         }
7001
7002         i_attname = PQfnumber(res, "attname");
7003         i_atttypdefn = PQfnumber(res, "atttypdefn");
7004
7005         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
7006                                           fmtId(tinfo->dobj.name));
7007
7008         for (i = 0; i < ntups; i++)
7009         {
7010                 char       *attname;
7011                 char       *atttypdefn;
7012
7013                 attname = PQgetvalue(res, i, i_attname);
7014                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
7015
7016                 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
7017                 if (i < ntups - 1)
7018                         appendPQExpBuffer(q, ",");
7019         }
7020         appendPQExpBuffer(q, "\n);\n");
7021
7022         /*
7023          * DROP must be fully qualified in case same name appears in pg_catalog
7024          */
7025         appendPQExpBuffer(delq, "DROP TYPE %s.",
7026                                           fmtId(tinfo->dobj.namespace->dobj.name));
7027         appendPQExpBuffer(delq, "%s;\n",
7028                                           fmtId(tinfo->dobj.name));
7029
7030         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
7031                                  tinfo->dobj.name,
7032                                  tinfo->dobj.namespace->dobj.name,
7033                                  NULL,
7034                                  tinfo->rolname, false,
7035                                  "TYPE", SECTION_PRE_DATA,
7036                                  q->data, delq->data, NULL,
7037                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
7038                                  NULL, NULL);
7039
7040
7041         /* Dump Type Comments */
7042         resetPQExpBuffer(q);
7043
7044         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
7045         dumpComment(fout, q->data,
7046                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
7047                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
7048
7049         PQclear(res);
7050         destroyPQExpBuffer(q);
7051         destroyPQExpBuffer(delq);
7052         destroyPQExpBuffer(query);
7053
7054         /* Dump any per-column comments */
7055         dumpCompositeTypeColComments(fout, tinfo);
7056 }
7057
7058 /*
7059  * dumpCompositeTypeColComments
7060  *        writes out to fout the queries to recreate comments on the columns of
7061  *        a user-defined stand-alone composite type
7062  */
7063 static void
7064 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tinfo)
7065 {
7066         CommentItem *comments;
7067         int ncomments;
7068         PGresult *res;
7069         PQExpBuffer query;
7070         PQExpBuffer target;
7071         Oid pgClassOid;
7072         int i;
7073         int ntups;
7074         int i_attname;
7075         int i_attnum;
7076
7077         query = createPQExpBuffer();
7078
7079         /* We assume here that remoteVersion must be at least 70300 */
7080         appendPQExpBuffer(query,
7081                                           "SELECT c.tableoid, a.attname, a.attnum "
7082                                           "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
7083                                           "WHERE c.oid = '%u' AND c.oid = a.attrelid "
7084                                           "  AND NOT a.attisdropped "
7085                                           "ORDER BY a.attnum ",
7086                                           tinfo->typrelid);
7087
7088         /* Fetch column attnames */
7089         res = PQexec(g_conn, query->data);
7090         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7091
7092         /* Expecting at least a single result */
7093         ntups = PQntuples(res);
7094         if (ntups < 1)
7095         {
7096                 write_msg(NULL, "query returned no rows: %s\n", query->data);
7097                 exit_nicely();
7098         }
7099
7100         pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
7101
7102         /* Search for comments associated with type's pg_class OID */
7103         ncomments = findComments(fout,
7104                                                          pgClassOid,
7105                                                          tinfo->typrelid,
7106                                                          &comments);
7107
7108         /* If no comments exist, we're done */
7109         if (ncomments <= 0)
7110         {
7111                 PQclear(res);
7112                 destroyPQExpBuffer(query);
7113                 return;
7114         }
7115
7116         /* Build COMMENT ON statements */
7117         target = createPQExpBuffer();
7118
7119         i_attnum = PQfnumber(res, "attnum");
7120         i_attname = PQfnumber(res, "attname");
7121         while (ncomments > 0)
7122         {
7123                 const char *attname;
7124
7125                 attname = NULL;
7126                 for (i = 0; i < ntups; i++)
7127                 {
7128                         if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
7129                         {
7130                                 attname = PQgetvalue(res, i, i_attname);
7131                                 break;
7132                         }
7133                 }
7134                 if (attname)                    /* just in case we don't find it */
7135                 {
7136                         const char *descr = comments->descr;
7137
7138                         resetPQExpBuffer(target);
7139                         appendPQExpBuffer(target, "COLUMN %s.",
7140                                                           fmtId(tinfo->dobj.name));
7141                         appendPQExpBuffer(target, "%s",
7142                                                           fmtId(attname));
7143
7144                         resetPQExpBuffer(query);
7145                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
7146                         appendStringLiteralAH(query, descr, fout);
7147                         appendPQExpBuffer(query, ";\n");
7148
7149                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7150                                                  target->data,
7151                                                  tinfo->dobj.namespace->dobj.name,
7152                                                  NULL, tinfo->rolname,
7153                                                  false, "COMMENT", SECTION_NONE,
7154                                                  query->data, "", NULL,
7155                                                  &(tinfo->dobj.dumpId), 1,
7156                                                  NULL, NULL);
7157                 }
7158
7159                 comments++;
7160                 ncomments--;
7161         }
7162
7163         PQclear(res);
7164         destroyPQExpBuffer(query);
7165         destroyPQExpBuffer(target);
7166 }
7167
7168 /*
7169  * dumpShellType
7170  *        writes out to fout the queries to create a shell type
7171  *
7172  * We dump a shell definition in advance of the I/O functions for the type.
7173  */
7174 static void
7175 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
7176 {
7177         PQExpBuffer q;
7178
7179         /* Skip if not to be dumped */
7180         if (!stinfo->dobj.dump || dataOnly)
7181                 return;
7182
7183         q = createPQExpBuffer();
7184
7185         /*
7186          * Note the lack of a DROP command for the shell type; any required DROP
7187          * is driven off the base type entry, instead.  This interacts with
7188          * _printTocEntry()'s use of the presence of a DROP command to decide
7189          * whether an entry needs an ALTER OWNER command.  We don't want to alter
7190          * the shell type's owner immediately on creation; that should happen only
7191          * after it's filled in, otherwise the backend complains.
7192          */
7193
7194         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
7195                                           fmtId(stinfo->dobj.name));
7196
7197         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
7198                                  stinfo->dobj.name,
7199                                  stinfo->dobj.namespace->dobj.name,
7200                                  NULL,
7201                                  stinfo->baseType->rolname, false,
7202                                  "SHELL TYPE", SECTION_PRE_DATA,
7203                                  q->data, "", NULL,
7204                                  stinfo->dobj.dependencies, stinfo->dobj.nDeps,
7205                                  NULL, NULL);
7206
7207         destroyPQExpBuffer(q);
7208 }
7209
7210 /*
7211  * Determine whether we want to dump definitions for procedural languages.
7212  * Since the languages themselves don't have schemas, we can't rely on
7213  * the normal schema-based selection mechanism.  We choose to dump them
7214  * whenever neither --schema nor --table was given.  (Before 8.1, we used
7215  * the dump flag of the PL's call handler function, but in 8.1 this will
7216  * probably always be false since call handlers are created in pg_catalog.)
7217  *
7218  * For some backwards compatibility with the older behavior, we forcibly
7219  * dump a PL if its handler function (and validator if any) are in a
7220  * dumpable namespace.  That case is not checked here.
7221  */
7222 static bool
7223 shouldDumpProcLangs(void)
7224 {
7225         if (!include_everything)
7226                 return false;
7227         /* And they're schema not data */
7228         if (dataOnly)
7229                 return false;
7230         return true;
7231 }
7232
7233 /*
7234  * dumpProcLang
7235  *                writes out to fout the queries to recreate a user-defined
7236  *                procedural language
7237  */
7238 static void
7239 dumpProcLang(Archive *fout, ProcLangInfo *plang)
7240 {
7241         PQExpBuffer defqry;
7242         PQExpBuffer delqry;
7243         bool            useParams;
7244         char       *qlanname;
7245         char       *lanschema;
7246         FuncInfo   *funcInfo;
7247         FuncInfo   *inlineInfo = NULL;
7248         FuncInfo   *validatorInfo = NULL;
7249
7250         if (dataOnly)
7251                 return;
7252
7253         /*
7254          * Try to find the support function(s).  It is not an error if we don't
7255          * find them --- if the functions are in the pg_catalog schema, as is
7256          * standard in 8.1 and up, then we won't have loaded them. (In this case
7257          * we will emit a parameterless CREATE LANGUAGE command, which will
7258          * require PL template knowledge in the backend to reload.)
7259          */
7260
7261         funcInfo = findFuncByOid(plang->lanplcallfoid);
7262         if (funcInfo != NULL && !funcInfo->dobj.dump)
7263                 funcInfo = NULL;                /* treat not-dumped same as not-found */
7264
7265         if (OidIsValid(plang->laninline))
7266         {
7267                 inlineInfo = findFuncByOid(plang->laninline);
7268                 if (inlineInfo != NULL && !inlineInfo->dobj.dump)
7269                         inlineInfo = NULL;
7270         }
7271
7272         if (OidIsValid(plang->lanvalidator))
7273         {
7274                 validatorInfo = findFuncByOid(plang->lanvalidator);
7275                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
7276                         validatorInfo = NULL;
7277         }
7278
7279         /*
7280          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
7281          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
7282          * dump it.
7283          */
7284         useParams = (funcInfo != NULL &&
7285                                  (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
7286                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
7287
7288         if (!useParams && !shouldDumpProcLangs())
7289                 return;
7290
7291         defqry = createPQExpBuffer();
7292         delqry = createPQExpBuffer();
7293
7294         qlanname = strdup(fmtId(plang->dobj.name));
7295
7296         /*
7297          * If dumping a HANDLER clause, treat the language as being in the handler
7298          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
7299          * it doesn't really have a schema.
7300          */
7301         if (useParams)
7302                 lanschema = funcInfo->dobj.namespace->dobj.name;
7303         else
7304                 lanschema = NULL;
7305
7306         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
7307                                           qlanname);
7308
7309         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
7310                                           (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
7311                                           qlanname);
7312         if (useParams)
7313         {
7314                 appendPQExpBuffer(defqry, " HANDLER %s",
7315                                                   fmtId(funcInfo->dobj.name));
7316                 if (OidIsValid(plang->laninline))
7317                 {
7318                         appendPQExpBuffer(defqry, " INLINE ");
7319                         /* Cope with possibility that inline is in different schema */
7320                         if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
7321                                 appendPQExpBuffer(defqry, "%s.",
7322                                                         fmtId(inlineInfo->dobj.namespace->dobj.name));
7323                         appendPQExpBuffer(defqry, "%s",
7324                                                           fmtId(inlineInfo->dobj.name));
7325                 }
7326                 if (OidIsValid(plang->lanvalidator))
7327                 {
7328                         appendPQExpBuffer(defqry, " VALIDATOR ");
7329                         /* Cope with possibility that validator is in different schema */
7330                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
7331                                 appendPQExpBuffer(defqry, "%s.",
7332                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
7333                         appendPQExpBuffer(defqry, "%s",
7334                                                           fmtId(validatorInfo->dobj.name));
7335                 }
7336         }
7337         appendPQExpBuffer(defqry, ";\n");
7338
7339         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
7340                                  plang->dobj.name,
7341                                  lanschema, NULL, plang->lanowner,
7342                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
7343                                  defqry->data, delqry->data, NULL,
7344                                  plang->dobj.dependencies, plang->dobj.nDeps,
7345                                  NULL, NULL);
7346
7347         /* Dump Proc Lang Comments */
7348         resetPQExpBuffer(defqry);
7349         appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
7350         dumpComment(fout, defqry->data,
7351                                 NULL, "",
7352                                 plang->dobj.catId, 0, plang->dobj.dumpId);
7353
7354         if (plang->lanpltrusted)
7355                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
7356                                 qlanname, NULL, plang->dobj.name,
7357                                 lanschema,
7358                                 plang->lanowner, plang->lanacl);
7359
7360         free(qlanname);
7361
7362         destroyPQExpBuffer(defqry);
7363         destroyPQExpBuffer(delqry);
7364 }
7365
7366 /*
7367  * format_function_arguments: generate function name and argument list
7368  *
7369  * This is used when we can rely on pg_get_function_arguments to format
7370  * the argument list.
7371  */
7372 static char *
7373 format_function_arguments(FuncInfo *finfo, char *funcargs)
7374 {
7375         PQExpBufferData fn;
7376
7377         initPQExpBuffer(&fn);
7378         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
7379         return fn.data;
7380 }
7381
7382 /*
7383  * format_function_arguments_old: generate function name and argument list
7384  *
7385  * The argument type names are qualified if needed.  The function name
7386  * is never qualified.
7387  *
7388  * This is used only with pre-8.4 servers, so we aren't expecting to see
7389  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
7390  *
7391  * Any or all of allargtypes, argmodes, argnames may be NULL.
7392  */
7393 static char *
7394 format_function_arguments_old(FuncInfo *finfo, int nallargs,
7395                                                           char **allargtypes,
7396                                                           char **argmodes,
7397                                                           char **argnames)
7398 {
7399         PQExpBufferData fn;
7400         int                     j;
7401
7402         initPQExpBuffer(&fn);
7403         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
7404         for (j = 0; j < nallargs; j++)
7405         {
7406                 Oid                     typid;
7407                 char       *typname;
7408                 const char *argmode;
7409                 const char *argname;
7410
7411                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
7412                 typname = getFormattedTypeName(typid, zeroAsOpaque);
7413
7414                 if (argmodes)
7415                 {
7416                         switch (argmodes[j][0])
7417                         {
7418                                 case PROARGMODE_IN:
7419                                         argmode = "";
7420                                         break;
7421                                 case PROARGMODE_OUT:
7422                                         argmode = "OUT ";
7423                                         break;
7424                                 case PROARGMODE_INOUT:
7425                                         argmode = "INOUT ";
7426                                         break;
7427                                 default:
7428                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
7429                                         argmode = "";
7430                                         break;
7431                         }
7432                 }
7433                 else
7434                         argmode = "";
7435
7436                 argname = argnames ? argnames[j] : (char *) NULL;
7437                 if (argname && argname[0] == '\0')
7438                         argname = NULL;
7439
7440                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
7441                                                   (j > 0) ? ", " : "",
7442                                                   argmode,
7443                                                   argname ? fmtId(argname) : "",
7444                                                   argname ? " " : "",
7445                                                   typname);
7446                 free(typname);
7447         }
7448         appendPQExpBuffer(&fn, ")");
7449         return fn.data;
7450 }
7451
7452 /*
7453  * format_function_signature: generate function name and argument list
7454  *
7455  * This is like format_function_arguments_old except that only a minimal
7456  * list of input argument types is generated; this is sufficient to
7457  * reference the function, but not to define it.
7458  *
7459  * If honor_quotes is false then the function name is never quoted.
7460  * This is appropriate for use in TOC tags, but not in SQL commands.
7461  */
7462 static char *
7463 format_function_signature(FuncInfo *finfo, bool honor_quotes)
7464 {
7465         PQExpBufferData fn;
7466         int                     j;
7467
7468         initPQExpBuffer(&fn);
7469         if (honor_quotes)
7470                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
7471         else
7472                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
7473         for (j = 0; j < finfo->nargs; j++)
7474         {
7475                 char       *typname;
7476
7477                 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7478
7479                 appendPQExpBuffer(&fn, "%s%s",
7480                                                   (j > 0) ? ", " : "",
7481                                                   typname);
7482                 free(typname);
7483         }
7484         appendPQExpBuffer(&fn, ")");
7485         return fn.data;
7486 }
7487
7488
7489 /*
7490  * dumpFunc:
7491  *        dump out one function
7492  */
7493 static void
7494 dumpFunc(Archive *fout, FuncInfo *finfo)
7495 {
7496         PQExpBuffer query;
7497         PQExpBuffer q;
7498         PQExpBuffer delqry;
7499         PQExpBuffer asPart;
7500         PGresult   *res;
7501         char       *funcsig;            /* identity signature */
7502         char       *funcfullsig;        /* full signature */
7503         char       *funcsig_tag;
7504         int                     ntups;
7505         char       *proretset;
7506         char       *prosrc;
7507         char       *probin;
7508         char       *funcargs;
7509         char       *funciargs;
7510         char       *funcresult;
7511         char       *proallargtypes;
7512         char       *proargmodes;
7513         char       *proargnames;
7514         char       *proiswindow;
7515         char       *provolatile;
7516         char       *proisstrict;
7517         char       *prosecdef;
7518         char       *proconfig;
7519         char       *procost;
7520         char       *prorows;
7521         char       *lanname;
7522         char       *rettypename;
7523         int                     nallargs;
7524         char      **allargtypes = NULL;
7525         char      **argmodes = NULL;
7526         char      **argnames = NULL;
7527         char      **configitems = NULL;
7528         int                     nconfigitems = 0;
7529         int                     i;
7530
7531         /* Skip if not to be dumped */
7532         if (!finfo->dobj.dump || dataOnly)
7533                 return;
7534
7535         query = createPQExpBuffer();
7536         q = createPQExpBuffer();
7537         delqry = createPQExpBuffer();
7538         asPart = createPQExpBuffer();
7539
7540         /* Set proper schema search path so type references list correctly */
7541         selectSourceSchema(finfo->dobj.namespace->dobj.name);
7542
7543         /* Fetch function-specific details */
7544         if (g_fout->remoteVersion >= 80400)
7545         {
7546                 /*
7547                  * In 8.4 and up we rely on pg_get_function_arguments and
7548                  * pg_get_function_result instead of examining proallargtypes etc.
7549                  */
7550                 appendPQExpBuffer(query,
7551                                                   "SELECT proretset, prosrc, probin, "
7552                                         "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7553                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7554                                          "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7555                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
7556                                                   "proconfig, procost, prorows, "
7557                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7558                                                   "FROM pg_catalog.pg_proc "
7559                                                   "WHERE oid = '%u'::pg_catalog.oid",
7560                                                   finfo->dobj.catId.oid);
7561         }
7562         else if (g_fout->remoteVersion >= 80300)
7563         {
7564                 appendPQExpBuffer(query,
7565                                                   "SELECT proretset, prosrc, probin, "
7566                                                   "proallargtypes, proargmodes, proargnames, "
7567                                                   "false AS proiswindow, "
7568                                                   "provolatile, proisstrict, prosecdef, "
7569                                                   "proconfig, procost, prorows, "
7570                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7571                                                   "FROM pg_catalog.pg_proc "
7572                                                   "WHERE oid = '%u'::pg_catalog.oid",
7573                                                   finfo->dobj.catId.oid);
7574         }
7575         else if (g_fout->remoteVersion >= 80100)
7576         {
7577                 appendPQExpBuffer(query,
7578                                                   "SELECT proretset, prosrc, probin, "
7579                                                   "proallargtypes, proargmodes, proargnames, "
7580                                                   "false AS proiswindow, "
7581                                                   "provolatile, proisstrict, prosecdef, "
7582                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7583                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7584                                                   "FROM pg_catalog.pg_proc "
7585                                                   "WHERE oid = '%u'::pg_catalog.oid",
7586                                                   finfo->dobj.catId.oid);
7587         }
7588         else if (g_fout->remoteVersion >= 80000)
7589         {
7590                 appendPQExpBuffer(query,
7591                                                   "SELECT proretset, prosrc, probin, "
7592                                                   "null AS proallargtypes, "
7593                                                   "null AS proargmodes, "
7594                                                   "proargnames, "
7595                                                   "false AS proiswindow, "
7596                                                   "provolatile, proisstrict, prosecdef, "
7597                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7598                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7599                                                   "FROM pg_catalog.pg_proc "
7600                                                   "WHERE oid = '%u'::pg_catalog.oid",
7601                                                   finfo->dobj.catId.oid);
7602         }
7603         else if (g_fout->remoteVersion >= 70300)
7604         {
7605                 appendPQExpBuffer(query,
7606                                                   "SELECT proretset, prosrc, probin, "
7607                                                   "null AS proallargtypes, "
7608                                                   "null AS proargmodes, "
7609                                                   "null AS proargnames, "
7610                                                   "false AS proiswindow, "
7611                                                   "provolatile, proisstrict, prosecdef, "
7612                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7613                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7614                                                   "FROM pg_catalog.pg_proc "
7615                                                   "WHERE oid = '%u'::pg_catalog.oid",
7616                                                   finfo->dobj.catId.oid);
7617         }
7618         else if (g_fout->remoteVersion >= 70100)
7619         {
7620                 appendPQExpBuffer(query,
7621                                                   "SELECT proretset, prosrc, probin, "
7622                                                   "null AS proallargtypes, "
7623                                                   "null AS proargmodes, "
7624                                                   "null AS proargnames, "
7625                                                   "false AS proiswindow, "
7626                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
7627                                                   "proisstrict, "
7628                                                   "false AS prosecdef, "
7629                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7630                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7631                                                   "FROM pg_proc "
7632                                                   "WHERE oid = '%u'::oid",
7633                                                   finfo->dobj.catId.oid);
7634         }
7635         else
7636         {
7637                 appendPQExpBuffer(query,
7638                                                   "SELECT proretset, prosrc, probin, "
7639                                                   "null AS proallargtypes, "
7640                                                   "null AS proargmodes, "
7641                                                   "null AS proargnames, "
7642                                                   "false AS proiswindow, "
7643                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7644                                                   "false AS proisstrict, "
7645                                                   "false AS prosecdef, "
7646                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7647                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7648                                                   "FROM pg_proc "
7649                                                   "WHERE oid = '%u'::oid",
7650                                                   finfo->dobj.catId.oid);
7651         }
7652
7653         res = PQexec(g_conn, query->data);
7654         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7655
7656         /* Expecting a single result only */
7657         ntups = PQntuples(res);
7658         if (ntups != 1)
7659         {
7660                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7661                                                            "query returned %d rows instead of one: %s\n",
7662                                                                  ntups),
7663                                   ntups, query->data);
7664                 exit_nicely();
7665         }
7666
7667         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
7668         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
7669         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
7670         if (g_fout->remoteVersion >= 80400)
7671         {
7672                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
7673                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
7674                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
7675                 proallargtypes = proargmodes = proargnames = NULL;
7676         }
7677         else
7678         {
7679                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
7680                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
7681                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
7682                 funcargs = funciargs = funcresult = NULL;
7683         }
7684         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
7685         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7686         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7687         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
7688         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
7689         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
7690         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
7691         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
7692
7693         /*
7694          * See backend/commands/functioncmds.c for details of how the 'AS' clause
7695          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
7696          * versions would set it to "-".  There are no known cases in which prosrc
7697          * is unused, so the tests below for "-" are probably useless.
7698          */
7699         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7700         {
7701                 appendPQExpBuffer(asPart, "AS ");
7702                 appendStringLiteralAH(asPart, probin, fout);
7703                 if (strcmp(prosrc, "-") != 0)
7704                 {
7705                         appendPQExpBuffer(asPart, ", ");
7706
7707                         /*
7708                          * where we have bin, use dollar quoting if allowed and src
7709                          * contains quote or backslash; else use regular quoting.
7710                          */
7711                         if (disable_dollar_quoting ||
7712                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7713                                 appendStringLiteralAH(asPart, prosrc, fout);
7714                         else
7715                                 appendStringLiteralDQ(asPart, prosrc, NULL);
7716                 }
7717         }
7718         else
7719         {
7720                 if (strcmp(prosrc, "-") != 0)
7721                 {
7722                         appendPQExpBuffer(asPart, "AS ");
7723                         /* with no bin, dollar quote src unconditionally if allowed */
7724                         if (disable_dollar_quoting)
7725                                 appendStringLiteralAH(asPart, prosrc, fout);
7726                         else
7727                                 appendStringLiteralDQ(asPart, prosrc, NULL);
7728                 }
7729         }
7730
7731         nallargs = finfo->nargs;        /* unless we learn different from allargs */
7732
7733         if (proallargtypes && *proallargtypes)
7734         {
7735                 int                     nitems = 0;
7736
7737                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7738                         nitems < finfo->nargs)
7739                 {
7740                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7741                         if (allargtypes)
7742                                 free(allargtypes);
7743                         allargtypes = NULL;
7744                 }
7745                 else
7746                         nallargs = nitems;
7747         }
7748
7749         if (proargmodes && *proargmodes)
7750         {
7751                 int                     nitems = 0;
7752
7753                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7754                         nitems != nallargs)
7755                 {
7756                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7757                         if (argmodes)
7758                                 free(argmodes);
7759                         argmodes = NULL;
7760                 }
7761         }
7762
7763         if (proargnames && *proargnames)
7764         {
7765                 int                     nitems = 0;
7766
7767                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7768                         nitems != nallargs)
7769                 {
7770                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
7771                         if (argnames)
7772                                 free(argnames);
7773                         argnames = NULL;
7774                 }
7775         }
7776
7777         if (proconfig && *proconfig)
7778         {
7779                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7780                 {
7781                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
7782                         if (configitems)
7783                                 free(configitems);
7784                         configitems = NULL;
7785                         nconfigitems = 0;
7786                 }
7787         }
7788
7789         if (funcargs)
7790         {
7791                 /* 8.4 or later; we rely on server-side code for most of the work */
7792                 funcfullsig = format_function_arguments(finfo, funcargs);
7793                 funcsig = format_function_arguments(finfo, funciargs);
7794         }
7795         else
7796         {
7797                 /* pre-8.4, do it ourselves */
7798                 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7799                                                                                                 argmodes, argnames);
7800                 funcfullsig = funcsig;
7801         }
7802
7803         funcsig_tag = format_function_signature(finfo, false);
7804
7805         /*
7806          * DROP must be fully qualified in case same name appears in pg_catalog
7807          */
7808         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7809                                           fmtId(finfo->dobj.namespace->dobj.name),
7810                                           funcsig);
7811
7812         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7813         if (funcresult)
7814                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7815         else
7816         {
7817                 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7818                 appendPQExpBuffer(q, "RETURNS %s%s",
7819                                                   (proretset[0] == 't') ? "SETOF " : "",
7820                                                   rettypename);
7821                 free(rettypename);
7822         }
7823
7824         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
7825
7826         if (proiswindow[0] == 't')
7827                 appendPQExpBuffer(q, " WINDOW");
7828
7829         if (provolatile[0] != PROVOLATILE_VOLATILE)
7830         {
7831                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7832                         appendPQExpBuffer(q, " IMMUTABLE");
7833                 else if (provolatile[0] == PROVOLATILE_STABLE)
7834                         appendPQExpBuffer(q, " STABLE");
7835                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7836                 {
7837                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7838                                           finfo->dobj.name);
7839                         exit_nicely();
7840                 }
7841         }
7842
7843         if (proisstrict[0] == 't')
7844                 appendPQExpBuffer(q, " STRICT");
7845
7846         if (prosecdef[0] == 't')
7847                 appendPQExpBuffer(q, " SECURITY DEFINER");
7848
7849         /*
7850          * COST and ROWS are emitted only if present and not default, so as not to
7851          * break backwards-compatibility of the dump without need.      Keep this code
7852          * in sync with the defaults in functioncmds.c.
7853          */
7854         if (strcmp(procost, "0") != 0)
7855         {
7856                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7857                 {
7858                         /* default cost is 1 */
7859                         if (strcmp(procost, "1") != 0)
7860                                 appendPQExpBuffer(q, " COST %s", procost);
7861                 }
7862                 else
7863                 {
7864                         /* default cost is 100 */
7865                         if (strcmp(procost, "100") != 0)
7866                                 appendPQExpBuffer(q, " COST %s", procost);
7867                 }
7868         }
7869         if (proretset[0] == 't' &&
7870                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7871                 appendPQExpBuffer(q, " ROWS %s", prorows);
7872
7873         for (i = 0; i < nconfigitems; i++)
7874         {
7875                 /* we feel free to scribble on configitems[] here */
7876                 char       *configitem = configitems[i];
7877                 char       *pos;
7878
7879                 pos = strchr(configitem, '=');
7880                 if (pos == NULL)
7881                         continue;
7882                 *pos++ = '\0';
7883                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
7884
7885                 /*
7886                  * Some GUC variable names are 'LIST' type and hence must not be
7887                  * quoted.
7888                  */
7889                 if (pg_strcasecmp(configitem, "DateStyle") == 0
7890                         || pg_strcasecmp(configitem, "search_path") == 0)
7891                         appendPQExpBuffer(q, "%s", pos);
7892                 else
7893                         appendStringLiteralAH(q, pos, fout);
7894         }
7895
7896         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
7897
7898         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7899                                  funcsig_tag,
7900                                  finfo->dobj.namespace->dobj.name,
7901                                  NULL,
7902                                  finfo->rolname, false,
7903                                  "FUNCTION", SECTION_PRE_DATA,
7904                                  q->data, delqry->data, NULL,
7905                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
7906                                  NULL, NULL);
7907
7908         /* Dump Function Comments */
7909         resetPQExpBuffer(q);
7910         appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7911         dumpComment(fout, q->data,
7912                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
7913                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7914
7915         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7916                         funcsig, NULL, funcsig_tag,
7917                         finfo->dobj.namespace->dobj.name,
7918                         finfo->rolname, finfo->proacl);
7919
7920         PQclear(res);
7921
7922         destroyPQExpBuffer(query);
7923         destroyPQExpBuffer(q);
7924         destroyPQExpBuffer(delqry);
7925         destroyPQExpBuffer(asPart);
7926         free(funcsig);
7927         free(funcsig_tag);
7928         if (allargtypes)
7929                 free(allargtypes);
7930         if (argmodes)
7931                 free(argmodes);
7932         if (argnames)
7933                 free(argnames);
7934         if (configitems)
7935                 free(configitems);
7936 }
7937
7938
7939 /*
7940  * Dump a user-defined cast
7941  */
7942 static void
7943 dumpCast(Archive *fout, CastInfo *cast)
7944 {
7945         PQExpBuffer defqry;
7946         PQExpBuffer delqry;
7947         PQExpBuffer castsig;
7948         FuncInfo   *funcInfo = NULL;
7949         TypeInfo   *sourceInfo;
7950         TypeInfo   *targetInfo;
7951
7952         if (dataOnly)
7953                 return;
7954
7955         if (OidIsValid(cast->castfunc))
7956         {
7957                 funcInfo = findFuncByOid(cast->castfunc);
7958                 if (funcInfo == NULL)
7959                         return;
7960         }
7961
7962         /*
7963          * As per discussion we dump casts if one or more of the underlying
7964          * objects (the conversion function and the two data types) are not
7965          * builtin AND if all of the non-builtin objects are included in the dump.
7966          * Builtin meaning, the namespace name does not start with "pg_".
7967          */
7968         sourceInfo = findTypeByOid(cast->castsource);
7969         targetInfo = findTypeByOid(cast->casttarget);
7970
7971         if (sourceInfo == NULL || targetInfo == NULL)
7972                 return;
7973
7974         /*
7975          * Skip this cast if all objects are from pg_
7976          */
7977         if ((funcInfo == NULL ||
7978                  strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7979                 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7980                 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7981                 return;
7982
7983         /*
7984          * Skip cast if function isn't from pg_ and is not to be dumped.
7985          */
7986         if (funcInfo &&
7987                 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7988                 !funcInfo->dobj.dump)
7989                 return;
7990
7991         /*
7992          * Same for the source type
7993          */
7994         if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7995                 !sourceInfo->dobj.dump)
7996                 return;
7997
7998         /*
7999          * and the target type.
8000          */
8001         if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
8002                 !targetInfo->dobj.dump)
8003                 return;
8004
8005         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
8006         selectSourceSchema("pg_catalog");
8007
8008         defqry = createPQExpBuffer();
8009         delqry = createPQExpBuffer();
8010         castsig = createPQExpBuffer();
8011
8012         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
8013                                           getFormattedTypeName(cast->castsource, zeroAsNone),
8014                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
8015
8016         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
8017                                           getFormattedTypeName(cast->castsource, zeroAsNone),
8018                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
8019
8020         switch (cast->castmethod)
8021         {
8022                 case COERCION_METHOD_BINARY:
8023                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
8024                         break;
8025                 case COERCION_METHOD_INOUT:
8026                         appendPQExpBuffer(defqry, "WITH INOUT");
8027                         break;
8028                 case COERCION_METHOD_FUNCTION:
8029
8030                         /*
8031                          * Always qualify the function name, in case it is not in
8032                          * pg_catalog schema (format_function_signature won't qualify it).
8033                          */
8034                         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
8035                                                           fmtId(funcInfo->dobj.namespace->dobj.name));
8036                         appendPQExpBuffer(defqry, "%s",
8037                                                           format_function_signature(funcInfo, true));
8038                         break;
8039                 default:
8040                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
8041         }
8042
8043         if (cast->castcontext == 'a')
8044                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
8045         else if (cast->castcontext == 'i')
8046                 appendPQExpBuffer(defqry, " AS IMPLICIT");
8047         appendPQExpBuffer(defqry, ";\n");
8048
8049         appendPQExpBuffer(castsig, "CAST (%s AS %s)",
8050                                           getFormattedTypeName(cast->castsource, zeroAsNone),
8051                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
8052
8053         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
8054                                  castsig->data,
8055                                  "pg_catalog", NULL, "",
8056                                  false, "CAST", SECTION_PRE_DATA,
8057                                  defqry->data, delqry->data, NULL,
8058                                  cast->dobj.dependencies, cast->dobj.nDeps,
8059                                  NULL, NULL);
8060
8061         /* Dump Cast Comments */
8062         resetPQExpBuffer(defqry);
8063         appendPQExpBuffer(defqry, "CAST (%s AS %s)",
8064                                           getFormattedTypeName(cast->castsource, zeroAsNone),
8065                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
8066         dumpComment(fout, defqry->data,
8067                                 NULL, "",
8068                                 cast->dobj.catId, 0, cast->dobj.dumpId);
8069
8070         destroyPQExpBuffer(defqry);
8071         destroyPQExpBuffer(delqry);
8072         destroyPQExpBuffer(castsig);
8073 }
8074
8075 /*
8076  * dumpOpr
8077  *        write out a single operator definition
8078  */
8079 static void
8080 dumpOpr(Archive *fout, OprInfo *oprinfo)
8081 {
8082         PQExpBuffer query;
8083         PQExpBuffer q;
8084         PQExpBuffer delq;
8085         PQExpBuffer oprid;
8086         PQExpBuffer details;
8087         const char *name;
8088         PGresult   *res;
8089         int                     ntups;
8090         int                     i_oprkind;
8091         int                     i_oprcode;
8092         int                     i_oprleft;
8093         int                     i_oprright;
8094         int                     i_oprcom;
8095         int                     i_oprnegate;
8096         int                     i_oprrest;
8097         int                     i_oprjoin;
8098         int                     i_oprcanmerge;
8099         int                     i_oprcanhash;
8100         char       *oprkind;
8101         char       *oprcode;
8102         char       *oprleft;
8103         char       *oprright;
8104         char       *oprcom;
8105         char       *oprnegate;
8106         char       *oprrest;
8107         char       *oprjoin;
8108         char       *oprcanmerge;
8109         char       *oprcanhash;
8110
8111         /* Skip if not to be dumped */
8112         if (!oprinfo->dobj.dump || dataOnly)
8113                 return;
8114
8115         /*
8116          * some operators are invalid because they were the result of user
8117          * defining operators before commutators exist
8118          */
8119         if (!OidIsValid(oprinfo->oprcode))
8120                 return;
8121
8122         query = createPQExpBuffer();
8123         q = createPQExpBuffer();
8124         delq = createPQExpBuffer();
8125         oprid = createPQExpBuffer();
8126         details = createPQExpBuffer();
8127
8128         /* Make sure we are in proper schema so regoperator works correctly */
8129         selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
8130
8131         if (g_fout->remoteVersion >= 80300)
8132         {
8133                 appendPQExpBuffer(query, "SELECT oprkind, "
8134                                                   "oprcode::pg_catalog.regprocedure, "
8135                                                   "oprleft::pg_catalog.regtype, "
8136                                                   "oprright::pg_catalog.regtype, "
8137                                                   "oprcom::pg_catalog.regoperator, "
8138                                                   "oprnegate::pg_catalog.regoperator, "
8139                                                   "oprrest::pg_catalog.regprocedure, "
8140                                                   "oprjoin::pg_catalog.regprocedure, "
8141                                                   "oprcanmerge, oprcanhash "
8142                                                   "FROM pg_catalog.pg_operator "
8143                                                   "WHERE oid = '%u'::pg_catalog.oid",
8144                                                   oprinfo->dobj.catId.oid);
8145         }
8146         else if (g_fout->remoteVersion >= 70300)
8147         {
8148                 appendPQExpBuffer(query, "SELECT oprkind, "
8149                                                   "oprcode::pg_catalog.regprocedure, "
8150                                                   "oprleft::pg_catalog.regtype, "
8151                                                   "oprright::pg_catalog.regtype, "
8152                                                   "oprcom::pg_catalog.regoperator, "
8153                                                   "oprnegate::pg_catalog.regoperator, "
8154                                                   "oprrest::pg_catalog.regprocedure, "
8155                                                   "oprjoin::pg_catalog.regprocedure, "
8156                                                   "(oprlsortop != 0) AS oprcanmerge, "
8157                                                   "oprcanhash "
8158                                                   "FROM pg_catalog.pg_operator "
8159                                                   "WHERE oid = '%u'::pg_catalog.oid",
8160                                                   oprinfo->dobj.catId.oid);
8161         }
8162         else if (g_fout->remoteVersion >= 70100)
8163         {
8164                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
8165                                                   "CASE WHEN oprleft = 0 THEN '-' "
8166                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
8167                                                   "CASE WHEN oprright = 0 THEN '-' "
8168                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
8169                                                   "oprcom, oprnegate, oprrest, oprjoin, "
8170                                                   "(oprlsortop != 0) AS oprcanmerge, "
8171                                                   "oprcanhash "
8172                                                   "FROM pg_operator "
8173                                                   "WHERE oid = '%u'::oid",
8174                                                   oprinfo->dobj.catId.oid);
8175         }
8176         else
8177         {
8178                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
8179                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
8180                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
8181                                                   "CASE WHEN oprright = 0 THEN '-'::name "
8182                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
8183                                                   "oprcom, oprnegate, oprrest, oprjoin, "
8184                                                   "(oprlsortop != 0) AS oprcanmerge, "
8185                                                   "oprcanhash "
8186                                                   "FROM pg_operator "
8187                                                   "WHERE oid = '%u'::oid",
8188                                                   oprinfo->dobj.catId.oid);
8189         }
8190
8191         res = PQexec(g_conn, query->data);
8192         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8193
8194         /* Expecting a single result only */
8195         ntups = PQntuples(res);
8196         if (ntups != 1)
8197         {
8198                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8199                                                            "query returned %d rows instead of one: %s\n",
8200                                                                  ntups),
8201                                   ntups, query->data);
8202                 exit_nicely();
8203         }
8204
8205         i_oprkind = PQfnumber(res, "oprkind");
8206         i_oprcode = PQfnumber(res, "oprcode");
8207         i_oprleft = PQfnumber(res, "oprleft");
8208         i_oprright = PQfnumber(res, "oprright");
8209         i_oprcom = PQfnumber(res, "oprcom");
8210         i_oprnegate = PQfnumber(res, "oprnegate");
8211         i_oprrest = PQfnumber(res, "oprrest");
8212         i_oprjoin = PQfnumber(res, "oprjoin");
8213         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
8214         i_oprcanhash = PQfnumber(res, "oprcanhash");
8215
8216         oprkind = PQgetvalue(res, 0, i_oprkind);
8217         oprcode = PQgetvalue(res, 0, i_oprcode);
8218         oprleft = PQgetvalue(res, 0, i_oprleft);
8219         oprright = PQgetvalue(res, 0, i_oprright);
8220         oprcom = PQgetvalue(res, 0, i_oprcom);
8221         oprnegate = PQgetvalue(res, 0, i_oprnegate);
8222         oprrest = PQgetvalue(res, 0, i_oprrest);
8223         oprjoin = PQgetvalue(res, 0, i_oprjoin);
8224         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
8225         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
8226
8227         appendPQExpBuffer(details, "    PROCEDURE = %s",
8228                                           convertRegProcReference(oprcode));
8229
8230         appendPQExpBuffer(oprid, "%s (",
8231                                           oprinfo->dobj.name);
8232
8233         /*
8234          * right unary means there's a left arg and left unary means there's a
8235          * right arg
8236          */
8237         if (strcmp(oprkind, "r") == 0 ||
8238                 strcmp(oprkind, "b") == 0)
8239         {
8240                 if (g_fout->remoteVersion >= 70100)
8241                         name = oprleft;
8242                 else
8243                         name = fmtId(oprleft);
8244                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
8245                 appendPQExpBuffer(oprid, "%s", name);
8246         }
8247         else
8248                 appendPQExpBuffer(oprid, "NONE");
8249
8250         if (strcmp(oprkind, "l") == 0 ||
8251                 strcmp(oprkind, "b") == 0)
8252         {
8253                 if (g_fout->remoteVersion >= 70100)
8254                         name = oprright;
8255                 else
8256                         name = fmtId(oprright);
8257                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
8258                 appendPQExpBuffer(oprid, ", %s)", name);
8259         }
8260         else
8261                 appendPQExpBuffer(oprid, ", NONE)");
8262
8263         name = convertOperatorReference(oprcom);
8264         if (name)
8265                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
8266
8267         name = convertOperatorReference(oprnegate);
8268         if (name)
8269                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
8270
8271         if (strcmp(oprcanmerge, "t") == 0)
8272                 appendPQExpBuffer(details, ",\n    MERGES");
8273
8274         if (strcmp(oprcanhash, "t") == 0)
8275                 appendPQExpBuffer(details, ",\n    HASHES");
8276
8277         name = convertRegProcReference(oprrest);
8278         if (name)
8279                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
8280
8281         name = convertRegProcReference(oprjoin);
8282         if (name)
8283                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
8284
8285         /*
8286          * DROP must be fully qualified in case same name appears in pg_catalog
8287          */
8288         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
8289                                           fmtId(oprinfo->dobj.namespace->dobj.name),
8290                                           oprid->data);
8291
8292         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
8293                                           oprinfo->dobj.name, details->data);
8294
8295         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
8296                                  oprinfo->dobj.name,
8297                                  oprinfo->dobj.namespace->dobj.name,
8298                                  NULL,
8299                                  oprinfo->rolname,
8300                                  false, "OPERATOR", SECTION_PRE_DATA,
8301                                  q->data, delq->data, NULL,
8302                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
8303                                  NULL, NULL);
8304
8305         /* Dump Operator Comments */
8306         resetPQExpBuffer(q);
8307         appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
8308         dumpComment(fout, q->data,
8309                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
8310                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
8311
8312         PQclear(res);
8313
8314         destroyPQExpBuffer(query);
8315         destroyPQExpBuffer(q);
8316         destroyPQExpBuffer(delq);
8317         destroyPQExpBuffer(oprid);
8318         destroyPQExpBuffer(details);
8319 }
8320
8321 /*
8322  * Convert a function reference obtained from pg_operator
8323  *
8324  * Returns what to print, or NULL if function references is InvalidOid
8325  *
8326  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
8327  * argument-types part.  In prior versions, the input is a REGPROC display.
8328  */
8329 static const char *
8330 convertRegProcReference(const char *proc)
8331 {
8332         /* In all cases "-" means a null reference */
8333         if (strcmp(proc, "-") == 0)
8334                 return NULL;
8335
8336         if (g_fout->remoteVersion >= 70300)
8337         {
8338                 char       *name;
8339                 char       *paren;
8340                 bool            inquote;
8341
8342                 name = strdup(proc);
8343                 /* find non-double-quoted left paren */
8344                 inquote = false;
8345                 for (paren = name; *paren; paren++)
8346                 {
8347                         if (*paren == '(' && !inquote)
8348                         {
8349                                 *paren = '\0';
8350                                 break;
8351                         }
8352                         if (*paren == '"')
8353                                 inquote = !inquote;
8354                 }
8355                 return name;
8356         }
8357
8358         /* REGPROC before 7.3 does not quote its result */
8359         return fmtId(proc);
8360 }
8361
8362 /*
8363  * Convert an operator cross-reference obtained from pg_operator
8364  *
8365  * Returns what to print, or NULL to print nothing
8366  *
8367  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
8368  * argument-types part, and add OPERATOR() decoration if the name is
8369  * schema-qualified.  In older versions, the input is just a numeric OID,
8370  * which we search our operator list for.
8371  */
8372 static const char *
8373 convertOperatorReference(const char *opr)
8374 {
8375         OprInfo    *oprInfo;
8376
8377         /* In all cases "0" means a null reference */
8378         if (strcmp(opr, "0") == 0)
8379                 return NULL;
8380
8381         if (g_fout->remoteVersion >= 70300)
8382         {
8383                 char       *name;
8384                 char       *oname;
8385                 char       *ptr;
8386                 bool            inquote;
8387                 bool            sawdot;
8388
8389                 name = strdup(opr);
8390                 /* find non-double-quoted left paren, and check for non-quoted dot */
8391                 inquote = false;
8392                 sawdot = false;
8393                 for (ptr = name; *ptr; ptr++)
8394                 {
8395                         if (*ptr == '"')
8396                                 inquote = !inquote;
8397                         else if (*ptr == '.' && !inquote)
8398                                 sawdot = true;
8399                         else if (*ptr == '(' && !inquote)
8400                         {
8401                                 *ptr = '\0';
8402                                 break;
8403                         }
8404                 }
8405                 /* If not schema-qualified, don't need to add OPERATOR() */
8406                 if (!sawdot)
8407                         return name;
8408                 oname = malloc(strlen(name) + 11);
8409                 sprintf(oname, "OPERATOR(%s)", name);
8410                 free(name);
8411                 return oname;
8412         }
8413
8414         oprInfo = findOprByOid(atooid(opr));
8415         if (oprInfo == NULL)
8416         {
8417                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
8418                                   opr);
8419                 return NULL;
8420         }
8421         return oprInfo->dobj.name;
8422 }
8423
8424 /*
8425  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
8426  *
8427  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
8428  * argument lists of these functions are predetermined.  Note that the
8429  * caller should ensure we are in the proper schema, because the results
8430  * are search path dependent!
8431  */
8432 static const char *
8433 convertTSFunction(Oid funcOid)
8434 {
8435         char       *result;
8436         char            query[128];
8437         PGresult   *res;
8438         int                     ntups;
8439
8440         snprintf(query, sizeof(query),
8441                          "SELECT '%u'::pg_catalog.regproc", funcOid);
8442         res = PQexec(g_conn, query);
8443         check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
8444
8445         ntups = PQntuples(res);
8446         if (ntups != 1)
8447         {
8448                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8449                                                            "query returned %d rows instead of one: %s\n",
8450                                                                  ntups),
8451                                   ntups, query);
8452                 exit_nicely();
8453         }
8454
8455         result = strdup(PQgetvalue(res, 0, 0));
8456
8457         PQclear(res);
8458
8459         return result;
8460 }
8461
8462
8463 /*
8464  * dumpOpclass
8465  *        write out a single operator class definition
8466  */
8467 static void
8468 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
8469 {
8470         PQExpBuffer query;
8471         PQExpBuffer q;
8472         PQExpBuffer delq;
8473         PGresult   *res;
8474         int                     ntups;
8475         int                     i_opcintype;
8476         int                     i_opckeytype;
8477         int                     i_opcdefault;
8478         int                     i_opcfamily;
8479         int                     i_opcfamilynsp;
8480         int                     i_amname;
8481         int                     i_amopstrategy;
8482         int                     i_amopreqcheck;
8483         int                     i_amopopr;
8484         int                     i_amprocnum;
8485         int                     i_amproc;
8486         char       *opcintype;
8487         char       *opckeytype;
8488         char       *opcdefault;
8489         char       *opcfamily;
8490         char       *opcfamilynsp;
8491         char       *amname;
8492         char       *amopstrategy;
8493         char       *amopreqcheck;
8494         char       *amopopr;
8495         char       *amprocnum;
8496         char       *amproc;
8497         bool            needComma;
8498         int                     i;
8499
8500         /* Skip if not to be dumped */
8501         if (!opcinfo->dobj.dump || dataOnly)
8502                 return;
8503
8504         /*
8505          * XXX currently we do not implement dumping of operator classes from
8506          * pre-7.3 databases.  This could be done but it seems not worth the
8507          * trouble.
8508          */
8509         if (g_fout->remoteVersion < 70300)
8510                 return;
8511
8512         query = createPQExpBuffer();
8513         q = createPQExpBuffer();
8514         delq = createPQExpBuffer();
8515
8516         /* Make sure we are in proper schema so regoperator works correctly */
8517         selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8518
8519         /* Get additional fields from the pg_opclass row */
8520         if (g_fout->remoteVersion >= 80300)
8521         {
8522                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8523                                                   "opckeytype::pg_catalog.regtype, "
8524                                                   "opcdefault, "
8525                                                   "opfname AS opcfamily, "
8526                                                   "nspname AS opcfamilynsp, "
8527                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8528                                                   "FROM pg_catalog.pg_opclass c "
8529                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8530                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8531                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
8532                                                   opcinfo->dobj.catId.oid);
8533         }
8534         else
8535         {
8536                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8537                                                   "opckeytype::pg_catalog.regtype, "
8538                                                   "opcdefault, "
8539                                                   "NULL AS opcfamily, "
8540                                                   "NULL AS opcfamilynsp, "
8541                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8542                                                   "FROM pg_catalog.pg_opclass "
8543                                                   "WHERE oid = '%u'::pg_catalog.oid",
8544                                                   opcinfo->dobj.catId.oid);
8545         }
8546
8547         res = PQexec(g_conn, query->data);
8548         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8549
8550         /* Expecting a single result only */
8551         ntups = PQntuples(res);
8552         if (ntups != 1)
8553         {
8554                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8555                                                            "query returned %d rows instead of one: %s\n",
8556                                                                  ntups),
8557                                   ntups, query->data);
8558                 exit_nicely();
8559         }
8560
8561         i_opcintype = PQfnumber(res, "opcintype");
8562         i_opckeytype = PQfnumber(res, "opckeytype");
8563         i_opcdefault = PQfnumber(res, "opcdefault");
8564         i_opcfamily = PQfnumber(res, "opcfamily");
8565         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8566         i_amname = PQfnumber(res, "amname");
8567
8568         opcintype = PQgetvalue(res, 0, i_opcintype);
8569         opckeytype = PQgetvalue(res, 0, i_opckeytype);
8570         opcdefault = PQgetvalue(res, 0, i_opcdefault);
8571         opcfamily = PQgetvalue(res, 0, i_opcfamily);
8572         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
8573         /* amname will still be needed after we PQclear res */
8574         amname = strdup(PQgetvalue(res, 0, i_amname));
8575
8576         /*
8577          * DROP must be fully qualified in case same name appears in pg_catalog
8578          */
8579         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
8580                                           fmtId(opcinfo->dobj.namespace->dobj.name));
8581         appendPQExpBuffer(delq, ".%s",
8582                                           fmtId(opcinfo->dobj.name));
8583         appendPQExpBuffer(delq, " USING %s;\n",
8584                                           fmtId(amname));
8585
8586         /* Build the fixed portion of the CREATE command */
8587         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
8588                                           fmtId(opcinfo->dobj.name));
8589         if (strcmp(opcdefault, "t") == 0)
8590                 appendPQExpBuffer(q, "DEFAULT ");
8591         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
8592                                           opcintype,
8593                                           fmtId(amname));
8594         if (strlen(opcfamily) > 0 &&
8595                 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8596                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
8597         {
8598                 appendPQExpBuffer(q, " FAMILY ");
8599                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
8600                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
8601                 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
8602         }
8603         appendPQExpBuffer(q, " AS\n    ");
8604
8605         needComma = false;
8606
8607         if (strcmp(opckeytype, "-") != 0)
8608         {
8609                 appendPQExpBuffer(q, "STORAGE %s",
8610                                                   opckeytype);
8611                 needComma = true;
8612         }
8613
8614         PQclear(res);
8615
8616         /*
8617          * Now fetch and print the OPERATOR entries (pg_amop rows).
8618          */
8619         resetPQExpBuffer(query);
8620
8621         if (g_fout->remoteVersion >= 80400)
8622         {
8623                 /*
8624                  * Print only those opfamily members that are tied to the opclass by
8625                  * pg_depend entries.
8626                  *
8627                  * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8628                  * an older server's opclass in which it is used.  This is to avoid
8629                  * hard-to-detect breakage if a newer pg_dump is used to dump from an
8630                  * older server and then reload into that old version.  This can go
8631                  * away once 8.3 is so old as to not be of interest to anyone.
8632                  */
8633                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8634                                                   "amopopr::pg_catalog.regoperator "
8635                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8636                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8637                                                   "AND refobjid = '%u'::pg_catalog.oid "
8638                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8639                                                   "AND objid = ao.oid "
8640                                                   "ORDER BY amopstrategy",
8641                                                   opcinfo->dobj.catId.oid);
8642         }
8643         else if (g_fout->remoteVersion >= 80300)
8644         {
8645                 /*
8646                  * Print only those opfamily members that are tied to the opclass by
8647                  * pg_depend entries.
8648                  */
8649                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8650                                                   "amopopr::pg_catalog.regoperator "
8651                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8652                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8653                                                   "AND refobjid = '%u'::pg_catalog.oid "
8654                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8655                                                   "AND objid = ao.oid "
8656                                                   "ORDER BY amopstrategy",
8657                                                   opcinfo->dobj.catId.oid);
8658         }
8659         else
8660         {
8661                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8662                                                   "amopopr::pg_catalog.regoperator "
8663                                                   "FROM pg_catalog.pg_amop "
8664                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
8665                                                   "ORDER BY amopstrategy",
8666                                                   opcinfo->dobj.catId.oid);
8667         }
8668
8669         res = PQexec(g_conn, query->data);
8670         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8671
8672         ntups = PQntuples(res);
8673
8674         i_amopstrategy = PQfnumber(res, "amopstrategy");
8675         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8676         i_amopopr = PQfnumber(res, "amopopr");
8677
8678         for (i = 0; i < ntups; i++)
8679         {
8680                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8681                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8682                 amopopr = PQgetvalue(res, i, i_amopopr);
8683
8684                 if (needComma)
8685                         appendPQExpBuffer(q, " ,\n    ");
8686
8687                 appendPQExpBuffer(q, "OPERATOR %s %s",
8688                                                   amopstrategy, amopopr);
8689                 if (strcmp(amopreqcheck, "t") == 0)
8690                         appendPQExpBuffer(q, " RECHECK");
8691
8692                 needComma = true;
8693         }
8694
8695         PQclear(res);
8696
8697         /*
8698          * Now fetch and print the FUNCTION entries (pg_amproc rows).
8699          */
8700         resetPQExpBuffer(query);
8701
8702         if (g_fout->remoteVersion >= 80300)
8703         {
8704                 /*
8705                  * Print only those opfamily members that are tied to the opclass by
8706                  * pg_depend entries.
8707                  */
8708                 appendPQExpBuffer(query, "SELECT amprocnum, "
8709                                                   "amproc::pg_catalog.regprocedure "
8710                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8711                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8712                                                   "AND refobjid = '%u'::pg_catalog.oid "
8713                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8714                                                   "AND objid = ap.oid "
8715                                                   "ORDER BY amprocnum",
8716                                                   opcinfo->dobj.catId.oid);
8717         }
8718         else
8719         {
8720                 appendPQExpBuffer(query, "SELECT amprocnum, "
8721                                                   "amproc::pg_catalog.regprocedure "
8722                                                   "FROM pg_catalog.pg_amproc "
8723                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
8724                                                   "ORDER BY amprocnum",
8725                                                   opcinfo->dobj.catId.oid);
8726         }
8727
8728         res = PQexec(g_conn, query->data);
8729         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8730
8731         ntups = PQntuples(res);
8732
8733         i_amprocnum = PQfnumber(res, "amprocnum");
8734         i_amproc = PQfnumber(res, "amproc");
8735
8736         for (i = 0; i < ntups; i++)
8737         {
8738                 amprocnum = PQgetvalue(res, i, i_amprocnum);
8739                 amproc = PQgetvalue(res, i, i_amproc);
8740
8741                 if (needComma)
8742                         appendPQExpBuffer(q, " ,\n    ");
8743
8744                 appendPQExpBuffer(q, "FUNCTION %s %s",
8745                                                   amprocnum, amproc);
8746
8747                 needComma = true;
8748         }
8749
8750         PQclear(res);
8751
8752         appendPQExpBuffer(q, ";\n");
8753
8754         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8755                                  opcinfo->dobj.name,
8756                                  opcinfo->dobj.namespace->dobj.name,
8757                                  NULL,
8758                                  opcinfo->rolname,
8759                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
8760                                  q->data, delq->data, NULL,
8761                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8762                                  NULL, NULL);
8763
8764         /* Dump Operator Class Comments */
8765         resetPQExpBuffer(q);
8766         appendPQExpBuffer(q, "OPERATOR CLASS %s",
8767                                           fmtId(opcinfo->dobj.name));
8768         appendPQExpBuffer(q, " USING %s",
8769                                           fmtId(amname));
8770         dumpComment(fout, q->data,
8771                                 NULL, opcinfo->rolname,
8772                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8773
8774         free(amname);
8775         destroyPQExpBuffer(query);
8776         destroyPQExpBuffer(q);
8777         destroyPQExpBuffer(delq);
8778 }
8779
8780 /*
8781  * dumpOpfamily
8782  *        write out a single operator family definition
8783  */
8784 static void
8785 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8786 {
8787         PQExpBuffer query;
8788         PQExpBuffer q;
8789         PQExpBuffer delq;
8790         PGresult   *res;
8791         PGresult   *res_ops;
8792         PGresult   *res_procs;
8793         int                     ntups;
8794         int                     i_amname;
8795         int                     i_amopstrategy;
8796         int                     i_amopreqcheck;
8797         int                     i_amopopr;
8798         int                     i_amprocnum;
8799         int                     i_amproc;
8800         int                     i_amproclefttype;
8801         int                     i_amprocrighttype;
8802         char       *amname;
8803         char       *amopstrategy;
8804         char       *amopreqcheck;
8805         char       *amopopr;
8806         char       *amprocnum;
8807         char       *amproc;
8808         char       *amproclefttype;
8809         char       *amprocrighttype;
8810         bool            needComma;
8811         int                     i;
8812
8813         /* Skip if not to be dumped */
8814         if (!opfinfo->dobj.dump || dataOnly)
8815                 return;
8816
8817         /*
8818          * We want to dump the opfamily only if (1) it contains "loose" operators
8819          * or functions, or (2) it contains an opclass with a different name or
8820          * owner.  Otherwise it's sufficient to let it be created during creation
8821          * of the contained opclass, and not dumping it improves portability of
8822          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
8823          * that first.
8824          */
8825
8826         query = createPQExpBuffer();
8827         q = createPQExpBuffer();
8828         delq = createPQExpBuffer();
8829
8830         /* Make sure we are in proper schema so regoperator works correctly */
8831         selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8832
8833         /*
8834          * Fetch only those opfamily members that are tied directly to the
8835          * opfamily by pg_depend entries.
8836          */
8837         if (g_fout->remoteVersion >= 80400)
8838         {
8839                 /*
8840                  * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8841                  * an older server's opclass in which it is used.  This is to avoid
8842                  * hard-to-detect breakage if a newer pg_dump is used to dump from an
8843                  * older server and then reload into that old version.  This can go
8844                  * away once 8.3 is so old as to not be of interest to anyone.
8845                  */
8846                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8847                                                   "amopopr::pg_catalog.regoperator "
8848                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8849                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8850                                                   "AND refobjid = '%u'::pg_catalog.oid "
8851                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8852                                                   "AND objid = ao.oid "
8853                                                   "ORDER BY amopstrategy",
8854                                                   opfinfo->dobj.catId.oid);
8855         }
8856         else
8857         {
8858                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8859                                                   "amopopr::pg_catalog.regoperator "
8860                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8861                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8862                                                   "AND refobjid = '%u'::pg_catalog.oid "
8863                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8864                                                   "AND objid = ao.oid "
8865                                                   "ORDER BY amopstrategy",
8866                                                   opfinfo->dobj.catId.oid);
8867         }
8868
8869         res_ops = PQexec(g_conn, query->data);
8870         check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8871
8872         resetPQExpBuffer(query);
8873
8874         appendPQExpBuffer(query, "SELECT amprocnum, "
8875                                           "amproc::pg_catalog.regprocedure, "
8876                                           "amproclefttype::pg_catalog.regtype, "
8877                                           "amprocrighttype::pg_catalog.regtype "
8878                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8879                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8880                                           "AND refobjid = '%u'::pg_catalog.oid "
8881                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8882                                           "AND objid = ap.oid "
8883                                           "ORDER BY amprocnum",
8884                                           opfinfo->dobj.catId.oid);
8885
8886         res_procs = PQexec(g_conn, query->data);
8887         check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8888
8889         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8890         {
8891                 /* No loose members, so check contained opclasses */
8892                 resetPQExpBuffer(query);
8893
8894                 appendPQExpBuffer(query, "SELECT 1 "
8895                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8896                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
8897                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8898                                                   "AND refobjid = f.oid "
8899                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8900                                                   "AND objid = c.oid "
8901                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8902                                                   "LIMIT 1",
8903                                                   opfinfo->dobj.catId.oid);
8904
8905                 res = PQexec(g_conn, query->data);
8906                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8907
8908                 if (PQntuples(res) == 0)
8909                 {
8910                         /* no need to dump it, so bail out */
8911                         PQclear(res);
8912                         PQclear(res_ops);
8913                         PQclear(res_procs);
8914                         destroyPQExpBuffer(query);
8915                         destroyPQExpBuffer(q);
8916                         destroyPQExpBuffer(delq);
8917                         return;
8918                 }
8919
8920                 PQclear(res);
8921         }
8922
8923         /* Get additional fields from the pg_opfamily row */
8924         resetPQExpBuffer(query);
8925
8926         appendPQExpBuffer(query, "SELECT "
8927          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8928                                           "FROM pg_catalog.pg_opfamily "
8929                                           "WHERE oid = '%u'::pg_catalog.oid",
8930                                           opfinfo->dobj.catId.oid);
8931
8932         res = PQexec(g_conn, query->data);
8933         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8934
8935         /* Expecting a single result only */
8936         ntups = PQntuples(res);
8937         if (ntups != 1)
8938         {
8939                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8940                                                            "query returned %d rows instead of one: %s\n",
8941                                                                  ntups),
8942                                   ntups, query->data);
8943                 exit_nicely();
8944         }
8945
8946         i_amname = PQfnumber(res, "amname");
8947
8948         /* amname will still be needed after we PQclear res */
8949         amname = strdup(PQgetvalue(res, 0, i_amname));
8950
8951         /*
8952          * DROP must be fully qualified in case same name appears in pg_catalog
8953          */
8954         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8955                                           fmtId(opfinfo->dobj.namespace->dobj.name));
8956         appendPQExpBuffer(delq, ".%s",
8957                                           fmtId(opfinfo->dobj.name));
8958         appendPQExpBuffer(delq, " USING %s;\n",
8959                                           fmtId(amname));
8960
8961         /* Build the fixed portion of the CREATE command */
8962         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8963                                           fmtId(opfinfo->dobj.name));
8964         appendPQExpBuffer(q, " USING %s;\n",
8965                                           fmtId(amname));
8966
8967         PQclear(res);
8968
8969         /* Do we need an ALTER to add loose members? */
8970         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8971         {
8972                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8973                                                   fmtId(opfinfo->dobj.name));
8974                 appendPQExpBuffer(q, " USING %s ADD\n    ",
8975                                                   fmtId(amname));
8976
8977                 needComma = false;
8978
8979                 /*
8980                  * Now fetch and print the OPERATOR entries (pg_amop rows).
8981                  */
8982                 ntups = PQntuples(res_ops);
8983
8984                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8985                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8986                 i_amopopr = PQfnumber(res_ops, "amopopr");
8987
8988                 for (i = 0; i < ntups; i++)
8989                 {
8990                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8991                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8992                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
8993
8994                         if (needComma)
8995                                 appendPQExpBuffer(q, " ,\n    ");
8996
8997                         appendPQExpBuffer(q, "OPERATOR %s %s",
8998                                                           amopstrategy, amopopr);
8999                         if (strcmp(amopreqcheck, "t") == 0)
9000                                 appendPQExpBuffer(q, " RECHECK");
9001
9002                         needComma = true;
9003                 }
9004
9005                 /*
9006                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
9007                  */
9008                 ntups = PQntuples(res_procs);
9009
9010                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
9011                 i_amproc = PQfnumber(res_procs, "amproc");
9012                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
9013                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
9014
9015                 for (i = 0; i < ntups; i++)
9016                 {
9017                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
9018                         amproc = PQgetvalue(res_procs, i, i_amproc);
9019                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
9020                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
9021
9022                         if (needComma)
9023                                 appendPQExpBuffer(q, " ,\n    ");
9024
9025                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
9026                                                           amprocnum, amproclefttype, amprocrighttype,
9027                                                           amproc);
9028
9029                         needComma = true;
9030                 }
9031
9032                 appendPQExpBuffer(q, ";\n");
9033         }
9034
9035         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
9036                                  opfinfo->dobj.name,
9037                                  opfinfo->dobj.namespace->dobj.name,
9038                                  NULL,
9039                                  opfinfo->rolname,
9040                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
9041                                  q->data, delq->data, NULL,
9042                                  opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
9043                                  NULL, NULL);
9044
9045         /* Dump Operator Family Comments */
9046         resetPQExpBuffer(q);
9047         appendPQExpBuffer(q, "OPERATOR FAMILY %s",
9048                                           fmtId(opfinfo->dobj.name));
9049         appendPQExpBuffer(q, " USING %s",
9050                                           fmtId(amname));
9051         dumpComment(fout, q->data,
9052                                 NULL, opfinfo->rolname,
9053                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
9054
9055         free(amname);
9056         PQclear(res_ops);
9057         PQclear(res_procs);
9058         destroyPQExpBuffer(query);
9059         destroyPQExpBuffer(q);
9060         destroyPQExpBuffer(delq);
9061 }
9062
9063 /*
9064  * dumpConversion
9065  *        write out a single conversion definition
9066  */
9067 static void
9068 dumpConversion(Archive *fout, ConvInfo *convinfo)
9069 {
9070         PQExpBuffer query;
9071         PQExpBuffer q;
9072         PQExpBuffer delq;
9073         PQExpBuffer details;
9074         PGresult   *res;
9075         int                     ntups;
9076         int                     i_conname;
9077         int                     i_conforencoding;
9078         int                     i_contoencoding;
9079         int                     i_conproc;
9080         int                     i_condefault;
9081         const char *conname;
9082         const char *conforencoding;
9083         const char *contoencoding;
9084         const char *conproc;
9085         bool            condefault;
9086
9087         /* Skip if not to be dumped */
9088         if (!convinfo->dobj.dump || dataOnly)
9089                 return;
9090
9091         query = createPQExpBuffer();
9092         q = createPQExpBuffer();
9093         delq = createPQExpBuffer();
9094         details = createPQExpBuffer();
9095
9096         /* Make sure we are in proper schema */
9097         selectSourceSchema(convinfo->dobj.namespace->dobj.name);
9098
9099         /* Get conversion-specific details */
9100         appendPQExpBuffer(query, "SELECT conname, "
9101                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
9102                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
9103                                           "conproc, condefault "
9104                                           "FROM pg_catalog.pg_conversion c "
9105                                           "WHERE c.oid = '%u'::pg_catalog.oid",
9106                                           convinfo->dobj.catId.oid);
9107
9108         res = PQexec(g_conn, query->data);
9109         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9110
9111         /* Expecting a single result only */
9112         ntups = PQntuples(res);
9113         if (ntups != 1)
9114         {
9115                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9116                                                            "query returned %d rows instead of one: %s\n",
9117                                                                  ntups),
9118                                   ntups, query->data);
9119                 exit_nicely();
9120         }
9121
9122         i_conname = PQfnumber(res, "conname");
9123         i_conforencoding = PQfnumber(res, "conforencoding");
9124         i_contoencoding = PQfnumber(res, "contoencoding");
9125         i_conproc = PQfnumber(res, "conproc");
9126         i_condefault = PQfnumber(res, "condefault");
9127
9128         conname = PQgetvalue(res, 0, i_conname);
9129         conforencoding = PQgetvalue(res, 0, i_conforencoding);
9130         contoencoding = PQgetvalue(res, 0, i_contoencoding);
9131         conproc = PQgetvalue(res, 0, i_conproc);
9132         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
9133
9134         /*
9135          * DROP must be fully qualified in case same name appears in pg_catalog
9136          */
9137         appendPQExpBuffer(delq, "DROP CONVERSION %s",
9138                                           fmtId(convinfo->dobj.namespace->dobj.name));
9139         appendPQExpBuffer(delq, ".%s;\n",
9140                                           fmtId(convinfo->dobj.name));
9141
9142         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
9143                                           (condefault) ? "DEFAULT " : "",
9144                                           fmtId(convinfo->dobj.name));
9145         appendStringLiteralAH(q, conforencoding, fout);
9146         appendPQExpBuffer(q, " TO ");
9147         appendStringLiteralAH(q, contoencoding, fout);
9148         /* regproc is automatically quoted in 7.3 and above */
9149         appendPQExpBuffer(q, " FROM %s;\n", conproc);
9150
9151         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
9152                                  convinfo->dobj.name,
9153                                  convinfo->dobj.namespace->dobj.name,
9154                                  NULL,
9155                                  convinfo->rolname,
9156                                  false, "CONVERSION", SECTION_PRE_DATA,
9157                                  q->data, delq->data, NULL,
9158                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
9159                                  NULL, NULL);
9160
9161         /* Dump Conversion Comments */
9162         resetPQExpBuffer(q);
9163         appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
9164         dumpComment(fout, q->data,
9165                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
9166                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
9167
9168         PQclear(res);
9169
9170         destroyPQExpBuffer(query);
9171         destroyPQExpBuffer(q);
9172         destroyPQExpBuffer(delq);
9173         destroyPQExpBuffer(details);
9174 }
9175
9176 /*
9177  * format_aggregate_signature: generate aggregate name and argument list
9178  *
9179  * The argument type names are qualified if needed.  The aggregate name
9180  * is never qualified.
9181  */
9182 static char *
9183 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
9184 {
9185         PQExpBufferData buf;
9186         int                     j;
9187
9188         initPQExpBuffer(&buf);
9189         if (honor_quotes)
9190                 appendPQExpBuffer(&buf, "%s",
9191                                                   fmtId(agginfo->aggfn.dobj.name));
9192         else
9193                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
9194
9195         if (agginfo->aggfn.nargs == 0)
9196                 appendPQExpBuffer(&buf, "(*)");
9197         else
9198         {
9199                 appendPQExpBuffer(&buf, "(");
9200                 for (j = 0; j < agginfo->aggfn.nargs; j++)
9201                 {
9202                         char       *typname;
9203
9204                         typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
9205
9206                         appendPQExpBuffer(&buf, "%s%s",
9207                                                           (j > 0) ? ", " : "",
9208                                                           typname);
9209                         free(typname);
9210                 }
9211                 appendPQExpBuffer(&buf, ")");
9212         }
9213         return buf.data;
9214 }
9215
9216 /*
9217  * dumpAgg
9218  *        write out a single aggregate definition
9219  */
9220 static void
9221 dumpAgg(Archive *fout, AggInfo *agginfo)
9222 {
9223         PQExpBuffer query;
9224         PQExpBuffer q;
9225         PQExpBuffer delq;
9226         PQExpBuffer details;
9227         char       *aggsig;
9228         char       *aggsig_tag;
9229         PGresult   *res;
9230         int                     ntups;
9231         int                     i_aggtransfn;
9232         int                     i_aggfinalfn;
9233         int                     i_aggsortop;
9234         int                     i_aggtranstype;
9235         int                     i_agginitval;
9236         int                     i_convertok;
9237         const char *aggtransfn;
9238         const char *aggfinalfn;
9239         const char *aggsortop;
9240         const char *aggtranstype;
9241         const char *agginitval;
9242         bool            convertok;
9243
9244         /* Skip if not to be dumped */
9245         if (!agginfo->aggfn.dobj.dump || dataOnly)
9246                 return;
9247
9248         query = createPQExpBuffer();
9249         q = createPQExpBuffer();
9250         delq = createPQExpBuffer();
9251         details = createPQExpBuffer();
9252
9253         /* Make sure we are in proper schema */
9254         selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
9255
9256         /* Get aggregate-specific details */
9257         if (g_fout->remoteVersion >= 80100)
9258         {
9259                 appendPQExpBuffer(query, "SELECT aggtransfn, "
9260                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
9261                                                   "aggsortop::pg_catalog.regoperator, "
9262                                                   "agginitval, "
9263                                                   "'t'::boolean AS convertok "
9264                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
9265                                                   "WHERE a.aggfnoid = p.oid "
9266                                                   "AND p.oid = '%u'::pg_catalog.oid",
9267                                                   agginfo->aggfn.dobj.catId.oid);
9268         }
9269         else if (g_fout->remoteVersion >= 70300)
9270         {
9271                 appendPQExpBuffer(query, "SELECT aggtransfn, "
9272                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
9273                                                   "0 AS aggsortop, "
9274                                                   "agginitval, "
9275                                                   "'t'::boolean AS convertok "
9276                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
9277                                                   "WHERE a.aggfnoid = p.oid "
9278                                                   "AND p.oid = '%u'::pg_catalog.oid",
9279                                                   agginfo->aggfn.dobj.catId.oid);
9280         }
9281         else if (g_fout->remoteVersion >= 70100)
9282         {
9283                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
9284                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
9285                                                   "0 AS aggsortop, "
9286                                                   "agginitval, "
9287                                                   "'t'::boolean AS convertok "
9288                                                   "FROM pg_aggregate "
9289                                                   "WHERE oid = '%u'::oid",
9290                                                   agginfo->aggfn.dobj.catId.oid);
9291         }
9292         else
9293         {
9294                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
9295                                                   "aggfinalfn, "
9296                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
9297                                                   "0 AS aggsortop, "
9298                                                   "agginitval1 AS agginitval, "
9299                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
9300                                                   "FROM pg_aggregate "
9301                                                   "WHERE oid = '%u'::oid",
9302                                                   agginfo->aggfn.dobj.catId.oid);
9303         }
9304
9305         res = PQexec(g_conn, query->data);
9306         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9307
9308         /* Expecting a single result only */
9309         ntups = PQntuples(res);
9310         if (ntups != 1)
9311         {
9312                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9313                                                            "query returned %d rows instead of one: %s\n",
9314                                                                  ntups),
9315                                   ntups, query->data);
9316                 exit_nicely();
9317         }
9318
9319         i_aggtransfn = PQfnumber(res, "aggtransfn");
9320         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
9321         i_aggsortop = PQfnumber(res, "aggsortop");
9322         i_aggtranstype = PQfnumber(res, "aggtranstype");
9323         i_agginitval = PQfnumber(res, "agginitval");
9324         i_convertok = PQfnumber(res, "convertok");
9325
9326         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
9327         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
9328         aggsortop = PQgetvalue(res, 0, i_aggsortop);
9329         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
9330         agginitval = PQgetvalue(res, 0, i_agginitval);
9331         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
9332
9333         aggsig = format_aggregate_signature(agginfo, fout, true);
9334         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
9335
9336         if (!convertok)
9337         {
9338                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
9339                                   aggsig);
9340                 return;
9341         }
9342
9343         if (g_fout->remoteVersion >= 70300)
9344         {
9345                 /* If using 7.3's regproc or regtype, data is already quoted */
9346                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
9347                                                   aggtransfn,
9348                                                   aggtranstype);
9349         }
9350         else if (g_fout->remoteVersion >= 70100)
9351         {
9352                 /* format_type quotes, regproc does not */
9353                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
9354                                                   fmtId(aggtransfn),
9355                                                   aggtranstype);
9356         }
9357         else
9358         {
9359                 /* need quotes all around */
9360                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
9361                                                   fmtId(aggtransfn));
9362                 appendPQExpBuffer(details, "    STYPE = %s",
9363                                                   fmtId(aggtranstype));
9364         }
9365
9366         if (!PQgetisnull(res, 0, i_agginitval))
9367         {
9368                 appendPQExpBuffer(details, ",\n    INITCOND = ");
9369                 appendStringLiteralAH(details, agginitval, fout);
9370         }
9371
9372         if (strcmp(aggfinalfn, "-") != 0)
9373         {
9374                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
9375                                                   aggfinalfn);
9376         }
9377
9378         aggsortop = convertOperatorReference(aggsortop);
9379         if (aggsortop)
9380         {
9381                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
9382                                                   aggsortop);
9383         }
9384
9385         /*
9386          * DROP must be fully qualified in case same name appears in pg_catalog
9387          */
9388         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
9389                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
9390                                           aggsig);
9391
9392         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
9393                                           aggsig, details->data);
9394
9395         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
9396                                  aggsig_tag,
9397                                  agginfo->aggfn.dobj.namespace->dobj.name,
9398                                  NULL,
9399                                  agginfo->aggfn.rolname,
9400                                  false, "AGGREGATE", SECTION_PRE_DATA,
9401                                  q->data, delq->data, NULL,
9402                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
9403                                  NULL, NULL);
9404
9405         /* Dump Aggregate Comments */
9406         resetPQExpBuffer(q);
9407         appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
9408         dumpComment(fout, q->data,
9409                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
9410                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
9411
9412         /*
9413          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
9414          * command look like a function's GRANT; in particular this affects the
9415          * syntax for zero-argument aggregates.
9416          */
9417         free(aggsig);
9418         free(aggsig_tag);
9419
9420         aggsig = format_function_signature(&agginfo->aggfn, true);
9421         aggsig_tag = format_function_signature(&agginfo->aggfn, false);
9422
9423         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
9424                         "FUNCTION",
9425                         aggsig, NULL, aggsig_tag,
9426                         agginfo->aggfn.dobj.namespace->dobj.name,
9427                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
9428
9429         free(aggsig);
9430         free(aggsig_tag);
9431
9432         PQclear(res);
9433
9434         destroyPQExpBuffer(query);
9435         destroyPQExpBuffer(q);
9436         destroyPQExpBuffer(delq);
9437         destroyPQExpBuffer(details);
9438 }
9439
9440 /*
9441  * dumpTSParser
9442  *        write out a single text search parser
9443  */
9444 static void
9445 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
9446 {
9447         PQExpBuffer q;
9448         PQExpBuffer delq;
9449
9450         /* Skip if not to be dumped */
9451         if (!prsinfo->dobj.dump || dataOnly)
9452                 return;
9453
9454         q = createPQExpBuffer();
9455         delq = createPQExpBuffer();
9456
9457         /* Make sure we are in proper schema */
9458         selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
9459
9460         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
9461                                           fmtId(prsinfo->dobj.name));
9462
9463         appendPQExpBuffer(q, "    START = %s,\n",
9464                                           convertTSFunction(prsinfo->prsstart));
9465         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
9466                                           convertTSFunction(prsinfo->prstoken));
9467         appendPQExpBuffer(q, "    END = %s,\n",
9468                                           convertTSFunction(prsinfo->prsend));
9469         if (prsinfo->prsheadline != InvalidOid)
9470                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
9471                                                   convertTSFunction(prsinfo->prsheadline));
9472         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
9473                                           convertTSFunction(prsinfo->prslextype));
9474
9475         /*
9476          * DROP must be fully qualified in case same name appears in pg_catalog
9477          */
9478         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
9479                                           fmtId(prsinfo->dobj.namespace->dobj.name));
9480         appendPQExpBuffer(delq, ".%s;\n",
9481                                           fmtId(prsinfo->dobj.name));
9482
9483         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
9484                                  prsinfo->dobj.name,
9485                                  prsinfo->dobj.namespace->dobj.name,
9486                                  NULL,
9487                                  "",
9488                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
9489                                  q->data, delq->data, NULL,
9490                                  prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
9491                                  NULL, NULL);
9492
9493         /* Dump Parser Comments */
9494         resetPQExpBuffer(q);
9495         appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9496                                           fmtId(prsinfo->dobj.name));
9497         dumpComment(fout, q->data,
9498                                 NULL, "",
9499                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9500
9501         destroyPQExpBuffer(q);
9502         destroyPQExpBuffer(delq);
9503 }
9504
9505 /*
9506  * dumpTSDictionary
9507  *        write out a single text search dictionary
9508  */
9509 static void
9510 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9511 {
9512         PQExpBuffer q;
9513         PQExpBuffer delq;
9514         PQExpBuffer query;
9515         PGresult   *res;
9516         int                     ntups;
9517         char       *nspname;
9518         char       *tmplname;
9519
9520         /* Skip if not to be dumped */
9521         if (!dictinfo->dobj.dump || dataOnly)
9522                 return;
9523
9524         q = createPQExpBuffer();
9525         delq = createPQExpBuffer();
9526         query = createPQExpBuffer();
9527
9528         /* Fetch name and namespace of the dictionary's template */
9529         selectSourceSchema("pg_catalog");
9530         appendPQExpBuffer(query, "SELECT nspname, tmplname "
9531                                           "FROM pg_ts_template p, pg_namespace n "
9532                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9533                                           dictinfo->dicttemplate);
9534         res = PQexec(g_conn, query->data);
9535         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9536         ntups = PQntuples(res);
9537         if (ntups != 1)
9538         {
9539                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9540                                                            "query returned %d rows instead of one: %s\n",
9541                                                                  ntups),
9542                                   ntups, query->data);
9543                 exit_nicely();
9544         }
9545         nspname = PQgetvalue(res, 0, 0);
9546         tmplname = PQgetvalue(res, 0, 1);
9547
9548         /* Make sure we are in proper schema */
9549         selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9550
9551         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9552                                           fmtId(dictinfo->dobj.name));
9553
9554         appendPQExpBuffer(q, "    TEMPLATE = ");
9555         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
9556                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9557         appendPQExpBuffer(q, "%s", fmtId(tmplname));
9558
9559         PQclear(res);
9560
9561         /* the dictinitoption can be dumped straight into the command */
9562         if (dictinfo->dictinitoption)
9563                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
9564
9565         appendPQExpBuffer(q, " );\n");
9566
9567         /*
9568          * DROP must be fully qualified in case same name appears in pg_catalog
9569          */
9570         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
9571                                           fmtId(dictinfo->dobj.namespace->dobj.name));
9572         appendPQExpBuffer(delq, ".%s;\n",
9573                                           fmtId(dictinfo->dobj.name));
9574
9575         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9576                                  dictinfo->dobj.name,
9577                                  dictinfo->dobj.namespace->dobj.name,
9578                                  NULL,
9579                                  dictinfo->rolname,
9580                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9581                                  q->data, delq->data, NULL,
9582                                  dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
9583                                  NULL, NULL);
9584
9585         /* Dump Dictionary Comments */
9586         resetPQExpBuffer(q);
9587         appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
9588                                           fmtId(dictinfo->dobj.name));
9589         dumpComment(fout, q->data,
9590                                 NULL, dictinfo->rolname,
9591                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
9592
9593         destroyPQExpBuffer(q);
9594         destroyPQExpBuffer(delq);
9595         destroyPQExpBuffer(query);
9596 }
9597
9598 /*
9599  * dumpTSTemplate
9600  *        write out a single text search template
9601  */
9602 static void
9603 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9604 {
9605         PQExpBuffer q;
9606         PQExpBuffer delq;
9607
9608         /* Skip if not to be dumped */
9609         if (!tmplinfo->dobj.dump || dataOnly)
9610                 return;
9611
9612         q = createPQExpBuffer();
9613         delq = createPQExpBuffer();
9614
9615         /* Make sure we are in proper schema */
9616         selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9617
9618         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9619                                           fmtId(tmplinfo->dobj.name));
9620
9621         if (tmplinfo->tmplinit != InvalidOid)
9622                 appendPQExpBuffer(q, "    INIT = %s,\n",
9623                                                   convertTSFunction(tmplinfo->tmplinit));
9624         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
9625                                           convertTSFunction(tmplinfo->tmpllexize));
9626
9627         /*
9628          * DROP must be fully qualified in case same name appears in pg_catalog
9629          */
9630         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
9631                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
9632         appendPQExpBuffer(delq, ".%s;\n",
9633                                           fmtId(tmplinfo->dobj.name));
9634
9635         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9636                                  tmplinfo->dobj.name,
9637                                  tmplinfo->dobj.namespace->dobj.name,
9638                                  NULL,
9639                                  "",
9640                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9641                                  q->data, delq->data, NULL,
9642                                  tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9643                                  NULL, NULL);
9644
9645         /* Dump Template Comments */
9646         resetPQExpBuffer(q);
9647         appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9648                                           fmtId(tmplinfo->dobj.name));
9649         dumpComment(fout, q->data,
9650                                 NULL, "",
9651                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9652
9653         destroyPQExpBuffer(q);
9654         destroyPQExpBuffer(delq);
9655 }
9656
9657 /*
9658  * dumpTSConfig
9659  *        write out a single text search configuration
9660  */
9661 static void
9662 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9663 {
9664         PQExpBuffer q;
9665         PQExpBuffer delq;
9666         PQExpBuffer query;
9667         PGresult   *res;
9668         char       *nspname;
9669         char       *prsname;
9670         int                     ntups,
9671                                 i;
9672         int                     i_tokenname;
9673         int                     i_dictname;
9674
9675         /* Skip if not to be dumped */
9676         if (!cfginfo->dobj.dump || dataOnly)
9677                 return;
9678
9679         q = createPQExpBuffer();
9680         delq = createPQExpBuffer();
9681         query = createPQExpBuffer();
9682
9683         /* Fetch name and namespace of the config's parser */
9684         selectSourceSchema("pg_catalog");
9685         appendPQExpBuffer(query, "SELECT nspname, prsname "
9686                                           "FROM pg_ts_parser p, pg_namespace n "
9687                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9688                                           cfginfo->cfgparser);
9689         res = PQexec(g_conn, query->data);
9690         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9691         ntups = PQntuples(res);
9692         if (ntups != 1)
9693         {
9694                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9695                                                            "query returned %d rows instead of one: %s\n",
9696                                                                  ntups),
9697                                   ntups, query->data);
9698                 exit_nicely();
9699         }
9700         nspname = PQgetvalue(res, 0, 0);
9701         prsname = PQgetvalue(res, 0, 1);
9702
9703         /* Make sure we are in proper schema */
9704         selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9705
9706         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9707                                           fmtId(cfginfo->dobj.name));
9708
9709         appendPQExpBuffer(q, "    PARSER = ");
9710         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
9711                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9712         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
9713
9714         PQclear(res);
9715
9716         resetPQExpBuffer(query);
9717         appendPQExpBuffer(query,
9718                                           "SELECT \n"
9719                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9720                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9721                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
9722                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
9723                                           "WHERE m.mapcfg = '%u' \n"
9724                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9725                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
9726
9727         res = PQexec(g_conn, query->data);
9728         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9729         ntups = PQntuples(res);
9730
9731         i_tokenname = PQfnumber(res, "tokenname");
9732         i_dictname = PQfnumber(res, "dictname");
9733
9734         for (i = 0; i < ntups; i++)
9735         {
9736                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
9737                 char       *dictname = PQgetvalue(res, i, i_dictname);
9738
9739                 if (i == 0 ||
9740                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9741                 {
9742                         /* starting a new token type, so start a new command */
9743                         if (i > 0)
9744                                 appendPQExpBuffer(q, ";\n");
9745                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9746                                                           fmtId(cfginfo->dobj.name));
9747                         /* tokenname needs quoting, dictname does NOT */
9748                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
9749                                                           fmtId(tokenname), dictname);
9750                 }
9751                 else
9752                         appendPQExpBuffer(q, ", %s", dictname);
9753         }
9754
9755         if (ntups > 0)
9756                 appendPQExpBuffer(q, ";\n");
9757
9758         PQclear(res);
9759
9760         /*
9761          * DROP must be fully qualified in case same name appears in pg_catalog
9762          */
9763         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
9764                                           fmtId(cfginfo->dobj.namespace->dobj.name));
9765         appendPQExpBuffer(delq, ".%s;\n",
9766                                           fmtId(cfginfo->dobj.name));
9767
9768         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9769                                  cfginfo->dobj.name,
9770                                  cfginfo->dobj.namespace->dobj.name,
9771                                  NULL,
9772                                  cfginfo->rolname,
9773                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9774                                  q->data, delq->data, NULL,
9775                                  cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
9776                                  NULL, NULL);
9777
9778         /* Dump Configuration Comments */
9779         resetPQExpBuffer(q);
9780         appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
9781                                           fmtId(cfginfo->dobj.name));
9782         dumpComment(fout, q->data,
9783                                 NULL, cfginfo->rolname,
9784                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
9785
9786         destroyPQExpBuffer(q);
9787         destroyPQExpBuffer(delq);
9788         destroyPQExpBuffer(query);
9789 }
9790
9791 /*
9792  * dumpForeignDataWrapper
9793  *        write out a single foreign-data wrapper definition
9794  */
9795 static void
9796 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9797 {
9798         PQExpBuffer q;
9799         PQExpBuffer delq;
9800         char       *namecopy;
9801
9802         /* Skip if not to be dumped */
9803         if (!fdwinfo->dobj.dump || dataOnly)
9804                 return;
9805
9806         q = createPQExpBuffer();
9807         delq = createPQExpBuffer();
9808
9809         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9810                                           fmtId(fdwinfo->dobj.name));
9811
9812         if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9813                 appendPQExpBuffer(q, " VALIDATOR %s",
9814                                                   fdwinfo->fdwvalidator);
9815
9816         if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9817                 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9818
9819         appendPQExpBuffer(q, ";\n");
9820
9821         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9822                                           fmtId(fdwinfo->dobj.name));
9823
9824         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9825                                  fdwinfo->dobj.name,
9826                                  NULL,
9827                                  NULL,
9828                                  fdwinfo->rolname,
9829                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9830                                  q->data, delq->data, NULL,
9831                                  fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
9832                                  NULL, NULL);
9833
9834         /* Handle the ACL */
9835         namecopy = strdup(fmtId(fdwinfo->dobj.name));
9836         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9837                         "FOREIGN DATA WRAPPER",
9838                         namecopy, NULL, fdwinfo->dobj.name,
9839                         NULL, fdwinfo->rolname,
9840                         fdwinfo->fdwacl);
9841         free(namecopy);
9842
9843         destroyPQExpBuffer(q);
9844         destroyPQExpBuffer(delq);
9845 }
9846
9847 /*
9848  * dumpForeignServer
9849  *        write out a foreign server definition
9850  */
9851 static void
9852 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9853 {
9854         PQExpBuffer q;
9855         PQExpBuffer delq;
9856         PQExpBuffer query;
9857         PGresult   *res;
9858         int                     ntups;
9859         char       *namecopy;
9860         char       *fdwname;
9861
9862         /* Skip if not to be dumped */
9863         if (!srvinfo->dobj.dump || dataOnly)
9864                 return;
9865
9866         q = createPQExpBuffer();
9867         delq = createPQExpBuffer();
9868         query = createPQExpBuffer();
9869
9870         /* look up the foreign-data wrapper */
9871         appendPQExpBuffer(query, "SELECT fdwname "
9872                                           "FROM pg_foreign_data_wrapper w "
9873                                           "WHERE w.oid = '%u'",
9874                                           srvinfo->srvfdw);
9875         res = PQexec(g_conn, query->data);
9876         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9877         ntups = PQntuples(res);
9878         if (ntups != 1)
9879         {
9880                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9881                                                            "query returned %d rows instead of one: %s\n",
9882                                                                  ntups),
9883                                   ntups, query->data);
9884                 exit_nicely();
9885         }
9886         fdwname = PQgetvalue(res, 0, 0);
9887
9888         appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9889         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9890         {
9891                 appendPQExpBuffer(q, " TYPE ");
9892                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
9893         }
9894         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9895         {
9896                 appendPQExpBuffer(q, " VERSION ");
9897                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
9898         }
9899
9900         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9901         appendPQExpBuffer(q, "%s", fmtId(fdwname));
9902
9903         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9904                 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9905
9906         appendPQExpBuffer(q, ";\n");
9907
9908         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9909                                           fmtId(srvinfo->dobj.name));
9910
9911         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9912                                  srvinfo->dobj.name,
9913                                  NULL,
9914                                  NULL,
9915                                  srvinfo->rolname,
9916                                  false, "SERVER", SECTION_PRE_DATA,
9917                                  q->data, delq->data, NULL,
9918                                  srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9919                                  NULL, NULL);
9920
9921         /* Handle the ACL */
9922         namecopy = strdup(fmtId(srvinfo->dobj.name));
9923         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9924                         "SERVER",
9925                         namecopy, NULL, srvinfo->dobj.name,
9926                         NULL, srvinfo->rolname,
9927                         srvinfo->srvacl);
9928         free(namecopy);
9929
9930         /* Dump user mappings */
9931         resetPQExpBuffer(q);
9932         appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
9933         dumpUserMappings(fout, q->data,
9934                                          srvinfo->dobj.name, NULL,
9935                                          srvinfo->rolname,
9936                                          srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9937
9938         destroyPQExpBuffer(q);
9939         destroyPQExpBuffer(delq);
9940 }
9941
9942 /*
9943  * dumpUserMappings
9944  *
9945  * This routine is used to dump any user mappings associated with the
9946  * server handed to this routine. Should be called after ArchiveEntry()
9947  * for the server.
9948  */
9949 static void
9950 dumpUserMappings(Archive *fout, const char *target,
9951                                  const char *servername, const char *namespace,
9952                                  const char *owner,
9953                                  CatalogId catalogId, DumpId dumpId)
9954 {
9955         PQExpBuffer q;
9956         PQExpBuffer delq;
9957         PQExpBuffer query;
9958         PQExpBuffer tag;
9959         PGresult   *res;
9960         int                     ntups;
9961         int                     i_umuser;
9962         int                     i_umoptions;
9963         int                     i;
9964
9965         q = createPQExpBuffer();
9966         tag = createPQExpBuffer();
9967         delq = createPQExpBuffer();
9968         query = createPQExpBuffer();
9969
9970         appendPQExpBuffer(query,
9971                                           "SELECT (%s umuser) AS umuser, "
9972                                           "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9973                                           "FROM pg_user_mapping "
9974                                           "WHERE umserver=%u",
9975                                           username_subquery,
9976                                           catalogId.oid);
9977
9978         res = PQexec(g_conn, query->data);
9979         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9980
9981         ntups = PQntuples(res);
9982         i_umuser = PQfnumber(res, "umuser");
9983         i_umoptions = PQfnumber(res, "umoptions");
9984
9985         for (i = 0; i < ntups; i++)
9986         {
9987                 char       *umuser;
9988                 char       *umoptions;
9989
9990                 umuser = PQgetvalue(res, i, i_umuser);
9991                 umoptions = PQgetvalue(res, i, i_umoptions);
9992
9993                 resetPQExpBuffer(q);
9994                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9995                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9996
9997                 if (umoptions && strlen(umoptions) > 0)
9998                         appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9999
10000                 appendPQExpBuffer(q, ";\n");
10001
10002                 resetPQExpBuffer(delq);
10003                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
10004
10005                 resetPQExpBuffer(tag);
10006                 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
10007
10008                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10009                                          tag->data,
10010                                          namespace,
10011                                          NULL,
10012                                          owner, false,
10013                                          "USER MAPPING", SECTION_PRE_DATA,
10014                                          q->data, delq->data, NULL,
10015                                          &dumpId, 1,
10016                                          NULL, NULL);
10017         }
10018
10019         PQclear(res);
10020
10021         destroyPQExpBuffer(query);
10022         destroyPQExpBuffer(delq);
10023         destroyPQExpBuffer(q);
10024 }
10025
10026 /*
10027  * Write out default privileges information
10028  */
10029 static void
10030 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
10031 {
10032         PQExpBuffer q;
10033         PQExpBuffer tag;
10034         const char *type;
10035
10036         /* Skip if not to be dumped */
10037         if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
10038                 return;
10039
10040         q = createPQExpBuffer();
10041         tag = createPQExpBuffer();
10042
10043         switch (daclinfo->defaclobjtype)
10044         {
10045                 case DEFACLOBJ_RELATION:
10046                         type = "TABLES";
10047                         break;
10048                 case DEFACLOBJ_SEQUENCE:
10049                         type = "SEQUENCES";
10050                         break;
10051                 case DEFACLOBJ_FUNCTION:
10052                         type = "FUNCTIONS";
10053                         break;
10054                 default:
10055                         /* shouldn't get here */
10056                         write_msg(NULL, "unknown object type (%d) in default privileges\n",
10057                                           (int) daclinfo->defaclobjtype);
10058                         exit_nicely();
10059                         type = "";                      /* keep compiler quiet */
10060         }
10061
10062         appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
10063
10064         /* build the actual command(s) for this tuple */
10065         if (!buildDefaultACLCommands(type,
10066                                                                  daclinfo->dobj.namespace != NULL ?
10067                                                                  daclinfo->dobj.namespace->dobj.name : NULL,
10068                                                                  daclinfo->defaclacl,
10069                                                                  daclinfo->defaclrole,
10070                                                                  fout->remoteVersion,
10071                                                                  q))
10072         {
10073                 write_msg(NULL, "could not parse default ACL list (%s)\n",
10074                                   daclinfo->defaclacl);
10075                 exit_nicely();
10076         }
10077
10078         ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
10079                                  tag->data,
10080                                  daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
10081                                  NULL,
10082                                  daclinfo->defaclrole,
10083                                  false, "DEFAULT ACL", SECTION_NONE,
10084                                  q->data, "", NULL,
10085                                  daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
10086                                  NULL, NULL);
10087
10088         destroyPQExpBuffer(tag);
10089         destroyPQExpBuffer(q);
10090 }
10091
10092 /*----------
10093  * Write out grant/revoke information
10094  *
10095  * 'objCatId' is the catalog ID of the underlying object.
10096  * 'objDumpId' is the dump ID of the underlying object.
10097  * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
10098  * 'name' is the formatted name of the object.  Must be quoted etc. already.
10099  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
10100  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
10101  * 'nspname' is the namespace the object is in (NULL if none).
10102  * 'owner' is the owner, NULL if there is no owner (for languages).
10103  * 'acls' is the string read out of the fooacl system catalog field;
10104  * it will be parsed here.
10105  *----------
10106  */
10107 static void
10108 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
10109                 const char *type, const char *name, const char *subname,
10110                 const char *tag, const char *nspname, const char *owner,
10111                 const char *acls)
10112 {
10113         PQExpBuffer sql;
10114
10115         /* Do nothing if ACL dump is not enabled */
10116         if (dataOnly || aclsSkip)
10117                 return;
10118
10119         sql = createPQExpBuffer();
10120
10121         if (!buildACLCommands(name, subname, type, acls, owner,
10122                                                   "", fout->remoteVersion, sql))
10123         {
10124                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
10125                                   acls, name, type);
10126                 exit_nicely();
10127         }
10128
10129         if (sql->len > 0)
10130                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10131                                          tag, nspname,
10132                                          NULL,
10133                                          owner ? owner : "",
10134                                          false, "ACL", SECTION_NONE,
10135                                          sql->data, "", NULL,
10136                                          &(objDumpId), 1,
10137                                          NULL, NULL);
10138
10139         destroyPQExpBuffer(sql);
10140 }
10141
10142 /*
10143  * dumpTable
10144  *        write out to fout the declarations (not data) of a user-defined table
10145  */
10146 static void
10147 dumpTable(Archive *fout, TableInfo *tbinfo)
10148 {
10149         if (tbinfo->dobj.dump)
10150         {
10151                 char       *namecopy;
10152
10153                 if (tbinfo->relkind == RELKIND_SEQUENCE)
10154                         dumpSequence(fout, tbinfo);
10155                 else if (!dataOnly)
10156                         dumpTableSchema(fout, tbinfo);
10157
10158                 /* Handle the ACL here */
10159                 namecopy = strdup(fmtId(tbinfo->dobj.name));
10160                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10161                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
10162                                 namecopy, NULL, tbinfo->dobj.name,
10163                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10164                                 tbinfo->relacl);
10165
10166                 /*
10167                  * Handle column ACLs, if any.  Note: we pull these with a separate
10168                  * query rather than trying to fetch them during getTableAttrs, so
10169                  * that we won't miss ACLs on system columns.
10170                  */
10171                 if (g_fout->remoteVersion >= 80400)
10172                 {
10173                         PQExpBuffer query = createPQExpBuffer();
10174                         PGresult   *res;
10175                         int                     i;
10176
10177                         appendPQExpBuffer(query,
10178                                            "SELECT attname, attacl FROM pg_catalog.pg_attribute "
10179                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
10180                                                           "ORDER BY attnum",
10181                                                           tbinfo->dobj.catId.oid);
10182                         res = PQexec(g_conn, query->data);
10183                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10184
10185                         for (i = 0; i < PQntuples(res); i++)
10186                         {
10187                                 char       *attname = PQgetvalue(res, i, 0);
10188                                 char       *attacl = PQgetvalue(res, i, 1);
10189                                 char       *attnamecopy;
10190                                 char       *acltag;
10191
10192                                 attnamecopy = strdup(fmtId(attname));
10193                                 acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
10194                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
10195                                 /* Column's GRANT type is always TABLE */
10196                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
10197                                                 namecopy, attnamecopy, acltag,
10198                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10199                                                 attacl);
10200                                 free(attnamecopy);
10201                                 free(acltag);
10202                         }
10203                         PQclear(res);
10204                         destroyPQExpBuffer(query);
10205                 }
10206
10207                 free(namecopy);
10208         }
10209 }
10210
10211 /*
10212  * dumpTableSchema
10213  *        write the declaration (not data) of one user-defined table or view
10214  */
10215 static void
10216 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
10217 {
10218         PQExpBuffer query = createPQExpBuffer();
10219         PQExpBuffer q = createPQExpBuffer();
10220         PQExpBuffer delq = createPQExpBuffer();
10221         PGresult   *res;
10222         int                     numParents;
10223         TableInfo **parents;
10224         int                     actual_atts;    /* number of attrs in this CREATE statment */
10225         char       *reltypename;
10226         char       *storage;
10227         int                     j,
10228                                 k;
10229
10230         /* Make sure we are in proper schema */
10231         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10232
10233         /* Is it a table or a view? */
10234         if (tbinfo->relkind == RELKIND_VIEW)
10235         {
10236                 char       *viewdef;
10237
10238                 reltypename = "VIEW";
10239
10240                 /* Fetch the view definition */
10241                 if (g_fout->remoteVersion >= 70300)
10242                 {
10243                         /* Beginning in 7.3, viewname is not unique; rely on OID */
10244                         appendPQExpBuffer(query,
10245                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
10246                                                           tbinfo->dobj.catId.oid);
10247                 }
10248                 else
10249                 {
10250                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
10251                                                           "FROM pg_views WHERE viewname = ");
10252                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
10253                         appendPQExpBuffer(query, ";");
10254                 }
10255
10256                 res = PQexec(g_conn, query->data);
10257                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10258
10259                 if (PQntuples(res) != 1)
10260                 {
10261                         if (PQntuples(res) < 1)
10262                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
10263                                                   tbinfo->dobj.name);
10264                         else
10265                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
10266                                                   tbinfo->dobj.name);
10267                         exit_nicely();
10268                 }
10269
10270                 viewdef = PQgetvalue(res, 0, 0);
10271
10272                 if (strlen(viewdef) == 0)
10273                 {
10274                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
10275                                           tbinfo->dobj.name);
10276                         exit_nicely();
10277                 }
10278
10279                 /*
10280                  * DROP must be fully qualified in case same name appears in
10281                  * pg_catalog
10282                  */
10283                 appendPQExpBuffer(delq, "DROP VIEW %s.",
10284                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10285                 appendPQExpBuffer(delq, "%s;\n",
10286                                                   fmtId(tbinfo->dobj.name));
10287
10288                 appendPQExpBuffer(q, "CREATE VIEW %s AS\n    %s\n",
10289                                                   fmtId(tbinfo->dobj.name), viewdef);
10290
10291                 PQclear(res);
10292         }
10293         else
10294         {
10295                 reltypename = "TABLE";
10296                 numParents = tbinfo->numParents;
10297                 parents = tbinfo->parents;
10298
10299                 /*
10300                  * DROP must be fully qualified in case same name appears in
10301                  * pg_catalog
10302                  */
10303                 appendPQExpBuffer(delq, "DROP TABLE %s.",
10304                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10305                 appendPQExpBuffer(delq, "%s;\n",
10306                                                   fmtId(tbinfo->dobj.name));
10307
10308                 appendPQExpBuffer(q, "CREATE TABLE %s (",
10309                                                   fmtId(tbinfo->dobj.name));
10310                 actual_atts = 0;
10311                 for (j = 0; j < tbinfo->numatts; j++)
10312                 {
10313                         /*
10314                          * Normally, dump if it's one of the table's own attrs, and not
10315                          * dropped.  But for binary upgrade, dump all the columns.
10316                          */
10317                         if ((!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) ||
10318                                 binary_upgrade)
10319                         {
10320                                 /* Format properly if not first attr */
10321                                 if (actual_atts > 0)
10322                                         appendPQExpBuffer(q, ",");
10323                                 appendPQExpBuffer(q, "\n    ");
10324                                 actual_atts++;
10325
10326                                 /* Attribute name */
10327                                 appendPQExpBuffer(q, "%s ",
10328                                                                   fmtId(tbinfo->attnames[j]));
10329
10330                                 if (tbinfo->attisdropped[j])
10331                                 {
10332                                         /*
10333                                          * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
10334                                          * so we will not have gotten a valid type name; insert
10335                                          * INTEGER as a stopgap.  We'll clean things up later.
10336                                          */
10337                                         appendPQExpBuffer(q, "INTEGER /* dummy */");
10338                                         /* Skip all the rest, too */
10339                                         continue;
10340                                 }
10341
10342                                 /* Attribute type */
10343                                 if (g_fout->remoteVersion >= 70100)
10344                                 {
10345                                         appendPQExpBuffer(q, "%s",
10346                                                                           tbinfo->atttypnames[j]);
10347                                 }
10348                                 else
10349                                 {
10350                                         /* If no format_type, fake it */
10351                                         appendPQExpBuffer(q, "%s",
10352                                                                           myFormatType(tbinfo->atttypnames[j],
10353                                                                                                    tbinfo->atttypmod[j]));
10354                                 }
10355
10356                                 /*
10357                                  * Default value --- suppress if inherited (except in
10358                                  * binary-upgrade case, where we're not doing normal
10359                                  * inheritance) or if it's to be printed separately.
10360                                  */
10361                                 if (tbinfo->attrdefs[j] != NULL &&
10362                                         (!tbinfo->inhAttrDef[j] || binary_upgrade) &&
10363                                         !tbinfo->attrdefs[j]->separate)
10364                                         appendPQExpBuffer(q, " DEFAULT %s",
10365                                                                           tbinfo->attrdefs[j]->adef_expr);
10366
10367                                 /*
10368                                  * Not Null constraint --- suppress if inherited, except
10369                                  * in binary-upgrade case.
10370                                  */
10371                                 if (tbinfo->notnull[j] &&
10372                                         (!tbinfo->inhNotNull[j] || binary_upgrade))
10373                                         appendPQExpBuffer(q, " NOT NULL");
10374                         }
10375                 }
10376
10377                 /*
10378                  * Add non-inherited CHECK constraints, if any.
10379                  */
10380                 for (j = 0; j < tbinfo->ncheck; j++)
10381                 {
10382                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10383
10384                         if (constr->separate || !constr->conislocal)
10385                                 continue;
10386
10387                         if (actual_atts > 0)
10388                                 appendPQExpBuffer(q, ",\n    ");
10389
10390                         appendPQExpBuffer(q, "CONSTRAINT %s ",
10391                                                           fmtId(constr->dobj.name));
10392                         appendPQExpBuffer(q, "%s", constr->condef);
10393
10394                         actual_atts++;
10395                 }
10396
10397                 appendPQExpBuffer(q, "\n)");
10398
10399                 if (numParents > 0 && !binary_upgrade)
10400                 {
10401                         appendPQExpBuffer(q, "\nINHERITS (");
10402                         for (k = 0; k < numParents; k++)
10403                         {
10404                                 TableInfo  *parentRel = parents[k];
10405
10406                                 if (k > 0)
10407                                         appendPQExpBuffer(q, ", ");
10408                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
10409                                         appendPQExpBuffer(q, "%s.",
10410                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
10411                                 appendPQExpBuffer(q, "%s",
10412                                                                   fmtId(parentRel->dobj.name));
10413                         }
10414                         appendPQExpBuffer(q, ")");
10415                 }
10416
10417                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
10418                   (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
10419                 {
10420                         bool            addcomma = false;
10421
10422                         appendPQExpBuffer(q, "\nWITH (");
10423                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
10424                         {
10425                                 addcomma = true;
10426                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
10427                         }
10428                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
10429                         {
10430                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
10431                                                                   tbinfo->toast_reloptions);
10432                         }
10433                         appendPQExpBuffer(q, ")");
10434                 }
10435
10436                 appendPQExpBuffer(q, ";\n");
10437
10438                 /*
10439                  * To create binary-compatible heap files, we have to ensure the
10440                  * same physical column order, including dropped columns, as in the
10441                  * original.  Therefore, we create dropped columns above and drop
10442                  * them here, also updating their attlen/attalign values so that
10443                  * the dropped column can be skipped properly.  (We do not bother
10444                  * with restoring the original attbyval setting.)  Also, inheritance
10445                  * relationships are set up by doing ALTER INHERIT rather than using
10446                  * an INHERITS clause --- the latter would possibly mess up the
10447                  * column order.  That also means we have to take care about setting
10448                  * attislocal correctly, plus fix up any inherited CHECK constraints.
10449                  */
10450                 if (binary_upgrade)
10451                 {
10452                         for (j = 0; j < tbinfo->numatts; j++)
10453                         {
10454                                 if (tbinfo->attisdropped[j])
10455                                 {
10456                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column.\n");
10457                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
10458                                                                           "SET attlen = %d, "
10459                                                                           "attalign = '%c', attbyval = false\n"
10460                                                                           "WHERE attname = ",
10461                                                                           tbinfo->attlen[j],
10462                                                                           tbinfo->attalign[j]);
10463                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
10464                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
10465                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
10466                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
10467
10468                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10469                                                                           fmtId(tbinfo->dobj.name));
10470                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
10471                                                                           fmtId(tbinfo->attnames[j]));
10472                                 }
10473                                 else if (!tbinfo->attislocal[j])
10474                                 {
10475                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate inherited column.\n");
10476                                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
10477                                                                           "SET attislocal = false\n"
10478                                                                           "WHERE attname = ");
10479                                         appendStringLiteralAH(q, tbinfo->attnames[j], fout);
10480                                         appendPQExpBuffer(q, "\n  AND attrelid = ");
10481                                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
10482                                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
10483                                 }
10484                         }
10485
10486                         for (k = 0; k < tbinfo->ncheck; k++)
10487                         {
10488                                 ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
10489
10490                                 if (constr->separate || constr->conislocal)
10491                                         continue;
10492
10493                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inherited constraint.\n");
10494                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10495                                                                   fmtId(tbinfo->dobj.name));
10496                                 appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
10497                                                                   fmtId(constr->dobj.name));
10498                                 appendPQExpBuffer(q, "%s;\n", constr->condef);
10499                                 appendPQExpBuffer(q, "UPDATE pg_catalog.pg_constraint\n"
10500                                                                   "SET conislocal = false\n"
10501                                                                   "WHERE contype = 'c' AND conname = ");
10502                                 appendStringLiteralAH(q, constr->dobj.name, fout);
10503                                 appendPQExpBuffer(q, "\n  AND conrelid = ");
10504                                 appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
10505                                 appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
10506                         }
10507
10508                         if (numParents > 0)
10509                         {
10510                                 appendPQExpBuffer(q, "\n-- For binary upgrade, set up inheritance this way.\n");
10511                                 for (k = 0; k < numParents; k++)
10512                                 {
10513                                         TableInfo  *parentRel = parents[k];
10514
10515                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT ",
10516                                                                           fmtId(tbinfo->dobj.name));
10517                                         if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
10518                                                 appendPQExpBuffer(q, "%s.",
10519                                                                                   fmtId(parentRel->dobj.namespace->dobj.name));
10520                                         appendPQExpBuffer(q, "%s;\n",
10521                                                                           fmtId(parentRel->dobj.name));
10522                                 }
10523                         }
10524
10525                         appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
10526                         appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
10527                                                           "SET relfrozenxid = '%u'\n"
10528                                                           "WHERE oid = ",
10529                                                           tbinfo->frozenxid);
10530                         appendStringLiteralAH(q, fmtId(tbinfo->dobj.name), fout);
10531                         appendPQExpBuffer(q, "::pg_catalog.regclass;\n");
10532                 }
10533
10534                 /* Loop dumping statistics and storage statements */
10535                 for (j = 0; j < tbinfo->numatts; j++)
10536                 {
10537                         /*
10538                          * Dump per-column statistics information. We only issue an ALTER
10539                          * TABLE statement if the attstattarget entry for this column is
10540                          * non-negative (i.e. it's not the default value)
10541                          */
10542                         if (tbinfo->attstattarget[j] >= 0 &&
10543                                 !tbinfo->attisdropped[j])
10544                         {
10545                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10546                                                                   fmtId(tbinfo->dobj.name));
10547                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
10548                                                                   fmtId(tbinfo->attnames[j]));
10549                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
10550                                                                   tbinfo->attstattarget[j]);
10551                         }
10552
10553                         /*
10554                          * Dump per-column ndistinct information. We only issue an ALTER
10555                          * TABLE statement if the attdistinct entry for this column is
10556                          * non-zero (i.e. it's not the default value)
10557                          */
10558                         if (tbinfo->attdistinct[j] != 0 &&
10559                                 !tbinfo->attisdropped[j])
10560                         {
10561                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10562                                                                   fmtId(tbinfo->dobj.name));
10563                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
10564                                                                   fmtId(tbinfo->attnames[j]));
10565                                 appendPQExpBuffer(q, "SET STATISTICS DISTINCT %g;\n",
10566                                                                   tbinfo->attdistinct[j]);
10567                         }
10568
10569                         /*
10570                          * Dump per-column storage information.  The statement is only
10571                          * dumped if the storage has been changed from the type's default.
10572                          */
10573                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
10574                         {
10575                                 switch (tbinfo->attstorage[j])
10576                                 {
10577                                         case 'p':
10578                                                 storage = "PLAIN";
10579                                                 break;
10580                                         case 'e':
10581                                                 storage = "EXTERNAL";
10582                                                 break;
10583                                         case 'm':
10584                                                 storage = "MAIN";
10585                                                 break;
10586                                         case 'x':
10587                                                 storage = "EXTENDED";
10588                                                 break;
10589                                         default:
10590                                                 storage = NULL;
10591                                 }
10592
10593                                 /*
10594                                  * Only dump the statement if it's a storage type we recognize
10595                                  */
10596                                 if (storage != NULL)
10597                                 {
10598                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
10599                                                                           fmtId(tbinfo->dobj.name));
10600                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
10601                                                                           fmtId(tbinfo->attnames[j]));
10602                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
10603                                                                           storage);
10604                                 }
10605                         }
10606                 }
10607         }
10608
10609         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10610                                  tbinfo->dobj.name,
10611                                  tbinfo->dobj.namespace->dobj.name,
10612                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
10613                                  tbinfo->rolname,
10614                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
10615                                  reltypename, SECTION_PRE_DATA,
10616                                  q->data, delq->data, NULL,
10617                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10618                                  NULL, NULL);
10619
10620         /* Dump Table Comments */
10621         dumpTableComment(fout, tbinfo, reltypename);
10622
10623         /* Dump comments on inlined table constraints */
10624         for (j = 0; j < tbinfo->ncheck; j++)
10625         {
10626                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10627
10628                 if (constr->separate || !constr->conislocal)
10629                         continue;
10630
10631                 dumpTableConstraintComment(fout, constr);
10632         }
10633
10634         destroyPQExpBuffer(query);
10635         destroyPQExpBuffer(q);
10636         destroyPQExpBuffer(delq);
10637 }
10638
10639 /*
10640  * dumpAttrDef --- dump an attribute's default-value declaration
10641  */
10642 static void
10643 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
10644 {
10645         TableInfo  *tbinfo = adinfo->adtable;
10646         int                     adnum = adinfo->adnum;
10647         PQExpBuffer q;
10648         PQExpBuffer delq;
10649
10650         /* Only print it if "separate" mode is selected */
10651         if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10652                 return;
10653
10654         /* Don't print inherited defaults, either, except for binary upgrade */
10655         if (tbinfo->inhAttrDef[adnum - 1] && !binary_upgrade)
10656                 return;
10657
10658         q = createPQExpBuffer();
10659         delq = createPQExpBuffer();
10660
10661         appendPQExpBuffer(q, "ALTER TABLE %s ",
10662                                           fmtId(tbinfo->dobj.name));
10663         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
10664                                           fmtId(tbinfo->attnames[adnum - 1]),
10665                                           adinfo->adef_expr);
10666
10667         /*
10668          * DROP must be fully qualified in case same name appears in pg_catalog
10669          */
10670         appendPQExpBuffer(delq, "ALTER TABLE %s.",
10671                                           fmtId(tbinfo->dobj.namespace->dobj.name));
10672         appendPQExpBuffer(delq, "%s ",
10673                                           fmtId(tbinfo->dobj.name));
10674         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
10675                                           fmtId(tbinfo->attnames[adnum - 1]));
10676
10677         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10678                                  tbinfo->attnames[adnum - 1],
10679                                  tbinfo->dobj.namespace->dobj.name,
10680                                  NULL,
10681                                  tbinfo->rolname,
10682                                  false, "DEFAULT", SECTION_PRE_DATA,
10683                                  q->data, delq->data, NULL,
10684                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10685                                  NULL, NULL);
10686
10687         destroyPQExpBuffer(q);
10688         destroyPQExpBuffer(delq);
10689 }
10690
10691 /*
10692  * getAttrName: extract the correct name for an attribute
10693  *
10694  * The array tblInfo->attnames[] only provides names of user attributes;
10695  * if a system attribute number is supplied, we have to fake it.
10696  * We also do a little bit of bounds checking for safety's sake.
10697  */
10698 static const char *
10699 getAttrName(int attrnum, TableInfo *tblInfo)
10700 {
10701         if (attrnum > 0 && attrnum <= tblInfo->numatts)
10702                 return tblInfo->attnames[attrnum - 1];
10703         switch (attrnum)
10704         {
10705                 case SelfItemPointerAttributeNumber:
10706                         return "ctid";
10707                 case ObjectIdAttributeNumber:
10708                         return "oid";
10709                 case MinTransactionIdAttributeNumber:
10710                         return "xmin";
10711                 case MinCommandIdAttributeNumber:
10712                         return "cmin";
10713                 case MaxTransactionIdAttributeNumber:
10714                         return "xmax";
10715                 case MaxCommandIdAttributeNumber:
10716                         return "cmax";
10717                 case TableOidAttributeNumber:
10718                         return "tableoid";
10719         }
10720         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10721                           attrnum, tblInfo->dobj.name);
10722         exit_nicely();
10723         return NULL;                            /* keep compiler quiet */
10724 }
10725
10726 /*
10727  * dumpIndex
10728  *        write out to fout a user-defined index
10729  */
10730 static void
10731 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10732 {
10733         TableInfo  *tbinfo = indxinfo->indextable;
10734         PQExpBuffer q;
10735         PQExpBuffer delq;
10736
10737         if (dataOnly)
10738                 return;
10739
10740         q = createPQExpBuffer();
10741         delq = createPQExpBuffer();
10742
10743         /*
10744          * If there's an associated constraint, don't dump the index per se, but
10745          * do dump any comment for it.  (This is safe because dependency ordering
10746          * will have ensured the constraint is emitted first.)
10747          */
10748         if (indxinfo->indexconstraint == 0)
10749         {
10750                 /* Plain secondary index */
10751                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10752
10753                 /* If the index is clustered, we need to record that. */
10754                 if (indxinfo->indisclustered)
10755                 {
10756                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10757                                                           fmtId(tbinfo->dobj.name));
10758                         appendPQExpBuffer(q, " ON %s;\n",
10759                                                           fmtId(indxinfo->dobj.name));
10760                 }
10761
10762                 /*
10763                  * DROP must be fully qualified in case same name appears in
10764                  * pg_catalog
10765                  */
10766                 appendPQExpBuffer(delq, "DROP INDEX %s.",
10767                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10768                 appendPQExpBuffer(delq, "%s;\n",
10769                                                   fmtId(indxinfo->dobj.name));
10770
10771                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
10772                                          indxinfo->dobj.name,
10773                                          tbinfo->dobj.namespace->dobj.name,
10774                                          indxinfo->tablespace,
10775                                          tbinfo->rolname, false,
10776                                          "INDEX", SECTION_POST_DATA,
10777                                          q->data, delq->data, NULL,
10778                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
10779                                          NULL, NULL);
10780         }
10781
10782         /* Dump Index Comments */
10783         resetPQExpBuffer(q);
10784         appendPQExpBuffer(q, "INDEX %s",
10785                                           fmtId(indxinfo->dobj.name));
10786         dumpComment(fout, q->data,
10787                                 tbinfo->dobj.namespace->dobj.name,
10788                                 tbinfo->rolname,
10789                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10790
10791         destroyPQExpBuffer(q);
10792         destroyPQExpBuffer(delq);
10793 }
10794
10795 /*
10796  * dumpConstraint
10797  *        write out to fout a user-defined constraint
10798  */
10799 static void
10800 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10801 {
10802         TableInfo  *tbinfo = coninfo->contable;
10803         PQExpBuffer q;
10804         PQExpBuffer delq;
10805
10806         /* Skip if not to be dumped */
10807         if (!coninfo->dobj.dump || dataOnly)
10808                 return;
10809
10810         q = createPQExpBuffer();
10811         delq = createPQExpBuffer();
10812
10813         if (coninfo->contype == 'p' ||
10814                 coninfo->contype == 'u' ||
10815                 coninfo->contype == 'x')
10816         {
10817                 /* Index-related constraint */
10818                 IndxInfo   *indxinfo;
10819                 int                     k;
10820
10821                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10822
10823                 if (indxinfo == NULL)
10824                 {
10825                         write_msg(NULL, "missing index for constraint \"%s\"\n",
10826                                           coninfo->dobj.name);
10827                         exit_nicely();
10828                 }
10829
10830                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10831                                                   fmtId(tbinfo->dobj.name));
10832                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
10833                                                   fmtId(coninfo->dobj.name));
10834
10835                 if (coninfo->condef)
10836                 {
10837                         /* pg_get_constraintdef should have provided everything */
10838                         appendPQExpBuffer(q, "%s;\n", coninfo->condef);
10839                 }
10840                 else
10841                 {
10842                         appendPQExpBuffer(q, "%s (",
10843                                                           coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
10844                         for (k = 0; k < indxinfo->indnkeys; k++)
10845                         {
10846                                 int                     indkey = (int) indxinfo->indkeys[k];
10847                                 const char *attname;
10848
10849                                 if (indkey == InvalidAttrNumber)
10850                                         break;
10851                                 attname = getAttrName(indkey, tbinfo);
10852
10853                                 appendPQExpBuffer(q, "%s%s",
10854                                                                   (k == 0) ? "" : ", ",
10855                                                                   fmtId(attname));
10856                         }
10857
10858                         appendPQExpBuffer(q, ")");
10859
10860                         if (indxinfo->options && strlen(indxinfo->options) > 0)
10861                                 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10862
10863                         if (coninfo->condeferrable)
10864                         {
10865                                 appendPQExpBuffer(q, " DEFERRABLE");
10866                                 if (coninfo->condeferred)
10867                                         appendPQExpBuffer(q, " INITIALLY DEFERRED");
10868                         }
10869
10870                         appendPQExpBuffer(q, ";\n");
10871                 }
10872
10873                 /* If the index is clustered, we need to record that. */
10874                 if (indxinfo->indisclustered)
10875                 {
10876                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10877                                                           fmtId(tbinfo->dobj.name));
10878                         appendPQExpBuffer(q, " ON %s;\n",
10879                                                           fmtId(indxinfo->dobj.name));
10880                 }
10881
10882                 /*
10883                  * DROP must be fully qualified in case same name appears in
10884                  * pg_catalog
10885                  */
10886                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10887                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10888                 appendPQExpBuffer(delq, "%s ",
10889                                                   fmtId(tbinfo->dobj.name));
10890                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10891                                                   fmtId(coninfo->dobj.name));
10892
10893                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10894                                          coninfo->dobj.name,
10895                                          tbinfo->dobj.namespace->dobj.name,
10896                                          indxinfo->tablespace,
10897                                          tbinfo->rolname, false,
10898                                          "CONSTRAINT", SECTION_POST_DATA,
10899                                          q->data, delq->data, NULL,
10900                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10901                                          NULL, NULL);
10902         }
10903         else if (coninfo->contype == 'f')
10904         {
10905                 /*
10906                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10907                  * current table data is not processed
10908                  */
10909                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10910                                                   fmtId(tbinfo->dobj.name));
10911                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10912                                                   fmtId(coninfo->dobj.name),
10913                                                   coninfo->condef);
10914
10915                 /*
10916                  * DROP must be fully qualified in case same name appears in
10917                  * pg_catalog
10918                  */
10919                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10920                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10921                 appendPQExpBuffer(delq, "%s ",
10922                                                   fmtId(tbinfo->dobj.name));
10923                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10924                                                   fmtId(coninfo->dobj.name));
10925
10926                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10927                                          coninfo->dobj.name,
10928                                          tbinfo->dobj.namespace->dobj.name,
10929                                          NULL,
10930                                          tbinfo->rolname, false,
10931                                          "FK CONSTRAINT", SECTION_POST_DATA,
10932                                          q->data, delq->data, NULL,
10933                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10934                                          NULL, NULL);
10935         }
10936         else if (coninfo->contype == 'c' && tbinfo)
10937         {
10938                 /* CHECK constraint on a table */
10939
10940                 /* Ignore if not to be dumped separately */
10941                 if (coninfo->separate)
10942                 {
10943                         /* not ONLY since we want it to propagate to children */
10944                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
10945                                                           fmtId(tbinfo->dobj.name));
10946                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10947                                                           fmtId(coninfo->dobj.name),
10948                                                           coninfo->condef);
10949
10950                         /*
10951                          * DROP must be fully qualified in case same name appears in
10952                          * pg_catalog
10953                          */
10954                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
10955                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
10956                         appendPQExpBuffer(delq, "%s ",
10957                                                           fmtId(tbinfo->dobj.name));
10958                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10959                                                           fmtId(coninfo->dobj.name));
10960
10961                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10962                                                  coninfo->dobj.name,
10963                                                  tbinfo->dobj.namespace->dobj.name,
10964                                                  NULL,
10965                                                  tbinfo->rolname, false,
10966                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
10967                                                  q->data, delq->data, NULL,
10968                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10969                                                  NULL, NULL);
10970                 }
10971         }
10972         else if (coninfo->contype == 'c' && tbinfo == NULL)
10973         {
10974                 /* CHECK constraint on a domain */
10975                 TypeInfo   *tinfo = coninfo->condomain;
10976
10977                 /* Ignore if not to be dumped separately */
10978                 if (coninfo->separate)
10979                 {
10980                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
10981                                                           fmtId(tinfo->dobj.name));
10982                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10983                                                           fmtId(coninfo->dobj.name),
10984                                                           coninfo->condef);
10985
10986                         /*
10987                          * DROP must be fully qualified in case same name appears in
10988                          * pg_catalog
10989                          */
10990                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
10991                                                           fmtId(tinfo->dobj.namespace->dobj.name));
10992                         appendPQExpBuffer(delq, "%s ",
10993                                                           fmtId(tinfo->dobj.name));
10994                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10995                                                           fmtId(coninfo->dobj.name));
10996
10997                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10998                                                  coninfo->dobj.name,
10999                                                  tinfo->dobj.namespace->dobj.name,
11000                                                  NULL,
11001                                                  tinfo->rolname, false,
11002                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
11003                                                  q->data, delq->data, NULL,
11004                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
11005                                                  NULL, NULL);
11006                 }
11007         }
11008         else
11009         {
11010                 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
11011                 exit_nicely();
11012         }
11013
11014         /* Dump Constraint Comments --- only works for table constraints */
11015         if (tbinfo && coninfo->separate)
11016                 dumpTableConstraintComment(fout, coninfo);
11017
11018         destroyPQExpBuffer(q);
11019         destroyPQExpBuffer(delq);
11020 }
11021
11022 /*
11023  * dumpTableConstraintComment --- dump a constraint's comment if any
11024  *
11025  * This is split out because we need the function in two different places
11026  * depending on whether the constraint is dumped as part of CREATE TABLE
11027  * or as a separate ALTER command.
11028  */
11029 static void
11030 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
11031 {
11032         TableInfo  *tbinfo = coninfo->contable;
11033         PQExpBuffer q = createPQExpBuffer();
11034
11035         appendPQExpBuffer(q, "CONSTRAINT %s ",
11036                                           fmtId(coninfo->dobj.name));
11037         appendPQExpBuffer(q, "ON %s",
11038                                           fmtId(tbinfo->dobj.name));
11039         dumpComment(fout, q->data,
11040                                 tbinfo->dobj.namespace->dobj.name,
11041                                 tbinfo->rolname,
11042                                 coninfo->dobj.catId, 0,
11043                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
11044
11045         destroyPQExpBuffer(q);
11046 }
11047
11048 /*
11049  * findLastBuiltInOid -
11050  * find the last built in oid
11051  *
11052  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
11053  * pg_database entry for the current database
11054  */
11055 static Oid
11056 findLastBuiltinOid_V71(const char *dbname)
11057 {
11058         PGresult   *res;
11059         int                     ntups;
11060         Oid                     last_oid;
11061         PQExpBuffer query = createPQExpBuffer();
11062
11063         resetPQExpBuffer(query);
11064         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
11065         appendStringLiteralAH(query, dbname, g_fout);
11066
11067         res = PQexec(g_conn, query->data);
11068         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11069
11070         ntups = PQntuples(res);
11071         if (ntups < 1)
11072         {
11073                 write_msg(NULL, "missing pg_database entry for this database\n");
11074                 exit_nicely();
11075         }
11076         if (ntups > 1)
11077         {
11078                 write_msg(NULL, "found more than one pg_database entry for this database\n");
11079                 exit_nicely();
11080         }
11081         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
11082         PQclear(res);
11083         destroyPQExpBuffer(query);
11084         return last_oid;
11085 }
11086
11087 /*
11088  * findLastBuiltInOid -
11089  * find the last built in oid
11090  *
11091  * For 7.0, we do this by assuming that the last thing that initdb does is to
11092  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
11093  * initdb won't be changing anymore, it'll do.
11094  */
11095 static Oid
11096 findLastBuiltinOid_V70(void)
11097 {
11098         PGresult   *res;
11099         int                     ntups;
11100         int                     last_oid;
11101
11102         res = PQexec(g_conn,
11103                                  "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
11104         check_sql_result(res, g_conn,
11105                                          "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
11106                                          PGRES_TUPLES_OK);
11107         ntups = PQntuples(res);
11108         if (ntups < 1)
11109         {
11110                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
11111                 exit_nicely();
11112         }
11113         if (ntups > 1)
11114         {
11115                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
11116                 exit_nicely();
11117         }
11118         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
11119         PQclear(res);
11120         return last_oid;
11121 }
11122
11123 static void
11124 dumpSequence(Archive *fout, TableInfo *tbinfo)
11125 {
11126         PGresult   *res;
11127         char       *startv,
11128                            *last,
11129                            *incby,
11130                            *maxv = NULL,
11131                            *minv = NULL,
11132                            *cache;
11133         char            bufm[100],
11134                                 bufx[100];
11135         bool            cycled,
11136                                 called;
11137         PQExpBuffer query = createPQExpBuffer();
11138         PQExpBuffer delqry = createPQExpBuffer();
11139
11140         /* Make sure we are in proper schema */
11141         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
11142
11143         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
11144         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
11145
11146         if (g_fout->remoteVersion >= 80400)
11147         {
11148                 appendPQExpBuffer(query,
11149                                                   "SELECT sequence_name, "
11150                                                   "start_value, last_value, increment_by, "
11151                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
11152                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
11153                                                   "     ELSE max_value "
11154                                                   "END AS max_value, "
11155                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
11156                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
11157                                                   "     ELSE min_value "
11158                                                   "END AS min_value, "
11159                                                   "cache_value, is_cycled, is_called from %s",
11160                                                   bufx, bufm,
11161                                                   fmtId(tbinfo->dobj.name));
11162         }
11163         else
11164         {
11165                 appendPQExpBuffer(query,
11166                                                   "SELECT sequence_name, "
11167                                                   "0 AS start_value, last_value, increment_by, "
11168                                    "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
11169                                    "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
11170                                                   "     ELSE max_value "
11171                                                   "END AS max_value, "
11172                                         "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
11173                                    "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
11174                                                   "     ELSE min_value "
11175                                                   "END AS min_value, "
11176                                                   "cache_value, is_cycled, is_called from %s",
11177                                                   bufx, bufm,
11178                                                   fmtId(tbinfo->dobj.name));
11179         }
11180
11181         res = PQexec(g_conn, query->data);
11182         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11183
11184         if (PQntuples(res) != 1)
11185         {
11186                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
11187                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
11188                                                                  PQntuples(res)),
11189                                   tbinfo->dobj.name, PQntuples(res));
11190                 exit_nicely();
11191         }
11192
11193         /* Disable this check: it fails if sequence has been renamed */
11194 #ifdef NOT_USED
11195         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
11196         {
11197                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
11198                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
11199                 exit_nicely();
11200         }
11201 #endif
11202
11203         startv = PQgetvalue(res, 0, 1);
11204         last = PQgetvalue(res, 0, 2);
11205         incby = PQgetvalue(res, 0, 3);
11206         if (!PQgetisnull(res, 0, 4))
11207                 maxv = PQgetvalue(res, 0, 4);
11208         if (!PQgetisnull(res, 0, 5))
11209                 minv = PQgetvalue(res, 0, 5);
11210         cache = PQgetvalue(res, 0, 6);
11211         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
11212         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
11213
11214         /*
11215          * The logic we use for restoring sequences is as follows:
11216          *
11217          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
11218          * last_val for start if called is false, else use min_val for start_val).
11219          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
11220          * BY command for it.
11221          *
11222          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
11223          */
11224         if (!dataOnly)
11225         {
11226                 resetPQExpBuffer(delqry);
11227
11228                 /*
11229                  * DROP must be fully qualified in case same name appears in
11230                  * pg_catalog
11231                  */
11232                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
11233                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
11234                 appendPQExpBuffer(delqry, "%s;\n",
11235                                                   fmtId(tbinfo->dobj.name));
11236
11237                 resetPQExpBuffer(query);
11238                 appendPQExpBuffer(query,
11239                                                   "CREATE SEQUENCE %s\n",
11240                                                   fmtId(tbinfo->dobj.name));
11241
11242                 if (g_fout->remoteVersion >= 80400)
11243                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
11244                 else
11245                 {
11246                         /*
11247                          * Versions before 8.4 did not remember the true start value.  If
11248                          * is_called is false then the sequence has never been incremented
11249                          * so we can use last_val.      Otherwise punt and let it default.
11250                          */
11251                         if (!called)
11252                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
11253                 }
11254
11255                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
11256
11257                 if (minv)
11258                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
11259                 else
11260                         appendPQExpBuffer(query, "    NO MINVALUE\n");
11261
11262                 if (maxv)
11263                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
11264                 else
11265                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
11266
11267                 appendPQExpBuffer(query,
11268                                                   "    CACHE %s%s",
11269                                                   cache, (cycled ? "\n    CYCLE" : ""));
11270
11271                 appendPQExpBuffer(query, ";\n");
11272
11273                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
11274                                          tbinfo->dobj.name,
11275                                          tbinfo->dobj.namespace->dobj.name,
11276                                          NULL,
11277                                          tbinfo->rolname,
11278                                          false, "SEQUENCE", SECTION_PRE_DATA,
11279                                          query->data, delqry->data, NULL,
11280                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
11281                                          NULL, NULL);
11282
11283                 /*
11284                  * If the sequence is owned by a table column, emit the ALTER for it
11285                  * as a separate TOC entry immediately following the sequence's own
11286                  * entry.  It's OK to do this rather than using full sorting logic,
11287                  * because the dependency that tells us it's owned will have forced
11288                  * the table to be created first.  We can't just include the ALTER in
11289                  * the TOC entry because it will fail if we haven't reassigned the
11290                  * sequence owner to match the table's owner.
11291                  *
11292                  * We need not schema-qualify the table reference because both
11293                  * sequence and table must be in the same schema.
11294                  */
11295                 if (OidIsValid(tbinfo->owning_tab))
11296                 {
11297                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
11298
11299                         if (owning_tab && owning_tab->dobj.dump)
11300                         {
11301                                 resetPQExpBuffer(query);
11302                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
11303                                                                   fmtId(tbinfo->dobj.name));
11304                                 appendPQExpBuffer(query, " OWNED BY %s",
11305                                                                   fmtId(owning_tab->dobj.name));
11306                                 appendPQExpBuffer(query, ".%s;\n",
11307                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
11308
11309                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11310                                                          tbinfo->dobj.name,
11311                                                          tbinfo->dobj.namespace->dobj.name,
11312                                                          NULL,
11313                                                          tbinfo->rolname,
11314                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
11315                                                          query->data, "", NULL,
11316                                                          &(tbinfo->dobj.dumpId), 1,
11317                                                          NULL, NULL);
11318                         }
11319                 }
11320
11321                 /* Dump Sequence Comments */
11322                 resetPQExpBuffer(query);
11323                 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
11324                 dumpComment(fout, query->data,
11325                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
11326                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
11327         }
11328
11329         if (!schemaOnly)
11330         {
11331                 resetPQExpBuffer(query);
11332                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
11333                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
11334                 appendPQExpBuffer(query, ", %s, %s);\n",
11335                                                   last, (called ? "true" : "false"));
11336
11337                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
11338                                          tbinfo->dobj.name,
11339                                          tbinfo->dobj.namespace->dobj.name,
11340                                          NULL,
11341                                          tbinfo->rolname,
11342                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
11343                                          query->data, "", NULL,
11344                                          &(tbinfo->dobj.dumpId), 1,
11345                                          NULL, NULL);
11346         }
11347
11348         PQclear(res);
11349
11350         destroyPQExpBuffer(query);
11351         destroyPQExpBuffer(delqry);
11352 }
11353
11354 static void
11355 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
11356 {
11357         TableInfo  *tbinfo = tginfo->tgtable;
11358         PQExpBuffer query;
11359         PQExpBuffer delqry;
11360         char       *tgargs;
11361         size_t          lentgargs;
11362         const char *p;
11363         int                     findx;
11364
11365         if (dataOnly)
11366                 return;
11367
11368         query = createPQExpBuffer();
11369         delqry = createPQExpBuffer();
11370
11371         /*
11372          * DROP must be fully qualified in case same name appears in pg_catalog
11373          */
11374         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
11375                                           fmtId(tginfo->dobj.name));
11376         appendPQExpBuffer(delqry, "ON %s.",
11377                                           fmtId(tbinfo->dobj.namespace->dobj.name));
11378         appendPQExpBuffer(delqry, "%s;\n",
11379                                           fmtId(tbinfo->dobj.name));
11380
11381         if (tginfo->tgdef)
11382         {
11383                 appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
11384         }
11385         else
11386         {
11387                 if (tginfo->tgisconstraint)
11388                 {
11389                         appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
11390                         appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
11391                 }
11392                 else
11393                 {
11394                         appendPQExpBuffer(query, "CREATE TRIGGER ");
11395                         appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
11396                 }
11397                 appendPQExpBuffer(query, "\n    ");
11398
11399                 /* Trigger type */
11400                 findx = 0;
11401                 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
11402                         appendPQExpBuffer(query, "BEFORE");
11403                 else
11404                         appendPQExpBuffer(query, "AFTER");
11405                 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
11406                 {
11407                         appendPQExpBuffer(query, " INSERT");
11408                         findx++;
11409                 }
11410                 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
11411                 {
11412                         if (findx > 0)
11413                                 appendPQExpBuffer(query, " OR DELETE");
11414                         else
11415                                 appendPQExpBuffer(query, " DELETE");
11416                         findx++;
11417                 }
11418                 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
11419                 {
11420                         if (findx > 0)
11421                                 appendPQExpBuffer(query, " OR UPDATE");
11422                         else
11423                                 appendPQExpBuffer(query, " UPDATE");
11424                         findx++;
11425                 }
11426                 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
11427                 {
11428                         if (findx > 0)
11429                                 appendPQExpBuffer(query, " OR TRUNCATE");
11430                         else
11431                                 appendPQExpBuffer(query, " TRUNCATE");
11432                         findx++;
11433                 }
11434                 appendPQExpBuffer(query, " ON %s\n",
11435                                                   fmtId(tbinfo->dobj.name));
11436
11437                 if (tginfo->tgisconstraint)
11438                 {
11439                         if (OidIsValid(tginfo->tgconstrrelid))
11440                         {
11441                                 /* If we are using regclass, name is already quoted */
11442                                 if (g_fout->remoteVersion >= 70300)
11443                                         appendPQExpBuffer(query, "    FROM %s\n    ",
11444                                                                           tginfo->tgconstrrelname);
11445                                 else
11446                                         appendPQExpBuffer(query, "    FROM %s\n    ",
11447                                                                           fmtId(tginfo->tgconstrrelname));
11448                         }
11449                         if (!tginfo->tgdeferrable)
11450                                 appendPQExpBuffer(query, "NOT ");
11451                         appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
11452                         if (tginfo->tginitdeferred)
11453                                 appendPQExpBuffer(query, "DEFERRED\n");
11454                         else
11455                                 appendPQExpBuffer(query, "IMMEDIATE\n");
11456                 }
11457
11458                 if (TRIGGER_FOR_ROW(tginfo->tgtype))
11459                         appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
11460                 else
11461                         appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
11462
11463                 /* In 7.3, result of regproc is already quoted */
11464                 if (g_fout->remoteVersion >= 70300)
11465                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
11466                                                           tginfo->tgfname);
11467                 else
11468                         appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
11469                                                           fmtId(tginfo->tgfname));
11470
11471                 tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
11472                                                                                   &lentgargs);
11473                 p = tgargs;
11474                 for (findx = 0; findx < tginfo->tgnargs; findx++)
11475                 {
11476                         /* find the embedded null that terminates this trigger argument */
11477                         size_t  tlen = strlen(p);
11478
11479                         if (p + tlen >= tgargs + lentgargs)
11480                         {
11481                                 /* hm, not found before end of bytea value... */
11482                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
11483                                                   tginfo->tgargs,
11484                                                   tginfo->dobj.name,
11485                                                   tbinfo->dobj.name);
11486                                 exit_nicely();
11487                         }
11488
11489                         if (findx > 0)
11490                                 appendPQExpBuffer(query, ", ");
11491                         appendStringLiteralAH(query, p, fout);
11492                         p += tlen + 1;
11493                 }
11494                 free(tgargs);
11495                 appendPQExpBuffer(query, ");\n");
11496         }
11497
11498         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
11499         {
11500                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
11501                                                   fmtId(tbinfo->dobj.name));
11502                 switch (tginfo->tgenabled)
11503                 {
11504                         case 'D':
11505                         case 'f':
11506                                 appendPQExpBuffer(query, "DISABLE");
11507                                 break;
11508                         case 'A':
11509                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
11510                                 break;
11511                         case 'R':
11512                                 appendPQExpBuffer(query, "ENABLE REPLICA");
11513                                 break;
11514                         default:
11515                                 appendPQExpBuffer(query, "ENABLE");
11516                                 break;
11517                 }
11518                 appendPQExpBuffer(query, " TRIGGER %s;\n",
11519                                                   fmtId(tginfo->dobj.name));
11520         }
11521
11522         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
11523                                  tginfo->dobj.name,
11524                                  tbinfo->dobj.namespace->dobj.name,
11525                                  NULL,
11526                                  tbinfo->rolname, false,
11527                                  "TRIGGER", SECTION_POST_DATA,
11528                                  query->data, delqry->data, NULL,
11529                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
11530                                  NULL, NULL);
11531
11532         resetPQExpBuffer(query);
11533         appendPQExpBuffer(query, "TRIGGER %s ",
11534                                           fmtId(tginfo->dobj.name));
11535         appendPQExpBuffer(query, "ON %s",
11536                                           fmtId(tbinfo->dobj.name));
11537
11538         dumpComment(fout, query->data,
11539                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
11540                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
11541
11542         destroyPQExpBuffer(query);
11543         destroyPQExpBuffer(delqry);
11544 }
11545
11546 /*
11547  * dumpRule
11548  *              Dump a rule
11549  */
11550 static void
11551 dumpRule(Archive *fout, RuleInfo *rinfo)
11552 {
11553         TableInfo  *tbinfo = rinfo->ruletable;
11554         PQExpBuffer query;
11555         PQExpBuffer cmd;
11556         PQExpBuffer delcmd;
11557         PGresult   *res;
11558
11559         /* Skip if not to be dumped */
11560         if (!rinfo->dobj.dump || dataOnly)
11561                 return;
11562
11563         /*
11564          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
11565          * we do not want to dump it as a separate object.
11566          */
11567         if (!rinfo->separate)
11568                 return;
11569
11570         /*
11571          * Make sure we are in proper schema.
11572          */
11573         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
11574
11575         query = createPQExpBuffer();
11576         cmd = createPQExpBuffer();
11577         delcmd = createPQExpBuffer();
11578
11579         if (g_fout->remoteVersion >= 70300)
11580         {
11581                 appendPQExpBuffer(query,
11582                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
11583                                                   rinfo->dobj.catId.oid);
11584         }
11585         else
11586         {
11587                 /* Rule name was unique before 7.3 ... */
11588                 appendPQExpBuffer(query,
11589                                                   "SELECT pg_get_ruledef('%s') AS definition",
11590                                                   rinfo->dobj.name);
11591         }
11592
11593         res = PQexec(g_conn, query->data);
11594         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11595
11596         if (PQntuples(res) != 1)
11597         {
11598                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
11599                                   rinfo->dobj.name, tbinfo->dobj.name);
11600                 exit_nicely();
11601         }
11602
11603         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
11604
11605         /*
11606          * Add the command to alter the rules replication firing semantics if it
11607          * differs from the default.
11608          */
11609         if (rinfo->ev_enabled != 'O')
11610         {
11611                 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
11612                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
11613                 appendPQExpBuffer(cmd, "%s ",
11614                                                   fmtId(tbinfo->dobj.name));
11615                 switch (rinfo->ev_enabled)
11616                 {
11617                         case 'A':
11618                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
11619                                                                   fmtId(rinfo->dobj.name));
11620                                 break;
11621                         case 'R':
11622                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
11623                                                                   fmtId(rinfo->dobj.name));
11624                                 break;
11625                         case 'D':
11626                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
11627                                                                   fmtId(rinfo->dobj.name));
11628                                 break;
11629                 }
11630         }
11631
11632         /*
11633          * DROP must be fully qualified in case same name appears in pg_catalog
11634          */
11635         appendPQExpBuffer(delcmd, "DROP RULE %s ",
11636                                           fmtId(rinfo->dobj.name));
11637         appendPQExpBuffer(delcmd, "ON %s.",
11638                                           fmtId(tbinfo->dobj.namespace->dobj.name));
11639         appendPQExpBuffer(delcmd, "%s;\n",
11640                                           fmtId(tbinfo->dobj.name));
11641
11642         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
11643                                  rinfo->dobj.name,
11644                                  tbinfo->dobj.namespace->dobj.name,
11645                                  NULL,
11646                                  tbinfo->rolname, false,
11647                                  "RULE", SECTION_POST_DATA,
11648                                  cmd->data, delcmd->data, NULL,
11649                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
11650                                  NULL, NULL);
11651
11652         /* Dump rule comments */
11653         resetPQExpBuffer(query);
11654         appendPQExpBuffer(query, "RULE %s",
11655                                           fmtId(rinfo->dobj.name));
11656         appendPQExpBuffer(query, " ON %s",
11657                                           fmtId(tbinfo->dobj.name));
11658         dumpComment(fout, query->data,
11659                                 tbinfo->dobj.namespace->dobj.name,
11660                                 tbinfo->rolname,
11661                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11662
11663         PQclear(res);
11664
11665         destroyPQExpBuffer(query);
11666         destroyPQExpBuffer(cmd);
11667         destroyPQExpBuffer(delcmd);
11668 }
11669
11670 /*
11671  * getDependencies --- obtain available dependency data
11672  */
11673 static void
11674 getDependencies(void)
11675 {
11676         PQExpBuffer query;
11677         PGresult   *res;
11678         int                     ntups,
11679                                 i;
11680         int                     i_classid,
11681                                 i_objid,
11682                                 i_refclassid,
11683                                 i_refobjid,
11684                                 i_deptype;
11685         DumpableObject *dobj,
11686                            *refdobj;
11687
11688         /* No dependency info available before 7.3 */
11689         if (g_fout->remoteVersion < 70300)
11690                 return;
11691
11692         if (g_verbose)
11693                 write_msg(NULL, "reading dependency data\n");
11694
11695         /* Make sure we are in proper schema */
11696         selectSourceSchema("pg_catalog");
11697
11698         query = createPQExpBuffer();
11699
11700         appendPQExpBuffer(query, "SELECT "
11701                                           "classid, objid, refclassid, refobjid, deptype "
11702                                           "FROM pg_depend "
11703                                           "WHERE deptype != 'p' "
11704                                           "ORDER BY 1,2");
11705
11706         res = PQexec(g_conn, query->data);
11707         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11708
11709         ntups = PQntuples(res);
11710
11711         i_classid = PQfnumber(res, "classid");
11712         i_objid = PQfnumber(res, "objid");
11713         i_refclassid = PQfnumber(res, "refclassid");
11714         i_refobjid = PQfnumber(res, "refobjid");
11715         i_deptype = PQfnumber(res, "deptype");
11716
11717         /*
11718          * Since we ordered the SELECT by referencing ID, we can expect that
11719          * multiple entries for the same object will appear together; this saves
11720          * on searches.
11721          */
11722         dobj = NULL;
11723
11724         for (i = 0; i < ntups; i++)
11725         {
11726                 CatalogId       objId;
11727                 CatalogId       refobjId;
11728                 char            deptype;
11729
11730                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
11731                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
11732                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
11733                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
11734                 deptype = *(PQgetvalue(res, i, i_deptype));
11735
11736                 if (dobj == NULL ||
11737                         dobj->catId.tableoid != objId.tableoid ||
11738                         dobj->catId.oid != objId.oid)
11739                         dobj = findObjectByCatalogId(objId);
11740
11741                 /*
11742                  * Failure to find objects mentioned in pg_depend is not unexpected,
11743                  * since for example we don't collect info about TOAST tables.
11744                  */
11745                 if (dobj == NULL)
11746                 {
11747 #ifdef NOT_USED
11748                         fprintf(stderr, "no referencing object %u %u\n",
11749                                         objId.tableoid, objId.oid);
11750 #endif
11751                         continue;
11752                 }
11753
11754                 refdobj = findObjectByCatalogId(refobjId);
11755
11756                 if (refdobj == NULL)
11757                 {
11758 #ifdef NOT_USED
11759                         fprintf(stderr, "no referenced object %u %u\n",
11760                                         refobjId.tableoid, refobjId.oid);
11761 #endif
11762                         continue;
11763                 }
11764
11765                 /*
11766                  * Ordinarily, table rowtypes have implicit dependencies on their
11767                  * tables.      However, for a composite type the implicit dependency goes
11768                  * the other way in pg_depend; which is the right thing for DROP but
11769                  * it doesn't produce the dependency ordering we need. So in that one
11770                  * case, we reverse the direction of the dependency.
11771                  */
11772                 if (deptype == 'i' &&
11773                         dobj->objType == DO_TABLE &&
11774                         refdobj->objType == DO_TYPE)
11775                         addObjectDependency(refdobj, dobj->dumpId);
11776                 else
11777                         /* normal case */
11778                         addObjectDependency(dobj, refdobj->dumpId);
11779         }
11780
11781         PQclear(res);
11782
11783         destroyPQExpBuffer(query);
11784 }
11785
11786
11787 /*
11788  * selectSourceSchema - make the specified schema the active search path
11789  * in the source database.
11790  *
11791  * NB: pg_catalog is explicitly searched after the specified schema;
11792  * so user names are only qualified if they are cross-schema references,
11793  * and system names are only qualified if they conflict with a user name
11794  * in the current schema.
11795  *
11796  * Whenever the selected schema is not pg_catalog, be careful to qualify
11797  * references to system catalogs and types in our emitted commands!
11798  */
11799 static void
11800 selectSourceSchema(const char *schemaName)
11801 {
11802         static char *curSchemaName = NULL;
11803         PQExpBuffer query;
11804
11805         /* Not relevant if fetching from pre-7.3 DB */
11806         if (g_fout->remoteVersion < 70300)
11807                 return;
11808         /* Ignore null schema names */
11809         if (schemaName == NULL || *schemaName == '\0')
11810                 return;
11811         /* Optimize away repeated selection of same schema */
11812         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
11813                 return;
11814
11815         query = createPQExpBuffer();
11816         appendPQExpBuffer(query, "SET search_path = %s",
11817                                           fmtId(schemaName));
11818         if (strcmp(schemaName, "pg_catalog") != 0)
11819                 appendPQExpBuffer(query, ", pg_catalog");
11820
11821         do_sql_command(g_conn, query->data);
11822
11823         destroyPQExpBuffer(query);
11824         if (curSchemaName)
11825                 free(curSchemaName);
11826         curSchemaName = strdup(schemaName);
11827 }
11828
11829 /*
11830  * getFormattedTypeName - retrieve a nicely-formatted type name for the
11831  * given type name.
11832  *
11833  * NB: in 7.3 and up the result may depend on the currently-selected
11834  * schema; this is why we don't try to cache the names.
11835  */
11836 static char *
11837 getFormattedTypeName(Oid oid, OidOptions opts)
11838 {
11839         char       *result;
11840         PQExpBuffer query;
11841         PGresult   *res;
11842         int                     ntups;
11843
11844         if (oid == 0)
11845         {
11846                 if ((opts & zeroAsOpaque) != 0)
11847                         return strdup(g_opaque_type);
11848                 else if ((opts & zeroAsAny) != 0)
11849                         return strdup("'any'");
11850                 else if ((opts & zeroAsStar) != 0)
11851                         return strdup("*");
11852                 else if ((opts & zeroAsNone) != 0)
11853                         return strdup("NONE");
11854         }
11855
11856         query = createPQExpBuffer();
11857         if (g_fout->remoteVersion >= 70300)
11858         {
11859                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11860                                                   oid);
11861         }
11862         else if (g_fout->remoteVersion >= 70100)
11863         {
11864                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11865                                                   oid);
11866         }
11867         else
11868         {
11869                 appendPQExpBuffer(query, "SELECT typname "
11870                                                   "FROM pg_type "
11871                                                   "WHERE oid = '%u'::oid",
11872                                                   oid);
11873         }
11874
11875         res = PQexec(g_conn, query->data);
11876         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11877
11878         /* Expecting a single result only */
11879         ntups = PQntuples(res);
11880         if (ntups != 1)
11881         {
11882                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11883                                                            "query returned %d rows instead of one: %s\n",
11884                                                                  ntups),
11885                                   ntups, query->data);
11886                 exit_nicely();
11887         }
11888
11889         if (g_fout->remoteVersion >= 70100)
11890         {
11891                 /* already quoted */
11892                 result = strdup(PQgetvalue(res, 0, 0));
11893         }
11894         else
11895         {
11896                 /* may need to quote it */
11897                 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11898         }
11899
11900         PQclear(res);
11901         destroyPQExpBuffer(query);
11902
11903         return result;
11904 }
11905
11906 /*
11907  * myFormatType --- local implementation of format_type for use with 7.0.
11908  */
11909 static char *
11910 myFormatType(const char *typname, int32 typmod)
11911 {
11912         char       *result;
11913         bool            isarray = false;
11914         PQExpBuffer buf = createPQExpBuffer();
11915
11916         /* Handle array types */
11917         if (typname[0] == '_')
11918         {
11919                 isarray = true;
11920                 typname++;
11921         }
11922
11923         /* Show lengths on bpchar and varchar */
11924         if (!strcmp(typname, "bpchar"))
11925         {
11926                 int                     len = (typmod - VARHDRSZ);
11927
11928                 appendPQExpBuffer(buf, "character");
11929                 if (len > 1)
11930                         appendPQExpBuffer(buf, "(%d)",
11931                                                           typmod - VARHDRSZ);
11932         }
11933         else if (!strcmp(typname, "varchar"))
11934         {
11935                 appendPQExpBuffer(buf, "character varying");
11936                 if (typmod != -1)
11937                         appendPQExpBuffer(buf, "(%d)",
11938                                                           typmod - VARHDRSZ);
11939         }
11940         else if (!strcmp(typname, "numeric"))
11941         {
11942                 appendPQExpBuffer(buf, "numeric");
11943                 if (typmod != -1)
11944                 {
11945                         int32           tmp_typmod;
11946                         int                     precision;
11947                         int                     scale;
11948
11949                         tmp_typmod = typmod - VARHDRSZ;
11950                         precision = (tmp_typmod >> 16) & 0xffff;
11951                         scale = tmp_typmod & 0xffff;
11952                         appendPQExpBuffer(buf, "(%d,%d)",
11953                                                           precision, scale);
11954                 }
11955         }
11956
11957         /*
11958          * char is an internal single-byte data type; Let's make sure we force it
11959          * through with quotes. - thomas 1998-12-13
11960          */
11961         else if (strcmp(typname, "char") == 0)
11962                 appendPQExpBuffer(buf, "\"char\"");
11963         else
11964                 appendPQExpBuffer(buf, "%s", fmtId(typname));
11965
11966         /* Append array qualifier for array types */
11967         if (isarray)
11968                 appendPQExpBuffer(buf, "[]");
11969
11970         result = strdup(buf->data);
11971         destroyPQExpBuffer(buf);
11972
11973         return result;
11974 }
11975
11976 /*
11977  * fmtQualifiedId - convert a qualified name to the proper format for
11978  * the source database.
11979  *
11980  * Like fmtId, use the result before calling again.
11981  */
11982 static const char *
11983 fmtQualifiedId(const char *schema, const char *id)
11984 {
11985         static PQExpBuffer id_return = NULL;
11986
11987         if (id_return)                          /* first time through? */
11988                 resetPQExpBuffer(id_return);
11989         else
11990                 id_return = createPQExpBuffer();
11991
11992         /* Suppress schema name if fetching from pre-7.3 DB */
11993         if (g_fout->remoteVersion >= 70300 && schema && *schema)
11994         {
11995                 appendPQExpBuffer(id_return, "%s.",
11996                                                   fmtId(schema));
11997         }
11998         appendPQExpBuffer(id_return, "%s",
11999                                           fmtId(id));
12000
12001         return id_return->data;
12002 }
12003
12004 /*
12005  * Return a column list clause for the given relation.
12006  *
12007  * Special case: if there are no undropped columns in the relation, return
12008  * "", not an invalid "()" column list.
12009  */
12010 static const char *
12011 fmtCopyColumnList(const TableInfo *ti)
12012 {
12013         static PQExpBuffer q = NULL;
12014         int                     numatts = ti->numatts;
12015         char      **attnames = ti->attnames;
12016         bool       *attisdropped = ti->attisdropped;
12017         bool            needComma;
12018         int                     i;
12019
12020         if (q)                                          /* first time through? */
12021                 resetPQExpBuffer(q);
12022         else
12023                 q = createPQExpBuffer();
12024
12025         appendPQExpBuffer(q, "(");
12026         needComma = false;
12027         for (i = 0; i < numatts; i++)
12028         {
12029                 if (attisdropped[i])
12030                         continue;
12031                 if (needComma)
12032                         appendPQExpBuffer(q, ", ");
12033                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
12034                 needComma = true;
12035         }
12036
12037         if (!needComma)
12038                 return "";                              /* no undropped columns */
12039
12040         appendPQExpBuffer(q, ")");
12041         return q->data;
12042 }
12043
12044 /*
12045  * Convenience subroutine to execute a SQL command and check for
12046  * COMMAND_OK status.
12047  */
12048 static void
12049 do_sql_command(PGconn *conn, const char *query)
12050 {
12051         PGresult   *res;
12052
12053         res = PQexec(conn, query);
12054         check_sql_result(res, conn, query, PGRES_COMMAND_OK);
12055         PQclear(res);
12056 }
12057
12058 /*
12059  * Convenience subroutine to verify a SQL command succeeded,
12060  * and exit with a useful error message if not.
12061  */
12062 static void
12063 check_sql_result(PGresult *res, PGconn *conn, const char *query,
12064                                  ExecStatusType expected)
12065 {
12066         const char *err;
12067
12068         if (res && PQresultStatus(res) == expected)
12069                 return;                                 /* A-OK */
12070
12071         write_msg(NULL, "SQL command failed\n");
12072         if (res)
12073                 err = PQresultErrorMessage(res);
12074         else
12075                 err = PQerrorMessage(conn);
12076         write_msg(NULL, "Error message from server: %s", err);
12077         write_msg(NULL, "The command was: %s\n", query);
12078         exit_nicely();
12079 }