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