OSDN Git Service

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