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