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