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