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