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