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