OSDN Git Service

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