]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Add PGETC (for pg_service.conf) and PGLOCALE (for locale dir)
[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-2003, 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.373 2004/06/03 00:07:36 momjian Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 /*
21  * Although this is not a backend module, we must include postgres.h anyway
22  * so that we can include a bunch of backend include files.  pg_dump has
23  * never pretended to be very independent of the backend anyhow ...
24  */
25 #include "postgres.h"
26
27 #include <unistd.h>
28 #include <ctype.h>
29 #ifdef ENABLE_NLS
30 #include <locale.h>
31 #endif
32 #ifdef HAVE_TERMIOS_H
33 #include <termios.h>
34 #endif
35
36 #ifndef HAVE_STRDUP
37 #include "strdup.h"
38 #endif
39
40 #include "getopt_long.h"
41
42 #ifndef HAVE_OPTRESET
43 int                     optreset;
44 #endif
45
46 #include "access/attnum.h"
47 #include "access/htup.h"
48 #include "catalog/pg_class.h"
49 #include "catalog/pg_proc.h"
50 #include "catalog/pg_trigger.h"
51 #include "catalog/pg_type.h"
52
53 #include "commands/sequence.h"
54
55 #include "libpq-fe.h"
56 #include "libpq/libpq-fs.h"
57
58 #include "pg_dump.h"
59 #include "pg_backup.h"
60 #include "pg_backup_archiver.h"
61 #include "dumputils.h"
62
63 #define _(x) gettext((x))
64
65 extern char *optarg;
66 extern int      optind,
67                         opterr;
68
69
70 typedef struct
71 {
72         const char *descr;                      /* comment for an object */
73         Oid                     classoid;               /* object class (catalog OID) */
74         Oid                     objoid;                 /* object OID */
75         int                     objsubid;               /* subobject (table column #) */
76 } CommentItem;
77
78
79 /* global decls */
80 bool            g_verbose;                      /* User wants verbose narration of our
81                                                                  * activities. */
82 Archive    *g_fout;                             /* the script file */
83 PGconn     *g_conn;                             /* the database connection */
84
85 /* various user-settable parameters */
86 bool            dumpInserts;            /* dump data using proper insert strings */
87 bool            attrNames;                      /* put attr names into insert strings */
88 bool            schemaOnly;
89 bool            dataOnly;
90 bool            aclsSkip;
91
92 /* obsolete as of 7.3: */
93 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
94
95 static char *selectTableName = NULL;    /* name of a single table to dump */
96 static char *selectSchemaName = NULL;   /* name of a single schema to dump */
97
98 char            g_opaque_type[10];      /* name for the opaque type */
99
100 /* placeholders for the delimiters for comments */
101 char            g_comment_start[10];
102 char            g_comment_end[10];
103
104 static const CatalogId nilCatalogId = { 0, 0 };
105
106 /* these are to avoid passing around info for findNamespace() */
107 static NamespaceInfo *g_namespaces;
108 static int      g_numNamespaces;
109
110 /* flag to turn on/off dollar quoting */
111 static int     disable_dollar_quoting = 0;
112
113
114 static void help(const char *progname);
115 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
116 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
117 static void dumpComment(Archive *fout, const char *target,
118                         const char *namespace, const char *owner,
119                         CatalogId catalogId, int subid, DumpId dumpId);
120 static int      findComments(Archive *fout, Oid classoid, Oid objoid,
121                                                  CommentItem **items);
122 static int      collectComments(Archive *fout, CommentItem **items);
123 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
124 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
125 static void dumpType(Archive *fout, TypeInfo *tinfo);
126 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
127 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
128 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
129 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
130 static void dumpFunc(Archive *fout, FuncInfo *finfo);
131 static void dumpCast(Archive *fout, CastInfo *cast);
132 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
133 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
134 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
135 static void dumpRule(Archive *fout, RuleInfo *rinfo);
136 static void dumpAgg(Archive *fout, AggInfo *agginfo);
137 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
138 static void dumpTable(Archive *fout, TableInfo *tbinfo);
139 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
140 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
141 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
142 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
143 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
144
145 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
146                 const char *type, const char *name,
147                 const char *tag, const char *nspname, const char *owner,
148                 const char *acls);
149
150 static void getDependencies(void);
151 static void getDomainConstraints(TypeInfo *tinfo);
152 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
153 static char *format_function_signature(FuncInfo *finfo, char **argnames,
154                                                                            bool honor_quotes);
155 static const char *convertRegProcReference(const char *proc);
156 static const char *convertOperatorReference(const char *opr);
157 static Oid      findLastBuiltinOid_V71(const char *);
158 static Oid      findLastBuiltinOid_V70(void);
159 static void setMaxOid(Archive *fout);
160 static void selectSourceSchema(const char *schemaName);
161 static char *getFormattedTypeName(Oid oid, OidOptions opts);
162 static char *myFormatType(const char *typname, int32 typmod);
163 static const char *fmtQualifiedId(const char *schema, const char *id);
164 static int      dumpBlobs(Archive *AH, void *arg);
165 static void dumpDatabase(Archive *AH);
166 static void dumpEncoding(Archive *AH);
167 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
168 static const char *fmtCopyColumnList(const TableInfo *ti);
169 static void do_sql_command(PGconn *conn, const char *query);
170 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
171                                                          ExecStatusType expected);
172
173
174 int
175 main(int argc, char **argv)
176 {
177         int                     c;
178         const char *filename = NULL;
179         const char *format = "p";
180         const char *dbname = NULL;
181         const char *pghost = NULL;
182         const char *pgport = NULL;
183         const char *username = NULL;
184         bool            oids = false;
185         TableInfo  *tblinfo;
186         int                     numTables;
187         DumpableObject **dobjs;
188         int                     numObjs;
189         int                     i;
190         bool            force_password = false;
191         int                     compressLevel = -1;
192         bool            ignore_version = false;
193         int                     plainText = 0;
194         int                     outputClean = 0;
195         int                     outputCreate = 0;
196         int                     outputBlobs = 0;
197         int                     outputNoOwner = 0;
198         static int      use_setsessauth = 0;
199         static int      disable_triggers = 0;
200         char       *outputSuperuser = NULL;
201
202         RestoreOptions *ropt;
203
204         static struct option long_options[] = {
205                 {"data-only", no_argument, NULL, 'a'},
206                 {"blobs", no_argument, NULL, 'b'},
207                 {"clean", no_argument, NULL, 'c'},
208                 {"create", no_argument, NULL, 'C'},
209                 {"file", required_argument, NULL, 'f'},
210                 {"format", required_argument, NULL, 'F'},
211                 {"inserts", no_argument, NULL, 'd'},
212                 {"attribute-inserts", no_argument, NULL, 'D'},
213                 {"column-inserts", no_argument, NULL, 'D'},
214                 {"host", required_argument, NULL, 'h'},
215                 {"ignore-version", no_argument, NULL, 'i'},
216                 {"no-reconnect", no_argument, NULL, 'R'},
217                 {"oids", no_argument, NULL, 'o'},
218                 {"no-owner", no_argument, NULL, 'O'},
219                 {"port", required_argument, NULL, 'p'},
220                 {"schema", required_argument, NULL, 'n'},
221                 {"schema-only", no_argument, NULL, 's'},
222                 {"superuser", required_argument, NULL, 'S'},
223                 {"table", required_argument, NULL, 't'},
224                 {"password", no_argument, NULL, 'W'},
225                 {"username", required_argument, NULL, 'U'},
226                 {"verbose", no_argument, NULL, 'v'},
227                 {"no-privileges", no_argument, NULL, 'x'},
228                 {"no-acl", no_argument, NULL, 'x'},
229                 {"compress", required_argument, NULL, 'Z'},
230                 {"help", no_argument, NULL, '?'},
231                 {"version", no_argument, NULL, 'V'},
232
233                 /*
234                  * the following options don't have an equivalent short option
235                  * letter, but are available as '-X long-name'
236                  */
237                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
238                 {"disable-triggers", no_argument, &disable_triggers, 1},
239                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
240
241                 {NULL, 0, NULL, 0}
242         };
243         int                     optindex;
244
245         set_pglocale_pgservice(argv[0], "pg_dump");
246
247         g_verbose = false;
248
249         strcpy(g_comment_start, "-- ");
250         g_comment_end[0] = '\0';
251         strcpy(g_opaque_type, "opaque");
252
253         dataOnly = schemaOnly = dumpInserts = attrNames = false;
254
255         progname = get_progname(argv[0]);
256
257         /* Set default options based on progname */
258         if (strcmp(progname, "pg_backup") == 0)
259         {
260                 format = "c";
261                 outputBlobs = true;
262         }
263
264         if (argc > 1)
265         {
266                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
267                 {
268                         help(progname);
269                         exit(0);
270                 }
271                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
272                 {
273                         puts("pg_dump (PostgreSQL) " PG_VERSION);
274                         exit(0);
275                 }
276         }
277
278         while ((c = getopt_long(argc, argv, "abcCdDf:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
279                                                         long_options, &optindex)) != -1)
280         {
281                 switch (c)
282                 {
283                         case 'a':                       /* Dump data only */
284                                 dataOnly = true;
285                                 break;
286
287                         case 'b':                       /* Dump blobs */
288                                 outputBlobs = true;
289                                 break;
290
291                         case 'c':                       /* clean (i.e., drop) schema prior to
292                                                                  * create */
293                                 outputClean = 1;
294                                 break;
295
296                         case 'C':                       /* Create DB */
297                                 outputCreate = 1;
298                                 break;
299
300                         case 'd':                       /* dump data as proper insert strings */
301                                 dumpInserts = true;
302                                 break;
303
304                         case 'D':                       /* dump data as proper insert strings with
305                                                                  * attr names */
306                                 dumpInserts = true;
307                                 attrNames = true;
308                                 break;
309
310                         case 'f':
311                                 filename = optarg;
312                                 break;
313
314                         case 'F':
315                                 format = optarg;
316                                 break;
317
318                         case 'h':                       /* server host */
319                                 pghost = optarg;
320                                 break;
321
322                         case 'i':                       /* ignore database version mismatch */
323                                 ignore_version = true;
324                                 break;
325
326                         case 'n':                       /* Dump data for this schema only */
327                                 selectSchemaName = strdup(optarg);
328                                 break;
329
330                         case 'o':                       /* Dump oids */
331                                 oids = true;
332                                 break;
333
334                         case 'O':                       /* Don't reconnect to match owner */
335                                 outputNoOwner = 1;
336                                 break;
337
338                         case 'p':                       /* server port */
339                                 pgport = optarg;
340                                 break;
341
342                         case 'R':
343                                 /* no-op, still accepted for backwards compatibility */
344                                 break;
345
346                         case 's':                       /* dump schema only */
347                                 schemaOnly = true;
348                                 break;
349
350                         case 'S':                       /* Username for superuser in plain text
351                                                                  * output */
352                                 outputSuperuser = strdup(optarg);
353                                 break;
354
355                         case 't':                       /* Dump data for this table only */
356                                 selectTableName = strdup(optarg);
357                                 break;
358
359                         case 'u':
360                                 force_password = true;
361                                 username = simple_prompt("User name: ", 100, true);
362                                 break;
363
364                         case 'U':
365                                 username = optarg;
366                                 break;
367
368                         case 'v':                       /* verbose */
369                                 g_verbose = true;
370                                 break;
371
372                         case 'W':
373                                 force_password = true;
374                                 break;
375
376                         case 'x':                       /* skip ACL dump */
377                                 aclsSkip = true;
378                                 break;
379
380                                 /*
381                                  * Option letters were getting scarce, so I invented this
382                                  * new scheme: '-X feature' turns on some feature. Compare
383                                  * to the -f option in GCC.  You should also add an
384                                  * equivalent GNU-style option --feature.  Features that
385                                  * require arguments should use '-X feature=foo'.
386                                  */
387                         case 'X':
388                                 if (strcmp(optarg, "disable-dollar-quoting") == 0)
389                                         disable_dollar_quoting = 1;
390                                 else if (strcmp(optarg, "disable-triggers") == 0)
391                                         disable_triggers = 1;
392                                 else if (strcmp(optarg, "use-set-session-authorization") == 0)
393                                         /* no-op, still allowed for compatibility */ ;
394                                 else
395                                 {
396                                         fprintf(stderr,
397                                                         _("%s: invalid -X option -- %s\n"),
398                                                         progname, optarg);
399                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
400                                         exit(1);
401                                 }
402                                 break;
403
404                         case 'Z':                       /* Compression Level */
405                                 compressLevel = atoi(optarg);
406                                 break;
407                                 /* This covers the long options equivalent to -X xxx. */
408
409                         case 0:
410                                 break;
411
412                         default:
413                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
414                                 exit(1);
415                 }
416         }
417
418         if (optind < (argc - 1))
419         {
420                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
421                                 progname, argv[optind + 1]);
422                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
423                                 progname);
424                 exit(1);
425         }
426
427         /* Get database name from command line */
428         if (optind < argc)
429                 dbname = argv[optind];
430
431         if (dataOnly && schemaOnly)
432         {
433                 write_msg(NULL, "options \"schema only\" (-s) and \"data only\" (-a) cannot be used together\n");
434                 exit(1);
435         }
436
437         if (dataOnly && outputClean)
438         {
439                 write_msg(NULL, "options \"clean\" (-c) and \"data only\" (-a) cannot be used together\n");
440                 exit(1);
441         }
442
443         if (outputBlobs && selectTableName != NULL)
444         {
445                 write_msg(NULL, "large-object output not supported for a single table\n");
446                 write_msg(NULL, "use a full dump instead\n");
447                 exit(1);
448         }
449
450         if (outputBlobs && selectSchemaName != NULL)
451         {
452                 write_msg(NULL, "large-object output not supported for a single schema\n");
453                 write_msg(NULL, "use a full dump instead\n");
454                 exit(1);
455         }
456
457         if (dumpInserts == true && oids == true)
458         {
459                 write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together\n");
460                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
461                 exit(1);
462         }
463
464         if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
465         {
466                 write_msg(NULL, "large-object output is not supported for plain-text dump files\n");
467                 write_msg(NULL, "(Use a different output format.)\n");
468                 exit(1);
469         }
470
471         /* open the output file */
472         switch (format[0])
473         {
474                 case 'c':
475                 case 'C':
476                         g_fout = CreateArchive(filename, archCustom, compressLevel);
477                         break;
478
479                 case 'f':
480                 case 'F':
481                         g_fout = CreateArchive(filename, archFiles, compressLevel);
482                         break;
483
484                 case 'p':
485                 case 'P':
486                         plainText = 1;
487                         g_fout = CreateArchive(filename, archNull, 0);
488                         break;
489
490                 case 't':
491                 case 'T':
492                         g_fout = CreateArchive(filename, archTar, compressLevel);
493                         break;
494
495                 default:
496                         write_msg(NULL, "invalid output format \"%s\" specified\n", format);
497                         exit(1);
498         }
499
500         if (g_fout == NULL)
501         {
502                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
503                 exit(1);
504         }
505
506         /* Let the archiver know how noisy to be */
507         g_fout->verbose = g_verbose;
508
509         g_fout->minRemoteVersion = 70000;       /* we can handle back to 7.0 */
510         g_fout->maxRemoteVersion = parse_version(PG_VERSION);
511         if (g_fout->maxRemoteVersion < 0)
512         {
513                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
514                 exit(1);
515         }
516
517         /*
518          * Open the database using the Archiver, so it knows about it. Errors
519          * mean death.
520          */
521         g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
522                                                          username, force_password, ignore_version);
523
524         /*
525          * Start serializable transaction to dump consistent data.
526          */
527         do_sql_command(g_conn, "BEGIN");
528
529         do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
530
531         /* Set the datestyle to ISO to ensure the dump's portability */
532         do_sql_command(g_conn, "SET DATESTYLE = ISO");
533
534         /*
535          * If supported, set extra_float_digits so that we can dump float data
536          * exactly (given correctly implemented float I/O code, anyway)
537          */
538         if (g_fout->remoteVersion >= 70400)
539                 do_sql_command(g_conn, "SET extra_float_digits TO 2");
540
541         /* Find the last built-in OID, if needed */
542         if (g_fout->remoteVersion < 70300)
543         {
544                 if (g_fout->remoteVersion >= 70100)
545                         g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
546                 else
547                         g_last_builtin_oid = findLastBuiltinOid_V70();
548                 if (g_verbose)
549                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
550         }
551
552         /*
553          * Now scan the database and create DumpableObject structs for all the
554          * objects we intend to dump.
555          */
556         tblinfo = getSchemaData(&numTables, schemaOnly, dataOnly);
557
558         if (!schemaOnly)
559                 getTableData(tblinfo, numTables, oids);
560
561         if (outputBlobs)
562         {
563                 /* This is just a placeholder to allow correct sorting of blobs */
564                 DumpableObject *blobobj;
565
566                 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
567                 blobobj->objType = DO_BLOBS;
568                 blobobj->catId = nilCatalogId;
569                 AssignDumpId(blobobj);
570                 blobobj->name = strdup("BLOBS");
571         }
572
573         /*
574          * Collect dependency data to assist in ordering the objects.
575          */
576         getDependencies();
577
578         /*
579          * Sort the objects into a safe dump order (no forward references).
580          *
581          * In 7.3 or later, we can rely on dependency information to help us
582          * determine a safe order, so the initial sort is mostly for cosmetic
583          * purposes: we sort by name to ensure that logically identical schemas
584          * will dump identically.  Before 7.3 we don't have dependencies and
585          * we use OID ordering as an (unreliable) guide to creation order.
586          */
587         getDumpableObjects(&dobjs, &numObjs);
588
589         if (g_fout->remoteVersion >= 70300)
590                 sortDumpableObjectsByTypeName(dobjs, numObjs);
591         else
592                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
593
594         sortDumpableObjects(dobjs, numObjs);
595
596         /*
597          * Create archive TOC entries for all the objects to be dumped,
598          * in a safe order.
599          */
600
601         /* First the special encoding entry. */
602         dumpEncoding(g_fout);
603
604         /* The database item is always second. */
605         if (!dataOnly)
606                 dumpDatabase(g_fout);
607
608         /* Max OID is next. */
609         if (oids == true)
610                 setMaxOid(g_fout);
611
612         /* Now the rearrangeable objects. */
613         for (i = 0; i < numObjs; i++)
614         {
615                 dumpDumpableObject(g_fout, dobjs[i]);
616         }
617
618         /*
619          * And finally we can do the actual output.
620          */
621         if (plainText)
622         {
623                 ropt = NewRestoreOptions();
624                 ropt->filename = (char *) filename;
625                 ropt->dropSchema = outputClean;
626                 ropt->aclsSkip = aclsSkip;
627                 ropt->superuser = outputSuperuser;
628                 ropt->create = outputCreate;
629                 ropt->noOwner = outputNoOwner;
630                 ropt->disable_triggers = disable_triggers;
631
632                 if (compressLevel == -1)
633                         ropt->compression = 0;
634                 else
635                         ropt->compression = compressLevel;
636
637                 ropt->suppressDumpWarnings = true;              /* We've already shown
638                                                                                                  * them */
639
640                 RestoreArchive(g_fout, ropt);
641         }
642
643         CloseArchive(g_fout);
644
645         PQfinish(g_conn);
646
647         exit(0);
648 }
649
650
651 static void
652 help(const char *progname)
653 {
654         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
655         printf(_("Usage:\n"));
656         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
657
658         printf(_("\nGeneral options:\n"));
659         printf(_("  -f, --file=FILENAME      output file name\n"));
660         printf(_("  -F, --format=c|t|p       output file format (custom, tar, plain text)\n"));
661         printf(_("  -i, --ignore-version     proceed even when server version mismatches\n"
662                          "                           pg_dump version\n"));
663         printf(_("  -v, --verbose            verbose mode\n"));
664         printf(_("  -Z, --compress=0-9       compression level for compressed formats\n"));
665         printf(_("  --help                   show this help, then exit\n"));
666         printf(_("  --version                output version information, then exit\n"));
667
668         printf(_("\nOptions controlling the output content:\n"));
669         printf(_("  -a, --data-only          dump only the data, not the schema\n"));
670         printf(_("  -b, --blobs              include large objects in dump\n"));
671         printf(_("  -c, --clean              clean (drop) schema prior to create\n"));
672         printf(_("  -C, --create             include commands to create database in dump\n"));
673         printf(_("  -d, --inserts            dump data as INSERT, rather than COPY, commands\n"));
674         printf(_("  -D, --column-inserts     dump data as INSERT commands with column names\n"));
675         printf(_("  -n, --schema=SCHEMA      dump the named schema only\n"));
676         printf(_("  -o, --oids               include OIDs in dump\n"));
677         printf(_("  -O, --no-owner           do not output commands to set object ownership\n"
678                          "                           in plain text format\n"));
679         printf(_("  -s, --schema-only        dump only the schema, no data\n"));
680         printf(_("  -S, --superuser=NAME     specify the superuser user name to use in\n"
681                          "                           plain text format\n"));
682         printf(_("  -t, --table=TABLE        dump the named table only\n"));
683         printf(_("  -x, --no-privileges      do not dump privileges (grant/revoke)\n"));
684         printf(_("  -X disable-dollar-quoting, --disable-dollar-quoting\n"
685                          "                           disable dollar quoting, use SQL standard quoting\n"));
686         printf(_("  -X disable-triggers, --disable-triggers\n"
687                          "                           disable triggers during data-only restore\n"));
688
689         printf(_("\nConnection options:\n"));
690         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
691         printf(_("  -p, --port=PORT          database server port number\n"));
692         printf(_("  -U, --username=NAME      connect as specified database user\n"));
693         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
694
695         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
696                          "variable value is used.\n\n"));
697         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
698 }
699
700 void
701 exit_nicely(void)
702 {
703         PQfinish(g_conn);
704         if (g_verbose)
705                 write_msg(NULL, "*** aborted because of error\n");
706         exit(1);
707 }
708
709 /*
710  * selectDumpableNamespace: policy-setting subroutine
711  *              Mark a namespace as to be dumped or not
712  */
713 static void
714 selectDumpableNamespace(NamespaceInfo *nsinfo)
715 {
716         /*
717          * If a specific table is being dumped, do not dump any complete
718          * namespaces.  If a specific namespace is being dumped, dump just
719          * that namespace. Otherwise, dump all non-system namespaces.
720          */
721         if (selectTableName != NULL)
722                 nsinfo->dump = false;
723         else if (selectSchemaName != NULL)
724         {
725                 if (strcmp(nsinfo->dobj.name, selectSchemaName) == 0)
726                         nsinfo->dump = true;
727                 else
728                         nsinfo->dump = false;
729         }
730         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
731                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
732                 nsinfo->dump = false;
733         else
734                 nsinfo->dump = true;
735 }
736
737 /*
738  * selectDumpableTable: policy-setting subroutine
739  *              Mark a table as to be dumped or not
740  */
741 static void
742 selectDumpableTable(TableInfo *tbinfo)
743 {
744         /*
745          * Always dump if dumping parent namespace; else, if a particular
746          * tablename has been specified, dump matching table name; else, do
747          * not dump.
748          */
749         tbinfo->dump = false;
750         if (tbinfo->dobj.namespace->dump)
751                 tbinfo->dump = true;
752         else if (selectTableName != NULL &&
753                          strcmp(tbinfo->dobj.name, selectTableName) == 0)
754         {
755                 /* If both -s and -t specified, must match both to dump */
756                 if (selectSchemaName == NULL)
757                         tbinfo->dump = true;
758                 else if (strcmp(tbinfo->dobj.namespace->dobj.name, selectSchemaName) == 0)
759                         tbinfo->dump = true;
760         }
761 }
762
763 /*
764  *      Dump a table's contents for loading using the COPY command
765  *      - this routine is called by the Archiver when it wants the table
766  *        to be dumped.
767  */
768
769 #define COPYBUFSIZ              8192
770
771 static int
772 dumpTableData_copy(Archive *fout, void *dcontext)
773 {
774         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
775         TableInfo  *tbinfo = tdinfo->tdtable;
776         const char *classname = tbinfo->dobj.name;
777         const bool      hasoids = tbinfo->hasoids;
778         const bool      oids = tdinfo->oids;
779         PQExpBuffer q = createPQExpBuffer();
780         PGresult   *res;
781         int                     ret;
782         bool            copydone;
783         char            copybuf[COPYBUFSIZ];
784         const char *column_list;
785
786         if (g_verbose)
787                 write_msg(NULL, "dumping contents of table %s\n", classname);
788
789         /*
790          * Make sure we are in proper schema.  We will qualify the table name
791          * below anyway (in case its name conflicts with a pg_catalog table);
792          * but this ensures reproducible results in case the table contains
793          * regproc, regclass, etc columns.
794          */
795         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
796
797         /*
798          * If possible, specify the column list explicitly so that we have no
799          * possibility of retrieving data in the wrong column order.  (The
800          * default column ordering of COPY will not be what we want in certain
801          * corner cases involving ADD COLUMN and inheritance.)
802          */
803         if (g_fout->remoteVersion >= 70300)
804                 column_list = fmtCopyColumnList(tbinfo);
805         else
806                 column_list = "";               /* can't select columns in COPY */
807
808         if (oids && hasoids)
809         {
810                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
811                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
812                                                                                  classname),
813                                                   column_list);
814         }
815         else
816         {
817                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
818                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
819                                                                                  classname),
820                                                   column_list);
821         }
822         res = PQexec(g_conn, q->data);
823         check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
824
825         copydone = false;
826
827         while (!copydone)
828         {
829                 ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
830
831                 if (copybuf[0] == '\\' &&
832                         copybuf[1] == '.' &&
833                         copybuf[2] == '\0')
834                 {
835                         copydone = true;        /* don't print this... */
836                 }
837                 else
838                 {
839                         archputs(copybuf, fout);
840                         switch (ret)
841                         {
842                                 case EOF:
843                                         copydone = true;
844                                         /* FALLTHROUGH */
845                                 case 0:
846                                         archputs("\n", fout);
847                                         break;
848                                 case 1:
849                                         break;
850                         }
851                 }
852
853                 /*
854                  * THROTTLE:
855                  *
856                  * There was considerable discussion in late July, 2000 regarding
857                  * slowing down pg_dump when backing up large tables. Users with
858                  * both slow & fast (muti-processor) machines experienced
859                  * performance degradation when doing a backup.
860                  *
861                  * Initial attempts based on sleeping for a number of ms for each ms
862                  * of work were deemed too complex, then a simple 'sleep in each
863                  * loop' implementation was suggested. The latter failed because
864                  * the loop was too tight. Finally, the following was implemented:
865                  *
866                  * If throttle is non-zero, then See how long since the last sleep.
867                  * Work out how long to sleep (based on ratio). If sleep is more
868                  * than 100ms, then sleep reset timer EndIf EndIf
869                  *
870                  * where the throttle value was the number of ms to sleep per ms of
871                  * work. The calculation was done in each loop.
872                  *
873                  * Most of the hard work is done in the backend, and this solution
874                  * still did not work particularly well: on slow machines, the
875                  * ratio was 50:1, and on medium paced machines, 1:1, and on fast
876                  * multi-processor machines, it had little or no effect, for
877                  * reasons that were unclear.
878                  *
879                  * Further discussion ensued, and the proposal was dropped.
880                  *
881                  * For those people who want this feature, it can be implemented
882                  * using gettimeofday in each loop, calculating the time since
883                  * last sleep, multiplying that by the sleep ratio, then if the
884                  * result is more than a preset 'minimum sleep time' (say 100ms),
885                  * call the 'select' function to sleep for a subsecond period ie.
886                  *
887                  * select(0, NULL, NULL, NULL, &tvi);
888                  *
889                  * This will return after the interval specified in the structure
890                  * tvi. Finally, call gettimeofday again to save the 'last sleep
891                  * time'.
892                  */
893         }
894         archprintf(fout, "\\.\n\n\n");
895
896         ret = PQendcopy(g_conn);
897         if (ret != 0)
898         {
899                 write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
900                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
901                 write_msg(NULL, "The command was: %s\n", q->data);
902                 exit_nicely();
903         }
904
905         PQclear(res);
906         destroyPQExpBuffer(q);
907         return 1;
908 }
909
910 static int
911 dumpTableData_insert(Archive *fout, void *dcontext)
912 {
913         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
914         TableInfo  *tbinfo = tdinfo->tdtable;
915         const char *classname = tbinfo->dobj.name;
916         PQExpBuffer q = createPQExpBuffer();
917         PGresult   *res;
918         int                     tuple;
919         int                     nfields;
920         int                     field;
921
922         /*
923          * Make sure we are in proper schema.  We will qualify the table name
924          * below anyway (in case its name conflicts with a pg_catalog table);
925          * but this ensures reproducible results in case the table contains
926          * regproc, regclass, etc columns.
927          */
928         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
929
930         if (fout->remoteVersion >= 70100)
931         {
932                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
933                                                   "SELECT * FROM ONLY %s",
934                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
935                                                                                  classname));
936         }
937         else
938         {
939                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
940                                                   "SELECT * FROM %s",
941                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
942                                                                                  classname));
943         }
944
945         res = PQexec(g_conn, q->data);
946         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
947
948         do
949         {
950                 PQclear(res);
951
952                 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
953                 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
954                                                  PGRES_TUPLES_OK);
955                 nfields = PQnfields(res);
956                 for (tuple = 0; tuple < PQntuples(res); tuple++)
957                 {
958                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
959                         if (nfields == 0)
960                         {
961                                 /* corner case for zero-column table */
962                                 archprintf(fout, "DEFAULT VALUES;\n");
963                                 continue;
964                         }
965                         if (attrNames == true)
966                         {
967                                 resetPQExpBuffer(q);
968                                 appendPQExpBuffer(q, "(");
969                                 for (field = 0; field < nfields; field++)
970                                 {
971                                         if (field > 0)
972                                                 appendPQExpBuffer(q, ", ");
973                                         appendPQExpBuffer(q, fmtId(PQfname(res, field)));
974                                 }
975                                 appendPQExpBuffer(q, ") ");
976                                 archprintf(fout, "%s", q->data);
977                         }
978                         archprintf(fout, "VALUES (");
979                         for (field = 0; field < nfields; field++)
980                         {
981                                 if (field > 0)
982                                         archprintf(fout, ", ");
983                                 if (PQgetisnull(res, tuple, field))
984                                 {
985                                         archprintf(fout, "NULL");
986                                         continue;
987                                 }
988
989                                 /* XXX This code is partially duplicated in ruleutils.c */
990                                 switch (PQftype(res, field))
991                                 {
992                                         case INT2OID:
993                                         case INT4OID:
994                                         case INT8OID:
995                                         case OIDOID:
996                                         case FLOAT4OID:
997                                         case FLOAT8OID:
998                                         case NUMERICOID:
999                                                 {
1000                                                         /*
1001                                                          * These types are printed without quotes
1002                                                          * unless they contain values that aren't
1003                                                          * accepted by the scanner unquoted (e.g.,
1004                                                          * 'NaN').      Note that strtod() and friends
1005                                                          * might accept NaN, so we can't use that to
1006                                                          * test.
1007                                                          *
1008                                                          * In reality we only need to defend against
1009                                                          * infinity and NaN, so we need not get too
1010                                                          * crazy about pattern matching here.
1011                                                          */
1012                                                         const char *s = PQgetvalue(res, tuple, field);
1013
1014                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1015                                                                 archprintf(fout, "%s", s);
1016                                                         else
1017                                                                 archprintf(fout, "'%s'", s);
1018                                                 }
1019                                                 break;
1020
1021                                         case BITOID:
1022                                         case VARBITOID:
1023                                                 archprintf(fout, "B'%s'",
1024                                                                    PQgetvalue(res, tuple, field));
1025                                                 break;
1026
1027                                         case BOOLOID:
1028                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1029                                                         archprintf(fout, "true");
1030                                                 else
1031                                                         archprintf(fout, "false");
1032                                                 break;
1033
1034                                         default:
1035                                                 /* All other types are printed as string literals. */
1036                                                 resetPQExpBuffer(q);
1037                                                 appendStringLiteral(q, PQgetvalue(res, tuple, field), false);
1038                                                 archprintf(fout, "%s", q->data);
1039                                                 break;
1040                                 }
1041                         }
1042                         archprintf(fout, ");\n");
1043                 }
1044         } while (PQntuples(res) > 0);
1045
1046         PQclear(res);
1047
1048         archprintf(fout, "\n\n");
1049
1050         do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1051
1052         destroyPQExpBuffer(q);
1053         return 1;
1054 }
1055
1056
1057 /*
1058  * dumpTableData -
1059  *        dump the contents of a single table
1060  *
1061  * Actually, this just makes an ArchiveEntry for the table contents.
1062  */
1063 static void
1064 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1065 {
1066         TableInfo  *tbinfo = tdinfo->tdtable;
1067         PQExpBuffer copyBuf = createPQExpBuffer();
1068         DataDumperPtr dumpFn;
1069         char       *copyStmt;
1070
1071         if (!dumpInserts)
1072         {
1073                 /* Dump/restore using COPY */
1074                 dumpFn = dumpTableData_copy;
1075                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1076                 appendPQExpBuffer(copyBuf, "COPY %s ",
1077                                                   fmtId(tbinfo->dobj.name));
1078                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1079                                                   fmtCopyColumnList(tbinfo),
1080                                                   (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1081                 copyStmt = copyBuf->data;
1082         }
1083         else
1084         {
1085                 /* Restore using INSERT */
1086                 dumpFn = dumpTableData_insert;
1087                 copyStmt = NULL;
1088         }
1089
1090         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1091                                  tbinfo->dobj.name,
1092                                  tbinfo->dobj.namespace->dobj.name,
1093                                  tbinfo->usename, false,
1094                                  "TABLE DATA", "", "", copyStmt,
1095                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1096                                  dumpFn, tdinfo);
1097
1098         destroyPQExpBuffer(copyBuf);
1099 }
1100
1101 /*
1102  * getTableData -
1103  *        set up dumpable objects representing the contents of tables
1104  */
1105 static void
1106 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1107 {
1108         int                     i;
1109
1110         for (i = 0; i < numTables; i++)
1111         {
1112                 /* Skip VIEWs (no data to dump) */
1113                 if (tblinfo[i].relkind == RELKIND_VIEW)
1114                         continue;
1115                 /* Skip SEQUENCEs (handled elsewhere) */
1116                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1117                         continue;
1118
1119                 if (tblinfo[i].dump)
1120                 {
1121                         TableDataInfo *tdinfo;
1122
1123                         tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1124
1125                         tdinfo->dobj.objType = DO_TABLE_DATA;
1126                         /*
1127                          * Note: use tableoid 0 so that this object won't be mistaken
1128                          * for something that pg_depend entries apply to.
1129                          */
1130                         tdinfo->dobj.catId.tableoid = 0;
1131                         tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1132                         AssignDumpId(&tdinfo->dobj);
1133                         tdinfo->dobj.name = tblinfo[i].dobj.name;
1134                         tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1135                         tdinfo->tdtable = &(tblinfo[i]);
1136                         tdinfo->oids = oids;
1137                         addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1138                 }
1139         }
1140 }
1141
1142
1143 /*
1144  * dumpDatabase:
1145  *      dump the database definition
1146  */
1147 static void
1148 dumpDatabase(Archive *AH)
1149 {
1150         PQExpBuffer dbQry = createPQExpBuffer();
1151         PQExpBuffer delQry = createPQExpBuffer();
1152         PQExpBuffer creaQry = createPQExpBuffer();
1153         PGresult   *res;
1154         int                     ntups;
1155         int                     i_tableoid,
1156                                 i_oid,
1157                                 i_dba,
1158                                 i_encoding,
1159                                 i_datpath;
1160         CatalogId       dbCatId;
1161         DumpId          dbDumpId;
1162         const char *datname,
1163                            *dba,
1164                            *encoding,
1165                            *datpath;
1166
1167         datname = PQdb(g_conn);
1168
1169         if (g_verbose)
1170                 write_msg(NULL, "saving database definition\n");
1171
1172         /* Make sure we are in proper schema */
1173         selectSourceSchema("pg_catalog");
1174
1175         /* Get the database owner and parameters from pg_database */
1176         if (g_fout->remoteVersion >= 70100)
1177         {
1178                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1179                                                   "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
1180                                                   "pg_encoding_to_char(encoding) as encoding, "
1181                                                   "datpath "
1182                                                   "FROM pg_database "
1183                                                   "WHERE datname = ");
1184                 appendStringLiteral(dbQry, datname, true);
1185         }
1186         else
1187         {
1188                 /*
1189                  * In 7.0, datpath is either the same as datname, or the user-given
1190                  * location with "/" and the datname appended.  We must strip this
1191                  * junk off to produce a correct LOCATION value.
1192                  */
1193                 appendPQExpBuffer(dbQry, "SELECT "
1194                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1195                                                   "oid, "
1196                                                   "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
1197                                                   "pg_encoding_to_char(encoding) as encoding, "
1198                                                   "CASE WHEN length(datpath) > length(datname) THEN "
1199                                                   "substr(datpath,1,length(datpath)-length(datname)-1) "
1200                                                   "ELSE '' END as datpath "
1201                                                   "FROM pg_database "
1202                                                   "WHERE datname = ");
1203                 appendStringLiteral(dbQry, datname, true);
1204         }
1205
1206         res = PQexec(g_conn, dbQry->data);
1207         check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1208
1209         ntups = PQntuples(res);
1210
1211         if (ntups <= 0)
1212         {
1213                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1214                                   datname);
1215                 exit_nicely();
1216         }
1217
1218         if (ntups != 1)
1219         {
1220                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1221                                   ntups, datname);
1222                 exit_nicely();
1223         }
1224
1225         i_tableoid = PQfnumber(res, "tableoid");
1226         i_oid = PQfnumber(res, "oid");
1227         i_dba = PQfnumber(res, "dba");
1228         i_encoding = PQfnumber(res, "encoding");
1229         i_datpath = PQfnumber(res, "datpath");
1230
1231         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1232         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1233         dba = PQgetvalue(res, 0, i_dba);
1234         encoding = PQgetvalue(res, 0, i_encoding);
1235         datpath = PQgetvalue(res, 0, i_datpath);
1236
1237         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1238                                           fmtId(datname));
1239         if (strlen(datpath) > 0)
1240         {
1241                 appendPQExpBuffer(creaQry, " LOCATION = ");
1242                 appendStringLiteral(creaQry, datpath, true);
1243         }
1244         if (strlen(encoding) > 0)
1245         {
1246                 appendPQExpBuffer(creaQry, " ENCODING = ");
1247                 appendStringLiteral(creaQry, encoding, true);
1248         }
1249         appendPQExpBuffer(creaQry, ";\n");
1250
1251         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1252                                           fmtId(datname));
1253
1254         dbDumpId = createDumpId();
1255
1256         ArchiveEntry(AH,
1257                                  dbCatId,               /* catalog ID */
1258                                  dbDumpId,              /* dump ID */
1259                                  datname,               /* Name */
1260                                  NULL,                  /* Namespace */
1261                                  dba,                   /* Owner */
1262                                  false,                 /* with oids */
1263                                  "DATABASE",    /* Desc */
1264                                  creaQry->data, /* Create */
1265                                  delQry->data,  /* Del */
1266                                  NULL,                  /* Copy */
1267                                  NULL,                  /* Deps */
1268                                  0,                             /* # Deps */
1269                                  NULL,                  /* Dumper */
1270                                  NULL);                 /* Dumper Arg */
1271
1272         /* Dump DB comment if any */
1273         resetPQExpBuffer(dbQry);
1274         appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1275         dumpComment(AH, dbQry->data, NULL, "",
1276                                 dbCatId, 0, dbDumpId);
1277
1278         PQclear(res);
1279
1280         destroyPQExpBuffer(dbQry);
1281         destroyPQExpBuffer(delQry);
1282         destroyPQExpBuffer(creaQry);
1283 }
1284
1285
1286 /*
1287  * dumpEncoding: put the correct encoding into the archive
1288  */
1289 static void
1290 dumpEncoding(Archive *AH)
1291 {
1292         PQExpBuffer qry;
1293         PGresult   *res;
1294
1295         /* Can't read the encoding from pre-7.3 servers (SHOW isn't a query) */
1296         if (AH->remoteVersion < 70300)
1297                 return;
1298
1299         if (g_verbose)
1300                 write_msg(NULL, "saving encoding\n");
1301
1302         qry = createPQExpBuffer();
1303
1304         appendPQExpBuffer(qry, "SHOW client_encoding");
1305
1306         res = PQexec(g_conn, qry->data);
1307
1308         check_sql_result(res, g_conn, qry->data, PGRES_TUPLES_OK);
1309
1310         resetPQExpBuffer(qry);
1311
1312         appendPQExpBuffer(qry, "SET client_encoding = ");
1313         appendStringLiteral(qry, PQgetvalue(res, 0, 0), true);
1314         appendPQExpBuffer(qry, ";\n");
1315
1316         ArchiveEntry(AH, nilCatalogId, createDumpId(),
1317                                  "ENCODING", NULL, "",
1318                                  false, "ENCODING", qry->data, "", NULL,
1319                                  NULL, 0,
1320                                  NULL, NULL);
1321
1322         PQclear(res);
1323
1324         destroyPQExpBuffer(qry);
1325 }
1326
1327
1328 /*
1329  * dumpBlobs:
1330  *      dump all blobs
1331  *
1332  */
1333
1334 #define loBufSize 16384
1335 #define loFetchSize 1000
1336
1337 static int
1338 dumpBlobs(Archive *AH, void *arg)
1339 {
1340         PQExpBuffer oidQry = createPQExpBuffer();
1341         PQExpBuffer oidFetchQry = createPQExpBuffer();
1342         PGresult   *res;
1343         int                     i;
1344         int                     loFd;
1345         char            buf[loBufSize];
1346         int                     cnt;
1347         Oid                     blobOid;
1348
1349         if (g_verbose)
1350                 write_msg(NULL, "saving large objects\n");
1351
1352         /* Make sure we are in proper schema */
1353         selectSourceSchema("pg_catalog");
1354
1355         /* Cursor to get all BLOB tables */
1356         if (AH->remoteVersion >= 70100)
1357                 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1358         else
1359                 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
1360
1361         res = PQexec(g_conn, oidQry->data);
1362         check_sql_result(res, g_conn, oidQry->data, PGRES_COMMAND_OK);
1363
1364         /* Fetch for cursor */
1365         appendPQExpBuffer(oidFetchQry, "Fetch %d in blobOid", loFetchSize);
1366
1367         do
1368         {
1369                 /* Do a fetch */
1370                 PQclear(res);
1371
1372                 res = PQexec(g_conn, oidFetchQry->data);
1373                 check_sql_result(res, g_conn, oidFetchQry->data, PGRES_TUPLES_OK);
1374
1375                 /* Process the tuples, if any */
1376                 for (i = 0; i < PQntuples(res); i++)
1377                 {
1378                         blobOid = atooid(PQgetvalue(res, i, 0));
1379                         /* Open the BLOB */
1380                         loFd = lo_open(g_conn, blobOid, INV_READ);
1381                         if (loFd == -1)
1382                         {
1383                                 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1384                                                   PQerrorMessage(g_conn));
1385                                 exit_nicely();
1386                         }
1387
1388                         StartBlob(AH, blobOid);
1389
1390                         /* Now read it in chunks, sending data to archive */
1391                         do
1392                         {
1393                                 cnt = lo_read(g_conn, loFd, buf, loBufSize);
1394                                 if (cnt < 0)
1395                                 {
1396                                         write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1397                                                           PQerrorMessage(g_conn));
1398                                         exit_nicely();
1399                                 }
1400
1401                                 WriteData(AH, buf, cnt);
1402
1403                         } while (cnt > 0);
1404
1405                         lo_close(g_conn, loFd);
1406
1407                         EndBlob(AH, blobOid);
1408
1409                 }
1410         } while (PQntuples(res) > 0);
1411
1412         destroyPQExpBuffer(oidQry);
1413         destroyPQExpBuffer(oidFetchQry);
1414
1415         return 1;
1416 }
1417
1418 /*
1419  * getNamespaces:
1420  *        read all namespaces in the system catalogs and return them in the
1421  * NamespaceInfo* structure
1422  *
1423  *      numNamespaces is set to the number of namespaces read in
1424  */
1425 NamespaceInfo *
1426 getNamespaces(int *numNamespaces)
1427 {
1428         PGresult   *res;
1429         int                     ntups;
1430         int                     i;
1431         PQExpBuffer query;
1432         NamespaceInfo *nsinfo;
1433         int                     i_tableoid;
1434         int                     i_oid;
1435         int                     i_nspname;
1436         int                     i_usename;
1437         int                     i_nspacl;
1438
1439         /*
1440          * Before 7.3, there are no real namespaces; create two dummy entries,
1441          * one for user stuff and one for system stuff.
1442          */
1443         if (g_fout->remoteVersion < 70300)
1444         {
1445                 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
1446
1447                 nsinfo[0].dobj.objType = DO_NAMESPACE;
1448                 nsinfo[0].dobj.catId.tableoid = 0;
1449                 nsinfo[0].dobj.catId.oid = 0;
1450                 AssignDumpId(&nsinfo[0].dobj);
1451                 nsinfo[0].dobj.name = strdup("");
1452                 nsinfo[0].usename = strdup("");
1453                 nsinfo[0].nspacl = strdup("");
1454
1455                 selectDumpableNamespace(&nsinfo[0]);
1456
1457                 nsinfo[1].dobj.objType = DO_NAMESPACE;
1458                 nsinfo[1].dobj.catId.tableoid = 0;
1459                 nsinfo[1].dobj.catId.oid = 1;
1460                 AssignDumpId(&nsinfo[1].dobj);
1461                 nsinfo[1].dobj.name = strdup("pg_catalog");
1462                 nsinfo[1].usename = strdup("");
1463                 nsinfo[1].nspacl = strdup("");
1464
1465                 selectDumpableNamespace(&nsinfo[1]);
1466
1467                 g_namespaces = nsinfo;
1468                 g_numNamespaces = *numNamespaces = 2;
1469
1470                 return nsinfo;
1471         }
1472
1473         query = createPQExpBuffer();
1474
1475         /* Make sure we are in proper schema */
1476         selectSourceSchema("pg_catalog");
1477
1478         /*
1479          * we fetch all namespaces including system ones, so that every object
1480          * we read in can be linked to a containing namespace.
1481          */
1482         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
1483         "(select usename from pg_user where nspowner = usesysid) as usename, "
1484                                           "nspacl "
1485                                           "FROM pg_namespace");
1486
1487         res = PQexec(g_conn, query->data);
1488         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1489
1490         ntups = PQntuples(res);
1491
1492         nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
1493
1494         i_tableoid = PQfnumber(res, "tableoid");
1495         i_oid = PQfnumber(res, "oid");
1496         i_nspname = PQfnumber(res, "nspname");
1497         i_usename = PQfnumber(res, "usename");
1498         i_nspacl = PQfnumber(res, "nspacl");
1499
1500         for (i = 0; i < ntups; i++)
1501         {
1502                 nsinfo[i].dobj.objType = DO_NAMESPACE;
1503                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
1504                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
1505                 AssignDumpId(&nsinfo[i].dobj);
1506                 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
1507                 nsinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1508                 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
1509
1510                 /* Decide whether to dump this namespace */
1511                 selectDumpableNamespace(&nsinfo[i]);
1512
1513                 if (strlen(nsinfo[i].usename) == 0)
1514                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
1515                                           nsinfo[i].dobj.name);
1516         }
1517
1518         /*
1519          * If the user attempted to dump a specific namespace, check to ensure
1520          * that the specified namespace actually exists.
1521          */
1522         if (selectSchemaName)
1523         {
1524                 for (i = 0; i < ntups; i++)
1525                         if (strcmp(nsinfo[i].dobj.name, selectSchemaName) == 0)
1526                                 break;
1527
1528                 /* Didn't find a match */
1529                 if (i == ntups)
1530                 {
1531                         write_msg(NULL, "specified schema \"%s\" does not exist\n",
1532                                           selectSchemaName);
1533                         exit_nicely();
1534                 }
1535         }
1536
1537         PQclear(res);
1538         destroyPQExpBuffer(query);
1539
1540         g_namespaces = nsinfo;
1541         g_numNamespaces = *numNamespaces = ntups;
1542
1543         return nsinfo;
1544 }
1545
1546 /*
1547  * findNamespace:
1548  *              given a namespace OID and an object OID, look up the info read by
1549  *              getNamespaces
1550  *
1551  * NB: for pre-7.3 source database, we use object OID to guess whether it's
1552  * a system object or not.      In 7.3 and later there is no guessing.
1553  */
1554 static NamespaceInfo *
1555 findNamespace(Oid nsoid, Oid objoid)
1556 {
1557         int                     i;
1558
1559         if (g_fout->remoteVersion >= 70300)
1560         {
1561                 for (i = 0; i < g_numNamespaces; i++)
1562                 {
1563                         NamespaceInfo *nsinfo = &g_namespaces[i];
1564
1565                         if (nsoid == nsinfo->dobj.catId.oid)
1566                                 return nsinfo;
1567                 }
1568                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
1569                 exit_nicely();
1570         }
1571         else
1572         {
1573                 /* This code depends on the layout set up by getNamespaces. */
1574                 if (objoid > g_last_builtin_oid)
1575                         i = 0;                          /* user object */
1576                 else
1577                         i = 1;                          /* system object */
1578                 return &g_namespaces[i];
1579         }
1580
1581         return NULL;                            /* keep compiler quiet */
1582 }
1583
1584 /*
1585  * getTypes:
1586  *        read all types in the system catalogs and return them in the
1587  * TypeInfo* structure
1588  *
1589  *      numTypes is set to the number of types read in
1590  *
1591  * NB: this must run after getFuncs() because we assume we can do
1592  * findFuncByOid().
1593  */
1594 TypeInfo *
1595 getTypes(int *numTypes)
1596 {
1597         PGresult   *res;
1598         int                     ntups;
1599         int                     i;
1600         PQExpBuffer query = createPQExpBuffer();
1601         TypeInfo   *tinfo;
1602         int                     i_tableoid;
1603         int                     i_oid;
1604         int                     i_typname;
1605         int                     i_typnamespace;
1606         int                     i_usename;
1607         int                     i_typinput;
1608         int                     i_typoutput;
1609         int                     i_typelem;
1610         int                     i_typrelid;
1611         int                     i_typrelkind;
1612         int                     i_typtype;
1613         int                     i_typisdefined;
1614
1615         /*
1616          * we include even the built-in types because those may be used as
1617          * array elements by user-defined types
1618          *
1619          * we filter out the built-in types when we dump out the types
1620          *
1621          * same approach for undefined (shell) types
1622          */
1623
1624         /* Make sure we are in proper schema */
1625         selectSourceSchema("pg_catalog");
1626
1627         if (g_fout->remoteVersion >= 70300)
1628         {
1629                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
1630                                                   "typnamespace, "
1631                                                   "(select usename from pg_user where typowner = usesysid) as usename, "
1632                                                   "typinput::oid as typinput, "
1633                                                   "typoutput::oid as typoutput, typelem, typrelid, "
1634                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
1635                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
1636                                                   "typtype, typisdefined "
1637                                                   "FROM pg_type");
1638         }
1639         else if (g_fout->remoteVersion >= 70100)
1640         {
1641                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
1642                                                   "0::oid as typnamespace, "
1643                                                   "(select usename from pg_user where typowner = usesysid) as usename, "
1644                                                   "typinput::oid as typinput, "
1645                                                   "typoutput::oid as typoutput, typelem, typrelid, "
1646                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
1647                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
1648                                                   "typtype, typisdefined "
1649                                                   "FROM pg_type");
1650         }
1651         else
1652         {
1653                 appendPQExpBuffer(query, "SELECT "
1654                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
1655                                                   "oid, typname, "
1656                                                   "0::oid as typnamespace, "
1657                                                   "(select usename from pg_user where typowner = usesysid) as usename, "
1658                                                   "typinput::oid as typinput, "
1659                                                   "typoutput::oid as typoutput, typelem, typrelid, "
1660                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
1661                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
1662                                                   "typtype, typisdefined "
1663                                                   "FROM pg_type");
1664         }
1665
1666         res = PQexec(g_conn, query->data);
1667         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1668
1669         ntups = PQntuples(res);
1670
1671         tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
1672
1673         i_tableoid = PQfnumber(res, "tableoid");
1674         i_oid = PQfnumber(res, "oid");
1675         i_typname = PQfnumber(res, "typname");
1676         i_typnamespace = PQfnumber(res, "typnamespace");
1677         i_usename = PQfnumber(res, "usename");
1678         i_typinput = PQfnumber(res, "typinput");
1679         i_typoutput = PQfnumber(res, "typoutput");
1680         i_typelem = PQfnumber(res, "typelem");
1681         i_typrelid = PQfnumber(res, "typrelid");
1682         i_typrelkind = PQfnumber(res, "typrelkind");
1683         i_typtype = PQfnumber(res, "typtype");
1684         i_typisdefined = PQfnumber(res, "typisdefined");
1685
1686         for (i = 0; i < ntups; i++)
1687         {
1688                 Oid                     typoutput;
1689                 FuncInfo   *funcInfo;
1690
1691                 tinfo[i].dobj.objType = DO_TYPE;
1692                 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
1693                 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
1694                 AssignDumpId(&tinfo[i].dobj);
1695                 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
1696                 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
1697                                                                                           tinfo[i].dobj.catId.oid);
1698                 tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1699                 tinfo[i].typinput = atooid(PQgetvalue(res, i, i_typinput));
1700                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
1701                 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
1702                 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
1703                 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
1704                 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
1705
1706                 /*
1707                  * If it's a table's rowtype, use special type code to facilitate
1708                  * sorting into the desired order.  (We don't want to consider it
1709                  * an ordinary type because that would bring the table up into the
1710                  * datatype part of the dump order.)
1711                  */
1712                 if (OidIsValid(tinfo[i].typrelid) && tinfo[i].typrelkind != 'c')
1713                         tinfo[i].dobj.objType = DO_TABLE_TYPE;
1714
1715                 /*
1716                  * check for user-defined array types, omit system generated ones
1717                  */
1718                 if (OidIsValid(tinfo[i].typelem) &&
1719                         tinfo[i].dobj.name[0] != '_')
1720                         tinfo[i].isArray = true;
1721                 else
1722                         tinfo[i].isArray = false;
1723
1724                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
1725                         tinfo[i].isDefined = true;
1726                 else
1727                         tinfo[i].isDefined = false;
1728
1729                 /*
1730                  * If it's a domain, fetch info about its constraints, if any
1731                  */
1732                 tinfo[i].nDomChecks = 0;
1733                 tinfo[i].domChecks = NULL;
1734                 if (tinfo[i].typtype == 'd')
1735                         getDomainConstraints(&(tinfo[i]));
1736
1737                 /*
1738                  * Make sure there are dependencies from the type to its input and
1739                  * output functions.  (We don't worry about typsend, typreceive, or
1740                  * typanalyze since those are only valid in 7.4 and later, wherein
1741                  * the standard dependency mechanism will pick them up.)
1742                  */
1743                 funcInfo = findFuncByOid(tinfo[i].typinput);
1744                 if (funcInfo)
1745                         addObjectDependency(&tinfo[i].dobj,
1746                                                                 funcInfo->dobj.dumpId);
1747                 funcInfo = findFuncByOid(typoutput);
1748                 if (funcInfo)
1749                         addObjectDependency(&tinfo[i].dobj,
1750                                                                 funcInfo->dobj.dumpId);
1751
1752                 if (strlen(tinfo[i].usename) == 0 && tinfo[i].isDefined)
1753                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
1754                                           tinfo[i].dobj.name);
1755         }
1756
1757         *numTypes = ntups;
1758
1759         PQclear(res);
1760
1761         destroyPQExpBuffer(query);
1762
1763         return tinfo;
1764 }
1765
1766 /*
1767  * getOperators:
1768  *        read all operators in the system catalogs and return them in the
1769  * OprInfo* structure
1770  *
1771  *      numOprs is set to the number of operators read in
1772  */
1773 OprInfo *
1774 getOperators(int *numOprs)
1775 {
1776         PGresult   *res;
1777         int                     ntups;
1778         int                     i;
1779         PQExpBuffer query = createPQExpBuffer();
1780         OprInfo    *oprinfo;
1781         int                     i_tableoid;
1782         int                     i_oid;
1783         int                     i_oprname;
1784         int                     i_oprnamespace;
1785         int                     i_usename;
1786         int                     i_oprcode;
1787
1788         /*
1789          * find all operators, including builtin operators; we filter out
1790          * system-defined operators at dump-out time.
1791          */
1792
1793         /* Make sure we are in proper schema */
1794         selectSourceSchema("pg_catalog");
1795
1796         if (g_fout->remoteVersion >= 70300)
1797         {
1798                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
1799                                                   "oprnamespace, "
1800                                                   "(select usename from pg_user where oprowner = usesysid) as usename, "
1801                                                   "oprcode::oid as oprcode "
1802                                                   "FROM pg_operator");
1803         }
1804         else if (g_fout->remoteVersion >= 70100)
1805         {
1806                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
1807                                                   "0::oid as oprnamespace, "
1808                                                   "(select usename from pg_user where oprowner = usesysid) as usename, "
1809                                                   "oprcode::oid as oprcode "
1810                                                   "FROM pg_operator");
1811         }
1812         else
1813         {
1814                 appendPQExpBuffer(query, "SELECT "
1815                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
1816                                                   "oid, oprname, "
1817                                                   "0::oid as oprnamespace, "
1818                                                   "(select usename from pg_user where oprowner = usesysid) as usename, "
1819                                                   "oprcode::oid as oprcode "
1820                                                   "FROM pg_operator");
1821         }
1822
1823         res = PQexec(g_conn, query->data);
1824         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1825
1826         ntups = PQntuples(res);
1827         *numOprs = ntups;
1828
1829         oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
1830
1831         i_tableoid = PQfnumber(res, "tableoid");
1832         i_oid = PQfnumber(res, "oid");
1833         i_oprname = PQfnumber(res, "oprname");
1834         i_oprnamespace = PQfnumber(res, "oprnamespace");
1835         i_usename = PQfnumber(res, "usename");
1836         i_oprcode = PQfnumber(res, "oprcode");
1837
1838         for (i = 0; i < ntups; i++)
1839         {
1840                 oprinfo[i].dobj.objType = DO_OPERATOR;
1841                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
1842                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
1843                 AssignDumpId(&oprinfo[i].dobj);
1844                 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
1845                 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
1846                                                                                                 oprinfo[i].dobj.catId.oid);
1847                 oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1848                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
1849
1850                 if (strlen(oprinfo[i].usename) == 0)
1851                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
1852                                           oprinfo[i].dobj.name);
1853         }
1854
1855         PQclear(res);
1856
1857         destroyPQExpBuffer(query);
1858
1859         return oprinfo;
1860 }
1861
1862 /*
1863  * getConversions:
1864  *        read all conversions in the system catalogs and return them in the
1865  * ConvInfo* structure
1866  *
1867  *      numConversions is set to the number of conversions read in
1868  */
1869 ConvInfo *
1870 getConversions(int *numConversions)
1871 {
1872         PGresult   *res;
1873         int                     ntups;
1874         int                     i;
1875         PQExpBuffer query = createPQExpBuffer();
1876         ConvInfo *convinfo;
1877         int                     i_tableoid;
1878         int                     i_oid;
1879         int                     i_conname;
1880         int                     i_connamespace;
1881         int                     i_usename;
1882
1883         /* Conversions didn't exist pre-7.3 */
1884         if (g_fout->remoteVersion < 70300) {
1885                 *numConversions = 0;
1886                 return NULL;
1887         }
1888
1889         /*
1890          * find all conversions, including builtin conversions; we filter out
1891          * system-defined conversions at dump-out time.
1892          */
1893
1894         /* Make sure we are in proper schema */
1895         selectSourceSchema("pg_catalog");
1896
1897         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
1898                                           "connamespace, "
1899                                           "(select usename from pg_user where conowner = usesysid) as usename "
1900                                           "FROM pg_conversion");
1901
1902         res = PQexec(g_conn, query->data);
1903         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1904
1905         ntups = PQntuples(res);
1906         *numConversions = ntups;
1907
1908         convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
1909
1910         i_tableoid = PQfnumber(res, "tableoid");
1911         i_oid = PQfnumber(res, "oid");
1912         i_conname = PQfnumber(res, "conname");
1913         i_connamespace = PQfnumber(res, "connamespace");
1914         i_usename = PQfnumber(res, "usename");
1915
1916         for (i = 0; i < ntups; i++)
1917         {
1918                 convinfo[i].dobj.objType = DO_CONVERSION;
1919                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
1920                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
1921                 AssignDumpId(&convinfo[i].dobj);
1922                 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
1923                 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
1924                                                                                                  convinfo[i].dobj.catId.oid);
1925                 convinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1926         }
1927
1928         PQclear(res);
1929
1930         destroyPQExpBuffer(query);
1931
1932         return convinfo;
1933 }
1934
1935 /*
1936  * getOpclasses:
1937  *        read all opclasses in the system catalogs and return them in the
1938  * OpclassInfo* structure
1939  *
1940  *      numOpclasses is set to the number of opclasses read in
1941  */
1942 OpclassInfo *
1943 getOpclasses(int *numOpclasses)
1944 {
1945         PGresult   *res;
1946         int                     ntups;
1947         int                     i;
1948         PQExpBuffer query = createPQExpBuffer();
1949         OpclassInfo *opcinfo;
1950         int                     i_tableoid;
1951         int                     i_oid;
1952         int                     i_opcname;
1953         int                     i_opcnamespace;
1954         int                     i_usename;
1955
1956         /*
1957          * find all opclasses, including builtin opclasses; we filter out
1958          * system-defined opclasses at dump-out time.
1959          */
1960
1961         /* Make sure we are in proper schema */
1962         selectSourceSchema("pg_catalog");
1963
1964         if (g_fout->remoteVersion >= 70300)
1965         {
1966                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
1967                                                   "opcnamespace, "
1968                                                   "(select usename from pg_user where opcowner = usesysid) as usename "
1969                                                   "FROM pg_opclass");
1970         }
1971         else if (g_fout->remoteVersion >= 70100)
1972         {
1973                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
1974                                                   "0::oid as opcnamespace, "
1975                                                   "''::name as usename "
1976                                                   "FROM pg_opclass");
1977         }
1978         else
1979         {
1980                 appendPQExpBuffer(query, "SELECT "
1981                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
1982                                                   "oid, opcname, "
1983                                                   "0::oid as opcnamespace, "
1984                                                   "''::name as usename "
1985                                                   "FROM pg_opclass");
1986         }
1987
1988         res = PQexec(g_conn, query->data);
1989         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
1990
1991         ntups = PQntuples(res);
1992         *numOpclasses = ntups;
1993
1994         opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
1995
1996         i_tableoid = PQfnumber(res, "tableoid");
1997         i_oid = PQfnumber(res, "oid");
1998         i_opcname = PQfnumber(res, "opcname");
1999         i_opcnamespace = PQfnumber(res, "opcnamespace");
2000         i_usename = PQfnumber(res, "usename");
2001
2002         for (i = 0; i < ntups; i++)
2003         {
2004                 opcinfo[i].dobj.objType = DO_OPCLASS;
2005                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2006                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2007                 AssignDumpId(&opcinfo[i].dobj);
2008                 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2009                 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2010                                                                                                 opcinfo[i].dobj.catId.oid);
2011                 opcinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2012
2013                 if (g_fout->remoteVersion >= 70300)
2014                 {
2015                         if (strlen(opcinfo[i].usename) == 0)
2016                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2017                                                   opcinfo[i].dobj.name);
2018                 }
2019         }
2020
2021         PQclear(res);
2022
2023         destroyPQExpBuffer(query);
2024
2025         return opcinfo;
2026 }
2027
2028 /*
2029  * getAggregates:
2030  *        read all the user-defined aggregates in the system catalogs and
2031  * return them in the AggInfo* structure
2032  *
2033  * numAggs is set to the number of aggregates read in
2034  */
2035 AggInfo *
2036 getAggregates(int *numAggs)
2037 {
2038         PGresult   *res;
2039         int                     ntups;
2040         int                     i;
2041         PQExpBuffer query = createPQExpBuffer();
2042         AggInfo    *agginfo;
2043         int                     i_tableoid;
2044         int                     i_oid;
2045         int                     i_aggname;
2046         int                     i_aggnamespace;
2047         int                     i_aggbasetype;
2048         int                     i_usename;
2049         int                     i_aggacl;
2050
2051         /* Make sure we are in proper schema */
2052         selectSourceSchema("pg_catalog");
2053
2054         /* find all user-defined aggregates */
2055
2056         if (g_fout->remoteVersion >= 70300)
2057         {
2058                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname as aggname, "
2059                                                   "pronamespace as aggnamespace, "
2060                                                   "proargtypes[0] as aggbasetype, "
2061                                                   "(select usename from pg_user where proowner = usesysid) as usename, "
2062                                                   "proacl as aggacl "
2063                                                   "FROM pg_proc "
2064                                                   "WHERE proisagg "
2065                                                   "AND pronamespace != "
2066                   "(select oid from pg_namespace where nspname = 'pg_catalog')");
2067         }
2068         else if (g_fout->remoteVersion >= 70100)
2069         {
2070                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
2071                                                   "0::oid as aggnamespace, "
2072                                                   "aggbasetype, "
2073                                                   "(select usename from pg_user where aggowner = usesysid) as usename, "
2074                                                   "'{=X}' as aggacl "
2075                                                   "FROM pg_aggregate "
2076                                                   "where oid > '%u'::oid",
2077                                                   g_last_builtin_oid);
2078         }
2079         else
2080         {
2081                 appendPQExpBuffer(query, "SELECT "
2082                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2083                                                   "oid, aggname, "
2084                                                   "0::oid as aggnamespace, "
2085                                                   "aggbasetype, "
2086                                                   "(select usename from pg_user where aggowner = usesysid) as usename, "
2087                                                   "'{=X}' as aggacl "
2088                                                   "FROM pg_aggregate "
2089                                                   "where oid > '%u'::oid",
2090                                                   g_last_builtin_oid);
2091         }
2092
2093         res = PQexec(g_conn, query->data);
2094         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2095
2096         ntups = PQntuples(res);
2097         *numAggs = ntups;
2098
2099         agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
2100
2101         i_tableoid = PQfnumber(res, "tableoid");
2102         i_oid = PQfnumber(res, "oid");
2103         i_aggname = PQfnumber(res, "aggname");
2104         i_aggnamespace = PQfnumber(res, "aggnamespace");
2105         i_aggbasetype = PQfnumber(res, "aggbasetype");
2106         i_usename = PQfnumber(res, "usename");
2107         i_aggacl = PQfnumber(res, "aggacl");
2108
2109         for (i = 0; i < ntups; i++)
2110         {
2111                 agginfo[i].aggfn.dobj.objType = DO_AGG;
2112                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2113                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2114                 AssignDumpId(&agginfo[i].aggfn.dobj);
2115                 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
2116                 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
2117                                                                                                           agginfo[i].aggfn.dobj.catId.oid);
2118                 agginfo[i].aggfn.usename = strdup(PQgetvalue(res, i, i_usename));
2119                 if (strlen(agginfo[i].aggfn.usename) == 0)
2120                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2121                                           agginfo[i].aggfn.dobj.name);
2122                 agginfo[i].aggfn.lang = InvalidOid;     /* not currently interesting */
2123                 agginfo[i].aggfn.nargs = 1;
2124                 agginfo[i].aggfn.argtypes = (Oid *) malloc(sizeof(Oid));
2125                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_aggbasetype));
2126                 agginfo[i].aggfn.prorettype = InvalidOid;       /* not saved */
2127                 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
2128                 agginfo[i].anybasetype = false; /* computed when it's dumped */
2129                 agginfo[i].fmtbasetype = NULL;  /* computed when it's dumped */
2130         }
2131
2132         PQclear(res);
2133
2134         destroyPQExpBuffer(query);
2135
2136         return agginfo;
2137 }
2138
2139 /*
2140  * getFuncs:
2141  *        read all the user-defined functions in the system catalogs and
2142  * return them in the FuncInfo* structure
2143  *
2144  * numFuncs is set to the number of functions read in
2145  */
2146 FuncInfo *
2147 getFuncs(int *numFuncs)
2148 {
2149         PGresult   *res;
2150         int                     ntups;
2151         int                     i;
2152         PQExpBuffer query = createPQExpBuffer();
2153         FuncInfo   *finfo;
2154         int                     i_tableoid;
2155         int                     i_oid;
2156         int                     i_proname;
2157         int                     i_pronamespace;
2158         int                     i_usename;
2159         int                     i_prolang;
2160         int                     i_pronargs;
2161         int                     i_proargtypes;
2162         int                     i_prorettype;
2163         int                     i_proacl;
2164
2165         /* Make sure we are in proper schema */
2166         selectSourceSchema("pg_catalog");
2167
2168         /* find all user-defined funcs */
2169
2170         if (g_fout->remoteVersion >= 70300)
2171         {
2172                 appendPQExpBuffer(query,
2173                                                   "SELECT tableoid, oid, proname, prolang, "
2174                                                   "pronargs, proargtypes, prorettype, proacl, "
2175                                                   "pronamespace, "
2176                                                   "(select usename from pg_user where proowner = usesysid) as usename "
2177                                                   "FROM pg_proc "
2178                                                   "WHERE NOT proisagg "
2179                                                   "AND pronamespace != "
2180                   "(select oid from pg_namespace where nspname = 'pg_catalog')");
2181         }
2182         else if (g_fout->remoteVersion >= 70100)
2183         {
2184                 appendPQExpBuffer(query,
2185                                                   "SELECT tableoid, oid, proname, prolang, "
2186                                                   "pronargs, proargtypes, prorettype, "
2187                                                   "'{=X}' as proacl, "
2188                                                   "0::oid as pronamespace, "
2189                                                   "(select usename from pg_user where proowner = usesysid) as usename "
2190                                                   "FROM pg_proc "
2191                                                   "where pg_proc.oid > '%u'::oid",
2192                                                   g_last_builtin_oid);
2193         }
2194         else
2195         {
2196                 appendPQExpBuffer(query,
2197                                                   "SELECT "
2198                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_proc') AS tableoid, "
2199                                                   "oid, proname, prolang, "
2200                                                   "pronargs, proargtypes, prorettype, "
2201                                                   "'{=X}' as proacl, "
2202                                                   "0::oid as pronamespace, "
2203                                                   "(select usename from pg_user where proowner = usesysid) as usename "
2204                                                   "FROM pg_proc "
2205                                                   "where pg_proc.oid > '%u'::oid",
2206                                                   g_last_builtin_oid);
2207         }
2208
2209         res = PQexec(g_conn, query->data);
2210         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2211
2212         ntups = PQntuples(res);
2213
2214         *numFuncs = ntups;
2215
2216         finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
2217
2218         i_tableoid = PQfnumber(res, "tableoid");
2219         i_oid = PQfnumber(res, "oid");
2220         i_proname = PQfnumber(res, "proname");
2221         i_pronamespace = PQfnumber(res, "pronamespace");
2222         i_usename = PQfnumber(res, "usename");
2223         i_prolang = PQfnumber(res, "prolang");
2224         i_pronargs = PQfnumber(res, "pronargs");
2225         i_proargtypes = PQfnumber(res, "proargtypes");
2226         i_prorettype = PQfnumber(res, "prorettype");
2227         i_proacl = PQfnumber(res, "proacl");
2228
2229         for (i = 0; i < ntups; i++)
2230         {
2231                 finfo[i].dobj.objType = DO_FUNC;
2232                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2233                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2234                 AssignDumpId(&finfo[i].dobj);
2235                 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
2236                 finfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
2237                                                                                           finfo[i].dobj.catId.oid);
2238                 finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2239                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
2240                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
2241                 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
2242                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
2243                 if (finfo[i].nargs == 0)
2244                         finfo[i].argtypes = NULL;
2245                 else
2246                 {
2247                         finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
2248                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
2249                                                   finfo[i].argtypes, finfo[i].nargs);
2250                 }
2251
2252                 if (strlen(finfo[i].usename) == 0)
2253                         write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
2254                                           finfo[i].dobj.name);
2255         }
2256
2257         PQclear(res);
2258
2259         destroyPQExpBuffer(query);
2260
2261         return finfo;
2262 }
2263
2264 /*
2265  * getTables
2266  *        read all the user-defined tables (no indexes, no catalogs)
2267  * in the system catalogs return them in the TableInfo* structure
2268  *
2269  * numTables is set to the number of tables read in
2270  */
2271 TableInfo *
2272 getTables(int *numTables)
2273 {
2274         PGresult   *res;
2275         int                     ntups;
2276         int                     i;
2277         PQExpBuffer query = createPQExpBuffer();
2278         PQExpBuffer delqry = createPQExpBuffer();
2279         PQExpBuffer lockquery = createPQExpBuffer();
2280         TableInfo  *tblinfo;
2281         int                     i_reltableoid;
2282         int                     i_reloid;
2283         int                     i_relname;
2284         int                     i_relnamespace;
2285         int                     i_relkind;
2286         int                     i_relacl;
2287         int                     i_usename;
2288         int                     i_relchecks;
2289         int                     i_reltriggers;
2290         int                     i_relhasindex;
2291         int                     i_relhasrules;
2292         int                     i_relhasoids;
2293         int                     i_owning_tab;
2294         int                     i_owning_col;
2295
2296         /* Make sure we are in proper schema */
2297         selectSourceSchema("pg_catalog");
2298
2299         /*
2300          * Find all the tables (including views and sequences).
2301          *
2302          * We include system catalogs, so that we can work if a user table is
2303          * defined to inherit from a system catalog (pretty weird, but...)
2304          *
2305          * We ignore tables that are not type 'r' (ordinary relation) or 'S'
2306          * (sequence) or 'v' (view).
2307          *
2308          * Note: in this phase we should collect only a minimal amount of
2309          * information about each table, basically just enough to decide if it
2310          * is interesting.      We must fetch all tables in this phase because
2311          * otherwise we cannot correctly identify inherited columns, serial
2312          * columns, etc.
2313          */
2314
2315         if (g_fout->remoteVersion >= 70300)
2316         {
2317                 /*
2318                  * Left join to pick up dependency info linking sequences to their
2319                  * serial column, if any
2320                  */
2321                 appendPQExpBuffer(query,
2322                                                   "SELECT c.tableoid, c.oid, relname, "
2323                                                   "relacl, relkind, relnamespace, "
2324                                                   "(select usename from pg_user where relowner = usesysid) as usename, "
2325                                                   "relchecks, reltriggers, "
2326                                                   "relhasindex, relhasrules, relhasoids, "
2327                                                   "d.refobjid as owning_tab, "
2328                                                   "d.refobjsubid as owning_col "
2329                                                   "from pg_class c "
2330                                                   "left join pg_depend d on "
2331                                                   "(c.relkind = '%c' and "
2332                                                 "d.classid = c.tableoid and d.objid = c.oid and "
2333                                                   "d.objsubid = 0 and "
2334                                                 "d.refclassid = c.tableoid and d.deptype = 'i') "
2335                                                   "where relkind in ('%c', '%c', '%c') "
2336                                                   "order by c.oid",
2337                                                   RELKIND_SEQUENCE,
2338                                            RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2339         }
2340         else if (g_fout->remoteVersion >= 70200)
2341         {
2342                 appendPQExpBuffer(query,
2343                                                 "SELECT tableoid, oid, relname, relacl, relkind, "
2344                                                   "0::oid as relnamespace, "
2345                                                   "(select usename from pg_user where relowner = usesysid) as usename, "
2346                                                   "relchecks, reltriggers, "
2347                                                   "relhasindex, relhasrules, relhasoids, "
2348                                                   "NULL::oid as owning_tab, "
2349                                                   "NULL::int4 as owning_col "
2350                                                   "from pg_class "
2351                                                   "where relkind in ('%c', '%c', '%c') "
2352                                                   "order by oid",
2353                                            RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2354         }
2355         else if (g_fout->remoteVersion >= 70100)
2356         {
2357                 /* all tables have oids in 7.1 */
2358                 appendPQExpBuffer(query,
2359                                                 "SELECT tableoid, oid, relname, relacl, relkind, "
2360                                                   "0::oid as relnamespace, "
2361                                                   "(select usename from pg_user where relowner = usesysid) as usename, "
2362                                                   "relchecks, reltriggers, "
2363                                                   "relhasindex, relhasrules, "
2364                                                   "'t'::bool as relhasoids, "
2365                                                   "NULL::oid as owning_tab, "
2366                                                   "NULL::int4 as owning_col "
2367                                                   "from pg_class "
2368                                                   "where relkind in ('%c', '%c', '%c') "
2369                                                   "order by oid",
2370                                            RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2371         }
2372         else
2373         {
2374                 /*
2375                  * Before 7.1, view relkind was not set to 'v', so we must check
2376                  * if we have a view by looking for a rule in pg_rewrite.
2377                  */
2378                 appendPQExpBuffer(query,
2379                                                   "SELECT "
2380                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
2381                                                   "oid, relname, relacl, "
2382                                                   "CASE WHEN relhasrules and relkind = 'r' "
2383                                   "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
2384                                   "             r.ev_class = c.oid AND r.ev_type = '1') "
2385                                                   "THEN '%c'::\"char\" "
2386                                                   "ELSE relkind END AS relkind,"
2387                                                   "0::oid as relnamespace, "
2388                                                   "(select usename from pg_user where relowner = usesysid) as usename, "
2389                                                   "relchecks, reltriggers, "
2390                                                   "relhasindex, relhasrules, "
2391                                                   "'t'::bool as relhasoids, "
2392                                                   "NULL::oid as owning_tab, "
2393                                                   "NULL::int4 as owning_col "
2394                                                   "from pg_class c "
2395                                                   "where relkind in ('%c', '%c') "
2396                                                   "order by oid",
2397                                                   RELKIND_VIEW,
2398                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
2399         }
2400
2401         res = PQexec(g_conn, query->data);
2402         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2403
2404         ntups = PQntuples(res);
2405
2406         *numTables = ntups;
2407
2408         /*
2409          * Extract data from result and lock dumpable tables.  We do the
2410          * locking before anything else, to minimize the window wherein a
2411          * table could disappear under us.
2412          *
2413          * Note that we have to save info about all tables here, even when
2414          * dumping only one, because we don't yet know which tables might be
2415          * inheritance ancestors of the target table.
2416          */
2417         tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
2418
2419         i_reltableoid = PQfnumber(res, "tableoid");
2420         i_reloid = PQfnumber(res, "oid");
2421         i_relname = PQfnumber(res, "relname");
2422         i_relnamespace = PQfnumber(res, "relnamespace");
2423         i_relacl = PQfnumber(res, "relacl");
2424         i_relkind = PQfnumber(res, "relkind");
2425         i_usename = PQfnumber(res, "usename");
2426         i_relchecks = PQfnumber(res, "relchecks");
2427         i_reltriggers = PQfnumber(res, "reltriggers");
2428         i_relhasindex = PQfnumber(res, "relhasindex");
2429         i_relhasrules = PQfnumber(res, "relhasrules");
2430         i_relhasoids = PQfnumber(res, "relhasoids");
2431         i_owning_tab = PQfnumber(res, "owning_tab");
2432         i_owning_col = PQfnumber(res, "owning_col");
2433
2434         for (i = 0; i < ntups; i++)
2435         {
2436                 tblinfo[i].dobj.objType = DO_TABLE;
2437                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
2438                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
2439                 AssignDumpId(&tblinfo[i].dobj);
2440                 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
2441                 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
2442                                                                                                 tblinfo[i].dobj.catId.oid);
2443                 tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2444                 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
2445                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
2446                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
2447                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
2448                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
2449                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
2450                 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2451                 if (PQgetisnull(res, i, i_owning_tab))
2452                 {
2453                         tblinfo[i].owning_tab = InvalidOid;
2454                         tblinfo[i].owning_col = 0;
2455                 }
2456                 else
2457                 {
2458                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
2459                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
2460                 }
2461
2462                 /* other fields were zeroed above */
2463
2464                 /*
2465                  * Decide whether we want to dump this table.  Sequences owned by
2466                  * serial columns are never dumpable on their own; we will
2467                  * transpose their owning table's dump flag to them below.
2468                  */
2469                 if (OidIsValid(tblinfo[i].owning_tab))
2470                         tblinfo[i].dump = false;
2471                 else
2472                         selectDumpableTable(&tblinfo[i]);
2473                 tblinfo[i].interesting = tblinfo[i].dump;
2474
2475                 /*
2476                  * Read-lock target tables to make sure they aren't DROPPED or
2477                  * altered in schema before we get around to dumping them.
2478                  *
2479                  * Note that we don't explicitly lock parents of the target tables;
2480                  * we assume our lock on the child is enough to prevent schema
2481                  * alterations to parent tables.
2482                  *
2483                  * NOTE: it'd be kinda nice to lock views and sequences too, not only
2484                  * plain tables, but the backend doesn't presently allow that.
2485                  */
2486                 if (tblinfo[i].dump && tblinfo[i].relkind == RELKIND_RELATION)
2487                 {
2488                         resetPQExpBuffer(lockquery);
2489                         appendPQExpBuffer(lockquery,
2490                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
2491                                                  fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
2492                                                                                 tblinfo[i].dobj.name));
2493                         do_sql_command(g_conn, lockquery->data);
2494                 }
2495
2496                 /* Emit notice if join for owner failed */
2497                 if (strlen(tblinfo[i].usename) == 0)
2498                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
2499                                           tblinfo[i].dobj.name);
2500         }
2501
2502         /*
2503          * If the user is attempting to dump a specific table, check to ensure
2504          * that the specified table actually exists.  (This is a bit simplistic
2505          * since we don't fully check the combination of -n and -t switches.)
2506          */
2507         if (selectTableName)
2508         {
2509                 for (i = 0; i < ntups; i++)
2510                         if (strcmp(tblinfo[i].dobj.name, selectTableName) == 0)
2511                                 break;
2512
2513                 /* Didn't find a match */
2514                 if (i == ntups)
2515                 {
2516                         write_msg(NULL, "specified table \"%s\" does not exist\n",
2517                                           selectTableName);
2518                         exit_nicely();
2519                 }
2520         }
2521
2522         PQclear(res);
2523         destroyPQExpBuffer(query);
2524         destroyPQExpBuffer(delqry);
2525         destroyPQExpBuffer(lockquery);
2526
2527         return tblinfo;
2528 }
2529
2530 /*
2531  * getInherits
2532  *        read all the inheritance information
2533  * from the system catalogs return them in the InhInfo* structure
2534  *
2535  * numInherits is set to the number of pairs read in
2536  */
2537 InhInfo *
2538 getInherits(int *numInherits)
2539 {
2540         PGresult   *res;
2541         int                     ntups;
2542         int                     i;
2543         PQExpBuffer query = createPQExpBuffer();
2544         InhInfo    *inhinfo;
2545
2546         int                     i_inhrelid;
2547         int                     i_inhparent;
2548
2549         /* Make sure we are in proper schema */
2550         selectSourceSchema("pg_catalog");
2551
2552         /* find all the inheritance information */
2553
2554         appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
2555
2556         res = PQexec(g_conn, query->data);
2557         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2558
2559         ntups = PQntuples(res);
2560
2561         *numInherits = ntups;
2562
2563         inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
2564
2565         i_inhrelid = PQfnumber(res, "inhrelid");
2566         i_inhparent = PQfnumber(res, "inhparent");
2567
2568         for (i = 0; i < ntups; i++)
2569         {
2570                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
2571                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
2572         }
2573
2574         PQclear(res);
2575
2576         destroyPQExpBuffer(query);
2577
2578         return inhinfo;
2579 }
2580
2581 /*
2582  * getIndexes
2583  *        get information about every index on a dumpable table
2584  *
2585  * Note: index data is not returned directly to the caller, but it
2586  * does get entered into the DumpableObject tables.
2587  */
2588 void
2589 getIndexes(TableInfo tblinfo[], int numTables)
2590 {
2591         int                     i,
2592                                 j;
2593         PQExpBuffer query = createPQExpBuffer();
2594         PGresult   *res;
2595         IndxInfo   *indxinfo;
2596         ConstraintInfo *constrinfo;
2597         int                     i_tableoid,
2598                                 i_oid,
2599                                 i_indexname,
2600                                 i_indexdef,
2601                                 i_indnkeys,
2602                                 i_indkey,
2603                                 i_indisclustered,
2604                                 i_contype,
2605                                 i_conname,
2606                                 i_contableoid,
2607                                 i_conoid;
2608         int                     ntups;
2609
2610         for (i = 0; i < numTables; i++)
2611         {
2612                 TableInfo  *tbinfo = &tblinfo[i];
2613
2614                 /* Only plain tables have indexes */
2615                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
2616                         continue;
2617
2618                 if (!tbinfo->dump)
2619                         continue;
2620
2621                 if (g_verbose)
2622                         write_msg(NULL, "reading indexes for table \"%s\"\n",
2623                                           tbinfo->dobj.name);
2624
2625                 /* Make sure we are in proper schema so indexdef is right */
2626                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
2627
2628                 /*
2629                  * The point of the messy-looking outer join is to find a
2630                  * constraint that is related by an internal dependency link to
2631                  * the index. If we find one, create a CONSTRAINT entry linked
2632                  * to the INDEX entry.  We assume an index won't have more than
2633                  * one internal dependency.
2634                  */
2635                 resetPQExpBuffer(query);
2636                 if (g_fout->remoteVersion >= 70300)
2637                 {
2638                         appendPQExpBuffer(query,
2639                                                           "SELECT t.tableoid, t.oid, "
2640                                                           "t.relname as indexname, "
2641                                  "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
2642                                                           "t.relnatts as indnkeys, "
2643                                                           "i.indkey, i.indisclustered, "
2644                                                           "c.contype, c.conname, "
2645                                                           "c.tableoid as contableoid, "
2646                                                           "c.oid as conoid "
2647                                                           "FROM pg_catalog.pg_index i "
2648                                   "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
2649                                                           "LEFT JOIN pg_catalog.pg_depend d "
2650                                                           "ON (d.classid = t.tableoid "
2651                                                           "AND d.objid = t.oid "
2652                                                           "AND d.deptype = 'i') "
2653                                                           "LEFT JOIN pg_catalog.pg_constraint c "
2654                                                           "ON (d.refclassid = c.tableoid "
2655                                                           "AND d.refobjid = c.oid) "
2656                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
2657                                                           "ORDER BY indexname",
2658                                                           tbinfo->dobj.catId.oid);
2659                 }
2660                 else if (g_fout->remoteVersion >= 70100)
2661                 {
2662                         appendPQExpBuffer(query,
2663                                                           "SELECT t.tableoid, t.oid, "
2664                                                           "t.relname as indexname, "
2665                                                           "pg_get_indexdef(i.indexrelid) as indexdef, "
2666                                                           "t.relnatts as indnkeys, "
2667                                                           "i.indkey, false as indisclustered, "
2668                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
2669                                                           "ELSE '0'::char END as contype, "
2670                                                           "t.relname as conname, "
2671                                                           "0::oid as contableoid, "
2672                                                           "t.oid as conoid "
2673                                                           "FROM pg_index i, pg_class t "
2674                                                           "WHERE t.oid = i.indexrelid "
2675                                                           "AND i.indrelid = '%u'::oid "
2676                                                           "ORDER BY indexname",
2677                                                           tbinfo->dobj.catId.oid);
2678                 }
2679                 else
2680                 {
2681                         appendPQExpBuffer(query,
2682                                                           "SELECT "
2683                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
2684                                                           "t.oid, "
2685                                                           "t.relname as indexname, "
2686                                                           "pg_get_indexdef(i.indexrelid) as indexdef, "
2687                                                           "t.relnatts as indnkeys, "
2688                                                           "i.indkey, false as indisclustered, "
2689                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
2690                                                           "ELSE '0'::char END as contype, "
2691                                                           "t.relname as conname, "
2692                                                           "0::oid as contableoid, "
2693                                                           "t.oid as conoid "
2694                                                           "FROM pg_index i, pg_class t "
2695                                                           "WHERE t.oid = i.indexrelid "
2696                                                           "AND i.indrelid = '%u'::oid "
2697                                                           "ORDER BY indexname",
2698                                                           tbinfo->dobj.catId.oid);
2699                 }
2700
2701                 res = PQexec(g_conn, query->data);
2702                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2703
2704                 ntups = PQntuples(res);
2705
2706                 i_tableoid = PQfnumber(res, "tableoid");
2707                 i_oid = PQfnumber(res, "oid");
2708                 i_indexname = PQfnumber(res, "indexname");
2709                 i_indexdef = PQfnumber(res, "indexdef");
2710                 i_indnkeys = PQfnumber(res, "indnkeys");
2711                 i_indkey = PQfnumber(res, "indkey");
2712                 i_indisclustered = PQfnumber(res, "indisclustered");
2713                 i_contype = PQfnumber(res, "contype");
2714                 i_conname = PQfnumber(res, "conname");
2715                 i_contableoid = PQfnumber(res, "contableoid");
2716                 i_conoid = PQfnumber(res, "conoid");
2717
2718                 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
2719                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
2720
2721                 for (j = 0; j < ntups; j++)
2722                 {
2723                         char            contype;
2724
2725                         indxinfo[j].dobj.objType = DO_INDEX;
2726                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
2727                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
2728                         AssignDumpId(&indxinfo[j].dobj);
2729                         indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
2730                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
2731                         indxinfo[j].indextable = tbinfo;
2732                         indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
2733                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
2734                         /*
2735                          * In pre-7.4 releases, indkeys may contain more entries than
2736                          * indnkeys says (since indnkeys will be 1 for a functional
2737                          * index).  We don't actually care about this case since we don't
2738                          * examine indkeys except for indexes associated with PRIMARY
2739                          * and UNIQUE constraints, which are never functional indexes.
2740                          * But we have to allocate enough space to keep parseOidArray
2741                          * from complaining.
2742                          */
2743                         indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
2744                         parseOidArray(PQgetvalue(res, j, i_indkey),
2745                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
2746                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
2747                         contype = *(PQgetvalue(res, j, i_contype));
2748
2749                         if (contype == 'p' || contype == 'u')
2750                         {
2751                                 /*
2752                                  * If we found a constraint matching the index, create an
2753                                  * entry for it.
2754                                  *
2755                                  * In a pre-7.3 database, we take this path iff the index was
2756                                  * marked indisprimary.
2757                                  */
2758                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
2759                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
2760                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
2761                                 AssignDumpId(&constrinfo[j].dobj);
2762                                 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
2763                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
2764                                 constrinfo[j].contable = tbinfo;
2765                                 constrinfo[j].condomain = NULL;
2766                                 constrinfo[j].contype = contype;
2767                                 constrinfo[j].condef = NULL;
2768                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
2769                                 constrinfo[j].coninherited = false;
2770                                 constrinfo[j].separate = true;
2771                                 
2772                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
2773
2774                                 /* If pre-7.3 DB, better make sure table comes first */
2775                                 addObjectDependency(&constrinfo[j].dobj,
2776                                                                         tbinfo->dobj.dumpId);
2777                         }
2778                         else
2779                         {
2780                                 /* Plain secondary index */
2781                                 indxinfo[j].indexconstraint = 0;
2782                         }
2783                 }
2784
2785                 PQclear(res);
2786         }
2787
2788         destroyPQExpBuffer(query);
2789 }
2790
2791 /*
2792  * getConstraints
2793  *
2794  * Get info about constraints on dumpable tables.
2795  *
2796  * Currently handles foreign keys only.
2797  * Unique and primary key constraints are handled with indexes,
2798  * while check constraints are processed in getTableAttrs().
2799  */
2800 void
2801 getConstraints(TableInfo tblinfo[], int numTables)
2802 {
2803         int                     i,
2804                                 j;
2805         ConstraintInfo *constrinfo;
2806         PQExpBuffer query;
2807         PGresult   *res;
2808         int                     i_condef,
2809                                 i_contableoid,
2810                                 i_conoid,
2811                                 i_conname;
2812         int                     ntups;
2813
2814         /* pg_constraint was created in 7.3, so nothing to do if older */
2815         if (g_fout->remoteVersion < 70300)
2816                 return;
2817
2818         query = createPQExpBuffer();
2819
2820         for (i = 0; i < numTables; i++)
2821         {
2822                 TableInfo  *tbinfo = &tblinfo[i];
2823
2824                 if (tbinfo->ntrig == 0 || !tbinfo->dump)
2825                         continue;
2826
2827                 if (g_verbose)
2828                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
2829                                           tbinfo->dobj.name);
2830
2831                 /*
2832                  * select table schema to ensure constraint expr is qualified if
2833                  * needed
2834                  */
2835                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
2836
2837                 resetPQExpBuffer(query);
2838                 appendPQExpBuffer(query,
2839                                                   "SELECT tableoid, oid, conname, "
2840                                                   "pg_catalog.pg_get_constraintdef(oid) as condef "
2841                                                   "FROM pg_catalog.pg_constraint "
2842                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
2843                                                   "AND contype = 'f'",
2844                                                   tbinfo->dobj.catId.oid);
2845                 res = PQexec(g_conn, query->data);
2846                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2847
2848                 ntups = PQntuples(res);
2849
2850                 i_contableoid = PQfnumber(res, "tableoid");
2851                 i_conoid = PQfnumber(res, "oid");
2852                 i_conname = PQfnumber(res, "conname");
2853                 i_condef = PQfnumber(res, "condef");
2854
2855                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
2856
2857                 for (j = 0; j < ntups; j++)
2858                 {
2859                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
2860                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
2861                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
2862                         AssignDumpId(&constrinfo[j].dobj);
2863                         constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
2864                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
2865                         constrinfo[j].contable = tbinfo;
2866                         constrinfo[j].condomain = NULL;
2867                         constrinfo[j].contype = 'f';
2868                         constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
2869                         constrinfo[j].conindex = 0;
2870                         constrinfo[j].coninherited = false;
2871                         constrinfo[j].separate = true;
2872                 }
2873
2874                 PQclear(res);
2875         }
2876
2877         destroyPQExpBuffer(query);
2878 }
2879
2880 /*
2881  * getDomainConstraints
2882  *
2883  * Get info about constraints on a domain.
2884  */
2885 static void
2886 getDomainConstraints(TypeInfo *tinfo)
2887 {
2888         int                     i;
2889         ConstraintInfo *constrinfo;
2890         PQExpBuffer query;
2891         PGresult   *res;
2892         int                     i_tableoid,
2893                                 i_oid,
2894                                 i_conname,
2895                                 i_consrc;
2896         int                     ntups;
2897
2898         /* pg_constraint was created in 7.3, so nothing to do if older */
2899         if (g_fout->remoteVersion < 70300)
2900                 return;
2901
2902         /*
2903          * select appropriate schema to ensure names in constraint are properly
2904          * qualified
2905          */
2906         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
2907
2908         query = createPQExpBuffer();
2909
2910         if (g_fout->remoteVersion >= 70400)
2911                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2912                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc "
2913                                                   "FROM pg_catalog.pg_constraint "
2914                                                   "WHERE contypid = '%u'::pg_catalog.oid "
2915                                                   "ORDER BY conname",
2916                                                   tinfo->dobj.catId.oid);
2917         else
2918                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2919                                                   "'CHECK (' || consrc || ')' AS consrc "
2920                                                   "FROM pg_catalog.pg_constraint "
2921                                                   "WHERE contypid = '%u'::pg_catalog.oid "
2922                                                   "ORDER BY conname",
2923                                                   tinfo->dobj.catId.oid);
2924
2925         res = PQexec(g_conn, query->data);
2926         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2927
2928         ntups = PQntuples(res);
2929
2930         i_tableoid = PQfnumber(res, "tableoid");
2931         i_oid = PQfnumber(res, "oid");
2932         i_conname = PQfnumber(res, "conname");
2933         i_consrc = PQfnumber(res, "consrc");
2934
2935         constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
2936
2937         tinfo->nDomChecks = ntups;
2938         tinfo->domChecks = constrinfo;
2939
2940         for (i = 0; i < ntups; i++)
2941         {
2942                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
2943                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2944                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2945                 AssignDumpId(&constrinfo[i].dobj);
2946                 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2947                 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
2948                 constrinfo[i].contable = NULL;
2949                 constrinfo[i].condomain = tinfo;
2950                 constrinfo[i].contype = 'c';
2951                 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
2952                 constrinfo[i].conindex = 0;
2953                 constrinfo[i].coninherited = false;
2954                 constrinfo[i].separate = false;
2955                 /*
2956                  * Make the domain depend on the constraint, ensuring it won't
2957                  * be output till any constraint dependencies are OK.
2958                  */
2959                 addObjectDependency(&tinfo->dobj,
2960                                                         constrinfo[i].dobj.dumpId);
2961         }
2962
2963         PQclear(res);
2964
2965         destroyPQExpBuffer(query);
2966 }
2967
2968 /*
2969  * getRules
2970  *        get basic information about every rule in the system
2971  *
2972  * numRules is set to the number of rules read in
2973  */
2974 RuleInfo *
2975 getRules(int *numRules)
2976 {
2977         PGresult   *res;
2978         int                     ntups;
2979         int                     i;
2980         PQExpBuffer query = createPQExpBuffer();
2981         RuleInfo   *ruleinfo;
2982         int                     i_tableoid;
2983         int                     i_oid;
2984         int                     i_rulename;
2985         int                     i_ruletable;
2986         int                     i_ev_type;
2987         int                     i_is_instead;
2988
2989         /* Make sure we are in proper schema */
2990         selectSourceSchema("pg_catalog");
2991
2992         if (g_fout->remoteVersion >= 70100)
2993         {
2994                 appendPQExpBuffer(query, "SELECT "
2995                                                   "tableoid, oid, rulename, "
2996                                                   "ev_class as ruletable, ev_type, is_instead "
2997                                                   "FROM pg_rewrite "
2998                                                   "ORDER BY oid");
2999         }
3000         else
3001         {
3002                 appendPQExpBuffer(query, "SELECT "
3003                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
3004                                                   "oid, rulename, "
3005                                                   "ev_class as ruletable, ev_type, is_instead "
3006                                                   "FROM pg_rewrite "
3007                                                   "ORDER BY oid");
3008         }
3009
3010         res = PQexec(g_conn, query->data);
3011         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3012
3013         ntups = PQntuples(res);
3014
3015         *numRules = ntups;
3016
3017         ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
3018
3019         i_tableoid = PQfnumber(res, "tableoid");
3020         i_oid = PQfnumber(res, "oid");
3021         i_rulename = PQfnumber(res, "rulename");
3022         i_ruletable = PQfnumber(res, "ruletable");
3023         i_ev_type = PQfnumber(res, "ev_type");
3024         i_is_instead = PQfnumber(res, "is_instead");
3025
3026         for (i = 0; i < ntups; i++)
3027         {
3028                 Oid             ruletableoid;
3029
3030                 ruleinfo[i].dobj.objType = DO_RULE;
3031                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3032                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3033                 AssignDumpId(&ruleinfo[i].dobj);
3034                 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
3035                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
3036                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
3037                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
3038                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
3039                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
3040                 if (ruleinfo[i].ruletable)
3041                 {
3042                         /*
3043                          * If the table is a view, force its ON SELECT rule to be sorted
3044                          * before the view itself --- this ensures that any dependencies
3045                          * for the rule affect the table's positioning.  Other rules
3046                          * are forced to appear after their table.
3047                          */
3048                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
3049                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
3050                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
3051                                                                         ruleinfo[i].dobj.dumpId);
3052                         else
3053                                 addObjectDependency(&ruleinfo[i].dobj,
3054                                                                         ruleinfo[i].ruletable->dobj.dumpId);
3055                 }
3056         }
3057
3058         PQclear(res);
3059
3060         destroyPQExpBuffer(query);
3061
3062         return ruleinfo;
3063 }
3064
3065 /*
3066  * getTriggers
3067  *        get information about every trigger on a dumpable table
3068  *
3069  * Note: trigger data is not returned directly to the caller, but it
3070  * does get entered into the DumpableObject tables.
3071  */
3072 void
3073 getTriggers(TableInfo tblinfo[], int numTables)
3074 {
3075         int                     i,
3076                                 j;
3077         PQExpBuffer query = createPQExpBuffer();
3078         PGresult   *res;
3079         TriggerInfo *tginfo;
3080         int                     i_tableoid,
3081                                 i_oid,
3082                                 i_tgname,
3083                                 i_tgfname,
3084                                 i_tgtype,
3085                                 i_tgnargs,
3086                                 i_tgargs,
3087                                 i_tgisconstraint,
3088                                 i_tgconstrname,
3089                                 i_tgconstrrelid,
3090                                 i_tgconstrrelname,
3091                                 i_tgdeferrable,
3092                                 i_tginitdeferred;
3093         int                     ntups;
3094
3095         for (i = 0; i < numTables; i++)
3096         {
3097                 TableInfo  *tbinfo = &tblinfo[i];
3098
3099                 if (tbinfo->ntrig == 0 || !tbinfo->dump)
3100                         continue;
3101
3102                 if (g_verbose)
3103                         write_msg(NULL, "reading triggers for table \"%s\"\n",
3104                                           tbinfo->dobj.name);
3105
3106                 /*
3107                  * select table schema to ensure regproc name is qualified if
3108                  * needed
3109                  */
3110                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3111
3112                 resetPQExpBuffer(query);
3113                 if (g_fout->remoteVersion >= 70300)
3114                 {
3115                         /*
3116                          * We ignore triggers that are tied to a foreign-key
3117                          * constraint
3118                          */
3119                         appendPQExpBuffer(query,
3120                                                           "SELECT tgname, "
3121                                                           "tgfoid::pg_catalog.regproc as tgfname, "
3122                                                           "tgtype, tgnargs, tgargs, "
3123                                                    "tgisconstraint, tgconstrname, tgdeferrable, "
3124                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
3125                                  "tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
3126                                                           "from pg_catalog.pg_trigger t "
3127                                                           "where tgrelid = '%u'::pg_catalog.oid "
3128                                                           "and (not tgisconstraint "
3129                                                           " OR NOT EXISTS"
3130                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
3131                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
3132                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
3133                                                           tbinfo->dobj.catId.oid);
3134                 }
3135                 else if (g_fout->remoteVersion >= 70100)
3136                 {
3137                         appendPQExpBuffer(query,
3138                                                         "SELECT tgname, tgfoid::regproc as tgfname, "
3139                                                           "tgtype, tgnargs, tgargs, "
3140                                                    "tgisconstraint, tgconstrname, tgdeferrable, "
3141                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
3142                           "(select relname from pg_class where oid = tgconstrrelid) "
3143                                                           "             as tgconstrrelname "
3144                                                           "from pg_trigger "
3145                                                           "where tgrelid = '%u'::oid",
3146                                                           tbinfo->dobj.catId.oid);
3147                 }
3148                 else
3149                 {
3150                         appendPQExpBuffer(query,
3151                                                         "SELECT tgname, tgfoid::regproc as tgfname, "
3152                                                           "tgtype, tgnargs, tgargs, "
3153                                                    "tgisconstraint, tgconstrname, tgdeferrable, "
3154                                                           "tgconstrrelid, tginitdeferred, "
3155                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
3156
3157                                                           "oid, "
3158                           "(select relname from pg_class where oid = tgconstrrelid) "
3159                                                           "             as tgconstrrelname "
3160                                                           "from pg_trigger "
3161                                                           "where tgrelid = '%u'::oid",
3162                                                           tbinfo->dobj.catId.oid);
3163                 }
3164                 res = PQexec(g_conn, query->data);
3165                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3166
3167                 ntups = PQntuples(res);
3168
3169                 /*
3170                  * We may have less triggers than recorded due to having ignored
3171                  * foreign-key triggers
3172                  */
3173                 if (ntups > tbinfo->ntrig)
3174                 {
3175                         write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
3176                                           tbinfo->ntrig, tbinfo->dobj.name, ntups);
3177                         exit_nicely();
3178                 }
3179                 i_tableoid = PQfnumber(res, "tableoid");
3180                 i_oid = PQfnumber(res, "oid");
3181                 i_tgname = PQfnumber(res, "tgname");
3182                 i_tgfname = PQfnumber(res, "tgfname");
3183                 i_tgtype = PQfnumber(res, "tgtype");
3184                 i_tgnargs = PQfnumber(res, "tgnargs");
3185                 i_tgargs = PQfnumber(res, "tgargs");
3186                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
3187                 i_tgconstrname = PQfnumber(res, "tgconstrname");
3188                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
3189                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
3190                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
3191                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
3192
3193                 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
3194
3195                 for (j = 0; j < ntups; j++)
3196                 {
3197                         tginfo[j].dobj.objType = DO_TRIGGER;
3198                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3199                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3200                         AssignDumpId(&tginfo[j].dobj);
3201                         tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
3202                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
3203                         tginfo[j].tgtable = tbinfo;
3204                         tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
3205                         tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
3206                         tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
3207                         tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
3208                         tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
3209                         tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
3210                         tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
3211
3212                         if (tginfo[j].tgisconstraint)
3213                         {
3214                                 tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
3215                                 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
3216                                 if (OidIsValid(tginfo[j].tgconstrrelid))
3217                                 {
3218                                         if (PQgetisnull(res, j, i_tgconstrrelname))
3219                                         {
3220                                                 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
3221                                                                   tginfo[j].dobj.name, tbinfo->dobj.name,
3222                                                                   tginfo[j].tgconstrrelid);
3223                                                 exit_nicely();
3224                                         }
3225                                         tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
3226                                 }
3227                                 else
3228                                         tginfo[j].tgconstrrelname = NULL;
3229                         }
3230                         else
3231                         {
3232                                 tginfo[j].tgconstrname = NULL;
3233                                 tginfo[j].tgconstrrelid = InvalidOid;
3234                                 tginfo[j].tgconstrrelname = NULL;
3235                         }
3236                 }
3237
3238                 PQclear(res);
3239         }
3240
3241         destroyPQExpBuffer(query);
3242 }
3243
3244 /*
3245  * getProcLangs
3246  *        get basic information about every procedural language in the system
3247  *
3248  * numProcLangs is set to the number of langs read in
3249  *
3250  * NB: this must run after getFuncs() because we assume we can do
3251  * findFuncByOid().
3252  */
3253 ProcLangInfo *
3254 getProcLangs(int *numProcLangs)
3255 {
3256         PGresult   *res;
3257         int                     ntups;
3258         int                     i;
3259         PQExpBuffer query = createPQExpBuffer();
3260         ProcLangInfo *planginfo;
3261         int                     i_tableoid;
3262         int                     i_oid;
3263         int                     i_lanname;
3264         int                     i_lanpltrusted;
3265         int                     i_lanplcallfoid;
3266         int                     i_lanvalidator = -1;
3267         int                     i_lanacl = -1;
3268
3269         /* Make sure we are in proper schema */
3270         selectSourceSchema("pg_catalog");
3271
3272         if (g_fout->remoteVersion >= 70100)
3273         {
3274                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
3275                                                   "WHERE lanispl "
3276                                                   "ORDER BY oid");
3277         }
3278         else
3279         {
3280                 appendPQExpBuffer(query, "SELECT "
3281                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
3282                                                   "oid, * FROM pg_language "
3283                                                   "WHERE lanispl "
3284                                                   "ORDER BY oid");
3285         }
3286
3287         res = PQexec(g_conn, query->data);
3288         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3289
3290         ntups = PQntuples(res);
3291
3292         *numProcLangs = ntups;
3293
3294         planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
3295
3296         i_tableoid = PQfnumber(res, "tableoid");
3297         i_oid = PQfnumber(res, "oid");
3298         i_lanname = PQfnumber(res, "lanname");
3299         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
3300         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
3301         if (g_fout->remoteVersion >= 70300)
3302         {
3303                 i_lanvalidator = PQfnumber(res, "lanvalidator");
3304                 i_lanacl = PQfnumber(res, "lanacl");
3305         }
3306
3307         for (i = 0; i < ntups; i++)
3308         {
3309                 planginfo[i].dobj.objType = DO_PROCLANG;
3310                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3311                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3312                 AssignDumpId(&planginfo[i].dobj);
3313
3314                 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
3315                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
3316                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
3317                 if (g_fout->remoteVersion >= 70300)
3318                 {
3319                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
3320                         planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
3321                 }
3322                 else
3323                 {
3324                         FuncInfo   *funcInfo;
3325
3326                         planginfo[i].lanvalidator = InvalidOid;
3327                         planginfo[i].lanacl = strdup("{=U}");
3328                         /*
3329                          * We need to make a dependency to ensure the function will
3330                          * be dumped first.  (In 7.3 and later the regular dependency
3331                          * mechanism will handle this for us.)
3332                          */
3333                         funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
3334                         if (funcInfo)
3335                                 addObjectDependency(&planginfo[i].dobj,
3336                                                                         funcInfo->dobj.dumpId);
3337                 }
3338         }
3339
3340         PQclear(res);
3341
3342         destroyPQExpBuffer(query);
3343
3344         return planginfo;
3345 }
3346
3347 /*
3348  * getCasts
3349  *        get basic information about every cast in the system
3350  *
3351  * numCasts is set to the number of casts read in
3352  */
3353 CastInfo *
3354 getCasts(int *numCasts)
3355 {
3356         PGresult   *res;
3357         int                     ntups;
3358         int                     i;
3359         PQExpBuffer query = createPQExpBuffer();
3360         CastInfo   *castinfo;
3361         int                     i_tableoid;
3362         int                     i_oid;
3363         int                     i_castsource;
3364         int                     i_casttarget;
3365         int                     i_castfunc;
3366         int                     i_castcontext;
3367
3368         /* Make sure we are in proper schema */
3369         selectSourceSchema("pg_catalog");
3370
3371         if (g_fout->remoteVersion >= 70300)
3372         {
3373                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
3374                                                   "castsource, casttarget, castfunc, castcontext "
3375                                                   "FROM pg_cast ORDER BY 3,4");
3376         }
3377         else
3378         {
3379                 appendPQExpBuffer(query, "SELECT 0 as tableoid, p.oid, "
3380                                                   "t1.oid as castsource, t2.oid as casttarget, "
3381                                                   "p.oid as castfunc, 'e' as castcontext "
3382                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
3383                                                   "WHERE p.pronargs = 1 AND "
3384                                                   "p.proargtypes[0] = t1.oid AND "
3385                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
3386                                                   "ORDER BY 3,4");
3387         }
3388
3389         res = PQexec(g_conn, query->data);
3390         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3391
3392         ntups = PQntuples(res);
3393
3394         *numCasts = ntups;
3395
3396         castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
3397
3398         i_tableoid = PQfnumber(res, "tableoid");
3399         i_oid = PQfnumber(res, "oid");
3400         i_castsource = PQfnumber(res, "castsource");
3401         i_casttarget = PQfnumber(res, "casttarget");
3402         i_castfunc = PQfnumber(res, "castfunc");
3403         i_castcontext = PQfnumber(res, "castcontext");
3404
3405         for (i = 0; i < ntups; i++)
3406         {
3407                 PQExpBufferData namebuf;
3408                 TypeInfo   *sTypeInfo;
3409                 TypeInfo   *tTypeInfo;
3410
3411                 castinfo[i].dobj.objType = DO_CAST;
3412                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3413                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3414                 AssignDumpId(&castinfo[i].dobj);
3415                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
3416                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
3417                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
3418                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
3419
3420                 /*
3421                  * Try to name cast as concatenation of typnames.  This is only
3422                  * used for purposes of sorting.  If we fail to find either type,
3423                  * the name will be an empty string.
3424                  */
3425                 initPQExpBuffer(&namebuf);
3426                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
3427                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
3428                 if (sTypeInfo && tTypeInfo)
3429                         appendPQExpBuffer(&namebuf, "%s %s",
3430                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
3431                 castinfo[i].dobj.name = namebuf.data;
3432
3433                 if (OidIsValid(castinfo[i].castfunc))
3434                 {
3435                         /*
3436                          * We need to make a dependency to ensure the function will
3437                          * be dumped first.  (In 7.3 and later the regular dependency
3438                          * mechanism will handle this for us.)
3439                          */
3440                         FuncInfo   *funcInfo;
3441
3442                         funcInfo = findFuncByOid(castinfo[i].castfunc);
3443                         if (funcInfo)
3444                                 addObjectDependency(&castinfo[i].dobj,
3445                                                                         funcInfo->dobj.dumpId);
3446                 }
3447         }
3448
3449         PQclear(res);
3450
3451         destroyPQExpBuffer(query);
3452
3453         return castinfo;
3454 }
3455
3456 /*
3457  * getTableAttrs -
3458  *        for each interesting table, read info about its attributes
3459  *        (names, types, default values, CHECK constraints, etc)
3460  *
3461  * This is implemented in a very inefficient way right now, looping
3462  * through the tblinfo and doing a join per table to find the attrs and their
3463  * types.  However, because we want type names and so forth to be named
3464  * relative to the schema of each table, we couldn't do it in just one
3465  * query.  (Maybe one query per schema?)
3466  *
3467  *      modifies tblinfo
3468  */
3469 void
3470 getTableAttrs(TableInfo *tblinfo, int numTables)
3471 {
3472         int                     i,
3473                                 j,
3474                                 k;
3475         PQExpBuffer q = createPQExpBuffer();
3476         int                     i_attnum;
3477         int                     i_attname;
3478         int                     i_atttypname;
3479         int                     i_atttypmod;
3480         int                     i_attstattarget;
3481         int                     i_attstorage;
3482         int                     i_typstorage;
3483         int                     i_attnotnull;
3484         int                     i_atthasdef;
3485         int                     i_attisdropped;
3486         int                     i_attislocal;
3487         PGresult   *res;
3488         int                     ntups;
3489         bool            hasdefaults;
3490
3491         for (i = 0; i < numTables; i++)
3492         {
3493                 TableInfo  *tbinfo = &tblinfo[i];
3494
3495                 /* Don't bother to collect info for sequences */
3496                 if (tbinfo->relkind == RELKIND_SEQUENCE)
3497                         continue;
3498
3499                 /* Don't bother with uninteresting tables, either */
3500                 if (!tbinfo->interesting)
3501                         continue;
3502
3503                 /*
3504                  * Make sure we are in proper schema for this table; this allows
3505                  * correct retrieval of formatted type names and default exprs
3506                  */
3507                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3508
3509                 /* find all the user attributes and their types */
3510
3511                 /*
3512                  * we must read the attribute names in attribute number order!
3513                  * because we will use the attnum to index into the attnames array
3514                  * later.  We actually ask to order by "attrelid, attnum" because
3515                  * (at least up to 7.3) the planner is not smart enough to realize
3516                  * it needn't re-sort the output of an indexscan on
3517                  * pg_attribute_relid_attnum_index.
3518                  */
3519                 if (g_verbose)
3520                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
3521                                           tbinfo->dobj.name);
3522
3523                 resetPQExpBuffer(q);
3524
3525                 if (g_fout->remoteVersion >= 70300)
3526                 {
3527                         /* need left join here to not fail on dropped columns ... */
3528                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, "
3529                           "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, "
3530                            "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname "
3531                                                           "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t "
3532                                                           "on a.atttypid = t.oid "
3533                                                           "where a.attrelid = '%u'::pg_catalog.oid "
3534                                                           "and a.attnum > 0::pg_catalog.int2 "
3535                                                           "order by a.attrelid, a.attnum",
3536                                                           tbinfo->dobj.catId.oid);
3537                 }
3538                 else if (g_fout->remoteVersion >= 70100)
3539                 {
3540                         /*
3541                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2,
3542                          * but we don't dump it because we can't tell whether it's
3543                          * been explicitly set or was just a default.
3544                          */
3545                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, "
3546                                                           "a.attnotnull, a.atthasdef, false as attisdropped, false as attislocal, "
3547                                                   "format_type(t.oid,a.atttypmod) as atttypname "
3548                                                           "from pg_attribute a left join pg_type t "
3549                                                           "on a.atttypid = t.oid "
3550                                                           "where a.attrelid = '%u'::oid "
3551                                                           "and a.attnum > 0::int2 "
3552                                                           "order by a.attrelid, a.attnum",
3553                                                           tbinfo->dobj.catId.oid);
3554                 }
3555                 else
3556                 {
3557                         /* format_type not available before 7.1 */
3558                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, "
3559                                                           "attnotnull, atthasdef, false as attisdropped, false as attislocal, "
3560                                                           "(select typname from pg_type where oid = atttypid) as atttypname "
3561                                                           "from pg_attribute a "
3562                                                           "where attrelid = '%u'::oid "
3563                                                           "and attnum > 0::int2 "
3564                                                           "order by attrelid, attnum",
3565                                                           tbinfo->dobj.catId.oid);
3566                 }
3567
3568                 res = PQexec(g_conn, q->data);
3569                 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
3570
3571                 ntups = PQntuples(res);
3572
3573                 i_attnum = PQfnumber(res, "attnum");
3574                 i_attname = PQfnumber(res, "attname");
3575                 i_atttypname = PQfnumber(res, "atttypname");
3576                 i_atttypmod = PQfnumber(res, "atttypmod");
3577                 i_attstattarget = PQfnumber(res, "attstattarget");
3578                 i_attstorage = PQfnumber(res, "attstorage");
3579                 i_typstorage = PQfnumber(res, "typstorage");
3580                 i_attnotnull = PQfnumber(res, "attnotnull");
3581                 i_atthasdef = PQfnumber(res, "atthasdef");
3582                 i_attisdropped = PQfnumber(res, "attisdropped");
3583                 i_attislocal = PQfnumber(res, "attislocal");
3584
3585                 tbinfo->numatts = ntups;
3586                 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
3587                 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
3588                 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
3589                 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
3590                 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
3591                 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
3592                 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
3593                 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
3594                 tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
3595                 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
3596                 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
3597                 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
3598                 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
3599                 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
3600                 hasdefaults = false;
3601
3602                 for (j = 0; j < ntups; j++)
3603                 {
3604                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
3605                         {
3606                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
3607                                                   tbinfo->dobj.name);
3608                                 exit_nicely();
3609                         }
3610                         tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
3611                         tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
3612                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
3613                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
3614                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
3615                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
3616                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
3617                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
3618                         tbinfo->attisserial[j] = false;         /* fix below */
3619                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
3620                         tbinfo->attrdefs[j] = NULL;                     /* fix below */
3621                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
3622                                 hasdefaults = true;
3623                         /* these flags will be set in flagInhAttrs() */
3624                         tbinfo->inhAttrs[j] = false;
3625                         tbinfo->inhAttrDef[j] = false;
3626                         tbinfo->inhNotNull[j] = false;
3627                 }
3628
3629                 PQclear(res);
3630
3631                 /*
3632                  * Get info about column defaults
3633                  */
3634                 if (hasdefaults)
3635                 {
3636                         AttrDefInfo *attrdefs;
3637                         int                     numDefaults;
3638
3639                         if (g_verbose)
3640                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
3641                                                   tbinfo->dobj.name);
3642
3643                         resetPQExpBuffer(q);
3644                         if (g_fout->remoteVersion >= 70300)
3645                         {
3646                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
3647                                            "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
3648                                                                   "FROM pg_catalog.pg_attrdef "
3649                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
3650                                                                   tbinfo->dobj.catId.oid);
3651                         }
3652                         else if (g_fout->remoteVersion >= 70200)
3653                         {
3654                                 /* 7.2 did not have OIDs in pg_attrdef */
3655                                 appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, adnum, "
3656                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
3657                                                                   "FROM pg_attrdef "
3658                                                                   "WHERE adrelid = '%u'::oid",
3659                                                                   tbinfo->dobj.catId.oid);
3660                         }
3661                         else if (g_fout->remoteVersion >= 70100)
3662                         {
3663                                 /* no pg_get_expr, so must rely on adsrc */
3664                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
3665                                                                   "FROM pg_attrdef "
3666                                                                   "WHERE adrelid = '%u'::oid",
3667                                                                   tbinfo->dobj.catId.oid);
3668                         }
3669                         else
3670                         {
3671                                 /* no pg_get_expr, no tableoid either */
3672                                 appendPQExpBuffer(q, "SELECT "
3673                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
3674                                                                   "oid, adnum, adsrc "
3675                                                                   "FROM pg_attrdef "
3676                                                                   "WHERE adrelid = '%u'::oid",
3677                                                                   tbinfo->dobj.catId.oid);
3678                         }
3679                         res = PQexec(g_conn, q->data);
3680                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
3681
3682                         numDefaults = PQntuples(res);
3683                         attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
3684
3685                         for (j = 0; j < numDefaults; j++)
3686                         {
3687                                 int             adnum;
3688
3689                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
3690                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
3691                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
3692                                 AssignDumpId(&attrdefs[j].dobj);
3693                                 attrdefs[j].adtable = tbinfo;
3694                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
3695                                 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
3696
3697                                 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
3698                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
3699
3700                                 /*
3701                                  * Defaults on a VIEW must always be dumped as separate
3702                                  * ALTER TABLE commands.  Defaults on regular tables are
3703                                  * dumped as part of the CREATE TABLE if possible.  To check
3704                                  * if it's safe, we mark the default as needing to appear
3705                                  * before the CREATE.
3706                                  */
3707                                 if (tbinfo->relkind == RELKIND_VIEW)
3708                                 {
3709                                         attrdefs[j].separate = true;
3710                                         /* needed in case pre-7.3 DB: */
3711                                         addObjectDependency(&attrdefs[j].dobj,
3712                                                                                 tbinfo->dobj.dumpId);
3713                                 }
3714                                 else
3715                                 {
3716                                         attrdefs[j].separate = false;
3717                                         addObjectDependency(&tbinfo->dobj,
3718                                                                                 attrdefs[j].dobj.dumpId);
3719                                 }
3720
3721                                 if (adnum <= 0 || adnum > ntups)
3722                                 {
3723                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
3724                                                           adnum, tbinfo->dobj.name);
3725                                         exit_nicely();
3726                                 }
3727                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
3728                         }
3729                         PQclear(res);
3730                 }
3731
3732                 /*
3733                  * Get info about table CHECK constraints
3734                  */
3735                 if (tbinfo->ncheck > 0)
3736                 {
3737                         ConstraintInfo *constrs;
3738                         int                     numConstrs;
3739
3740                         if (g_verbose)
3741                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
3742                                                   tbinfo->dobj.name);
3743
3744                         resetPQExpBuffer(q);
3745                         if (g_fout->remoteVersion >= 70400)
3746                         {
3747                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
3748                                         "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3749                                                                   "FROM pg_catalog.pg_constraint "
3750                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
3751                                                                   "   AND contype = 'c' "
3752                                                                   "ORDER BY conname",
3753                                                                   tbinfo->dobj.catId.oid);
3754                         }
3755                         else if (g_fout->remoteVersion >= 70300)
3756                         {
3757                                 /* no pg_get_constraintdef, must use consrc */
3758                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
3759                                                                   "'CHECK (' || consrc || ')' AS consrc "
3760                                                                   "FROM pg_catalog.pg_constraint "
3761                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
3762                                                                   "   AND contype = 'c' "
3763                                                                   "ORDER BY conname",
3764                                                                   tbinfo->dobj.catId.oid);
3765                         }
3766                         else if (g_fout->remoteVersion >= 70200)
3767                         {
3768                                 /* 7.2 did not have OIDs in pg_relcheck */
3769                                 appendPQExpBuffer(q, "SELECT tableoid, 0 as oid, "
3770                                                                   "rcname AS conname, "
3771                                                                   "'CHECK (' || rcsrc || ')' AS consrc "
3772                                                                   "FROM pg_relcheck "
3773                                                                   "WHERE rcrelid = '%u'::oid "
3774                                                                   "ORDER BY rcname",
3775                                                                   tbinfo->dobj.catId.oid);
3776                         }
3777                         else if (g_fout->remoteVersion >= 70100)
3778                         {
3779                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
3780                                                                   "rcname AS conname, "
3781                                                                   "'CHECK (' || rcsrc || ')' AS consrc "
3782                                                                   "FROM pg_relcheck "
3783                                                                   "WHERE rcrelid = '%u'::oid "
3784                                                                   "ORDER BY rcname",
3785                                                                   tbinfo->dobj.catId.oid);
3786                         }
3787                         else
3788                         {
3789                                 /* no tableoid in 7.0 */
3790                                 appendPQExpBuffer(q, "SELECT "
3791                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
3792                                                                   "oid, rcname AS conname, "
3793                                                                   "'CHECK (' || rcsrc || ')' AS consrc "
3794                                                                   "FROM pg_relcheck "
3795                                                                   "WHERE rcrelid = '%u'::oid "
3796                                                                   "ORDER BY rcname",
3797                                                                   tbinfo->dobj.catId.oid);
3798                         }
3799                         res = PQexec(g_conn, q->data);
3800                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
3801
3802                         numConstrs = PQntuples(res);
3803                         if (numConstrs != tbinfo->ncheck)
3804                         {
3805                                 write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
3806                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
3807                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
3808                                 exit_nicely();
3809                         }
3810
3811                         constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
3812                         tbinfo->checkexprs = constrs;
3813
3814                         for (j = 0; j < numConstrs; j++)
3815                         {
3816                                 constrs[j].dobj.objType = DO_CONSTRAINT;
3817                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
3818                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
3819                                 AssignDumpId(&constrs[j].dobj);
3820                                 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
3821                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
3822                                 constrs[j].contable = tbinfo;
3823                                 constrs[j].condomain = NULL;
3824                                 constrs[j].contype = 'c';
3825                                 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
3826                                 constrs[j].conindex = 0;
3827                                 constrs[j].coninherited = false;
3828                                 constrs[j].separate = false;
3829                                 addObjectDependency(&tbinfo->dobj,
3830                                                                         constrs[j].dobj.dumpId);
3831                                 /*
3832                                  * If the constraint is inherited, this will be detected
3833                                  * later.  We also detect later if the constraint must be
3834                                  * split out from the table definition.
3835                                  */
3836                         }
3837                         PQclear(res);
3838                 }
3839
3840                 /*
3841                  * Check to see if any columns are serial columns.      Our first
3842                  * quick filter is that it must be integer or bigint with a
3843                  * default.  If so, we scan to see if we found a sequence linked
3844                  * to this column. If we did, mark the column and sequence
3845                  * appropriately.
3846                  */
3847                 for (j = 0; j < ntups; j++)
3848                 {
3849                         /*
3850                          * Note assumption that format_type will show these types as
3851                          * exactly "integer" and "bigint" regardless of schema path.
3852                          * This is correct in 7.3 but needs to be watched.
3853                          */
3854                         if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
3855                                 strcmp(tbinfo->atttypnames[j], "bigint") != 0)
3856                                 continue;
3857                         if (tbinfo->attrdefs[j] == NULL)
3858                                 continue;
3859                         for (k = 0; k < numTables; k++)
3860                         {
3861                                 TableInfo  *seqinfo = &tblinfo[k];
3862
3863                                 if (OidIsValid(seqinfo->owning_tab) &&
3864                                         seqinfo->owning_tab == tbinfo->dobj.catId.oid &&
3865                                         seqinfo->owning_col == j + 1)
3866                                 {
3867                                         /*
3868                                          * Found a match.  Copy the table's interesting and
3869                                          * dumpable flags to the sequence.
3870                                          */
3871                                         tbinfo->attisserial[j] = true;
3872                                         seqinfo->interesting = tbinfo->interesting;
3873                                         seqinfo->dump = tbinfo->dump;
3874                                         break;
3875                                 }
3876                         }
3877                 }
3878         }
3879
3880         destroyPQExpBuffer(q);
3881 }
3882
3883
3884 /*
3885  * dumpComment --
3886  *
3887  * This routine is used to dump any comments associated with the
3888  * object handed to this routine. The routine takes a constant character
3889  * string for the target part of the comment-creation command, plus
3890  * the namespace and owner of the object (for labeling the ArchiveEntry),
3891  * plus catalog ID and subid which are the lookup key for pg_description,
3892  * plus the dump ID for the object (for setting a dependency).
3893  * If a matching pg_description entry is found, it is dumped.
3894  */
3895 static void
3896 dumpComment(Archive *fout, const char *target,
3897                         const char *namespace, const char *owner,
3898                         CatalogId catalogId, int subid, DumpId dumpId)
3899 {
3900         CommentItem *comments;
3901         int                     ncomments;
3902
3903         /* Comments are SCHEMA not data */
3904         if (dataOnly)
3905                 return;
3906
3907         /* Search for comments associated with catalogId, using table */
3908         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
3909                                                          &comments);
3910
3911         /* Is there one matching the subid? */
3912         while (ncomments > 0)
3913         {
3914                 if (comments->objsubid == subid)
3915                         break;
3916                 comments++;
3917                 ncomments--;
3918         }
3919
3920         /* If a comment exists, build COMMENT ON statement */
3921         if (ncomments > 0)
3922         {
3923                 PQExpBuffer query = createPQExpBuffer();
3924
3925                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
3926                 appendStringLiteral(query, comments->descr, false);
3927                 appendPQExpBuffer(query, ";\n");
3928
3929                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
3930                                          target, namespace, owner, false,
3931                                          "COMMENT", query->data, "", NULL,
3932                                          &(dumpId), 1,
3933                                          NULL, NULL);
3934
3935                 destroyPQExpBuffer(query);
3936         }
3937 }
3938
3939 /*
3940  * dumpTableComment --
3941  *
3942  * As above, but dump comments for both the specified table (or view)
3943  * and its columns.
3944  */
3945 static void
3946 dumpTableComment(Archive *fout, TableInfo *tbinfo,
3947                                  const char *reltypename)
3948 {
3949         CommentItem *comments;
3950         int                     ncomments;
3951         PQExpBuffer query;
3952         PQExpBuffer target;
3953
3954         /* Comments are SCHEMA not data */
3955         if (dataOnly)
3956                 return;
3957
3958         /* Search for comments associated with relation, using table */
3959         ncomments = findComments(fout,
3960                                                          tbinfo->dobj.catId.tableoid,
3961                                                          tbinfo->dobj.catId.oid,
3962                                                          &comments);
3963
3964         /* If comments exist, build COMMENT ON statements */
3965         if (ncomments <= 0)
3966                 return;
3967
3968         query = createPQExpBuffer();
3969         target = createPQExpBuffer();
3970
3971         while (ncomments > 0)
3972         {
3973                 const char *descr = comments->descr;
3974                 int                     objsubid = comments->objsubid;
3975
3976                 if (objsubid == 0)
3977                 {
3978                         resetPQExpBuffer(target);
3979                         appendPQExpBuffer(target, "%s %s", reltypename,
3980                                                           fmtId(tbinfo->dobj.name));
3981
3982                         resetPQExpBuffer(query);
3983                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
3984                         appendStringLiteral(query, descr, false);
3985                         appendPQExpBuffer(query, ";\n");
3986
3987                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
3988                                                  target->data,
3989                                                  tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
3990                                                  false, "COMMENT", query->data, "", NULL,
3991                                                  &(tbinfo->dobj.dumpId), 1,
3992                                                  NULL, NULL);
3993                 }
3994                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
3995                 {
3996                         resetPQExpBuffer(target);
3997                         appendPQExpBuffer(target, "COLUMN %s.",
3998                                                           fmtId(tbinfo->dobj.name));
3999                         appendPQExpBuffer(target, "%s",
4000                                                           fmtId(tbinfo->attnames[objsubid - 1]));
4001
4002                         resetPQExpBuffer(query);
4003                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
4004                         appendStringLiteral(query, descr, false);
4005                         appendPQExpBuffer(query, ";\n");
4006
4007                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
4008                                                  target->data,
4009                                                  tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
4010                                                  false, "COMMENT", query->data, "", NULL,
4011                                                  &(tbinfo->dobj.dumpId), 1,
4012                                                  NULL, NULL);
4013                 }
4014
4015                 comments++;
4016                 ncomments--;
4017         }
4018
4019         destroyPQExpBuffer(query);
4020         destroyPQExpBuffer(target);
4021 }
4022
4023 /*
4024  * findComments --
4025  *
4026  * Find the comment(s), if any, associated with the given object.  All the
4027  * objsubid values associated with the given classoid/objoid are found with
4028  * one search.
4029  */
4030 static int
4031 findComments(Archive *fout, Oid classoid, Oid objoid,
4032                          CommentItem **items)
4033 {
4034         /* static storage for table of comments */
4035         static CommentItem *comments = NULL;
4036         static int      ncomments = -1;
4037
4038         CommentItem *middle = NULL;
4039         CommentItem *low;
4040         CommentItem *high;
4041         int                     nmatch;
4042
4043         /* Get comments if we didn't already */
4044         if (ncomments < 0)
4045                 ncomments = collectComments(fout, &comments);
4046
4047         /*
4048          * Pre-7.2, pg_description does not contain classoid, so collectComments
4049          * just stores a zero.  If there's a collision on object OID, well, you
4050          * get duplicate comments.
4051          */
4052         if (fout->remoteVersion < 70200)
4053                 classoid = 0;
4054
4055         /*
4056          * Do binary search to find some item matching the object.
4057          */
4058         low = &comments[0];
4059         high = &comments[ncomments-1];
4060         while (low <= high)
4061         {
4062                 middle = low + (high - low) / 2;
4063
4064                 if (classoid < middle->classoid)
4065                         high = middle - 1;
4066                 else if (classoid > middle->classoid)
4067                         low = middle + 1;
4068                 else if (objoid < middle->objoid)
4069                         high = middle - 1;
4070                 else if (objoid > middle->objoid)
4071                         low = middle + 1;
4072                 else
4073                         break;                          /* found a match */
4074         }
4075
4076         if (low > high)                         /* no matches */
4077         {
4078                 *items = NULL;
4079                 return 0;
4080         }
4081
4082         /*
4083          * Now determine how many items match the object.  The search loop
4084          * invariant still holds: only items between low and high inclusive
4085          * could match.
4086          */
4087         nmatch = 1;
4088         while (middle > low)
4089         {
4090                 if (classoid != middle[-1].classoid ||
4091                         objoid != middle[-1].objoid)
4092                         break;
4093                 middle--;
4094                 nmatch++;
4095         }
4096
4097         *items = middle;
4098
4099         middle += nmatch;
4100         while (middle <= high)
4101         {
4102                 if (classoid != middle->classoid ||
4103                         objoid != middle->objoid)
4104                         break;
4105                 middle++;
4106                 nmatch++;
4107         }
4108
4109         return nmatch;
4110 }
4111
4112 /*
4113  * collectComments --
4114  *
4115  * Construct a table of all comments available for database objects.
4116  * We used to do per-object queries for the comments, but it's much faster
4117  * to pull them all over at once, and on most databases the memory cost
4118  * isn't high.
4119  *
4120  * The table is sorted by classoid/objid/objsubid for speed in lookup.
4121  */
4122 static int
4123 collectComments(Archive *fout, CommentItem **items)
4124 {
4125         PGresult   *res;
4126         PQExpBuffer query;
4127         int                     i_description;
4128         int                     i_classoid;
4129         int                     i_objoid;
4130         int                     i_objsubid;
4131         int                     ntups;
4132         int                     i;
4133         CommentItem *comments;
4134
4135         /*
4136          * Note we do NOT change source schema here; preserve the caller's
4137          * setting, instead.
4138          */
4139
4140         query = createPQExpBuffer();
4141
4142         if (fout->remoteVersion >= 70300)
4143         {
4144                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
4145                                                   "FROM pg_catalog.pg_description "
4146                                                   "ORDER BY classoid, objoid, objsubid");
4147         }
4148         else if (fout->remoteVersion >= 70200)
4149         {
4150                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
4151                                                   "FROM pg_description "
4152                                                   "ORDER BY classoid, objoid, objsubid");
4153         }
4154         else
4155         {
4156                 /* Note: this will fail to find attribute comments in pre-7.2... */
4157                 appendPQExpBuffer(query, "SELECT description, 0 as classoid, objoid, 0 as objsubid "
4158                                                   "FROM pg_description "
4159                                                   "ORDER BY objoid");
4160         }
4161
4162         res = PQexec(g_conn, query->data);
4163         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4164
4165         /* Construct lookup table containing OIDs in numeric form */
4166
4167         i_description = PQfnumber(res, "description");
4168         i_classoid = PQfnumber(res, "classoid");
4169         i_objoid = PQfnumber(res, "objoid");
4170         i_objsubid = PQfnumber(res, "objsubid");
4171
4172         ntups = PQntuples(res);
4173
4174         comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
4175
4176         for (i = 0; i < ntups; i++)
4177         {
4178                 comments[i].descr = PQgetvalue(res, i, i_description);
4179                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
4180                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
4181                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
4182         }
4183
4184         /* Do NOT free the PGresult since we are keeping pointers into it */
4185         destroyPQExpBuffer(query);
4186
4187         *items = comments;
4188         return ntups;
4189 }
4190
4191 /*
4192  * dumpDumpableObject
4193  *
4194  * This routine and its subsidiaries are responsible for creating
4195  * ArchiveEntries (TOC objects) for each object to be dumped.
4196  */
4197 static void
4198 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
4199 {
4200         switch (dobj->objType)
4201         {
4202                 case DO_NAMESPACE:
4203                         dumpNamespace(fout, (NamespaceInfo *) dobj);
4204                         break;
4205                 case DO_TYPE:
4206                         dumpType(fout, (TypeInfo *) dobj);
4207                         break;
4208                 case DO_FUNC:
4209                         dumpFunc(fout, (FuncInfo *) dobj);
4210                         break;
4211                 case DO_AGG:
4212                         dumpAgg(fout, (AggInfo *) dobj);
4213                         break;
4214                 case DO_OPERATOR:
4215                         dumpOpr(fout, (OprInfo *) dobj);
4216                         break;
4217                 case DO_OPCLASS:
4218                         dumpOpclass(fout, (OpclassInfo *) dobj);
4219                         break;
4220                 case DO_CONVERSION:
4221                         dumpConversion(fout, (ConvInfo *) dobj);
4222                         break;
4223                 case DO_TABLE:
4224                         dumpTable(fout, (TableInfo *) dobj);
4225                         break;
4226                 case DO_ATTRDEF:
4227                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
4228                         break;
4229                 case DO_INDEX:
4230                         dumpIndex(fout, (IndxInfo *) dobj);
4231                         break;
4232                 case DO_RULE:
4233                         dumpRule(fout, (RuleInfo *) dobj);
4234                         break;
4235                 case DO_TRIGGER:
4236                         dumpTrigger(fout, (TriggerInfo *) dobj);
4237                         break;
4238                 case DO_CONSTRAINT:
4239                         dumpConstraint(fout, (ConstraintInfo *) dobj);
4240                         break;
4241                 case DO_FK_CONSTRAINT:
4242                         dumpConstraint(fout, (ConstraintInfo *) dobj);
4243                         break;
4244                 case DO_PROCLANG:
4245                         dumpProcLang(fout, (ProcLangInfo *) dobj);
4246                         break;
4247                 case DO_CAST:
4248                         dumpCast(fout, (CastInfo *) dobj);
4249                         break;
4250                 case DO_TABLE_DATA:
4251                         dumpTableData(fout, (TableDataInfo *) dobj);
4252                         break;
4253                 case DO_TABLE_TYPE:
4254                         /* table rowtypes are never dumped separately */
4255                         break;
4256                 case DO_BLOBS:
4257                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
4258                                                  dobj->name, NULL, "",
4259                                                  false, "BLOBS", "", "", NULL,
4260                                                  NULL, 0,
4261                                                  dumpBlobs, NULL);
4262                         break;
4263         }
4264 }
4265
4266 /*
4267  * dumpNamespace
4268  *        writes out to fout the queries to recreate a user-defined namespace
4269  */
4270 static void
4271 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
4272 {
4273         PQExpBuffer q;
4274         PQExpBuffer delq;
4275         char       *qnspname;
4276
4277         /* skip if not to be dumped */
4278         if (!nspinfo->dump || dataOnly)
4279                 return;
4280
4281         /* don't dump dummy namespace from pre-7.3 source */
4282         if (strlen(nspinfo->dobj.name) == 0)
4283                 return;
4284
4285         q = createPQExpBuffer();
4286         delq = createPQExpBuffer();
4287
4288         qnspname = strdup(fmtId(nspinfo->dobj.name));
4289
4290         /*
4291          * If it's the PUBLIC namespace, suppress the CREATE SCHEMA record
4292          * for it, since we expect PUBLIC to exist already in the
4293          * destination database.  But do emit ACL in case it's not standard,
4294          * likewise comment.
4295          *
4296          * Note that ownership is shown in the AUTHORIZATION clause,
4297          * while the archive entry is listed with empty owner (causing
4298          * it to be emitted with SET SESSION AUTHORIZATION DEFAULT).
4299          * This seems the best way of dealing with schemas owned by
4300          * users without CREATE SCHEMA privilege.  Further hacking has
4301          * to be applied for --no-owner mode, though!
4302          */
4303         if (strcmp(nspinfo->dobj.name, "public") != 0)
4304         {
4305                 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
4306
4307                 appendPQExpBuffer(q, "CREATE SCHEMA %s AUTHORIZATION %s;\n",
4308                                                   qnspname, fmtId(nspinfo->usename));
4309
4310                 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
4311                                          nspinfo->dobj.name,
4312                                          NULL, "",
4313                                          false, "SCHEMA", q->data, delq->data, NULL,
4314                                          nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
4315                                          NULL, NULL);
4316         }
4317
4318         /* Dump Schema Comments */
4319         resetPQExpBuffer(q);
4320         appendPQExpBuffer(q, "SCHEMA %s", qnspname);
4321         dumpComment(fout, q->data,
4322                                 NULL, nspinfo->usename,
4323                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
4324
4325         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
4326                         qnspname, nspinfo->dobj.name, NULL,
4327                         nspinfo->usename, nspinfo->nspacl);
4328
4329         free(qnspname);
4330
4331         destroyPQExpBuffer(q);
4332         destroyPQExpBuffer(delq);
4333 }
4334
4335 /*
4336  * dumpType
4337  *        writes out to fout the queries to recreate a user-defined type
4338  */
4339 static void
4340 dumpType(Archive *fout, TypeInfo *tinfo)
4341 {
4342         /* Dump only types in dumpable namespaces */
4343         if (!tinfo->dobj.namespace->dump || dataOnly)
4344                 return;
4345
4346         /* skip complex types, except for standalone composite types */
4347         /* (note: this test should now be unnecessary) */
4348         if (OidIsValid(tinfo->typrelid) && tinfo->typrelkind != 'c')
4349                 return;
4350
4351         /* skip undefined placeholder types */
4352         if (!tinfo->isDefined)
4353                 return;
4354
4355         /* skip all array types that start w/ underscore */
4356         if ((tinfo->dobj.name[0] == '_') &&
4357                 OidIsValid(tinfo->typelem))
4358                 return;
4359
4360         /* Dump out in proper style */
4361         if (tinfo->typtype == 'b')
4362                 dumpBaseType(fout, tinfo);
4363         else if (tinfo->typtype == 'd')
4364                 dumpDomain(fout, tinfo);
4365         else if (tinfo->typtype == 'c')
4366                 dumpCompositeType(fout, tinfo);
4367 }
4368
4369 /*
4370  * dumpBaseType
4371  *        writes out to fout the queries to recreate a user-defined base type
4372  */
4373 static void
4374 dumpBaseType(Archive *fout, TypeInfo *tinfo)
4375 {
4376         PQExpBuffer q = createPQExpBuffer();
4377         PQExpBuffer delq = createPQExpBuffer();
4378         PQExpBuffer query = createPQExpBuffer();
4379         PGresult   *res;
4380         int                     ntups;
4381         char       *typlen;
4382         char       *typinput;
4383         char       *typoutput;
4384         char       *typreceive;
4385         char       *typsend;
4386         char       *typanalyze;
4387         Oid                     typinputoid;
4388         Oid                     typoutputoid;
4389         Oid                     typreceiveoid;
4390         Oid                     typsendoid;
4391         Oid                     typanalyzeoid;
4392         char       *typdelim;
4393         char       *typdefault;
4394         char       *typbyval;
4395         char       *typalign;
4396         char       *typstorage;
4397
4398         /* Set proper schema search path so regproc references list correctly */
4399         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
4400
4401         /* Fetch type-specific details */
4402         if (fout->remoteVersion >= 70500)
4403         {
4404                 appendPQExpBuffer(query, "SELECT typlen, "
4405                                                   "typinput, typoutput, typreceive, typsend, "
4406                                                   "typanalyze, "
4407                                                   "typinput::pg_catalog.oid as typinputoid, "
4408                                                   "typoutput::pg_catalog.oid as typoutputoid, "
4409                                                   "typreceive::pg_catalog.oid as typreceiveoid, "
4410                                                   "typsend::pg_catalog.oid as typsendoid, "
4411                                                   "typanalyze::pg_catalog.oid as typanalyzeoid, "
4412                                                   "typdelim, typdefault, typbyval, typalign, "
4413                                                   "typstorage "
4414                                                   "FROM pg_catalog.pg_type "
4415                                                   "WHERE oid = '%u'::pg_catalog.oid",
4416                                                   tinfo->dobj.catId.oid);
4417         }
4418         else if (fout->remoteVersion >= 70400)
4419         {
4420                 appendPQExpBuffer(query, "SELECT typlen, "
4421                                                   "typinput, typoutput, typreceive, typsend, "
4422                                                   "'-' as typanalyze, "
4423                                                   "typinput::pg_catalog.oid as typinputoid, "
4424                                                   "typoutput::pg_catalog.oid as typoutputoid, "
4425                                                   "typreceive::pg_catalog.oid as typreceiveoid, "
4426                                                   "typsend::pg_catalog.oid as typsendoid, "
4427                                                   "0 as typanalyzeoid, "
4428                                                   "typdelim, typdefault, typbyval, typalign, "
4429                                                   "typstorage "
4430                                                   "FROM pg_catalog.pg_type "
4431                                                   "WHERE oid = '%u'::pg_catalog.oid",
4432                                                   tinfo->dobj.catId.oid);
4433         }
4434         else if (fout->remoteVersion >= 70300)
4435         {
4436                 appendPQExpBuffer(query, "SELECT typlen, "
4437                                                   "typinput, typoutput, "
4438                                                   "'-' as typreceive, '-' as typsend, "
4439                                                   "'-' as typanalyze, "
4440                                                   "typinput::pg_catalog.oid as typinputoid, "
4441                                                   "typoutput::pg_catalog.oid as typoutputoid, "
4442                                                   "0 as typreceiveoid, 0 as typsendoid, "
4443                                                   "0 as typanalyzeoid, "
4444                                                   "typdelim, typdefault, typbyval, typalign, "
4445                                                   "typstorage "
4446                                                   "FROM pg_catalog.pg_type "
4447                                                   "WHERE oid = '%u'::pg_catalog.oid",
4448                                                   tinfo->dobj.catId.oid);
4449         }
4450         else if (fout->remoteVersion >= 70100)
4451         {
4452                 /*
4453                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
4454                  * ignore them because they are not right.
4455                  */
4456                 appendPQExpBuffer(query, "SELECT typlen, "
4457                                                   "typinput, typoutput, "
4458                                                   "'-' as typreceive, '-' as typsend, "
4459                                                   "'-' as typanalyze, "
4460                                                   "typinput::oid as typinputoid, "
4461                                                   "typoutput::oid as typoutputoid, "
4462                                                   "0 as typreceiveoid, 0 as typsendoid, "
4463                                                   "0 as typanalyzeoid, "
4464                                                   "typdelim, typdefault, typbyval, typalign, "
4465                                                   "typstorage "
4466                                                   "FROM pg_type "
4467                                                   "WHERE oid = '%u'::oid",
4468                                                   tinfo->dobj.catId.oid);
4469         }
4470         else
4471         {
4472                 appendPQExpBuffer(query, "SELECT typlen, "
4473                                                   "typinput, typoutput, "
4474                                                   "'-' as typreceive, '-' as typsend, "
4475                                                   "'-' as typanalyze, "
4476                                                   "typinput::oid as typinputoid, "
4477                                                   "typoutput::oid as typoutputoid, "
4478                                                   "0 as typreceiveoid, 0 as typsendoid, "
4479                                                   "0 as typanalyzeoid, "
4480                                                   "typdelim, typdefault, typbyval, typalign, "
4481                                                   "'p'::char as typstorage "
4482                                                   "FROM pg_type "
4483                                                   "WHERE oid = '%u'::oid",
4484                                                   tinfo->dobj.catId.oid);
4485         }
4486
4487         res = PQexec(g_conn, query->data);
4488         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4489
4490         /* Expecting a single result only */
4491         ntups = PQntuples(res);
4492         if (ntups != 1)
4493         {
4494                 write_msg(NULL, "Got %d rows instead of one from: %s",
4495                                   ntups, query->data);
4496                 exit_nicely();
4497         }
4498
4499         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
4500         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
4501         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
4502         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
4503         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
4504         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
4505         typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
4506         typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
4507         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
4508         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
4509         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
4510         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
4511         if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
4512                 typdefault = NULL;
4513         else
4514                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
4515         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
4516         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
4517         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
4518
4519         /*
4520          * DROP must be fully qualified in case same name appears in
4521          * pg_catalog
4522          */
4523         appendPQExpBuffer(delq, "DROP TYPE %s.",
4524                                           fmtId(tinfo->dobj.namespace->dobj.name));
4525         appendPQExpBuffer(delq, "%s CASCADE;\n",
4526                                           fmtId(tinfo->dobj.name));
4527
4528         appendPQExpBuffer(q,
4529                                           "CREATE TYPE %s (\n"
4530                                           "    INTERNALLENGTH = %s",
4531                                           fmtId(tinfo->dobj.name),
4532                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
4533
4534         if (fout->remoteVersion >= 70300)
4535         {
4536                 /* regproc result is correctly quoted as of 7.3 */
4537                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
4538                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
4539                 if (OidIsValid(typreceiveoid))
4540                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
4541                 if (OidIsValid(typsendoid))
4542                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
4543                 if (OidIsValid(typanalyzeoid))
4544                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
4545         }
4546         else
4547         {
4548                 /* regproc delivers an unquoted name before 7.3 */
4549                 /* cannot combine these because fmtId uses static result area */
4550                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
4551                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
4552                 /* no chance that receive/send/analyze need be printed */
4553         }
4554
4555         if (typdefault != NULL)
4556         {
4557                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
4558                 appendStringLiteral(q, typdefault, true);
4559         }
4560
4561         if (tinfo->isArray)
4562         {
4563                 char       *elemType;
4564
4565                 /* reselect schema in case changed by function dump */
4566                 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
4567                 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
4568                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
4569                 free(elemType);
4570         }
4571
4572         if (typdelim && strcmp(typdelim, ",") != 0)
4573         {
4574                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
4575                 appendStringLiteral(q, typdelim, true);
4576         }
4577
4578         if (strcmp(typalign, "c") == 0)
4579                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
4580         else if (strcmp(typalign, "s") == 0)
4581                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
4582         else if (strcmp(typalign, "i") == 0)
4583                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
4584         else if (strcmp(typalign, "d") == 0)
4585                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
4586
4587         if (strcmp(typstorage, "p") == 0)
4588                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
4589         else if (strcmp(typstorage, "e") == 0)
4590                 appendPQExpBuffer(q, ",\n    STORAGE = external");
4591         else if (strcmp(typstorage, "x") == 0)
4592                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
4593         else if (strcmp(typstorage, "m") == 0)
4594                 appendPQExpBuffer(q, ",\n    STORAGE = main");
4595
4596         if (strcmp(typbyval, "t") == 0)
4597                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
4598
4599         appendPQExpBuffer(q, "\n);\n");
4600
4601         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
4602                                  tinfo->dobj.name,
4603                                  tinfo->dobj.namespace->dobj.name,
4604                                  tinfo->usename, false,
4605                                  "TYPE", q->data, delq->data, NULL,
4606                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
4607                                  NULL, NULL);
4608
4609         /* Dump Type Comments */
4610         resetPQExpBuffer(q);
4611
4612         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
4613         dumpComment(fout, q->data,
4614                                 tinfo->dobj.namespace->dobj.name, tinfo->usename,
4615                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
4616
4617         PQclear(res);
4618         destroyPQExpBuffer(q);
4619         destroyPQExpBuffer(delq);
4620         destroyPQExpBuffer(query);
4621 }
4622
4623 /*
4624  * dumpDomain
4625  *        writes out to fout the queries to recreate a user-defined domain
4626  */
4627 static void
4628 dumpDomain(Archive *fout, TypeInfo *tinfo)
4629 {
4630         PQExpBuffer q = createPQExpBuffer();
4631         PQExpBuffer delq = createPQExpBuffer();
4632         PQExpBuffer query = createPQExpBuffer();
4633         PGresult   *res;
4634         int                     ntups;
4635         int                     i;
4636         char       *typnotnull;
4637         char       *typdefn;
4638         char       *typdefault;
4639
4640         /* Set proper schema search path so type references list correctly */
4641         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
4642
4643         /* Fetch domain specific details */
4644         /* We assume here that remoteVersion must be at least 70300 */
4645         appendPQExpBuffer(query, "SELECT typnotnull, "
4646                         "pg_catalog.format_type(typbasetype, typtypmod) as typdefn, "
4647                                           "typdefault "
4648                                           "FROM pg_catalog.pg_type "
4649                                           "WHERE oid = '%u'::pg_catalog.oid",
4650                                           tinfo->dobj.catId.oid);
4651
4652         res = PQexec(g_conn, query->data);
4653         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4654
4655         /* Expecting a single result only */
4656         ntups = PQntuples(res);
4657         if (ntups != 1)
4658         {
4659                 write_msg(NULL, "Got %d rows instead of one from: %s",
4660                                   ntups, query->data);
4661                 exit_nicely();
4662         }
4663
4664         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
4665         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
4666         if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
4667                 typdefault = NULL;
4668         else
4669                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
4670
4671         appendPQExpBuffer(q,
4672                                           "CREATE DOMAIN %s AS %s",
4673                                           fmtId(tinfo->dobj.name),
4674                                           typdefn);
4675
4676         if (typnotnull[0] == 't')
4677                 appendPQExpBuffer(q, " NOT NULL");
4678
4679         if (typdefault)
4680                 appendPQExpBuffer(q, " DEFAULT %s", typdefault);
4681
4682         PQclear(res);
4683
4684         /*
4685          * Add any CHECK constraints for the domain
4686          */
4687         for (i = 0; i < tinfo->nDomChecks; i++)
4688         {
4689                 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
4690
4691                 if (!domcheck->separate)
4692                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
4693                                                           fmtId(domcheck->dobj.name), domcheck->condef);
4694         }
4695
4696         appendPQExpBuffer(q, ";\n");
4697
4698         /*
4699          * DROP must be fully qualified in case same name appears in
4700          * pg_catalog
4701          */
4702         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
4703                                           fmtId(tinfo->dobj.namespace->dobj.name));
4704         appendPQExpBuffer(delq, "%s;\n",
4705                                           fmtId(tinfo->dobj.name));
4706
4707         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
4708                                  tinfo->dobj.name,
4709                                  tinfo->dobj.namespace->dobj.name,
4710                                  tinfo->usename, false,
4711                                  "DOMAIN", q->data, delq->data, NULL,
4712                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
4713                                  NULL, NULL);
4714
4715         /* Dump Domain Comments */
4716         resetPQExpBuffer(q);
4717
4718         appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
4719         dumpComment(fout, q->data,
4720                                 tinfo->dobj.namespace->dobj.name, tinfo->usename,
4721                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
4722
4723         destroyPQExpBuffer(q);
4724         destroyPQExpBuffer(delq);
4725         destroyPQExpBuffer(query);
4726 }
4727
4728 /*
4729  * dumpCompositeType
4730  *        writes out to fout the queries to recreate a user-defined stand-alone
4731  *        composite type
4732  */
4733 static void
4734 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
4735 {
4736         PQExpBuffer q = createPQExpBuffer();
4737         PQExpBuffer delq = createPQExpBuffer();
4738         PQExpBuffer query = createPQExpBuffer();
4739         PGresult   *res;
4740         int                     ntups;
4741         int                     i_attname;
4742         int                     i_atttypdefn;
4743         int                     i;
4744
4745         /* Set proper schema search path so type references list correctly */
4746         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
4747
4748         /* Fetch type specific details */
4749         /* We assume here that remoteVersion must be at least 70300 */
4750
4751         appendPQExpBuffer(query, "SELECT a.attname, "
4752                  "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn "
4753                                   "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
4754                                           "WHERE t.oid = '%u'::pg_catalog.oid "
4755                                           "AND a.attrelid = t.typrelid "
4756                                           "AND NOT a.attisdropped "
4757                                           "ORDER BY a.attnum ",
4758                                           tinfo->dobj.catId.oid);
4759
4760         res = PQexec(g_conn, query->data);
4761         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4762
4763         /* Expecting at least a single result */
4764         ntups = PQntuples(res);
4765         if (ntups < 1)
4766         {
4767                 write_msg(NULL, "query yielded no rows: %s\n", query->data);
4768                 exit_nicely();
4769         }
4770
4771         i_attname = PQfnumber(res, "attname");
4772         i_atttypdefn = PQfnumber(res, "atttypdefn");
4773
4774         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
4775                                           fmtId(tinfo->dobj.name));
4776
4777         for (i = 0; i < ntups; i++)
4778         {
4779                 char       *attname;
4780                 char       *atttypdefn;
4781
4782                 attname = PQgetvalue(res, i, i_attname);
4783                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
4784
4785                 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
4786                 if (i < ntups - 1)
4787                         appendPQExpBuffer(q, ",");
4788         }
4789         appendPQExpBuffer(q, "\n);\n");
4790
4791         /*
4792          * DROP must be fully qualified in case same name appears in
4793          * pg_catalog
4794          */
4795         appendPQExpBuffer(delq, "DROP TYPE %s.",
4796                                           fmtId(tinfo->dobj.namespace->dobj.name));
4797         appendPQExpBuffer(delq, "%s;\n",
4798                                           fmtId(tinfo->dobj.name));
4799
4800         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
4801                                  tinfo->dobj.name,
4802                                  tinfo->dobj.namespace->dobj.name,
4803                                  tinfo->usename, false,
4804                                  "TYPE", q->data, delq->data, NULL,
4805                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
4806                                  NULL, NULL);
4807
4808
4809         /* Dump Type Comments */
4810         resetPQExpBuffer(q);
4811
4812         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
4813         dumpComment(fout, q->data,
4814                                 tinfo->dobj.namespace->dobj.name, tinfo->usename,
4815                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
4816
4817         PQclear(res);
4818         destroyPQExpBuffer(q);
4819         destroyPQExpBuffer(delq);
4820         destroyPQExpBuffer(query);
4821 }
4822
4823 /*
4824  * dumpProcLang
4825  *                writes out to fout the queries to recreate a user-defined
4826  *                procedural language
4827  */
4828 static void
4829 dumpProcLang(Archive *fout, ProcLangInfo *plang)
4830 {
4831         PQExpBuffer defqry;
4832         PQExpBuffer delqry;
4833         char       *qlanname;
4834         FuncInfo   *funcInfo;
4835         FuncInfo   *validatorInfo = NULL;
4836
4837         if (dataOnly)
4838                 return;
4839
4840         /*
4841          * Current theory is to dump PLs iff their underlying functions
4842          * will be dumped (are in a dumpable namespace, or have a
4843          * non-system OID in pre-7.3 databases).  Actually, we treat the
4844          * PL itself as being in the underlying function's namespace,
4845          * though it isn't really.  This avoids searchpath problems for
4846          * the HANDLER clause.
4847          *
4848          * If the underlying function is in the pg_catalog namespace,
4849          * we won't have loaded it into finfo[] at all; therefore,
4850          * treat failure to find it in finfo[] as indicating we shouldn't
4851          * dump it, not as an error condition.  Ditto for the validator.
4852          */
4853
4854         funcInfo = findFuncByOid(plang->lanplcallfoid);
4855         if (funcInfo == NULL)
4856                 return;
4857
4858         if (!funcInfo->dobj.namespace->dump)
4859                 return;
4860
4861         if (OidIsValid(plang->lanvalidator))
4862         {
4863                 validatorInfo = findFuncByOid(plang->lanvalidator);
4864                 if (validatorInfo == NULL)
4865                         return;
4866         }
4867
4868         defqry = createPQExpBuffer();
4869         delqry = createPQExpBuffer();
4870
4871         qlanname = strdup(fmtId(plang->dobj.name));
4872
4873         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
4874                                           qlanname);
4875
4876         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
4877                                           plang->lanpltrusted ? "TRUSTED " : "",
4878                                           qlanname);
4879         appendPQExpBuffer(defqry, " HANDLER %s",
4880                                           fmtId(funcInfo->dobj.name));
4881         if (OidIsValid(plang->lanvalidator))
4882         {
4883                 appendPQExpBuffer(defqry, " VALIDATOR ");
4884                 /* Cope with possibility that validator is in different schema */
4885                 if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
4886                         appendPQExpBuffer(defqry, "%s.",
4887                                                           fmtId(validatorInfo->dobj.namespace->dobj.name));
4888                 appendPQExpBuffer(defqry, "%s",
4889                                                   fmtId(validatorInfo->dobj.name));
4890         }
4891         appendPQExpBuffer(defqry, ";\n");
4892
4893         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
4894                                  plang->dobj.name,
4895                                  funcInfo->dobj.namespace->dobj.name, "",
4896                                  false, "PROCEDURAL LANGUAGE",
4897                                  defqry->data, delqry->data, NULL,
4898                                  plang->dobj.dependencies, plang->dobj.nDeps,
4899                                  NULL, NULL);
4900
4901         /* Dump Proc Lang Comments */
4902         resetPQExpBuffer(defqry);
4903
4904         appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
4905         dumpComment(fout, defqry->data,
4906                                 NULL, "",
4907                                 plang->dobj.catId, 0, plang->dobj.dumpId);
4908
4909         if (plang->lanpltrusted)
4910                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
4911                                 qlanname, plang->dobj.name,
4912                                 funcInfo->dobj.namespace->dobj.name,
4913                                 NULL, plang->lanacl);
4914
4915         free(qlanname);
4916
4917         destroyPQExpBuffer(defqry);
4918         destroyPQExpBuffer(delqry);
4919 }
4920
4921 /*
4922  * format_function_signature: generate function name and argument list
4923  *
4924  * The argument type names are qualified if needed.  The function name
4925  * is never qualified.
4926  *
4927  * argnames may be NULL if no names are available.
4928  */
4929 static char *
4930 format_function_signature(FuncInfo *finfo, char **argnames,
4931                                                   bool honor_quotes)
4932 {
4933         PQExpBufferData fn;
4934         int                     j;
4935
4936         initPQExpBuffer(&fn);
4937         if (honor_quotes)
4938                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
4939         else
4940                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
4941         for (j = 0; j < finfo->nargs; j++)
4942         {
4943                 char       *typname;
4944                 char       *argname;
4945
4946                 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
4947
4948                 argname = argnames ? argnames[j] : (char *) NULL;
4949                 if (argname && argname[0] == '\0')
4950                         argname = NULL;
4951
4952                 appendPQExpBuffer(&fn, "%s%s%s%s",
4953                                                   (j > 0) ? ", " : "",
4954                                                   argname ? fmtId(argname) : "",
4955                                                   argname ? " " : "",
4956                                                   typname);
4957                 free(typname);
4958         }
4959         appendPQExpBuffer(&fn, ")");
4960         return fn.data;
4961 }
4962
4963
4964 /*
4965  * dumpFunc:
4966  *        dump out one function
4967  */
4968 static void
4969 dumpFunc(Archive *fout, FuncInfo *finfo)
4970 {
4971         PQExpBuffer query;
4972         PQExpBuffer q;
4973         PQExpBuffer delqry;
4974         PQExpBuffer asPart;
4975         PGresult   *res;
4976         char       *funcsig;
4977         char       *funcsig_tag;
4978         int                     ntups;
4979         char       *proretset;
4980         char       *prosrc;
4981         char       *probin;
4982         char       *proargnames;
4983         char       *provolatile;
4984         char       *proisstrict;
4985         char       *prosecdef;
4986         char       *lanname;
4987         char       *rettypename;
4988         char      **argnamearray = NULL;
4989
4990         /* Dump only funcs in dumpable namespaces */
4991         if (!finfo->dobj.namespace->dump || dataOnly)
4992                 return;
4993
4994         query = createPQExpBuffer();
4995         q = createPQExpBuffer();
4996         delqry = createPQExpBuffer();
4997         asPart = createPQExpBuffer();
4998
4999         /* Set proper schema search path so type references list correctly */
5000         selectSourceSchema(finfo->dobj.namespace->dobj.name);
5001
5002         /* Fetch function-specific details */
5003         if (g_fout->remoteVersion >= 70500)
5004         {
5005                 appendPQExpBuffer(query,
5006                                                   "SELECT proretset, prosrc, probin, "
5007                                                   "proargnames, "
5008                                                   "provolatile, proisstrict, prosecdef, "
5009                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
5010                                                   "FROM pg_catalog.pg_proc "
5011                                                   "WHERE oid = '%u'::pg_catalog.oid",
5012                                                   finfo->dobj.catId.oid);
5013         }
5014         else if (g_fout->remoteVersion >= 70300)
5015         {
5016                 appendPQExpBuffer(query,
5017                                                   "SELECT proretset, prosrc, probin, "
5018                                                   "null::text as proargnames, "
5019                                                   "provolatile, proisstrict, prosecdef, "
5020                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
5021                                                   "FROM pg_catalog.pg_proc "
5022                                                   "WHERE oid = '%u'::pg_catalog.oid",
5023                                                   finfo->dobj.catId.oid);
5024         }
5025         else if (g_fout->remoteVersion >= 70100)
5026         {
5027                 appendPQExpBuffer(query,
5028                                                   "SELECT proretset, prosrc, probin, "
5029                                                   "null::text as proargnames, "
5030                  "case when proiscachable then 'i' else 'v' end as provolatile, "
5031                                                   "proisstrict, "
5032                                                   "'f'::boolean as prosecdef, "
5033                                                   "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
5034                                                   "FROM pg_proc "
5035                                                   "WHERE oid = '%u'::oid",
5036                                                   finfo->dobj.catId.oid);
5037         }
5038         else
5039         {
5040                 appendPQExpBuffer(query,
5041                                                   "SELECT proretset, prosrc, probin, "
5042                                                   "null::text as proargnames, "
5043                  "case when proiscachable then 'i' else 'v' end as provolatile, "
5044                                                   "'f'::boolean as proisstrict, "
5045                                                   "'f'::boolean as prosecdef, "
5046                                                   "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
5047                                                   "FROM pg_proc "
5048                                                   "WHERE oid = '%u'::oid",
5049                                                   finfo->dobj.catId.oid);
5050         }
5051
5052         res = PQexec(g_conn, query->data);
5053         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5054
5055         /* Expecting a single result only */
5056         ntups = PQntuples(res);
5057         if (ntups != 1)
5058         {
5059                 write_msg(NULL, "Got %d rows instead of one from: %s",
5060                                   ntups, query->data);
5061                 exit_nicely();
5062         }
5063
5064         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
5065         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
5066         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
5067         proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
5068         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
5069         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
5070         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
5071         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
5072
5073         /*
5074          * See backend/commands/define.c for details of how the 'AS' clause is
5075          * used.
5076          */
5077         if (strcmp(probin, "-") != 0)
5078         {
5079                 appendPQExpBuffer(asPart, "AS ");
5080                 appendStringLiteral(asPart, probin, true);
5081                 if (strcmp(prosrc, "-") != 0)
5082                 {
5083                         appendPQExpBuffer(asPart, ", ");
5084                         /* 
5085                          * where we have bin, use dollar quoting if allowed and src
5086                          * contains quote or backslash; else use regular quoting.
5087                          */
5088                         if (disable_dollar_quoting)
5089                                 appendStringLiteral(asPart, prosrc, false);
5090                         else
5091                                 appendStringLiteralDQOpt(asPart, prosrc, false, NULL);
5092                 }
5093         }
5094         else
5095         {
5096                 if (strcmp(prosrc, "-") != 0)
5097                 {
5098                         appendPQExpBuffer(asPart, "AS ");
5099                         /* with no bin, dollar quote src unconditionally if allowed */
5100                         if (disable_dollar_quoting)
5101                                 appendStringLiteral(asPart, prosrc, false);
5102                         else
5103                                 appendStringLiteralDQ(asPart, prosrc, NULL);
5104                 }
5105         }
5106
5107         if (proargnames && *proargnames)
5108         {
5109                 int             nitems = 0;
5110
5111                 if (!parsePGArray(proargnames, &argnamearray, &nitems) ||
5112                         nitems != finfo->nargs)
5113                 {
5114                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
5115                         if (argnamearray)
5116                                 free(argnamearray);
5117                         argnamearray = NULL;
5118                 }
5119         }
5120
5121         funcsig = format_function_signature(finfo, argnamearray, true);
5122         funcsig_tag = format_function_signature(finfo, NULL, false);
5123
5124         /*
5125          * DROP must be fully qualified in case same name appears in
5126          * pg_catalog
5127          */
5128         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
5129                                           fmtId(finfo->dobj.namespace->dobj.name),
5130                                           funcsig);
5131
5132         rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
5133
5134         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
5135         appendPQExpBuffer(q, "RETURNS %s%s\n    %s\n    LANGUAGE %s",
5136                                           (proretset[0] == 't') ? "SETOF " : "",
5137                                           rettypename,
5138                                           asPart->data,
5139                                           fmtId(lanname));
5140
5141         free(rettypename);
5142
5143         if (provolatile[0] != PROVOLATILE_VOLATILE)
5144         {
5145                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
5146                         appendPQExpBuffer(q, " IMMUTABLE");
5147                 else if (provolatile[0] == PROVOLATILE_STABLE)
5148                         appendPQExpBuffer(q, " STABLE");
5149                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
5150                 {
5151                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
5152                                           finfo->dobj.name);
5153                         exit_nicely();
5154                 }
5155         }
5156
5157         if (proisstrict[0] == 't')
5158                 appendPQExpBuffer(q, " STRICT");
5159
5160         if (prosecdef[0] == 't')
5161                 appendPQExpBuffer(q, " SECURITY DEFINER");
5162
5163         appendPQExpBuffer(q, ";\n");
5164
5165         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
5166                                  funcsig_tag,
5167                                  finfo->dobj.namespace->dobj.name,
5168                                  finfo->usename, false,
5169                                  "FUNCTION", q->data, delqry->data, NULL,
5170                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
5171                                  NULL, NULL);
5172
5173         /* Dump Function Comments */
5174         resetPQExpBuffer(q);
5175         appendPQExpBuffer(q, "FUNCTION %s", funcsig);
5176         dumpComment(fout, q->data,
5177                                 finfo->dobj.namespace->dobj.name, finfo->usename,
5178                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
5179
5180         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
5181                         funcsig, funcsig_tag,
5182                         finfo->dobj.namespace->dobj.name,
5183                         finfo->usename, finfo->proacl);
5184
5185         PQclear(res);
5186
5187         destroyPQExpBuffer(query);
5188         destroyPQExpBuffer(q);
5189         destroyPQExpBuffer(delqry);
5190         destroyPQExpBuffer(asPart);
5191         free(funcsig);
5192         free(funcsig_tag);
5193         if (argnamearray)
5194                 free(argnamearray);
5195 }
5196
5197
5198 /*
5199  * Dump a user-defined cast
5200  */
5201 static void
5202 dumpCast(Archive *fout, CastInfo *cast)
5203 {
5204         PQExpBuffer defqry;
5205         PQExpBuffer delqry;
5206         PQExpBuffer castsig;
5207         FuncInfo   *funcInfo = NULL;
5208         TypeInfo   *sourceInfo;
5209         TypeInfo   *targetInfo;
5210
5211         if (dataOnly)
5212                 return;
5213
5214         if (OidIsValid(cast->castfunc))
5215         {
5216                 funcInfo = findFuncByOid(cast->castfunc);
5217                 if (funcInfo == NULL)
5218                         return;
5219         }
5220
5221         /*
5222          * As per discussion we dump casts if one or more of the underlying
5223          * objects (the conversion function and the two data types) are not
5224          * builtin AND if all of the non-builtin objects namespaces are
5225          * included in the dump. Builtin meaning, the namespace name does
5226          * not start with "pg_".
5227          */
5228         sourceInfo = findTypeByOid(cast->castsource);
5229         targetInfo = findTypeByOid(cast->casttarget);
5230
5231         if (sourceInfo == NULL || targetInfo == NULL)
5232                 return;
5233
5234         /*
5235          * Skip this cast if all objects are from pg_
5236          */
5237         if ((funcInfo == NULL ||
5238                  strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
5239                 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
5240                 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
5241                 return;
5242
5243         /*
5244          * Skip cast if function isn't from pg_ and that namespace is
5245          * not dumped.
5246          */
5247         if (funcInfo && 
5248                 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
5249                 !funcInfo->dobj.namespace->dump)
5250                 return;
5251
5252         /*
5253          * Same for the Source type
5254          */
5255         if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
5256                 !sourceInfo->dobj.namespace->dump)
5257                 return;
5258
5259         /*
5260          * and the target type.
5261          */
5262         if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
5263                 !targetInfo->dobj.namespace->dump)
5264                 return;
5265
5266         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
5267         selectSourceSchema("pg_catalog");
5268
5269         defqry = createPQExpBuffer();
5270         delqry = createPQExpBuffer();
5271         castsig = createPQExpBuffer();
5272
5273         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
5274                                           getFormattedTypeName(cast->castsource, zeroAsNone),
5275                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
5276
5277         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
5278                                           getFormattedTypeName(cast->castsource, zeroAsNone),
5279                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
5280
5281         if (!OidIsValid(cast->castfunc))
5282                 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
5283         else
5284         {
5285                 /*
5286                  * Always qualify the function name, in case it is not in pg_catalog
5287                  * schema (format_function_signature won't qualify it).
5288                  */
5289                 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
5290                                                   fmtId(funcInfo->dobj.namespace->dobj.name));
5291                 appendPQExpBuffer(defqry, "%s",
5292                                                   format_function_signature(funcInfo, NULL, true));
5293         }
5294
5295         if (cast->castcontext == 'a')
5296                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
5297         else if (cast->castcontext == 'i')
5298                 appendPQExpBuffer(defqry, " AS IMPLICIT");
5299         appendPQExpBuffer(defqry, ";\n");
5300
5301         appendPQExpBuffer(castsig, "CAST (%s AS %s)",
5302                                           getFormattedTypeName(cast->castsource, zeroAsNone),
5303                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
5304
5305         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
5306                                  castsig->data,
5307                                  "pg_catalog", "",
5308                                  false, "CAST", defqry->data, delqry->data, NULL,
5309                                  cast->dobj.dependencies, cast->dobj.nDeps,
5310                                  NULL, NULL);
5311
5312         /* Dump Cast Comments */
5313         resetPQExpBuffer(defqry);
5314         appendPQExpBuffer(defqry, "CAST (%s AS %s)",
5315                                           getFormattedTypeName(cast->castsource, zeroAsNone),
5316                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
5317         dumpComment(fout, defqry->data,
5318                                 NULL, "",
5319                                 cast->dobj.catId, 0, cast->dobj.dumpId);
5320
5321         destroyPQExpBuffer(defqry);
5322         destroyPQExpBuffer(delqry);
5323         destroyPQExpBuffer(castsig);
5324 }
5325
5326 /*
5327  * dumpOpr
5328  *        write out a single operator definition
5329  */
5330 static void
5331 dumpOpr(Archive *fout, OprInfo *oprinfo)
5332 {
5333         PQExpBuffer query;
5334         PQExpBuffer q;
5335         PQExpBuffer delq;
5336         PQExpBuffer oprid;
5337         PQExpBuffer details;
5338         const char *name;
5339         PGresult   *res;
5340         int                     ntups;
5341         int                     i_oprkind;
5342         int                     i_oprcode;
5343         int                     i_oprleft;
5344         int                     i_oprright;
5345         int                     i_oprcom;
5346         int                     i_oprnegate;
5347         int                     i_oprrest;
5348         int                     i_oprjoin;
5349         int                     i_oprcanhash;
5350         int                     i_oprlsortop;
5351         int                     i_oprrsortop;
5352         int                     i_oprltcmpop;
5353         int                     i_oprgtcmpop;
5354         char       *oprkind;
5355         char       *oprcode;
5356         char       *oprleft;
5357         char       *oprright;
5358         char       *oprcom;
5359         char       *oprnegate;
5360         char       *oprrest;
5361         char       *oprjoin;
5362         char       *oprcanhash;
5363         char       *oprlsortop;
5364         char       *oprrsortop;
5365         char       *oprltcmpop;
5366         char       *oprgtcmpop;
5367
5368         /* Dump only operators in dumpable namespaces */
5369         if (!oprinfo->dobj.namespace->dump || dataOnly)
5370                 return;
5371
5372         /*
5373          * some operators are invalid because they were the result of user
5374          * defining operators before commutators exist
5375          */
5376         if (!OidIsValid(oprinfo->oprcode))
5377                 return;
5378
5379         query = createPQExpBuffer();
5380         q = createPQExpBuffer();
5381         delq = createPQExpBuffer();
5382         oprid = createPQExpBuffer();
5383         details = createPQExpBuffer();
5384
5385         /* Make sure we are in proper schema so regoperator works correctly */
5386         selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
5387
5388         if (g_fout->remoteVersion >= 70300)
5389         {
5390                 appendPQExpBuffer(query, "SELECT oprkind, "
5391                                                   "oprcode::pg_catalog.regprocedure, "
5392                                                   "oprleft::pg_catalog.regtype, "
5393                                                   "oprright::pg_catalog.regtype, "
5394                                                   "oprcom::pg_catalog.regoperator, "
5395                                                   "oprnegate::pg_catalog.regoperator, "
5396                                                   "oprrest::pg_catalog.regprocedure, "
5397                                                   "oprjoin::pg_catalog.regprocedure, "
5398                                                   "oprcanhash, "
5399                                                   "oprlsortop::pg_catalog.regoperator, "
5400                                                   "oprrsortop::pg_catalog.regoperator, "
5401                                                   "oprltcmpop::pg_catalog.regoperator, "
5402                                                   "oprgtcmpop::pg_catalog.regoperator "
5403                                                   "from pg_catalog.pg_operator "
5404                                                   "where oid = '%u'::pg_catalog.oid",
5405                                                   oprinfo->dobj.catId.oid);
5406         }
5407         else if (g_fout->remoteVersion >= 70100)
5408         {
5409                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
5410                                                   "CASE WHEN oprleft = 0 THEN '-' "
5411                                            "ELSE format_type(oprleft, NULL) END as oprleft, "
5412                                                   "CASE WHEN oprright = 0 THEN '-' "
5413                                          "ELSE format_type(oprright, NULL) END as oprright, "
5414                                                   "oprcom, oprnegate, oprrest, oprjoin, "
5415                                                   "oprcanhash, oprlsortop, oprrsortop, "
5416                                                   "0 as oprltcmpop, 0 as oprgtcmpop "
5417                                                   "from pg_operator "
5418                                                   "where oid = '%u'::oid",
5419                                                   oprinfo->dobj.catId.oid);
5420         }
5421         else
5422         {
5423                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
5424                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
5425                                                   "ELSE (select typname from pg_type where oid = oprleft) END as oprleft, "
5426                                                   "CASE WHEN oprright = 0 THEN '-'::name "
5427                                                   "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
5428                                                   "oprcom, oprnegate, oprrest, oprjoin, "
5429                                                   "oprcanhash, oprlsortop, oprrsortop, "
5430                                                   "0 as oprltcmpop, 0 as oprgtcmpop "
5431                                                   "from pg_operator "
5432                                                   "where oid = '%u'::oid",
5433                                                   oprinfo->dobj.catId.oid);
5434         }
5435
5436         res = PQexec(g_conn, query->data);
5437         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5438
5439         /* Expecting a single result only */
5440         ntups = PQntuples(res);
5441         if (ntups != 1)
5442         {
5443                 write_msg(NULL, "Got %d rows instead of one from: %s",
5444                                   ntups, query->data);
5445                 exit_nicely();
5446         }
5447
5448         i_oprkind = PQfnumber(res, "oprkind");
5449         i_oprcode = PQfnumber(res, "oprcode");
5450         i_oprleft = PQfnumber(res, "oprleft");
5451         i_oprright = PQfnumber(res, "oprright");
5452         i_oprcom = PQfnumber(res, "oprcom");
5453         i_oprnegate = PQfnumber(res, "oprnegate");
5454         i_oprrest = PQfnumber(res, "oprrest");
5455         i_oprjoin = PQfnumber(res, "oprjoin");
5456         i_oprcanhash = PQfnumber(res, "oprcanhash");
5457         i_oprlsortop = PQfnumber(res, "oprlsortop");
5458         i_oprrsortop = PQfnumber(res, "oprrsortop");
5459         i_oprltcmpop = PQfnumber(res, "oprltcmpop");
5460         i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
5461
5462         oprkind = PQgetvalue(res, 0, i_oprkind);
5463         oprcode = PQgetvalue(res, 0, i_oprcode);
5464         oprleft = PQgetvalue(res, 0, i_oprleft);
5465         oprright = PQgetvalue(res, 0, i_oprright);
5466         oprcom = PQgetvalue(res, 0, i_oprcom);
5467         oprnegate = PQgetvalue(res, 0, i_oprnegate);
5468         oprrest = PQgetvalue(res, 0, i_oprrest);
5469         oprjoin = PQgetvalue(res, 0, i_oprjoin);
5470         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
5471         oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
5472         oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
5473         oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
5474         oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
5475
5476         appendPQExpBuffer(details, "    PROCEDURE = %s",
5477                                           convertRegProcReference(oprcode));
5478
5479         appendPQExpBuffer(oprid, "%s (",
5480                                           oprinfo->dobj.name);
5481
5482         /*
5483          * right unary means there's a left arg and left unary means there's a
5484          * right arg
5485          */
5486         if (strcmp(oprkind, "r") == 0 ||
5487                 strcmp(oprkind, "b") == 0)
5488         {
5489                 if (g_fout->remoteVersion >= 70100)
5490                         name = oprleft;
5491                 else
5492                         name = fmtId(oprleft);
5493                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
5494                 appendPQExpBuffer(oprid, "%s", name);
5495         }
5496         else
5497                 appendPQExpBuffer(oprid, "NONE");
5498
5499         if (strcmp(oprkind, "l") == 0 ||
5500                 strcmp(oprkind, "b") == 0)
5501         {
5502                 if (g_fout->remoteVersion >= 70100)
5503                         name = oprright;
5504                 else
5505                         name = fmtId(oprright);
5506                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
5507                 appendPQExpBuffer(oprid, ", %s)", name);
5508         }
5509         else
5510                 appendPQExpBuffer(oprid, ", NONE)");
5511
5512         name = convertOperatorReference(oprcom);
5513         if (name)
5514                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
5515
5516         name = convertOperatorReference(oprnegate);
5517         if (name)
5518                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
5519
5520         if (strcmp(oprcanhash, "t") == 0)
5521                 appendPQExpBuffer(details, ",\n    HASHES");
5522
5523         name = convertRegProcReference(oprrest);
5524         if (name)
5525                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
5526
5527         name = convertRegProcReference(oprjoin);
5528         if (name)
5529                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
5530
5531         name = convertOperatorReference(oprlsortop);
5532         if (name)
5533                 appendPQExpBuffer(details, ",\n    SORT1 = %s", name);
5534
5535         name = convertOperatorReference(oprrsortop);
5536         if (name)
5537                 appendPQExpBuffer(details, ",\n    SORT2 = %s", name);
5538
5539         name = convertOperatorReference(oprltcmpop);
5540         if (name)
5541                 appendPQExpBuffer(details, ",\n    LTCMP = %s", name);
5542
5543         name = convertOperatorReference(oprgtcmpop);
5544         if (name)
5545                 appendPQExpBuffer(details, ",\n    GTCMP = %s", name);
5546
5547         /*
5548          * DROP must be fully qualified in case same name appears in
5549          * pg_catalog
5550          */
5551         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
5552                                           fmtId(oprinfo->dobj.namespace->dobj.name),
5553                                           oprid->data);
5554
5555         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
5556                                           oprinfo->dobj.name, details->data);
5557
5558         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
5559                                  oprinfo->dobj.name,
5560                                  oprinfo->dobj.namespace->dobj.name, oprinfo->usename,
5561                                  false, "OPERATOR", q->data, delq->data, NULL,
5562                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
5563                                  NULL, NULL);
5564
5565         /* Dump Operator Comments */
5566         resetPQExpBuffer(q);
5567         appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
5568         dumpComment(fout, q->data,
5569                                 oprinfo->dobj.namespace->dobj.name, oprinfo->usename,
5570                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
5571
5572         PQclear(res);
5573
5574         destroyPQExpBuffer(query);
5575         destroyPQExpBuffer(q);
5576         destroyPQExpBuffer(delq);
5577         destroyPQExpBuffer(oprid);
5578         destroyPQExpBuffer(details);
5579 }
5580
5581 /*
5582  * Convert a function reference obtained from pg_operator
5583  *
5584  * Returns what to print, or NULL if function references is InvalidOid
5585  *
5586  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
5587  * argument-types part.  In prior versions, the input is a REGPROC display.
5588  */
5589 static const char *
5590 convertRegProcReference(const char *proc)
5591 {
5592         /* In all cases "-" means a null reference */
5593         if (strcmp(proc, "-") == 0)
5594                 return NULL;
5595
5596         if (g_fout->remoteVersion >= 70300)
5597         {
5598                 char       *name;
5599                 char       *paren;
5600                 bool            inquote;
5601
5602                 name = strdup(proc);
5603                 /* find non-double-quoted left paren */
5604                 inquote = false;
5605                 for (paren = name; *paren; paren++)
5606                 {
5607                         if (*paren == '(' && !inquote)
5608                         {
5609                                 *paren = '\0';
5610                                 break;
5611                         }
5612                         if (*paren == '"')
5613                                 inquote = !inquote;
5614                 }
5615                 return name;
5616         }
5617
5618         /* REGPROC before 7.3 does not quote its result */
5619         return fmtId(proc);
5620 }
5621
5622 /*
5623  * Convert an operator cross-reference obtained from pg_operator
5624  *
5625  * Returns what to print, or NULL to print nothing
5626  *
5627  * In 7.3 the input is a REGOPERATOR display; we have to strip the
5628  * argument-types part.  In prior versions, the input is just a
5629  * numeric OID, which we search our operator list for.
5630  */
5631 static const char *
5632 convertOperatorReference(const char *opr)
5633 {
5634         OprInfo    *oprInfo;
5635
5636         /* In all cases "0" means a null reference */
5637         if (strcmp(opr, "0") == 0)
5638                 return NULL;
5639
5640         if (g_fout->remoteVersion >= 70300)
5641         {
5642                 char       *name;
5643                 char       *paren;
5644                 bool            inquote;
5645
5646                 name = strdup(opr);
5647                 /* find non-double-quoted left paren */
5648                 inquote = false;
5649                 for (paren = name; *paren; paren++)
5650                 {
5651                         if (*paren == '(' && !inquote)
5652                         {
5653                                 *paren = '\0';
5654                                 break;
5655                         }
5656                         if (*paren == '"')
5657                                 inquote = !inquote;
5658                 }
5659                 return name;
5660         }
5661
5662         oprInfo = findOprByOid(atooid(opr));
5663         if (oprInfo == NULL)
5664         {
5665                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
5666                                   opr);
5667                 return NULL;
5668         }
5669         return oprInfo->dobj.name;
5670 }
5671
5672 /*
5673  * dumpOpclass
5674  *        write out a single operator class definition
5675  */
5676 static void
5677 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
5678 {
5679         PQExpBuffer query;
5680         PQExpBuffer q;
5681         PQExpBuffer delq;
5682         PGresult   *res;
5683         int                     ntups;
5684         int                     i_opcintype;
5685         int                     i_opckeytype;
5686         int                     i_opcdefault;
5687         int                     i_amname;
5688         int                     i_amopstrategy;
5689         int                     i_amopreqcheck;
5690         int                     i_amopopr;
5691         int                     i_amprocnum;
5692         int                     i_amproc;
5693         char       *opcintype;
5694         char       *opckeytype;
5695         char       *opcdefault;
5696         char       *amname;
5697         char       *amopstrategy;
5698         char       *amopreqcheck;
5699         char       *amopopr;
5700         char       *amprocnum;
5701         char       *amproc;
5702         bool            needComma;
5703         int                     i;
5704
5705         /* Dump only opclasses in dumpable namespaces */
5706         if (!opcinfo->dobj.namespace->dump || dataOnly)
5707                 return;
5708
5709         /*
5710          * XXX currently we do not implement dumping of operator classes from
5711          * pre-7.3 databases.  This could be done but it seems not worth the
5712          * trouble.
5713          */
5714         if (g_fout->remoteVersion < 70300)
5715                 return;
5716
5717         query = createPQExpBuffer();
5718         q = createPQExpBuffer();
5719         delq = createPQExpBuffer();
5720
5721         /* Make sure we are in proper schema so regoperator works correctly */
5722         selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
5723
5724         /* Get additional fields from the pg_opclass row */
5725         appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
5726                                           "opckeytype::pg_catalog.regtype, "
5727                                           "opcdefault, "
5728         "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
5729                                           "FROM pg_catalog.pg_opclass "
5730                                           "WHERE oid = '%u'::pg_catalog.oid",
5731                                           opcinfo->dobj.catId.oid);
5732
5733         res = PQexec(g_conn, query->data);
5734         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5735
5736         /* Expecting a single result only */
5737         ntups = PQntuples(res);
5738         if (ntups != 1)
5739         {
5740                 write_msg(NULL, "Got %d rows instead of one from: %s",
5741                                   ntups, query->data);
5742                 exit_nicely();
5743         }
5744
5745         i_opcintype = PQfnumber(res, "opcintype");
5746         i_opckeytype = PQfnumber(res, "opckeytype");
5747         i_opcdefault = PQfnumber(res, "opcdefault");
5748         i_amname = PQfnumber(res, "amname");
5749
5750         opcintype = PQgetvalue(res, 0, i_opcintype);
5751         opckeytype = PQgetvalue(res, 0, i_opckeytype);
5752         opcdefault = PQgetvalue(res, 0, i_opcdefault);
5753         /* amname will still be needed after we PQclear res */
5754         amname = strdup(PQgetvalue(res, 0, i_amname));
5755
5756         /*
5757          * DROP must be fully qualified in case same name appears in
5758          * pg_catalog
5759          */
5760         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
5761                                           fmtId(opcinfo->dobj.namespace->dobj.name));
5762         appendPQExpBuffer(delq, ".%s",
5763                                           fmtId(opcinfo->dobj.name));
5764         appendPQExpBuffer(delq, " USING %s;\n",
5765                                           fmtId(amname));
5766
5767         /* Build the fixed portion of the CREATE command */
5768         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
5769                                           fmtId(opcinfo->dobj.name));
5770         if (strcmp(opcdefault, "t") == 0)
5771                 appendPQExpBuffer(q, "DEFAULT ");
5772         appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n    ",
5773                                           opcintype,
5774                                           fmtId(amname));
5775
5776         needComma = false;
5777
5778         if (strcmp(opckeytype, "-") != 0)
5779         {
5780                 appendPQExpBuffer(q, "STORAGE %s",
5781                                                   opckeytype);
5782                 needComma = true;
5783         }
5784
5785         PQclear(res);
5786
5787         /*
5788          * Now fetch and print the OPERATOR entries (pg_amop rows).
5789          */
5790         resetPQExpBuffer(query);
5791
5792         appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
5793                                           "amopopr::pg_catalog.regoperator "
5794                                           "FROM pg_catalog.pg_amop "
5795                                           "WHERE amopclaid = '%u'::pg_catalog.oid "
5796                                           "ORDER BY amopstrategy",
5797                                           opcinfo->dobj.catId.oid);
5798
5799         res = PQexec(g_conn, query->data);
5800         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5801
5802         ntups = PQntuples(res);
5803
5804         i_amopstrategy = PQfnumber(res, "amopstrategy");
5805         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
5806         i_amopopr = PQfnumber(res, "amopopr");
5807
5808         for (i = 0; i < ntups; i++)
5809         {
5810                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
5811                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
5812                 amopopr = PQgetvalue(res, i, i_amopopr);
5813
5814                 if (needComma)
5815                         appendPQExpBuffer(q, " ,\n    ");
5816
5817                 appendPQExpBuffer(q, "OPERATOR %s %s",
5818                                                   amopstrategy, amopopr);
5819                 if (strcmp(amopreqcheck, "t") == 0)
5820                         appendPQExpBuffer(q, " RECHECK");
5821
5822                 needComma = true;
5823         }
5824
5825         PQclear(res);
5826
5827         /*
5828          * Now fetch and print the FUNCTION entries (pg_amproc rows).
5829          */
5830         resetPQExpBuffer(query);
5831
5832         appendPQExpBuffer(query, "SELECT amprocnum, "
5833                                           "amproc::pg_catalog.regprocedure "
5834                                           "FROM pg_catalog.pg_amproc "
5835                                           "WHERE amopclaid = '%u'::pg_catalog.oid "
5836                                           "ORDER BY amprocnum",
5837                                           opcinfo->dobj.catId.oid);
5838
5839         res = PQexec(g_conn, query->data);
5840         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5841
5842         ntups = PQntuples(res);
5843
5844         i_amprocnum = PQfnumber(res, "amprocnum");
5845         i_amproc = PQfnumber(res, "amproc");
5846
5847         for (i = 0; i < ntups; i++)
5848         {
5849                 amprocnum = PQgetvalue(res, i, i_amprocnum);
5850                 amproc = PQgetvalue(res, i, i_amproc);
5851
5852                 if (needComma)
5853                         appendPQExpBuffer(q, " ,\n    ");
5854
5855                 appendPQExpBuffer(q, "FUNCTION %s %s",
5856                                                   amprocnum, amproc);
5857
5858                 needComma = true;
5859         }
5860
5861         PQclear(res);
5862
5863         appendPQExpBuffer(q, ";\n");
5864
5865         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
5866                                  opcinfo->dobj.name,
5867                                  opcinfo->dobj.namespace->dobj.name, opcinfo->usename,
5868                                  false, "OPERATOR CLASS", q->data, delq->data, NULL,
5869                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
5870                                  NULL, NULL);
5871
5872         /* Dump Operator Class Comments */
5873         resetPQExpBuffer(q);
5874         appendPQExpBuffer(q, "OPERATOR CLASS %s",
5875                                           fmtId(opcinfo->dobj.name));
5876         appendPQExpBuffer(q, " USING %s",
5877                                           fmtId(amname));
5878         dumpComment(fout, q->data,
5879                                 NULL, opcinfo->usename,
5880                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
5881
5882         free(amname);
5883         destroyPQExpBuffer(query);
5884         destroyPQExpBuffer(q);
5885         destroyPQExpBuffer(delq);
5886 }
5887
5888 /*
5889  * dumpConversion
5890  *        write out a single conversion definition
5891  */
5892 static void
5893 dumpConversion(Archive *fout, ConvInfo *convinfo)
5894 {
5895         PQExpBuffer query;
5896         PQExpBuffer q;
5897         PQExpBuffer delq;
5898         PQExpBuffer details;
5899         PGresult   *res;
5900         int                     ntups;
5901         int                     i_conname;
5902         int                     i_conforencoding;
5903         int                     i_contoencoding;
5904         int                     i_conproc;
5905         int                     i_condefault;
5906         const char *conname;
5907         const char *conforencoding;
5908         const char *contoencoding;
5909         const char *conproc;
5910         bool            condefault;
5911
5912         /* Dump only conversions in dumpable namespaces */
5913         if (!convinfo->dobj.namespace->dump || dataOnly)
5914                 return;
5915
5916         query = createPQExpBuffer();
5917         q = createPQExpBuffer();
5918         delq = createPQExpBuffer();
5919         details = createPQExpBuffer();
5920
5921         /* Make sure we are in proper schema */
5922         selectSourceSchema(convinfo->dobj.namespace->dobj.name);
5923
5924         /* Get conversion-specific details */
5925         appendPQExpBuffer(query, "SELECT conname, "
5926                                           "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
5927                                           "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
5928                                           "conproc, condefault "
5929                                           "FROM pg_catalog.pg_conversion c "
5930                                           "WHERE c.oid = '%u'::pg_catalog.oid",
5931                                           convinfo->dobj.catId.oid);
5932
5933         res = PQexec(g_conn, query->data);
5934         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5935
5936         /* Expecting a single result only */
5937         ntups = PQntuples(res);
5938         if (ntups != 1)
5939         {
5940                 write_msg(NULL, "Got %d rows instead of one from: %s",
5941                                   ntups, query->data);
5942                 exit_nicely();
5943         }
5944
5945         i_conname = PQfnumber(res, "conname");
5946         i_conforencoding = PQfnumber(res, "conforencoding");
5947         i_contoencoding = PQfnumber(res, "contoencoding");
5948         i_conproc = PQfnumber(res, "conproc");
5949         i_condefault = PQfnumber(res, "condefault");
5950
5951         conname = PQgetvalue(res, 0, i_conname);
5952         conforencoding = PQgetvalue(res, 0, i_conforencoding);
5953         contoencoding = PQgetvalue(res, 0, i_contoencoding);
5954         conproc = PQgetvalue(res, 0, i_conproc);
5955         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
5956
5957         /*
5958          * DROP must be fully qualified in case same name appears in
5959          * pg_catalog
5960          */
5961         appendPQExpBuffer(delq, "DROP CONVERSION %s",
5962                                           fmtId(convinfo->dobj.namespace->dobj.name));
5963         appendPQExpBuffer(delq, ".%s;\n",
5964                                           fmtId(convinfo->dobj.name));
5965
5966         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
5967                                         (condefault) ? "DEFAULT " : "", 
5968                                         fmtId(convinfo->dobj.name));
5969         appendStringLiteral(q, conforencoding, true);
5970         appendPQExpBuffer(q, " TO ");
5971         appendStringLiteral(q, contoencoding, true);
5972         /* regproc is automatically quoted in 7.3 and above */
5973         appendPQExpBuffer(q, " FROM %s;\n", conproc);
5974         
5975         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
5976                                  convinfo->dobj.name,
5977                                  convinfo->dobj.namespace->dobj.name, convinfo->usename,
5978                                  false, "CONVERSION", q->data, delq->data, NULL,
5979                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
5980                                  NULL, NULL);
5981
5982         /* Dump Conversion Comments */
5983         resetPQExpBuffer(q);
5984         appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
5985         dumpComment(fout, q->data,
5986                                 convinfo->dobj.namespace->dobj.name, convinfo->usename,
5987                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
5988
5989         PQclear(res);
5990
5991         destroyPQExpBuffer(query);
5992         destroyPQExpBuffer(q);
5993         destroyPQExpBuffer(delq);
5994         destroyPQExpBuffer(details);
5995 }
5996
5997 /*
5998  * format_aggregate_signature: generate aggregate name and argument list
5999  *
6000  * The argument type names are qualified if needed.  The aggregate name
6001  * is never qualified.
6002  */
6003 static char *
6004 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
6005 {
6006         PQExpBufferData buf;
6007
6008         initPQExpBuffer(&buf);
6009         if (honor_quotes)
6010                 appendPQExpBuffer(&buf, "%s",
6011                                                   fmtId(agginfo->aggfn.dobj.name));
6012         else
6013                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
6014
6015         /* If using regtype or format_type, fmtbasetype is already quoted */
6016         if (fout->remoteVersion >= 70100)
6017         {
6018                 if (agginfo->anybasetype)
6019                         appendPQExpBuffer(&buf, "(*)");
6020                 else
6021                         appendPQExpBuffer(&buf, "(%s)", agginfo->fmtbasetype);
6022         }
6023         else
6024         {
6025                 if (agginfo->anybasetype)
6026                         appendPQExpBuffer(&buf, "(*)");
6027                 else
6028                         appendPQExpBuffer(&buf, "(%s)",
6029                                                           fmtId(agginfo->fmtbasetype));
6030         }
6031
6032         return buf.data;
6033 }
6034
6035 /*
6036  * dumpAgg
6037  *        write out a single aggregate definition
6038  */
6039 static void
6040 dumpAgg(Archive *fout, AggInfo *agginfo)
6041 {
6042         PQExpBuffer query;
6043         PQExpBuffer q;
6044         PQExpBuffer delq;
6045         PQExpBuffer details;
6046         char       *aggsig;
6047         char       *aggsig_tag;
6048         PGresult   *res;
6049         int                     ntups;
6050         int                     i_aggtransfn;
6051         int                     i_aggfinalfn;
6052         int                     i_aggtranstype;
6053         int                     i_agginitval;
6054         int                     i_anybasetype;
6055         int                     i_fmtbasetype;
6056         int                     i_convertok;
6057         const char *aggtransfn;
6058         const char *aggfinalfn;
6059         const char *aggtranstype;
6060         const char *agginitval;
6061         bool            convertok;
6062
6063         /* Dump only aggs in dumpable namespaces */
6064         if (!agginfo->aggfn.dobj.namespace->dump || dataOnly)
6065                 return;
6066
6067         query = createPQExpBuffer();
6068         q = createPQExpBuffer();
6069         delq = createPQExpBuffer();
6070         details = createPQExpBuffer();
6071
6072         /* Make sure we are in proper schema */
6073         selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
6074
6075         /* Get aggregate-specific details */
6076         if (g_fout->remoteVersion >= 70300)
6077         {
6078                 appendPQExpBuffer(query, "SELECT aggtransfn, "
6079                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
6080                                                   "agginitval, "
6081                                                   "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
6082                                         "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
6083                                                   "'t'::boolean as convertok "
6084                                   "from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
6085                                                   "where a.aggfnoid = p.oid "
6086                                                   "and p.oid = '%u'::pg_catalog.oid",
6087                                                   agginfo->aggfn.dobj.catId.oid);
6088         }
6089         else if (g_fout->remoteVersion >= 70100)
6090         {
6091                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
6092                                           "format_type(aggtranstype, NULL) as aggtranstype, "
6093                                                   "agginitval, "
6094                                                   "aggbasetype = 0 as anybasetype, "
6095                                                   "CASE WHEN aggbasetype = 0 THEN '-' "
6096                            "ELSE format_type(aggbasetype, NULL) END as fmtbasetype, "
6097                                                   "'t'::boolean as convertok "
6098                                                   "from pg_aggregate "
6099                                                   "where oid = '%u'::oid",
6100                                                   agginfo->aggfn.dobj.catId.oid);
6101         }
6102         else
6103         {
6104                 appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
6105                                                   "aggfinalfn, "
6106                                                   "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
6107                                                   "agginitval1 as agginitval, "
6108                                                   "aggbasetype = 0 as anybasetype, "
6109                                                   "(select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
6110                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
6111                                                   "from pg_aggregate "
6112                                                   "where oid = '%u'::oid",
6113                                                   agginfo->aggfn.dobj.catId.oid);
6114         }
6115
6116         res = PQexec(g_conn, query->data);
6117         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6118
6119         /* Expecting a single result only */
6120         ntups = PQntuples(res);
6121         if (ntups != 1)
6122         {
6123                 write_msg(NULL, "Got %d rows instead of one from: %s",
6124                                   ntups, query->data);
6125                 exit_nicely();
6126         }
6127
6128         i_aggtransfn = PQfnumber(res, "aggtransfn");
6129         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
6130         i_aggtranstype = PQfnumber(res, "aggtranstype");
6131         i_agginitval = PQfnumber(res, "agginitval");
6132         i_anybasetype = PQfnumber(res, "anybasetype");
6133         i_fmtbasetype = PQfnumber(res, "fmtbasetype");
6134         i_convertok = PQfnumber(res, "convertok");
6135
6136         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
6137         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
6138         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
6139         agginitval = PQgetvalue(res, 0, i_agginitval);
6140         /* we save anybasetype for format_aggregate_signature */
6141         agginfo->anybasetype = (PQgetvalue(res, 0, i_anybasetype)[0] == 't');
6142         /* we save fmtbasetype for format_aggregate_signature */
6143         agginfo->fmtbasetype = strdup(PQgetvalue(res, 0, i_fmtbasetype));
6144         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
6145
6146         aggsig = format_aggregate_signature(agginfo, fout, true);
6147         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
6148
6149         if (!convertok)
6150         {
6151                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
6152                                   aggsig);
6153                 return;
6154         }
6155
6156         if (g_fout->remoteVersion >= 70300)
6157         {
6158                 /* If using 7.3's regproc or regtype, data is already quoted */
6159                 appendPQExpBuffer(details, "    BASETYPE = %s,\n    SFUNC = %s,\n    STYPE = %s",
6160                                                   agginfo->anybasetype ? "'any'" :
6161                                                   agginfo->fmtbasetype,
6162                                                   aggtransfn,
6163                                                   aggtranstype);
6164         }
6165         else if (g_fout->remoteVersion >= 70100)
6166         {
6167                 /* format_type quotes, regproc does not */
6168                 appendPQExpBuffer(details, "    BASETYPE = %s,\n    SFUNC = %s,\n    STYPE = %s",
6169                                                   agginfo->anybasetype ? "'any'" :
6170                                                   agginfo->fmtbasetype,
6171                                                   fmtId(aggtransfn),
6172                                                   aggtranstype);
6173         }
6174         else
6175         {
6176                 /* need quotes all around */
6177                 appendPQExpBuffer(details, "    BASETYPE = %s,\n",
6178                                                   agginfo->anybasetype ? "'any'" :
6179                                                   fmtId(agginfo->fmtbasetype));
6180                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
6181                                                   fmtId(aggtransfn));
6182                 appendPQExpBuffer(details, "    STYPE = %s",
6183                                                   fmtId(aggtranstype));
6184         }
6185
6186         if (!PQgetisnull(res, 0, i_agginitval))
6187         {
6188                 appendPQExpBuffer(details, ",\n    INITCOND = ");
6189                 appendStringLiteral(details, agginitval, true);
6190         }
6191
6192         if (strcmp(aggfinalfn, "-") != 0)
6193         {
6194                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
6195                                                   aggfinalfn);
6196         }
6197
6198         /*
6199          * DROP must be fully qualified in case same name appears in
6200          * pg_catalog
6201          */
6202         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
6203                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
6204                                           aggsig);
6205
6206         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
6207                                           fmtId(agginfo->aggfn.dobj.name),
6208                                           details->data);
6209
6210         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
6211                                  aggsig_tag,
6212                                  agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.usename,
6213                                  false, "AGGREGATE", q->data, delq->data, NULL,
6214                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
6215                                  NULL, NULL);
6216
6217         /* Dump Aggregate Comments */
6218         resetPQExpBuffer(q);
6219         appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
6220         dumpComment(fout, q->data,
6221                                 agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.usename,
6222                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
6223
6224         /*
6225          * Since there is no GRANT ON AGGREGATE syntax, we have to make the
6226          * ACL command look like a function's GRANT; in particular this affects
6227          * the syntax for aggregates on ANY.
6228          */
6229         free(aggsig);
6230         free(aggsig_tag);
6231
6232         aggsig = format_function_signature(&agginfo->aggfn, NULL, true);
6233         aggsig_tag = format_function_signature(&agginfo->aggfn, NULL, false);
6234
6235         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
6236                         "FUNCTION",
6237                         aggsig, aggsig_tag,
6238                         agginfo->aggfn.dobj.namespace->dobj.name,
6239                         agginfo->aggfn.usename, agginfo->aggfn.proacl);
6240
6241         free(aggsig);
6242         free(aggsig_tag);
6243
6244         PQclear(res);
6245
6246         destroyPQExpBuffer(query);
6247         destroyPQExpBuffer(q);
6248         destroyPQExpBuffer(delq);
6249         destroyPQExpBuffer(details);
6250 }
6251
6252
6253 /*----------
6254  * Write out grant/revoke information
6255  *
6256  * 'objCatId' is the catalog ID of the underlying object.
6257  * 'objDumpId' is the dump ID of the underlying object.
6258  * 'type' must be TABLE, FUNCTION, LANGUAGE, or SCHEMA.
6259  * 'name' is the formatted name of the object.  Must be quoted etc. already.
6260  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
6261  * 'nspname' is the namespace the object is in (NULL if none).
6262  * 'owner' is the owner, NULL if there is no owner (for languages).
6263  * 'acls' is the string read out of the fooacl system catalog field;
6264  * it will be parsed here.
6265  *----------
6266  */
6267 static void
6268 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
6269                 const char *type, const char *name,
6270                 const char *tag, const char *nspname, const char *owner,
6271                 const char *acls)
6272 {
6273         PQExpBuffer sql;
6274
6275         /* Do nothing if ACL dump is not enabled */
6276         if (dataOnly || aclsSkip)
6277                 return;
6278
6279         sql = createPQExpBuffer();
6280
6281         if (!buildACLCommands(name, type, acls, owner, fout->remoteVersion, sql))
6282         {
6283                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
6284                                   acls, name, type);
6285                 exit_nicely();
6286         }
6287
6288         if (sql->len > 0)
6289                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
6290                                          tag, nspname,
6291                                          owner ? owner : "",
6292                                          false, "ACL", sql->data, "", NULL,
6293                                          &(objDumpId), 1,
6294                                          NULL, NULL);
6295
6296         destroyPQExpBuffer(sql);
6297 }
6298
6299 /*
6300  * dumpTable
6301  *        write out to fout the declarations (not data) of a user-defined table
6302  */
6303 static void
6304 dumpTable(Archive *fout, TableInfo *tbinfo)
6305 {
6306         char       *namecopy;
6307
6308         if (tbinfo->dump)
6309         {
6310                 if (tbinfo->relkind == RELKIND_SEQUENCE)
6311                         dumpSequence(fout, tbinfo);
6312                 else if (!dataOnly)
6313                         dumpTableSchema(fout, tbinfo);
6314
6315                 /* Handle the ACL here */
6316                 namecopy = strdup(fmtId(tbinfo->dobj.name));
6317                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
6318                                 namecopy, tbinfo->dobj.name,
6319                                 tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
6320                                 tbinfo->relacl);
6321                 free(namecopy);
6322         }
6323 }
6324
6325 /*
6326  * dumpTableSchema
6327  *        write the declaration (not data) of one user-defined table or view
6328  */
6329 static void
6330 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
6331 {
6332         PQExpBuffer query = createPQExpBuffer();
6333         PQExpBuffer q = createPQExpBuffer();
6334         PQExpBuffer delq = createPQExpBuffer();
6335         PGresult   *res;
6336         int                     numParents;
6337         TableInfo **parents;
6338         int                     actual_atts;    /* number of attrs in this CREATE statment */
6339         char       *reltypename;
6340         char       *storage;
6341         int                     j,
6342                                 k;
6343
6344         /* Make sure we are in proper schema */
6345         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
6346
6347         /* Is it a table or a view? */
6348         if (tbinfo->relkind == RELKIND_VIEW)
6349         {
6350                 char       *viewdef;
6351
6352                 reltypename = "VIEW";
6353
6354                 /* Fetch the view definition */
6355                 if (g_fout->remoteVersion >= 70300)
6356                 {
6357                         /* Beginning in 7.3, viewname is not unique; rely on OID */
6358                         appendPQExpBuffer(query,
6359                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) as viewdef",
6360                                                           tbinfo->dobj.catId.oid);
6361                 }
6362                 else
6363                 {
6364                         appendPQExpBuffer(query, "SELECT definition as viewdef "
6365                                                           " from pg_views where viewname = ");
6366                         appendStringLiteral(query, tbinfo->dobj.name, true);
6367                         appendPQExpBuffer(query, ";");
6368                 }
6369
6370                 res = PQexec(g_conn, query->data);
6371                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6372
6373                 if (PQntuples(res) != 1)
6374                 {
6375                         if (PQntuples(res) < 1)
6376                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
6377                                                   tbinfo->dobj.name);
6378                         else
6379                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
6380                                                   tbinfo->dobj.name);
6381                         exit_nicely();
6382                 }
6383
6384                 viewdef = PQgetvalue(res, 0, 0);
6385
6386                 if (strlen(viewdef) == 0)
6387                 {
6388                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
6389                                           tbinfo->dobj.name);
6390                         exit_nicely();
6391                 }
6392
6393                 /*
6394                  * DROP must be fully qualified in case same name appears in
6395                  * pg_catalog
6396                  */
6397                 appendPQExpBuffer(delq, "DROP VIEW %s.",
6398                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
6399                 appendPQExpBuffer(delq, "%s;\n",
6400                                                   fmtId(tbinfo->dobj.name));
6401
6402                 appendPQExpBuffer(q, "CREATE VIEW %s AS\n    %s\n",
6403                                                   fmtId(tbinfo->dobj.name), viewdef);
6404
6405                 PQclear(res);
6406         }
6407         else
6408         {
6409                 reltypename = "TABLE";
6410                 numParents = tbinfo->numParents;
6411                 parents = tbinfo->parents;
6412
6413                 /*
6414                  * DROP must be fully qualified in case same name appears in
6415                  * pg_catalog
6416                  */
6417                 appendPQExpBuffer(delq, "DROP TABLE %s.",
6418                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
6419                 appendPQExpBuffer(delq, "%s;\n",
6420                                                   fmtId(tbinfo->dobj.name));
6421
6422                 appendPQExpBuffer(q, "CREATE TABLE %s (",
6423                                                   fmtId(tbinfo->dobj.name));
6424                 actual_atts = 0;
6425                 for (j = 0; j < tbinfo->numatts; j++)
6426                 {
6427                         /* Is this one of the table's own attrs, and not dropped ? */
6428                         if (!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j])
6429                         {
6430                                 /* Format properly if not first attr */
6431                                 if (actual_atts > 0)
6432                                         appendPQExpBuffer(q, ",");
6433                                 appendPQExpBuffer(q, "\n    ");
6434
6435                                 /* Attribute name */
6436                                 appendPQExpBuffer(q, "%s ",
6437                                                                   fmtId(tbinfo->attnames[j]));
6438
6439                                 /* Attribute type */
6440                                 if (g_fout->remoteVersion >= 70100)
6441                                 {
6442                                         char       *typname = tbinfo->atttypnames[j];
6443
6444                                         if (tbinfo->attisserial[j])
6445                                         {
6446                                                 if (strcmp(typname, "integer") == 0)
6447                                                         typname = "serial";
6448                                                 else if (strcmp(typname, "bigint") == 0)
6449                                                         typname = "bigserial";
6450                                         }
6451                                         appendPQExpBuffer(q, "%s", typname);
6452                                 }
6453                                 else
6454                                 {
6455                                         /* If no format_type, fake it */
6456                                         appendPQExpBuffer(q, "%s",
6457                                                                           myFormatType(tbinfo->atttypnames[j],
6458                                                                                                    tbinfo->atttypmod[j]));
6459                                 }
6460
6461                                 /*
6462                                  * Default value --- suppress if inherited, serial,
6463                                  * or to be printed separately.
6464                                  */
6465                                 if (tbinfo->attrdefs[j] != NULL &&
6466                                         !tbinfo->inhAttrDef[j] &&
6467                                         !tbinfo->attisserial[j] &&
6468                                         !tbinfo->attrdefs[j]->separate)
6469                                         appendPQExpBuffer(q, " DEFAULT %s",
6470                                                                           tbinfo->attrdefs[j]->adef_expr);
6471
6472                                 /*
6473                                  * Not Null constraint --- suppress if inherited
6474                                  *
6475                                  * Note: we could suppress this for serial columns since
6476                                  * SERIAL implies NOT NULL.  We choose not to for forward
6477                                  * compatibility, since there has been some talk of making
6478                                  * SERIAL not imply NOT NULL, in which case the explicit
6479                                  * specification would be needed.
6480                                  */
6481                                 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
6482                                         appendPQExpBuffer(q, " NOT NULL");
6483
6484                                 actual_atts++;
6485                         }
6486                 }
6487
6488                 /*
6489                  * Add non-inherited CHECK constraints, if any.
6490                  */
6491                 for (j = 0; j < tbinfo->ncheck; j++)
6492                 {
6493                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
6494
6495                         if (constr->coninherited || constr->separate)
6496                                 continue;
6497
6498                         if (actual_atts > 0)
6499                                 appendPQExpBuffer(q, ",\n    ");
6500
6501                         appendPQExpBuffer(q, "CONSTRAINT %s ",
6502                                                           fmtId(constr->dobj.name));
6503                         appendPQExpBuffer(q, "%s", constr->condef);
6504
6505                         actual_atts++;
6506                 }
6507
6508                 appendPQExpBuffer(q, "\n)");
6509
6510                 if (numParents > 0)
6511                 {
6512                         appendPQExpBuffer(q, "\nINHERITS (");
6513                         for (k = 0; k < numParents; k++)
6514                         {
6515                                 TableInfo  *parentRel = parents[k];
6516
6517                                 if (k > 0)
6518                                         appendPQExpBuffer(q, ", ");
6519                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
6520                                         appendPQExpBuffer(q, "%s.",
6521                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
6522                                 appendPQExpBuffer(q, "%s",
6523                                                                   fmtId(parentRel->dobj.name));
6524                         }
6525                         appendPQExpBuffer(q, ")");
6526                 }
6527
6528                 appendPQExpBuffer(q, ";\n");
6529
6530                 /* Loop dumping statistics and storage statements */
6531                 for (j = 0; j < tbinfo->numatts; j++)
6532                 {
6533                         /*
6534                          * Dump per-column statistics information. We only issue an
6535                          * ALTER TABLE statement if the attstattarget entry for this
6536                          * column is non-negative (i.e. it's not the default value)
6537                          */
6538                         if (tbinfo->attstattarget[j] >= 0 &&
6539                                 !tbinfo->attisdropped[j])
6540                         {
6541                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
6542                                                                   fmtId(tbinfo->dobj.name));
6543                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
6544                                                                   fmtId(tbinfo->attnames[j]));
6545                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
6546                                                                   tbinfo->attstattarget[j]);
6547                         }
6548
6549                         /*
6550                          * Dump per-column storage information.  The statement is only
6551                          * dumped if the storage has been changed from the type's
6552                          * default.
6553                          */
6554                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
6555                         {
6556                                 switch (tbinfo->attstorage[j])
6557                                 {
6558                                         case 'p':
6559                                                 storage = "PLAIN";
6560                                                 break;
6561                                         case 'e':
6562                                                 storage = "EXTERNAL";
6563                                                 break;
6564                                         case 'm':
6565                                                 storage = "MAIN";
6566                                                 break;
6567                                         case 'x':
6568                                                 storage = "EXTENDED";
6569                                                 break;
6570                                         default:
6571                                                 storage = NULL;
6572                                 }
6573
6574                                 /*
6575                                  * Only dump the statement if it's a storage type we
6576                                  * recognize
6577                                  */
6578                                 if (storage != NULL)
6579                                 {
6580                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
6581                                                                           fmtId(tbinfo->dobj.name));
6582                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
6583                                                                           fmtId(tbinfo->attnames[j]));
6584                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
6585                                                                           storage);
6586                                 }
6587                         }
6588                 }
6589         }
6590
6591         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
6592                                  tbinfo->dobj.name,
6593                                  tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
6594                                  (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
6595                                  reltypename, q->data, delq->data, NULL,
6596                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
6597                                  NULL, NULL);
6598
6599         /* Dump Table Comments */
6600         dumpTableComment(fout, tbinfo, reltypename);
6601
6602         destroyPQExpBuffer(query);
6603         destroyPQExpBuffer(q);
6604         destroyPQExpBuffer(delq);
6605 }
6606
6607 /*
6608  * dumpAttrDef --- dump an attribute's default-value declaration
6609  */
6610 static void
6611 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
6612 {
6613         TableInfo  *tbinfo = adinfo->adtable;
6614         int                     adnum = adinfo->adnum;
6615         PQExpBuffer q;
6616         PQExpBuffer delq;
6617
6618         /* Only print it if "separate" mode is selected */
6619         if (!tbinfo->dump || !adinfo->separate || dataOnly)
6620                 return;
6621
6622         /* Don't print inherited or serial defaults, either */
6623         if (tbinfo->inhAttrDef[adnum-1] || tbinfo->attisserial[adnum-1])
6624                 return;
6625
6626         q = createPQExpBuffer();
6627         delq = createPQExpBuffer();
6628
6629         appendPQExpBuffer(q, "ALTER TABLE %s ",
6630                                           fmtId(tbinfo->dobj.name));
6631         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
6632                                           fmtId(tbinfo->attnames[adnum - 1]),
6633                                           adinfo->adef_expr);
6634
6635         /*
6636          * DROP must be fully qualified in case same name appears
6637          * in pg_catalog
6638          */
6639         appendPQExpBuffer(delq, "ALTER TABLE %s.",
6640                                           fmtId(tbinfo->dobj.namespace->dobj.name));
6641         appendPQExpBuffer(delq, "%s ",
6642                                           fmtId(tbinfo->dobj.name));
6643         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
6644                                           fmtId(tbinfo->attnames[adnum - 1]));
6645
6646         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
6647                                  tbinfo->attnames[adnum - 1],
6648                                  tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
6649                                  false, "DEFAULT", q->data, delq->data, NULL,
6650                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
6651                                  NULL, NULL);
6652
6653         destroyPQExpBuffer(q);
6654         destroyPQExpBuffer(delq);
6655 }
6656
6657 /*
6658  * getAttrName: extract the correct name for an attribute
6659  *
6660  * The array tblInfo->attnames[] only provides names of user attributes;
6661  * if a system attribute number is supplied, we have to fake it.
6662  * We also do a little bit of bounds checking for safety's sake.
6663  */
6664 static const char *
6665 getAttrName(int attrnum, TableInfo *tblInfo)
6666 {
6667         if (attrnum > 0 && attrnum <= tblInfo->numatts)
6668                 return tblInfo->attnames[attrnum - 1];
6669         switch (attrnum)
6670         {
6671                 case SelfItemPointerAttributeNumber:
6672                         return "ctid";
6673                 case ObjectIdAttributeNumber:
6674                         return "oid";
6675                 case MinTransactionIdAttributeNumber:
6676                         return "xmin";
6677                 case MinCommandIdAttributeNumber:
6678                         return "cmin";
6679                 case MaxTransactionIdAttributeNumber:
6680                         return "xmax";
6681                 case MaxCommandIdAttributeNumber:
6682                         return "cmax";
6683                 case TableOidAttributeNumber:
6684                         return "tableoid";
6685         }
6686         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
6687                           attrnum, tblInfo->dobj.name);
6688         exit_nicely();
6689         return NULL;                            /* keep compiler quiet */
6690 }
6691
6692 /*
6693  * dumpIndex
6694  *        write out to fout a user-defined index
6695  */
6696 static void
6697 dumpIndex(Archive *fout, IndxInfo *indxinfo)
6698 {
6699         TableInfo  *tbinfo = indxinfo->indextable;
6700         PQExpBuffer q;
6701         PQExpBuffer delq;
6702
6703         if (dataOnly)
6704                 return;
6705
6706         q = createPQExpBuffer();
6707         delq = createPQExpBuffer();
6708
6709         /*
6710          * If there's an associated constraint, don't dump the index per se,
6711          * but do dump any comment for it.
6712          */
6713         if (indxinfo->indexconstraint == 0)
6714         {
6715                 /* Plain secondary index */
6716                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
6717
6718                 /* If the index is clustered, we need to record that. */
6719                 if (indxinfo->indisclustered)
6720                 {
6721                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
6722                                                           fmtId(tbinfo->dobj.name));
6723                         appendPQExpBuffer(q, " ON %s;\n",
6724                                                           fmtId(indxinfo->dobj.name));
6725                 }
6726
6727                 /*
6728                  * DROP must be fully qualified in case same name appears
6729                  * in pg_catalog
6730                  */
6731                 appendPQExpBuffer(delq, "DROP INDEX %s.",
6732                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
6733                 appendPQExpBuffer(delq, "%s;\n",
6734                                                   fmtId(indxinfo->dobj.name));
6735
6736                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
6737                                          indxinfo->dobj.name,
6738                                          tbinfo->dobj.namespace->dobj.name,
6739                                          tbinfo->usename, false,
6740                                          "INDEX", q->data, delq->data, NULL,
6741                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
6742                                          NULL, NULL);
6743         }
6744
6745         /* Dump Index Comments */
6746         resetPQExpBuffer(q);
6747         appendPQExpBuffer(q, "INDEX %s",
6748                                           fmtId(indxinfo->dobj.name));
6749         dumpComment(fout, q->data,
6750                                 tbinfo->dobj.namespace->dobj.name,
6751                                 tbinfo->usename,
6752                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
6753
6754         destroyPQExpBuffer(q);
6755         destroyPQExpBuffer(delq);
6756 }
6757
6758 /*
6759  * dumpConstraint
6760  *        write out to fout a user-defined constraint
6761  */
6762 static void
6763 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
6764 {
6765         TableInfo  *tbinfo = coninfo->contable;
6766         PQExpBuffer q;
6767         PQExpBuffer delq;
6768
6769         if (dataOnly)
6770                 return;
6771         if (tbinfo && !tbinfo->dump)
6772                 return;
6773
6774         q = createPQExpBuffer();
6775         delq = createPQExpBuffer();
6776
6777         if (coninfo->contype == 'p' || coninfo->contype == 'u')
6778         {
6779                 /* Index-related constraint */
6780                 IndxInfo   *indxinfo;
6781                 int                     k;
6782
6783                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
6784
6785                 if (indxinfo == NULL)
6786                 {
6787                         write_msg(NULL, "missing index for constraint %s\n",
6788                                           coninfo->dobj.name);
6789                         exit_nicely();
6790                 }
6791
6792                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
6793                                                   fmtId(tbinfo->dobj.name));
6794                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s (",
6795                                                   fmtId(coninfo->dobj.name),
6796                                                   coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
6797
6798                 for (k = 0; k < indxinfo->indnkeys; k++)
6799                 {
6800                         int                     indkey = (int) indxinfo->indkeys[k];
6801                         const char *attname;
6802
6803                         if (indkey == InvalidAttrNumber)
6804                                 break;
6805                         attname = getAttrName(indkey, tbinfo);
6806
6807                         appendPQExpBuffer(q, "%s%s",
6808                                                           (k == 0) ? "" : ", ",
6809                                                           fmtId(attname));
6810                 }
6811
6812                 appendPQExpBuffer(q, ");\n");
6813
6814                 /* If the index is clustered, we need to record that. */
6815                 if (indxinfo->indisclustered)
6816                 {
6817                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
6818                                                           fmtId(tbinfo->dobj.name));
6819                         appendPQExpBuffer(q, " ON %s;\n",
6820                                                           fmtId(indxinfo->dobj.name));
6821                 }
6822
6823                 /*
6824                  * DROP must be fully qualified in case same name appears
6825                  * in pg_catalog
6826                  */
6827                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
6828                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
6829                 appendPQExpBuffer(delq, "%s ",
6830                                                   fmtId(tbinfo->dobj.name));
6831                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6832                                                   fmtId(coninfo->dobj.name));
6833
6834                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
6835                                          coninfo->dobj.name,
6836                                          tbinfo->dobj.namespace->dobj.name,
6837                                          tbinfo->usename, false,
6838                                          "CONSTRAINT", q->data, delq->data, NULL,
6839                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
6840                                          NULL, NULL);
6841         }
6842         else if (coninfo->contype == 'f')
6843         {
6844                 /*
6845                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that
6846                  * the current table data is not processed
6847                  */
6848                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
6849                                                   fmtId(tbinfo->dobj.name));
6850                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
6851                                                   fmtId(coninfo->dobj.name),
6852                                                   coninfo->condef);
6853
6854                 /*
6855                  * DROP must be fully qualified in case same name appears in
6856                  * pg_catalog
6857                  */
6858                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
6859                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
6860                 appendPQExpBuffer(delq, "%s ",
6861                                                   fmtId(tbinfo->dobj.name));
6862                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6863                                                   fmtId(coninfo->dobj.name));
6864
6865                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
6866                                          coninfo->dobj.name,
6867                                          tbinfo->dobj.namespace->dobj.name,
6868                                          tbinfo->usename, false,
6869                                          "FK CONSTRAINT", q->data, delq->data, NULL,
6870                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
6871                                          NULL, NULL);
6872         }
6873         else if (coninfo->contype == 'c' && tbinfo)
6874         {
6875                 /* CHECK constraint on a table */
6876
6877                 /* Ignore if not to be dumped separately */
6878                 if (coninfo->separate)
6879                 {
6880                         /* not ONLY since we want it to propagate to children */
6881                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
6882                                                           fmtId(tbinfo->dobj.name));
6883                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
6884                                                           fmtId(coninfo->dobj.name),
6885                                                           coninfo->condef);
6886
6887                         /*
6888                          * DROP must be fully qualified in case same name appears in
6889                          * pg_catalog
6890                          */
6891                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
6892                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
6893                         appendPQExpBuffer(delq, "%s ",
6894                                                           fmtId(tbinfo->dobj.name));
6895                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6896                                                           fmtId(coninfo->dobj.name));
6897
6898                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
6899                                                  coninfo->dobj.name,
6900                                                  tbinfo->dobj.namespace->dobj.name,
6901                                                  tbinfo->usename, false,
6902                                                  "CHECK CONSTRAINT", q->data, delq->data, NULL,
6903                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
6904                                                  NULL, NULL);
6905                 }
6906         }
6907         else if (coninfo->contype == 'c' && tbinfo == NULL)
6908         {
6909                 /* CHECK constraint on a domain */
6910                 TypeInfo   *tinfo = coninfo->condomain;
6911
6912                 /* Ignore if not to be dumped separately, or if not dumping domain */
6913                 if (coninfo->separate && tinfo->dobj.namespace->dump)
6914                 {
6915                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
6916                                                           fmtId(tinfo->dobj.name));
6917                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
6918                                                           fmtId(coninfo->dobj.name),
6919                                                           coninfo->condef);
6920
6921                         /*
6922                          * DROP must be fully qualified in case same name appears in
6923                          * pg_catalog
6924                          */
6925                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
6926                                                           fmtId(tinfo->dobj.namespace->dobj.name));
6927                         appendPQExpBuffer(delq, "%s ",
6928                                                           fmtId(tinfo->dobj.name));
6929                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
6930                                                           fmtId(coninfo->dobj.name));
6931
6932                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
6933                                                  coninfo->dobj.name,
6934                                                  tinfo->dobj.namespace->dobj.name,
6935                                                  tinfo->usename, false,
6936                                                  "CHECK CONSTRAINT", q->data, delq->data, NULL,
6937                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
6938                                                  NULL, NULL);
6939                 }
6940         }
6941         else
6942         {
6943                 write_msg(NULL, "unexpected constraint type\n");
6944                 exit_nicely();
6945         }
6946
6947         /* Dump Constraint Comments --- only works for table constraints */
6948         if (tbinfo)
6949         {
6950                 resetPQExpBuffer(q);
6951                 appendPQExpBuffer(q, "CONSTRAINT %s ",
6952                                                   fmtId(coninfo->dobj.name));
6953                 appendPQExpBuffer(q, "ON %s",
6954                                                   fmtId(tbinfo->dobj.name));
6955                 dumpComment(fout, q->data,
6956                                         tbinfo->dobj.namespace->dobj.name,
6957                                         tbinfo->usename,
6958                                         coninfo->dobj.catId, 0, coninfo->dobj.dumpId);
6959         }
6960
6961         destroyPQExpBuffer(q);
6962         destroyPQExpBuffer(delq);
6963 }
6964
6965 /*
6966  * setMaxOid -
6967  * find the maximum oid and generate a COPY statement to set it
6968 */
6969
6970 static void
6971 setMaxOid(Archive *fout)
6972 {
6973         PGresult   *res;
6974         Oid                     max_oid;
6975         char            sql[1024];
6976
6977         do_sql_command(g_conn,
6978                                    "CREATE TEMPORARY TABLE pgdump_oid (dummy integer)");
6979         res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
6980         check_sql_result(res, g_conn, "INSERT INTO pgdump_oid VALUES (0)",
6981                                          PGRES_COMMAND_OK);
6982         max_oid = PQoidValue(res);
6983         if (max_oid == 0)
6984         {
6985                 write_msg(NULL, "inserted invalid OID\n");
6986                 exit_nicely();
6987         }
6988         PQclear(res);
6989         do_sql_command(g_conn, "DROP TABLE pgdump_oid;");
6990         if (g_verbose)
6991                 write_msg(NULL, "maximum system OID is %u\n", max_oid);
6992         snprintf(sql, sizeof(sql),
6993                          "CREATE TEMPORARY TABLE pgdump_oid (dummy integer);\n"
6994                          "COPY pgdump_oid WITH OIDS FROM stdin;\n"
6995                          "%u\t0\n"
6996                          "\\.\n"
6997                          "DROP TABLE pgdump_oid;\n",
6998                          max_oid);
6999
7000         ArchiveEntry(fout, nilCatalogId, createDumpId(),
7001                                  "Max OID", NULL, "",
7002                                  false, "<Init>", sql, "", NULL,
7003                                  NULL, 0,
7004                                  NULL, NULL);
7005 }
7006
7007 /*
7008  * findLastBuiltInOid -
7009  * find the last built in oid
7010  *
7011  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
7012  * pg_database entry for the current database
7013  */
7014 static Oid
7015 findLastBuiltinOid_V71(const char *dbname)
7016 {
7017         PGresult   *res;
7018         int                     ntups;
7019         Oid                     last_oid;
7020         PQExpBuffer query = createPQExpBuffer();
7021
7022         resetPQExpBuffer(query);
7023         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
7024         appendStringLiteral(query, dbname, true);
7025
7026         res = PQexec(g_conn, query->data);
7027         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7028
7029         ntups = PQntuples(res);
7030         if (ntups < 1)
7031         {
7032                 write_msg(NULL, "missing pg_database entry for this database\n");
7033                 exit_nicely();
7034         }
7035         if (ntups > 1)
7036         {
7037                 write_msg(NULL, "found more than one pg_database entry for this database\n");
7038                 exit_nicely();
7039         }
7040         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
7041         PQclear(res);
7042         destroyPQExpBuffer(query);
7043         return last_oid;
7044 }
7045
7046 /*
7047  * findLastBuiltInOid -
7048  * find the last built in oid
7049  *
7050  * For 7.0, we do this by assuming that the last thing that initdb does is to
7051  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
7052  * initdb won't be changing anymore, it'll do.
7053  */
7054 static Oid
7055 findLastBuiltinOid_V70(void)
7056 {
7057         PGresult   *res;
7058         int                     ntups;
7059         int                     last_oid;
7060
7061         res = PQexec(g_conn,
7062                                  "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
7063         check_sql_result(res, g_conn,
7064                                          "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
7065                                          PGRES_TUPLES_OK);
7066         ntups = PQntuples(res);
7067         if (ntups < 1)
7068         {
7069                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
7070                 exit_nicely();
7071         }
7072         if (ntups > 1)
7073         {
7074                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
7075                 exit_nicely();
7076         }
7077         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
7078         PQclear(res);
7079         return last_oid;
7080 }
7081
7082 static void
7083 dumpSequence(Archive *fout, TableInfo *tbinfo)
7084 {
7085         PGresult   *res;
7086         char       *last,
7087                            *incby,
7088                            *maxv = NULL,
7089                            *minv = NULL,
7090                            *cache;
7091         char            bufm[100],
7092                                 bufx[100];
7093         bool            cycled,
7094                                 called;
7095         PQExpBuffer query = createPQExpBuffer();
7096         PQExpBuffer delqry = createPQExpBuffer();
7097
7098         /* Make sure we are in proper schema */
7099         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
7100
7101         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
7102         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
7103
7104         appendPQExpBuffer(query,
7105                                           "SELECT sequence_name, last_value, increment_by, "
7106                            "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
7107                            "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
7108                                           "     ELSE max_value "
7109                                           "END AS max_value, "
7110                                 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
7111                            "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
7112                                           "     ELSE min_value "
7113                                           "END AS min_value, "
7114                                           "cache_value, is_cycled, is_called from %s",
7115                                           bufx, bufm,
7116                                           fmtId(tbinfo->dobj.name));
7117
7118         res = PQexec(g_conn, query->data);
7119         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7120
7121         if (PQntuples(res) != 1)
7122         {
7123                 write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
7124                                   tbinfo->dobj.name, PQntuples(res));
7125                 exit_nicely();
7126         }
7127
7128         /* Disable this check: it fails if sequence has been renamed */
7129 #ifdef NOT_USED
7130         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
7131         {
7132                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
7133                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
7134                 exit_nicely();
7135         }
7136 #endif
7137
7138         last = PQgetvalue(res, 0, 1);
7139         incby = PQgetvalue(res, 0, 2);
7140         if (!PQgetisnull(res, 0, 3))
7141                 maxv = PQgetvalue(res, 0, 3);
7142         if (!PQgetisnull(res, 0, 4))
7143                 minv = PQgetvalue(res, 0, 4);
7144         cache = PQgetvalue(res, 0, 5);
7145         cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
7146         called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
7147
7148         /*
7149          * The logic we use for restoring sequences is as follows:
7150          *
7151          * Add a basic CREATE SEQUENCE statement (use last_val for start if
7152          * called is false, else use min_val for start_val).  Skip this if the
7153          * sequence came from a SERIAL column.
7154          *
7155          * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
7156          * data.  We do this for serial sequences too.
7157          */
7158
7159         if (!dataOnly && !OidIsValid(tbinfo->owning_tab))
7160         {
7161                 resetPQExpBuffer(delqry);
7162
7163                 /*
7164                  * DROP must be fully qualified in case same name appears in
7165                  * pg_catalog
7166                  */
7167                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
7168                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
7169                 appendPQExpBuffer(delqry, "%s;\n",
7170                                                   fmtId(tbinfo->dobj.name));
7171
7172                 resetPQExpBuffer(query);
7173                 appendPQExpBuffer(query,
7174                                                   "CREATE SEQUENCE %s\n",
7175                                                   fmtId(tbinfo->dobj.name));
7176
7177                 if (!called)
7178                         appendPQExpBuffer(query, "    START WITH %s\n", last);
7179
7180                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
7181
7182                 if (maxv)
7183                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
7184                 else
7185                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
7186
7187                 if (minv)
7188                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
7189                 else
7190                         appendPQExpBuffer(query, "    NO MINVALUE\n");
7191
7192                 appendPQExpBuffer(query,
7193                                                   "    CACHE %s%s;\n",
7194                                                   cache, (cycled ? "\n    CYCLE" : ""));
7195
7196                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
7197                                          tbinfo->dobj.name,
7198                                          tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
7199                                          false, "SEQUENCE", query->data, delqry->data, NULL,
7200                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
7201                                          NULL, NULL);
7202         }
7203
7204         if (!schemaOnly)
7205         {
7206                 resetPQExpBuffer(query);
7207                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
7208                 appendStringLiteral(query, fmtId(tbinfo->dobj.name), true);
7209                 appendPQExpBuffer(query, ", %s, %s);\n",
7210                                                   last, (called ? "true" : "false"));
7211
7212                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
7213                                          tbinfo->dobj.name,
7214                                          tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
7215                                          false, "SEQUENCE SET", query->data, "", NULL,
7216                                          &(tbinfo->dobj.dumpId), 1,
7217                                          NULL, NULL);
7218         }
7219
7220         if (!dataOnly)
7221         {
7222                 /* Dump Sequence Comments */
7223                 resetPQExpBuffer(query);
7224                 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
7225                 dumpComment(fout, query->data,
7226                                         tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
7227                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
7228         }
7229
7230         PQclear(res);
7231
7232         destroyPQExpBuffer(query);
7233         destroyPQExpBuffer(delqry);
7234 }
7235
7236 static void
7237 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
7238 {
7239         TableInfo  *tbinfo = tginfo->tgtable;
7240         PQExpBuffer query;
7241         PQExpBuffer delqry;
7242         const char *p;
7243         int                     findx;
7244
7245         if (dataOnly)
7246                 return;
7247
7248         query = createPQExpBuffer();
7249         delqry = createPQExpBuffer();
7250
7251         /*
7252          * DROP must be fully qualified in case same name appears in
7253          * pg_catalog
7254          */
7255         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
7256                                           fmtId(tginfo->dobj.name));
7257         appendPQExpBuffer(delqry, "ON %s.",
7258                                           fmtId(tbinfo->dobj.namespace->dobj.name));
7259         appendPQExpBuffer(delqry, "%s;\n",
7260                                           fmtId(tbinfo->dobj.name));
7261
7262         if (tginfo->tgisconstraint)
7263         {
7264                 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
7265                 appendPQExpBuffer(query, fmtId(tginfo->tgconstrname));
7266         }
7267         else
7268         {
7269                 appendPQExpBuffer(query, "CREATE TRIGGER ");
7270                 appendPQExpBuffer(query, fmtId(tginfo->dobj.name));
7271         }
7272         appendPQExpBuffer(query, "\n    ");
7273
7274         /* Trigger type */
7275         findx = 0;
7276         if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
7277                 appendPQExpBuffer(query, "BEFORE");
7278         else
7279                 appendPQExpBuffer(query, "AFTER");
7280         if (TRIGGER_FOR_INSERT(tginfo->tgtype))
7281         {
7282                 appendPQExpBuffer(query, " INSERT");
7283                 findx++;
7284         }
7285         if (TRIGGER_FOR_DELETE(tginfo->tgtype))
7286         {
7287                 if (findx > 0)
7288                         appendPQExpBuffer(query, " OR DELETE");
7289                 else
7290                         appendPQExpBuffer(query, " DELETE");
7291                 findx++;
7292         }
7293         if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
7294         {
7295                 if (findx > 0)
7296                         appendPQExpBuffer(query, " OR UPDATE");
7297                 else
7298                         appendPQExpBuffer(query, " UPDATE");
7299         }
7300         appendPQExpBuffer(query, " ON %s\n",
7301                                           fmtId(tbinfo->dobj.name));
7302
7303         if (tginfo->tgisconstraint)
7304         {
7305                 if (OidIsValid(tginfo->tgconstrrelid))
7306                 {
7307                         /* If we are using regclass, name is already quoted */
7308                         if (g_fout->remoteVersion >= 70300)
7309                                 appendPQExpBuffer(query, "    FROM %s\n    ",
7310                                                                   tginfo->tgconstrrelname);
7311                         else
7312                                 appendPQExpBuffer(query, "    FROM %s\n    ",
7313                                                                   fmtId(tginfo->tgconstrrelname));
7314                 }
7315                 if (!tginfo->tgdeferrable)
7316                         appendPQExpBuffer(query, "NOT ");
7317                 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
7318                 if (tginfo->tginitdeferred)
7319                         appendPQExpBuffer(query, "DEFERRED\n");
7320                 else
7321                         appendPQExpBuffer(query, "IMMEDIATE\n");
7322         }
7323
7324         if (TRIGGER_FOR_ROW(tginfo->tgtype))
7325                 appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
7326         else
7327                 appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
7328
7329         /* In 7.3, result of regproc is already quoted */
7330         if (g_fout->remoteVersion >= 70300)
7331                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
7332                                                   tginfo->tgfname);
7333         else
7334                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
7335                                                   fmtId(tginfo->tgfname));
7336
7337         p = tginfo->tgargs;
7338         for (findx = 0; findx < tginfo->tgnargs; findx++)
7339         {
7340                 const char *s = p;
7341
7342                 for (;;)
7343                 {
7344                         p = strchr(p, '\\');
7345                         if (p == NULL)
7346                         {
7347                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
7348                                                   tginfo->tgargs,
7349                                                   tginfo->dobj.name,
7350                                                   tbinfo->dobj.name);
7351                                 exit_nicely();
7352                         }
7353                         p++;
7354                         if (*p == '\\')
7355                         {
7356                                 p++;
7357                                 continue;
7358                         }
7359                         if (p[0] == '0' && p[1] == '0' && p[2] == '0')
7360                                 break;
7361                 }
7362                 p--;
7363                 appendPQExpBufferChar(query, '\'');
7364                 while (s < p)
7365                 {
7366                         if (*s == '\'')
7367                                 appendPQExpBufferChar(query, '\\');
7368                         appendPQExpBufferChar(query, *s++);
7369                 }
7370                 appendPQExpBufferChar(query, '\'');
7371                 appendPQExpBuffer(query,
7372                                                   (findx < tginfo->tgnargs - 1) ? ", " : "");
7373                 p = p + 4;
7374         }
7375         appendPQExpBuffer(query, ");\n");
7376
7377         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
7378                                  tginfo->dobj.name,
7379                                  tbinfo->dobj.namespace->dobj.name,
7380                                  tbinfo->usename, false,
7381                                  "TRIGGER", query->data, delqry->data, NULL,
7382                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
7383                                  NULL, NULL);
7384
7385         resetPQExpBuffer(query);
7386         appendPQExpBuffer(query, "TRIGGER %s ",
7387                                           fmtId(tginfo->dobj.name));
7388         appendPQExpBuffer(query, "ON %s",
7389                                           fmtId(tbinfo->dobj.name));
7390
7391         dumpComment(fout, query->data,
7392                                 tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
7393                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
7394
7395         destroyPQExpBuffer(query);
7396         destroyPQExpBuffer(delqry);
7397 }
7398
7399 /*
7400  * dumpRule
7401  *              Dump a rule
7402  */
7403 static void
7404 dumpRule(Archive *fout, RuleInfo *rinfo)
7405 {
7406         TableInfo  *tbinfo = rinfo->ruletable;
7407         PQExpBuffer query;
7408         PQExpBuffer cmd;
7409         PQExpBuffer delcmd;
7410         PGresult   *res;
7411
7412         /*
7413          * Ignore rules for not-to-be-dumped tables
7414          */
7415         if (tbinfo == NULL || !tbinfo->dump || dataOnly)
7416                 return;
7417
7418         /*
7419          * If it is an ON SELECT rule, we do not need to dump it because
7420          * it will be handled via CREATE VIEW for the table.
7421          */
7422         if (rinfo->ev_type == '1' && rinfo->is_instead)
7423                 return;
7424
7425         /*
7426          * Make sure we are in proper schema.
7427          */
7428         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
7429
7430         query = createPQExpBuffer();
7431         cmd = createPQExpBuffer();
7432         delcmd = createPQExpBuffer();
7433
7434         if (g_fout->remoteVersion >= 70300)
7435         {
7436                 appendPQExpBuffer(query,
7437                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
7438                                                   rinfo->dobj.catId.oid);
7439         }
7440         else
7441         {
7442                 /* Rule name was unique before 7.3 ... */
7443                 appendPQExpBuffer(query,
7444                                                   "SELECT pg_get_ruledef('%s') AS definition",
7445                                                   rinfo->dobj.name);
7446         }
7447
7448         res = PQexec(g_conn, query->data);
7449         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7450
7451         if (PQntuples(res) != 1)
7452         {
7453                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned",
7454                                   rinfo->dobj.name, tbinfo->dobj.name);
7455                 exit_nicely();
7456         }
7457
7458         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
7459
7460         /*
7461          * DROP must be fully qualified in case same name appears in
7462          * pg_catalog
7463          */
7464         appendPQExpBuffer(delcmd, "DROP RULE %s ",
7465                                           fmtId(rinfo->dobj.name));
7466         appendPQExpBuffer(delcmd, "ON %s.",
7467                                           fmtId(tbinfo->dobj.namespace->dobj.name));
7468         appendPQExpBuffer(delcmd, "%s;\n",
7469                                           fmtId(tbinfo->dobj.name));
7470
7471         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
7472                                  rinfo->dobj.name,
7473                                  tbinfo->dobj.namespace->dobj.name,
7474                                  tbinfo->usename, false,
7475                                  "RULE", cmd->data, delcmd->data, NULL,
7476                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
7477                                  NULL, NULL);
7478
7479         /* Dump rule comments */
7480         resetPQExpBuffer(query);
7481         appendPQExpBuffer(query, "RULE %s",
7482                                           fmtId(rinfo->dobj.name));
7483         appendPQExpBuffer(query, " ON %s",
7484                                           fmtId(tbinfo->dobj.name));
7485         dumpComment(fout, query->data,
7486                                 tbinfo->dobj.namespace->dobj.name,
7487                                 tbinfo->usename,
7488                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
7489
7490         PQclear(res);
7491
7492         destroyPQExpBuffer(query);
7493         destroyPQExpBuffer(cmd);
7494         destroyPQExpBuffer(delcmd);
7495 }
7496
7497 /*
7498  * getDependencies --- obtain available dependency data
7499  */
7500 static void
7501 getDependencies(void)
7502 {
7503         PQExpBuffer query;
7504         PGresult   *res;
7505         int                     ntups,
7506                                 i;
7507         int                     i_classid,
7508                                 i_objid,
7509                                 i_refclassid,
7510                                 i_refobjid,
7511                                 i_deptype;
7512         DumpableObject *dobj,
7513                            *refdobj;
7514
7515         /* No dependency info available before 7.3 */
7516         if (g_fout->remoteVersion < 70300)
7517                 return;
7518
7519         if (g_verbose)
7520                 write_msg(NULL, "fetching dependency data\n");
7521
7522         /* Make sure we are in proper schema */
7523         selectSourceSchema("pg_catalog");
7524
7525         query = createPQExpBuffer();
7526
7527         appendPQExpBuffer(query, "SELECT "
7528                                           "classid, objid, refclassid, refobjid, deptype "
7529                                           "FROM pg_depend "
7530                                           "WHERE deptype != 'p' "
7531                                           "ORDER BY 1,2");
7532
7533         res = PQexec(g_conn, query->data);
7534         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7535
7536         ntups = PQntuples(res);
7537
7538         i_classid = PQfnumber(res, "classid");
7539         i_objid = PQfnumber(res, "objid");
7540         i_refclassid = PQfnumber(res, "refclassid");
7541         i_refobjid = PQfnumber(res, "refobjid");
7542         i_deptype = PQfnumber(res, "deptype");
7543
7544         /*
7545          * Since we ordered the SELECT by referencing ID, we can expect that
7546          * multiple entries for the same object will appear together; this
7547          * saves on searches.
7548          */
7549         dobj = NULL;
7550
7551         for (i = 0; i < ntups; i++)
7552         {
7553                 CatalogId       objId;
7554                 CatalogId       refobjId;
7555                 char            deptype;
7556
7557                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
7558                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
7559                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
7560                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
7561                 deptype = *(PQgetvalue(res, i, i_deptype));
7562
7563                 if (dobj == NULL ||
7564                         dobj->catId.tableoid != objId.tableoid ||
7565                         dobj->catId.oid != objId.oid)
7566                         dobj = findObjectByCatalogId(objId);
7567
7568                 /*
7569                  * Failure to find objects mentioned in pg_depend is not unexpected,
7570                  * since for example we don't collect info about TOAST tables.
7571                  */
7572                 if (dobj == NULL)
7573                 {
7574 #ifdef NOT_USED
7575                         fprintf(stderr, "no referencing object %u %u\n",
7576                                         objId.tableoid, objId.oid);
7577 #endif
7578                         continue;
7579                 }
7580
7581                 refdobj = findObjectByCatalogId(refobjId);
7582
7583                 if (refdobj == NULL)
7584                 {
7585 #ifdef NOT_USED
7586                         fprintf(stderr, "no referenced object %u %u\n",
7587                                         refobjId.tableoid, refobjId.oid);
7588 #endif
7589                         continue;
7590                 }
7591
7592                 addObjectDependency(dobj, refdobj->dumpId);
7593         }
7594
7595         PQclear(res);
7596
7597         destroyPQExpBuffer(query);
7598 }
7599
7600
7601 /*
7602  * selectSourceSchema - make the specified schema the active search path
7603  * in the source database.
7604  *
7605  * NB: pg_catalog is explicitly searched after the specified schema;
7606  * so user names are only qualified if they are cross-schema references,
7607  * and system names are only qualified if they conflict with a user name
7608  * in the current schema.
7609  *
7610  * Whenever the selected schema is not pg_catalog, be careful to qualify
7611  * references to system catalogs and types in our emitted commands!
7612  */
7613 static void
7614 selectSourceSchema(const char *schemaName)
7615 {
7616         static char *curSchemaName = NULL;
7617         PQExpBuffer query;
7618
7619         /* Not relevant if fetching from pre-7.3 DB */
7620         if (g_fout->remoteVersion < 70300)
7621                 return;
7622         /* Ignore null schema names */
7623         if (schemaName == NULL || *schemaName == '\0')
7624                 return;
7625         /* Optimize away repeated selection of same schema */
7626         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
7627                 return;
7628
7629         query = createPQExpBuffer();
7630         appendPQExpBuffer(query, "SET search_path = %s",
7631                                           fmtId(schemaName));
7632         if (strcmp(schemaName, "pg_catalog") != 0)
7633                 appendPQExpBuffer(query, ", pg_catalog");
7634
7635         do_sql_command(g_conn, query->data);
7636
7637         destroyPQExpBuffer(query);
7638         if (curSchemaName)
7639                 free(curSchemaName);
7640         curSchemaName = strdup(schemaName);
7641 }
7642
7643 /*
7644  * getFormattedTypeName - retrieve a nicely-formatted type name for the
7645  * given type name.
7646  *
7647  * NB: in 7.3 and up the result may depend on the currently-selected
7648  * schema; this is why we don't try to cache the names.
7649  */
7650 static char *
7651 getFormattedTypeName(Oid oid, OidOptions opts)
7652 {
7653         char       *result;
7654         PQExpBuffer query;
7655         PGresult   *res;
7656         int                     ntups;
7657
7658         if (oid == 0)
7659         {
7660                 if ((opts & zeroAsOpaque) != 0)
7661                         return strdup(g_opaque_type);
7662                 else if ((opts & zeroAsAny) != 0)
7663                         return strdup("'any'");
7664                 else if ((opts & zeroAsStar) != 0)
7665                         return strdup("*");
7666                 else if ((opts & zeroAsNone) != 0)
7667                         return strdup("NONE");
7668         }
7669
7670         query = createPQExpBuffer();
7671         if (g_fout->remoteVersion >= 70300)
7672         {
7673                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
7674                                                   oid);
7675         }
7676         else if (g_fout->remoteVersion >= 70100)
7677         {
7678                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
7679                                                   oid);
7680         }
7681         else
7682         {
7683                 appendPQExpBuffer(query, "SELECT typname "
7684                                                   "FROM pg_type "
7685                                                   "WHERE oid = '%u'::oid",
7686                                                   oid);
7687         }
7688
7689         res = PQexec(g_conn, query->data);
7690         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7691
7692         /* Expecting a single result only */
7693         ntups = PQntuples(res);
7694         if (ntups != 1)
7695         {
7696                 write_msg(NULL, "query yielded %d rows instead of one: %s\n",
7697                                   ntups, query->data);
7698                 exit_nicely();
7699         }
7700
7701         if (g_fout->remoteVersion >= 70100)
7702         {
7703                 /* already quoted */
7704                 result = strdup(PQgetvalue(res, 0, 0));
7705         }
7706         else
7707         {
7708                 /* may need to quote it */
7709                 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
7710         }
7711
7712         PQclear(res);
7713         destroyPQExpBuffer(query);
7714
7715         return result;
7716 }
7717
7718 /*
7719  * myFormatType --- local implementation of format_type for use with 7.0.
7720  */
7721 static char *
7722 myFormatType(const char *typname, int32 typmod)
7723 {
7724         char       *result;
7725         bool    isarray = false;
7726         PQExpBuffer buf = createPQExpBuffer();
7727
7728         /* Handle array types */
7729         if (typname[0] == '_')
7730         {
7731                 isarray = true;
7732                 typname++;
7733         }
7734
7735         /* Show lengths on bpchar and varchar */
7736         if (!strcmp(typname, "bpchar"))
7737         {
7738                 int                     len = (typmod - VARHDRSZ);
7739
7740                 appendPQExpBuffer(buf, "character");
7741                 if (len > 1)
7742                         appendPQExpBuffer(buf, "(%d)",
7743                                                           typmod - VARHDRSZ);
7744         }
7745         else if (!strcmp(typname, "varchar"))
7746         {
7747                 appendPQExpBuffer(buf, "character varying");
7748                 if (typmod != -1)
7749                         appendPQExpBuffer(buf, "(%d)",
7750                                                           typmod - VARHDRSZ);
7751         }
7752         else if (!strcmp(typname, "numeric"))
7753         {
7754                 appendPQExpBuffer(buf, "numeric");
7755                 if (typmod != -1)
7756                 {
7757                         int32           tmp_typmod;
7758                         int                     precision;
7759                         int                     scale;
7760
7761                         tmp_typmod = typmod - VARHDRSZ;
7762                         precision = (tmp_typmod >> 16) & 0xffff;
7763                         scale = tmp_typmod & 0xffff;
7764                         appendPQExpBuffer(buf, "(%d,%d)",
7765                                                           precision, scale);
7766                 }
7767         }
7768
7769         /*
7770          * char is an internal single-byte data type; Let's make sure we force
7771          * it through with quotes. - thomas 1998-12-13
7772          */
7773         else if (strcmp(typname, "char") == 0)
7774                 appendPQExpBuffer(buf, "\"char\"");
7775         else
7776                 appendPQExpBuffer(buf, "%s", fmtId(typname));
7777
7778         /* Append array qualifier for array types */
7779         if (isarray)
7780                 appendPQExpBuffer(buf, "[]");
7781
7782         result = strdup(buf->data);
7783         destroyPQExpBuffer(buf);
7784
7785         return result;
7786 }
7787
7788 /*
7789  * fmtQualifiedId - convert a qualified name to the proper format for
7790  * the source database.
7791  *
7792  * Like fmtId, use the result before calling again.
7793  */
7794 static const char *
7795 fmtQualifiedId(const char *schema, const char *id)
7796 {
7797         static PQExpBuffer id_return = NULL;
7798
7799         if (id_return)                          /* first time through? */
7800                 resetPQExpBuffer(id_return);
7801         else
7802                 id_return = createPQExpBuffer();
7803
7804         /* Suppress schema name if fetching from pre-7.3 DB */
7805         if (g_fout->remoteVersion >= 70300 && schema && *schema)
7806         {
7807                 appendPQExpBuffer(id_return, "%s.",
7808                                                   fmtId(schema));
7809         }
7810         appendPQExpBuffer(id_return, "%s",
7811                                           fmtId(id));
7812
7813         return id_return->data;
7814 }
7815
7816 /*
7817  * Return a column list clause for the given relation.
7818  *
7819  * Special case: if there are no undropped columns in the relation, return
7820  * "", not an invalid "()" column list.
7821  */
7822 static const char *
7823 fmtCopyColumnList(const TableInfo *ti)
7824 {
7825         static PQExpBuffer q = NULL;
7826         int                     numatts = ti->numatts;
7827         char      **attnames = ti->attnames;
7828         bool       *attisdropped = ti->attisdropped;
7829         bool            needComma;
7830         int                     i;
7831
7832         if (q)                                          /* first time through? */
7833                 resetPQExpBuffer(q);
7834         else
7835                 q = createPQExpBuffer();
7836
7837         appendPQExpBuffer(q, "(");
7838         needComma = false;
7839         for (i = 0; i < numatts; i++)
7840         {
7841                 if (attisdropped[i])
7842                         continue;
7843                 if (needComma)
7844                         appendPQExpBuffer(q, ", ");
7845                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
7846                 needComma = true;
7847         }
7848
7849         if (!needComma)
7850                 return "";                              /* no undropped columns */
7851
7852         appendPQExpBuffer(q, ")");
7853         return q->data;
7854 }
7855
7856 /*
7857  * Convenience subroutine to execute a SQL command and check for
7858  * COMMAND_OK status.
7859  */
7860 static void
7861 do_sql_command(PGconn *conn, const char *query)
7862 {
7863         PGresult   *res;
7864
7865         res = PQexec(conn, query);
7866         check_sql_result(res, conn, query, PGRES_COMMAND_OK);
7867         PQclear(res);
7868 }
7869
7870 /*
7871  * Convenience subroutine to verify a SQL command succeeded,
7872  * and exit with a useful error message if not.
7873  */
7874 static void
7875 check_sql_result(PGresult *res, PGconn *conn, const char *query,
7876                                  ExecStatusType expected)
7877 {
7878         const char *err;
7879
7880         if (res && PQresultStatus(res) == expected)
7881                 return;                                 /* A-OK */
7882
7883         write_msg(NULL, "SQL command failed\n");
7884         if (res)
7885                 err = PQresultErrorMessage(res);
7886         else
7887                 err = PQerrorMessage(conn);
7888         write_msg(NULL, "Error message from server: %s", err);
7889         write_msg(NULL, "The command was: %s\n", query);
7890         exit_nicely();
7891 }