]> granicus.if.org Git - postgresql/blob - src/bin/pg_dump/pg_dump.c
Convert some messages to use ngettext().
[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-2009, 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.536 2009/05/21 01:08:43 petere Exp $
16  *
17  *-------------------------------------------------------------------------
18  */
19
20 #include "postgres_fe.h"
21
22 #include <unistd.h>
23 #include <ctype.h>
24 #ifdef ENABLE_NLS
25 #include <locale.h>
26 #endif
27 #ifdef HAVE_TERMIOS_H
28 #include <termios.h>
29 #endif
30
31 #include "getopt_long.h"
32
33 #include "access/attnum.h"
34 #include "access/sysattr.h"
35 #include "catalog/pg_cast.h"
36 #include "catalog/pg_class.h"
37 #include "catalog/pg_proc.h"
38 #include "catalog/pg_trigger.h"
39 #include "catalog/pg_type.h"
40 #include "libpq/libpq-fs.h"
41
42 #include "pg_backup_archiver.h"
43 #include "dumputils.h"
44
45 extern char *optarg;
46 extern int      optind,
47                         opterr;
48
49
50 typedef struct
51 {
52         const char *descr;                      /* comment for an object */
53         Oid                     classoid;               /* object class (catalog OID) */
54         Oid                     objoid;                 /* object OID */
55         int                     objsubid;               /* subobject (table column #) */
56 } CommentItem;
57
58
59 /* global decls */
60 bool            g_verbose;                      /* User wants verbose narration of our
61                                                                  * activities. */
62 Archive    *g_fout;                             /* the script file */
63 PGconn     *g_conn;                             /* the database connection */
64
65 /* various user-settable parameters */
66 bool            schemaOnly;
67 bool            dataOnly;
68 bool            aclsSkip;
69 const char *lockWaitTimeout;
70
71 /* subquery used to convert user ID (eg, datdba) to user name */
72 static const char *username_subquery;
73
74 /* obsolete as of 7.3: */
75 static Oid      g_last_builtin_oid; /* value of the last builtin oid */
76
77 /*
78  * Object inclusion/exclusion lists
79  *
80  * The string lists record the patterns given by command-line switches,
81  * which we then convert to lists of OIDs of matching objects.
82  */
83 static SimpleStringList schema_include_patterns = {NULL, NULL};
84 static SimpleOidList schema_include_oids = {NULL, NULL};
85 static SimpleStringList schema_exclude_patterns = {NULL, NULL};
86 static SimpleOidList schema_exclude_oids = {NULL, NULL};
87
88 static SimpleStringList table_include_patterns = {NULL, NULL};
89 static SimpleOidList table_include_oids = {NULL, NULL};
90 static SimpleStringList table_exclude_patterns = {NULL, NULL};
91 static SimpleOidList table_exclude_oids = {NULL, NULL};
92
93 /* default, if no "inclusion" switches appear, is to dump everything */
94 static bool include_everything = true;
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 /* flags for various command-line long options */
109 static int      binary_upgrade = 0;
110 static int      disable_dollar_quoting = 0;
111 static int      dump_inserts = 0;
112 static int      column_inserts = 0;
113
114
115 static void help(const char *progname);
116 static void expand_schema_name_patterns(SimpleStringList *patterns,
117                                                         SimpleOidList *oids);
118 static void expand_table_name_patterns(SimpleStringList *patterns,
119                                                    SimpleOidList *oids);
120 static NamespaceInfo *findNamespace(Oid nsoid, Oid objoid);
121 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
122 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
123 static void dumpComment(Archive *fout, const char *target,
124                         const char *namespace, const char *owner,
125                         CatalogId catalogId, int subid, DumpId dumpId);
126 static int findComments(Archive *fout, Oid classoid, Oid objoid,
127                          CommentItem **items);
128 static int      collectComments(Archive *fout, CommentItem **items);
129 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
130 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
131 static void dumpType(Archive *fout, TypeInfo *tinfo);
132 static void dumpBaseType(Archive *fout, TypeInfo *tinfo);
133 static void dumpEnumType(Archive *fout, TypeInfo *tinfo);
134 static void dumpDomain(Archive *fout, TypeInfo *tinfo);
135 static void dumpCompositeType(Archive *fout, TypeInfo *tinfo);
136 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
137 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
138 static void dumpFunc(Archive *fout, FuncInfo *finfo);
139 static void dumpCast(Archive *fout, CastInfo *cast);
140 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
141 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
142 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
143 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
144 static void dumpRule(Archive *fout, RuleInfo *rinfo);
145 static void dumpAgg(Archive *fout, AggInfo *agginfo);
146 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
147 static void dumpTable(Archive *fout, TableInfo *tbinfo);
148 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
149 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
150 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
151 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
152 static void dumpConstraint(Archive *fout, ConstraintInfo *coninfo);
153 static void dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo);
154 static void dumpTSParser(Archive *fout, TSParserInfo *prsinfo);
155 static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
156 static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
157 static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
158 static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
159 static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
160 static void dumpUserMappings(Archive *fout, const char *target,
161                         const char *servername, const char *namespace,
162                         const char *owner, CatalogId catalogId, DumpId dumpId);
163
164 static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
165                 const char *type, const char *name, const char *subname,
166                 const char *tag, const char *nspname, const char *owner,
167                 const char *acls);
168
169 static void getDependencies(void);
170 static void getDomainConstraints(TypeInfo *tinfo);
171 static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
172 static void getTableDataFKConstraints(void);
173 static char *format_function_arguments(FuncInfo *finfo, char *funcargs);
174 static char *format_function_arguments_old(FuncInfo *finfo, int nallargs,
175                                                   char **allargtypes,
176                                                   char **argmodes,
177                                                   char **argnames);
178 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
179 static const char *convertRegProcReference(const char *proc);
180 static const char *convertOperatorReference(const char *opr);
181 static const char *convertTSFunction(Oid funcOid);
182 static Oid      findLastBuiltinOid_V71(const char *);
183 static Oid      findLastBuiltinOid_V70(void);
184 static void selectSourceSchema(const char *schemaName);
185 static char *getFormattedTypeName(Oid oid, OidOptions opts);
186 static char *myFormatType(const char *typname, int32 typmod);
187 static const char *fmtQualifiedId(const char *schema, const char *id);
188 static bool hasBlobs(Archive *AH);
189 static int      dumpBlobs(Archive *AH, void *arg);
190 static int      dumpBlobComments(Archive *AH, void *arg);
191 static void dumpDatabase(Archive *AH);
192 static void dumpEncoding(Archive *AH);
193 static void dumpStdStrings(Archive *AH);
194 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
195 static const char *fmtCopyColumnList(const TableInfo *ti);
196 static void do_sql_command(PGconn *conn, const char *query);
197 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
198                                  ExecStatusType expected);
199
200
201 int
202 main(int argc, char **argv)
203 {
204         int                     c;
205         const char *filename = NULL;
206         const char *format = "p";
207         const char *dbname = NULL;
208         const char *pghost = NULL;
209         const char *pgport = NULL;
210         const char *username = NULL;
211         const char *dumpencoding = NULL;
212         const char *std_strings;
213         bool            oids = false;
214         TableInfo  *tblinfo;
215         int                     numTables;
216         DumpableObject **dobjs;
217         int                     numObjs;
218         int                     i;
219         enum trivalue prompt_password = TRI_DEFAULT;
220         int                     compressLevel = -1;
221         int                     plainText = 0;
222         int                     outputClean = 0;
223         int                     outputCreate = 0;
224         bool            outputBlobs = false;
225         int                     outputNoOwner = 0;
226         char       *outputSuperuser = NULL;
227         char       *use_role = NULL;
228         int                     my_version;
229         int                     optindex;
230         RestoreOptions *ropt;
231
232         static int      disable_triggers = 0;
233         static int  outputNoTablespaces = 0;
234         static int      use_setsessauth = 0;
235
236         struct option long_options[] = {
237                 {"data-only", no_argument, NULL, 'a'},
238                 {"blobs", no_argument, NULL, 'b'},
239                 {"clean", no_argument, NULL, 'c'},
240                 {"create", no_argument, NULL, 'C'},
241                 {"file", required_argument, NULL, 'f'},
242                 {"format", required_argument, NULL, 'F'},
243                 {"host", required_argument, NULL, 'h'},
244                 {"ignore-version", no_argument, NULL, 'i'},
245                 {"no-reconnect", no_argument, NULL, 'R'},
246                 {"oids", no_argument, NULL, 'o'},
247                 {"no-owner", no_argument, NULL, 'O'},
248                 {"port", required_argument, NULL, 'p'},
249                 {"schema", required_argument, NULL, 'n'},
250                 {"exclude-schema", required_argument, NULL, 'N'},
251                 {"schema-only", no_argument, NULL, 's'},
252                 {"superuser", required_argument, NULL, 'S'},
253                 {"table", required_argument, NULL, 't'},
254                 {"exclude-table", required_argument, NULL, 'T'},
255                 {"no-password", no_argument, NULL, 'w'},
256                 {"password", no_argument, NULL, 'W'},
257                 {"username", required_argument, NULL, 'U'},
258                 {"verbose", no_argument, NULL, 'v'},
259                 {"no-privileges", no_argument, NULL, 'x'},
260                 {"no-acl", no_argument, NULL, 'x'},
261                 {"compress", required_argument, NULL, 'Z'},
262                 {"encoding", required_argument, NULL, 'E'},
263                 {"help", no_argument, NULL, '?'},
264                 {"version", no_argument, NULL, 'V'},
265
266                 /*
267                  * the following options don't have an equivalent short option letter
268                  */
269                 {"attribute-inserts", no_argument, &column_inserts, 1},
270                 {"binary-upgrade", no_argument, &binary_upgrade, 1},
271                 {"column-inserts", no_argument, &column_inserts, 1},
272                 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
273                 {"disable-triggers", no_argument, &disable_triggers, 1},
274                 {"inserts", no_argument, &dump_inserts, 1},
275                 {"lock-wait-timeout", required_argument, NULL, 2},
276                 {"no-tablespaces", no_argument, &outputNoTablespaces, 1},
277                 {"role", required_argument, NULL, 3},
278                 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
279
280                 {NULL, 0, NULL, 0}
281         };
282
283         set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
284
285         g_verbose = false;
286
287         strcpy(g_comment_start, "-- ");
288         g_comment_end[0] = '\0';
289         strcpy(g_opaque_type, "opaque");
290
291         dataOnly = schemaOnly = false;
292         lockWaitTimeout = NULL;
293
294         progname = get_progname(argv[0]);
295
296         /* Set default options based on progname */
297         if (strcmp(progname, "pg_backup") == 0)
298                 format = "c";
299
300         if (argc > 1)
301         {
302                 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
303                 {
304                         help(progname);
305                         exit(0);
306                 }
307                 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
308                 {
309                         puts("pg_dump (PostgreSQL) " PG_VERSION);
310                         exit(0);
311                 }
312         }
313
314         while ((c = getopt_long(argc, argv, "abcCE:f:F:h:in:N:oOp:RsS:t:T:U:vwWxX:Z:",
315                                                         long_options, &optindex)) != -1)
316         {
317                 switch (c)
318                 {
319                         case 'a':                       /* Dump data only */
320                                 dataOnly = true;
321                                 break;
322
323                         case 'b':                       /* Dump blobs */
324                                 outputBlobs = true;
325                                 break;
326
327                         case 'c':                       /* clean (i.e., drop) schema prior to create */
328                                 outputClean = 1;
329                                 break;
330
331                         case 'C':                       /* Create DB */
332                                 outputCreate = 1;
333                                 break;
334
335                         case 'E':                       /* Dump encoding */
336                                 dumpencoding = optarg;
337                                 break;
338
339                         case 'f':
340                                 filename = optarg;
341                                 break;
342
343                         case 'F':
344                                 format = optarg;
345                                 break;
346
347                         case 'h':                       /* server host */
348                                 pghost = optarg;
349                                 break;
350
351                         case 'i':
352                                 /* ignored, deprecated option */
353                                 break;
354
355                         case 'n':                       /* include schema(s) */
356                                 simple_string_list_append(&schema_include_patterns, optarg);
357                                 include_everything = false;
358                                 break;
359
360                         case 'N':                       /* exclude schema(s) */
361                                 simple_string_list_append(&schema_exclude_patterns, optarg);
362                                 break;
363
364                         case 'o':                       /* Dump oids */
365                                 oids = true;
366                                 break;
367
368                         case 'O':                       /* Don't reconnect to match owner */
369                                 outputNoOwner = 1;
370                                 break;
371
372                         case 'p':                       /* server port */
373                                 pgport = optarg;
374                                 break;
375
376                         case 'R':
377                                 /* no-op, still accepted for backwards compatibility */
378                                 break;
379
380                         case 's':                       /* dump schema only */
381                                 schemaOnly = true;
382                                 break;
383
384                         case 'S':                       /* Username for superuser in plain text output */
385                                 outputSuperuser = strdup(optarg);
386                                 break;
387
388                         case 't':                       /* include table(s) */
389                                 simple_string_list_append(&table_include_patterns, optarg);
390                                 include_everything = false;
391                                 break;
392
393                         case 'T':                       /* exclude table(s) */
394                                 simple_string_list_append(&table_exclude_patterns, optarg);
395                                 break;
396
397                         case 'U':
398                                 username = optarg;
399                                 break;
400
401                         case 'v':                       /* verbose */
402                                 g_verbose = true;
403                                 break;
404
405                         case 'w':
406                                 prompt_password = TRI_NO;
407                                 break;
408
409                         case 'W':
410                                 prompt_password = TRI_YES;
411                                 break;
412
413                         case 'x':                       /* skip ACL dump */
414                                 aclsSkip = true;
415                                 break;
416
417                         case 'X':
418                                 /* -X is a deprecated alternative to long options */
419                                 if (strcmp(optarg, "disable-dollar-quoting") == 0)
420                                         disable_dollar_quoting = 1;
421                                 else if (strcmp(optarg, "disable-triggers") == 0)
422                                         disable_triggers = 1;
423                                 else if (strcmp(optarg, "no-tablespaces") == 0)
424                                         outputNoTablespaces = 1;
425                                 else if (strcmp(optarg, "use-set-session-authorization") == 0)
426                                         use_setsessauth = 1;
427                                 else
428                                 {
429                                         fprintf(stderr,
430                                                         _("%s: invalid -X option -- %s\n"),
431                                                         progname, optarg);
432                                         fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
433                                         exit(1);
434                                 }
435                                 break;
436
437                         case 'Z':                       /* Compression Level */
438                                 compressLevel = atoi(optarg);
439                                 break;
440
441                         case 0:
442                                 /* This covers the long options equivalent to -X xxx. */
443                                 break;
444
445                         case 2:                         /* lock-wait-timeout */
446                                 lockWaitTimeout = optarg;
447                                 break;
448
449                         case 3:                         /* SET ROLE */
450                                 use_role = optarg;
451                                 break;
452
453                         default:
454                                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
455                                 exit(1);
456                 }
457         }
458
459         if (optind < (argc - 1))
460         {
461                 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
462                                 progname, argv[optind + 1]);
463                 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
464                                 progname);
465                 exit(1);
466         }
467
468         /* Get database name from command line */
469         if (optind < argc)
470                 dbname = argv[optind];
471
472         /* --column-inserts implies --inserts */
473         if (column_inserts)
474                 dump_inserts = 1;
475
476         if (dataOnly && schemaOnly)
477         {
478                 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
479                 exit(1);
480         }
481
482         if (dataOnly && outputClean)
483         {
484                 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
485                 exit(1);
486         }
487
488         if (dump_inserts && oids)
489         {
490                 write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
491                 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
492                 exit(1);
493         }
494
495         /* open the output file */
496         if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
497         {
498                 /* This is used by pg_dumpall, and is not documented */
499                 plainText = 1;
500                 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
501         }
502         else if (pg_strcasecmp(format, "c") == 0 || pg_strcasecmp(format, "custom") == 0)
503                 g_fout = CreateArchive(filename, archCustom, compressLevel, archModeWrite);
504         else if (pg_strcasecmp(format, "f") == 0 || pg_strcasecmp(format, "file") == 0)
505         {
506                 /*
507                  * Dump files into the current directory; for demonstration only, not
508                  * documented.
509                  */
510                 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
511         }
512         else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
513         {
514                 plainText = 1;
515                 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
516         }
517         else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
518                 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
519         else
520         {
521                 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
522                 exit(1);
523         }
524
525         if (g_fout == NULL)
526         {
527                 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
528                 exit(1);
529         }
530
531         /* Let the archiver know how noisy to be */
532         g_fout->verbose = g_verbose;
533
534         my_version = parse_version(PG_VERSION);
535         if (my_version < 0)
536         {
537                 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
538                 exit(1);
539         }
540
541         /*
542          * We allow the server to be back to 7.0, and up to any minor release
543          * of our own major version.  (See also version check in pg_dumpall.c.)
544          */
545         g_fout->minRemoteVersion = 70000;
546         g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
547
548         /*
549          * Open the database using the Archiver, so it knows about it. Errors mean
550          * death.
551          */
552         g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
553                                                          username, prompt_password);
554
555         /* Set the client encoding if requested */
556         if (dumpencoding)
557         {
558                 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
559                 {
560                         write_msg(NULL, "invalid client encoding \"%s\" specified\n",
561                                           dumpencoding);
562                         exit(1);
563                 }
564         }
565
566         /*
567          * Get the active encoding and the standard_conforming_strings setting, so
568          * we know how to escape strings.
569          */
570         g_fout->encoding = PQclientEncoding(g_conn);
571
572         std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
573         g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
574
575         /* Set the role if requested */
576         if (use_role && g_fout->remoteVersion >= 80100)
577         {
578                 PQExpBuffer query = createPQExpBuffer();
579
580                 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
581                 do_sql_command(g_conn, query->data);
582                 destroyPQExpBuffer(query);
583         }
584
585         /* Set the datestyle to ISO to ensure the dump's portability */
586         do_sql_command(g_conn, "SET DATESTYLE = ISO");
587
588         /* Likewise, avoid using sql_standard intervalstyle */
589         if (g_fout->remoteVersion >= 80400)
590                 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
591
592         /*
593          * If supported, set extra_float_digits so that we can dump float data
594          * exactly (given correctly implemented float I/O code, anyway)
595          */
596         if (g_fout->remoteVersion >= 70400)
597                 do_sql_command(g_conn, "SET extra_float_digits TO 2");
598
599         /*
600          * If synchronized scanning is supported, disable it, to prevent
601          * unpredictable changes in row ordering across a dump and reload.
602          */
603         if (g_fout->remoteVersion >= 80300)
604                 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
605
606         /*
607          * Disable timeouts if supported.
608          */
609         if (g_fout->remoteVersion >= 70300)
610                 do_sql_command(g_conn, "SET statement_timeout = 0");
611
612         /*
613          * Start serializable transaction to dump consistent data.
614          */
615         do_sql_command(g_conn, "BEGIN");
616
617         do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
618
619         /* Select the appropriate subquery to convert user IDs to names */
620         if (g_fout->remoteVersion >= 80100)
621                 username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
622         else if (g_fout->remoteVersion >= 70300)
623                 username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
624         else
625                 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
626
627         /* Find the last built-in OID, if needed */
628         if (g_fout->remoteVersion < 70300)
629         {
630                 if (g_fout->remoteVersion >= 70100)
631                         g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
632                 else
633                         g_last_builtin_oid = findLastBuiltinOid_V70();
634                 if (g_verbose)
635                         write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
636         }
637
638         /* Expand schema selection patterns into OID lists */
639         if (schema_include_patterns.head != NULL)
640         {
641                 expand_schema_name_patterns(&schema_include_patterns,
642                                                                         &schema_include_oids);
643                 if (schema_include_oids.head == NULL)
644                 {
645                         write_msg(NULL, "No matching schemas were found\n");
646                         exit_nicely();
647                 }
648         }
649         expand_schema_name_patterns(&schema_exclude_patterns,
650                                                                 &schema_exclude_oids);
651         /* non-matching exclusion patterns aren't an error */
652
653         /* Expand table selection patterns into OID lists */
654         if (table_include_patterns.head != NULL)
655         {
656                 expand_table_name_patterns(&table_include_patterns,
657                                                                    &table_include_oids);
658                 if (table_include_oids.head == NULL)
659                 {
660                         write_msg(NULL, "No matching tables were found\n");
661                         exit_nicely();
662                 }
663         }
664         expand_table_name_patterns(&table_exclude_patterns,
665                                                            &table_exclude_oids);
666         /* non-matching exclusion patterns aren't an error */
667
668         /*
669          * Dumping blobs is now default unless we saw an inclusion switch or -s
670          * ... but even if we did see one of these, -b turns it back on.
671          */
672         if (include_everything && !schemaOnly)
673                 outputBlobs = true;
674
675         /*
676          * Now scan the database and create DumpableObject structs for all the
677          * objects we intend to dump.
678          */
679         tblinfo = getSchemaData(&numTables);
680
681         if (g_fout->remoteVersion < 80400)
682                 guessConstraintInheritance(tblinfo, numTables);
683
684         if (!schemaOnly)
685         {
686                 getTableData(tblinfo, numTables, oids);
687                 if (dataOnly)
688                         getTableDataFKConstraints();
689         }
690
691         if (outputBlobs && hasBlobs(g_fout))
692         {
693                 /* Add placeholders to allow correct sorting of blobs */
694                 DumpableObject *blobobj;
695                 DumpableObject *blobcobj;
696
697                 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
698                 blobobj->objType = DO_BLOBS;
699                 blobobj->catId = nilCatalogId;
700                 AssignDumpId(blobobj);
701                 blobobj->name = strdup("BLOBS");
702
703                 blobcobj = (DumpableObject *) malloc(sizeof(DumpableObject));
704                 blobcobj->objType = DO_BLOB_COMMENTS;
705                 blobcobj->catId = nilCatalogId;
706                 AssignDumpId(blobcobj);
707                 blobcobj->name = strdup("BLOB COMMENTS");
708                 addObjectDependency(blobcobj, blobobj->dumpId);
709         }
710
711         /*
712          * Collect dependency data to assist in ordering the objects.
713          */
714         getDependencies();
715
716         /*
717          * Sort the objects into a safe dump order (no forward references).
718          *
719          * In 7.3 or later, we can rely on dependency information to help us
720          * determine a safe order, so the initial sort is mostly for cosmetic
721          * purposes: we sort by name to ensure that logically identical schemas
722          * will dump identically.  Before 7.3 we don't have dependencies and we
723          * use OID ordering as an (unreliable) guide to creation order.
724          */
725         getDumpableObjects(&dobjs, &numObjs);
726
727         if (g_fout->remoteVersion >= 70300)
728                 sortDumpableObjectsByTypeName(dobjs, numObjs);
729         else
730                 sortDumpableObjectsByTypeOid(dobjs, numObjs);
731
732         sortDumpableObjects(dobjs, numObjs);
733
734         /*
735          * Create archive TOC entries for all the objects to be dumped, in a safe
736          * order.
737          */
738
739         /* First the special ENCODING and STDSTRINGS entries. */
740         dumpEncoding(g_fout);
741         dumpStdStrings(g_fout);
742
743         /* The database item is always next, unless we don't want it at all */
744         if (include_everything && !dataOnly)
745                 dumpDatabase(g_fout);
746
747         /* Now the rearrangeable objects. */
748         for (i = 0; i < numObjs; i++)
749                 dumpDumpableObject(g_fout, dobjs[i]);
750
751         /*
752          * And finally we can do the actual output.
753          */
754         if (plainText)
755         {
756                 ropt = NewRestoreOptions();
757                 ropt->filename = (char *) filename;
758                 ropt->dropSchema = outputClean;
759                 ropt->aclsSkip = aclsSkip;
760                 ropt->superuser = outputSuperuser;
761                 ropt->create = outputCreate;
762                 ropt->noOwner = outputNoOwner;
763                 ropt->noTablespace = outputNoTablespaces;
764                 ropt->disable_triggers = disable_triggers;
765                 ropt->use_setsessauth = use_setsessauth;
766                 ropt->dataOnly = dataOnly;
767
768                 if (compressLevel == -1)
769                         ropt->compression = 0;
770                 else
771                         ropt->compression = compressLevel;
772
773                 ropt->suppressDumpWarnings = true;              /* We've already shown them */
774
775                 RestoreArchive(g_fout, ropt);
776         }
777
778         CloseArchive(g_fout);
779
780         PQfinish(g_conn);
781
782         exit(0);
783 }
784
785
786 static void
787 help(const char *progname)
788 {
789         printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
790         printf(_("Usage:\n"));
791         printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
792
793         printf(_("\nGeneral options:\n"));
794         printf(_("  -f, --file=FILENAME         output file name\n"));
795         printf(_("  -F, --format=c|t|p          output file format (custom, tar, plain text)\n"));
796         printf(_("  -v, --verbose               verbose mode\n"));
797         printf(_("  -Z, --compress=0-9          compression level for compressed formats\n"));
798         printf(_("  --lock-wait-timeout=TIMEOUT fail after waiting TIMEOUT for a table lock\n"));
799         printf(_("  --help                      show this help, then exit\n"));
800         printf(_("  --version                   output version information, then exit\n"));
801
802         printf(_("\nOptions controlling the output content:\n"));
803         printf(_("  -a, --data-only             dump only the data, not the schema\n"));
804         printf(_("  -b, --blobs                 include large objects in dump\n"));
805         printf(_("  -c, --clean                 clean (drop) database objects before recreating\n"));
806         printf(_("  -C, --create                include commands to create database in dump\n"));
807         printf(_("  -E, --encoding=ENCODING     dump the data in encoding ENCODING\n"));
808         printf(_("  -n, --schema=SCHEMA         dump the named schema(s) only\n"));
809         printf(_("  -N, --exclude-schema=SCHEMA do NOT dump the named schema(s)\n"));
810         printf(_("  -o, --oids                  include OIDs in dump\n"));
811         printf(_("  -O, --no-owner              skip restoration of object ownership in\n"
812                  "                              plain-text format\n"));
813         printf(_("  -s, --schema-only           dump only the schema, no data\n"));
814         printf(_("  -S, --superuser=NAME        superuser user name to use in plain-text format\n"));
815         printf(_("  -t, --table=TABLE           dump the named table(s) only\n"));
816         printf(_("  -T, --exclude-table=TABLE   do NOT dump the named table(s)\n"));
817         printf(_("  -x, --no-privileges         do not dump privileges (grant/revoke)\n"));
818         printf(_("  --binary-upgrade            for use by upgrade utilities only\n"));
819         printf(_("  --inserts                   dump data as INSERT commands, rather than COPY\n"));
820         printf(_("  --column-inserts            dump data as INSERT commands with column names\n"));
821         printf(_("  --disable-dollar-quoting    disable dollar quoting, use SQL standard quoting\n"));
822         printf(_("  --disable-triggers          disable triggers during data-only restore\n"));
823         printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
824         printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
825         printf(_("  --use-set-session-authorization\n"
826                  "                              use SET SESSION AUTHORIZATION commands instead of\n"
827                  "                              ALTER OWNER commands to set ownership\n"));
828
829         printf(_("\nConnection options:\n"));
830         printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
831         printf(_("  -p, --port=PORT          database server port number\n"));
832         printf(_("  -U, --username=NAME      connect as specified database user\n"));
833         printf(_("  -w, --no-password        never prompt for password\n"));
834         printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
835
836         printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
837                          "variable value is used.\n\n"));
838         printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
839 }
840
841 void
842 exit_nicely(void)
843 {
844         PQfinish(g_conn);
845         if (g_verbose)
846                 write_msg(NULL, "*** aborted because of error\n");
847         exit(1);
848 }
849
850 /*
851  * Find the OIDs of all schemas matching the given list of patterns,
852  * and append them to the given OID list.
853  */
854 static void
855 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
856 {
857         PQExpBuffer query;
858         PGresult   *res;
859         SimpleStringListCell *cell;
860         int                     i;
861
862         if (patterns->head == NULL)
863                 return;                                 /* nothing to do */
864
865         if (g_fout->remoteVersion < 70300)
866         {
867                 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
868                 exit_nicely();
869         }
870
871         query = createPQExpBuffer();
872
873         /*
874          * We use UNION ALL rather than UNION; this might sometimes result in
875          * duplicate entries in the OID list, but we don't care.
876          */
877
878         for (cell = patterns->head; cell; cell = cell->next)
879         {
880                 if (cell != patterns->head)
881                         appendPQExpBuffer(query, "UNION ALL\n");
882                 appendPQExpBuffer(query,
883                                                   "SELECT oid FROM pg_catalog.pg_namespace n\n");
884                 processSQLNamePattern(g_conn, query, cell->val, false, false,
885                                                           NULL, "n.nspname", NULL,
886                                                           NULL);
887         }
888
889         res = PQexec(g_conn, query->data);
890         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
891
892         for (i = 0; i < PQntuples(res); i++)
893         {
894                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
895         }
896
897         PQclear(res);
898         destroyPQExpBuffer(query);
899 }
900
901 /*
902  * Find the OIDs of all tables matching the given list of patterns,
903  * and append them to the given OID list.
904  */
905 static void
906 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
907 {
908         PQExpBuffer query;
909         PGresult   *res;
910         SimpleStringListCell *cell;
911         int                     i;
912
913         if (patterns->head == NULL)
914                 return;                                 /* nothing to do */
915
916         query = createPQExpBuffer();
917
918         /*
919          * We use UNION ALL rather than UNION; this might sometimes result in
920          * duplicate entries in the OID list, but we don't care.
921          */
922
923         for (cell = patterns->head; cell; cell = cell->next)
924         {
925                 if (cell != patterns->head)
926                         appendPQExpBuffer(query, "UNION ALL\n");
927                 appendPQExpBuffer(query,
928                                                   "SELECT c.oid"
929                                                   "\nFROM pg_catalog.pg_class c"
930                 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace"
931                                                   "\nWHERE c.relkind in ('%c', '%c', '%c')\n",
932                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
933                 processSQLNamePattern(g_conn, query, cell->val, true, false,
934                                                           "n.nspname", "c.relname", NULL,
935                                                           "pg_catalog.pg_table_is_visible(c.oid)");
936         }
937
938         res = PQexec(g_conn, query->data);
939         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
940
941         for (i = 0; i < PQntuples(res); i++)
942         {
943                 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
944         }
945
946         PQclear(res);
947         destroyPQExpBuffer(query);
948 }
949
950 /*
951  * selectDumpableNamespace: policy-setting subroutine
952  *              Mark a namespace as to be dumped or not
953  */
954 static void
955 selectDumpableNamespace(NamespaceInfo *nsinfo)
956 {
957         /*
958          * If specific tables are being dumped, do not dump any complete
959          * namespaces. If specific namespaces are being dumped, dump just those
960          * namespaces. Otherwise, dump all non-system namespaces.
961          */
962         if (table_include_oids.head != NULL)
963                 nsinfo->dobj.dump = false;
964         else if (schema_include_oids.head != NULL)
965                 nsinfo->dobj.dump = simple_oid_list_member(&schema_include_oids,
966                                                                                                    nsinfo->dobj.catId.oid);
967         else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
968                          strcmp(nsinfo->dobj.name, "information_schema") == 0)
969                 nsinfo->dobj.dump = false;
970         else
971                 nsinfo->dobj.dump = true;
972
973         /*
974          * In any case, a namespace can be excluded by an exclusion switch
975          */
976         if (nsinfo->dobj.dump &&
977                 simple_oid_list_member(&schema_exclude_oids,
978                                                            nsinfo->dobj.catId.oid))
979                 nsinfo->dobj.dump = false;
980 }
981
982 /*
983  * selectDumpableTable: policy-setting subroutine
984  *              Mark a table as to be dumped or not
985  */
986 static void
987 selectDumpableTable(TableInfo *tbinfo)
988 {
989         /*
990          * If specific tables are being dumped, dump just those tables; else, dump
991          * according to the parent namespace's dump flag.
992          */
993         if (table_include_oids.head != NULL)
994                 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
995                                                                                                    tbinfo->dobj.catId.oid);
996         else
997                 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
998
999         /*
1000          * In any case, a table can be excluded by an exclusion switch
1001          */
1002         if (tbinfo->dobj.dump &&
1003                 simple_oid_list_member(&table_exclude_oids,
1004                                                            tbinfo->dobj.catId.oid))
1005                 tbinfo->dobj.dump = false;
1006 }
1007
1008 /*
1009  * selectDumpableType: policy-setting subroutine
1010  *              Mark a type as to be dumped or not
1011  *
1012  * If it's a table's rowtype or an autogenerated array type, we also apply a
1013  * special type code to facilitate sorting into the desired order.  (We don't
1014  * want to consider those to be ordinary types because that would bring tables
1015  * up into the datatype part of the dump order.)  Those tests should be made
1016  * first to ensure the objType change is applied regardless of namespace etc.
1017  */
1018 static void
1019 selectDumpableType(TypeInfo *tinfo)
1020 {
1021         /* skip complex types, except for standalone composite types */
1022         if (OidIsValid(tinfo->typrelid) &&
1023                 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1024         {
1025                 tinfo->dobj.dump = false;
1026                 tinfo->dobj.objType = DO_DUMMY_TYPE;
1027         }
1028
1029         /* skip auto-generated array types */
1030         else if (tinfo->isArray)
1031         {
1032                 tinfo->dobj.dump = false;
1033                 tinfo->dobj.objType = DO_DUMMY_TYPE;
1034         }
1035
1036         /* dump only types in dumpable namespaces */
1037         else if (!tinfo->dobj.namespace->dobj.dump)
1038                 tinfo->dobj.dump = false;
1039
1040         /* skip undefined placeholder types */
1041         else if (!tinfo->isDefined)
1042                 tinfo->dobj.dump = false;
1043
1044         else
1045                 tinfo->dobj.dump = true;
1046 }
1047
1048 /*
1049  * selectDumpableObject: policy-setting subroutine
1050  *              Mark a generic dumpable object as to be dumped or not
1051  *
1052  * Use this only for object types without a special-case routine above.
1053  */
1054 static void
1055 selectDumpableObject(DumpableObject *dobj)
1056 {
1057         /*
1058          * Default policy is to dump if parent namespace is dumpable, or always
1059          * for non-namespace-associated items.
1060          */
1061         if (dobj->namespace)
1062                 dobj->dump = dobj->namespace->dobj.dump;
1063         else
1064                 dobj->dump = true;
1065 }
1066
1067 /*
1068  *      Dump a table's contents for loading using the COPY command
1069  *      - this routine is called by the Archiver when it wants the table
1070  *        to be dumped.
1071  */
1072
1073 static int
1074 dumpTableData_copy(Archive *fout, void *dcontext)
1075 {
1076         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1077         TableInfo  *tbinfo = tdinfo->tdtable;
1078         const char *classname = tbinfo->dobj.name;
1079         const bool      hasoids = tbinfo->hasoids;
1080         const bool      oids = tdinfo->oids;
1081         PQExpBuffer q = createPQExpBuffer();
1082         PGresult   *res;
1083         int                     ret;
1084         char       *copybuf;
1085         const char *column_list;
1086
1087         if (g_verbose)
1088                 write_msg(NULL, "dumping contents of table %s\n", classname);
1089
1090         /*
1091          * Make sure we are in proper schema.  We will qualify the table name
1092          * below anyway (in case its name conflicts with a pg_catalog table); but
1093          * this ensures reproducible results in case the table contains regproc,
1094          * regclass, etc columns.
1095          */
1096         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1097
1098         /*
1099          * If possible, specify the column list explicitly so that we have no
1100          * possibility of retrieving data in the wrong column order.  (The default
1101          * column ordering of COPY will not be what we want in certain corner
1102          * cases involving ADD COLUMN and inheritance.)
1103          */
1104         if (g_fout->remoteVersion >= 70300)
1105                 column_list = fmtCopyColumnList(tbinfo);
1106         else
1107                 column_list = "";               /* can't select columns in COPY */
1108
1109         if (oids && hasoids)
1110         {
1111                 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1112                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1113                                                                                  classname),
1114                                                   column_list);
1115         }
1116         else
1117         {
1118                 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1119                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1120                                                                                  classname),
1121                                                   column_list);
1122         }
1123         res = PQexec(g_conn, q->data);
1124         check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1125         PQclear(res);
1126
1127         for (;;)
1128         {
1129                 ret = PQgetCopyData(g_conn, &copybuf, 0);
1130
1131                 if (ret < 0)
1132                         break;                          /* done or error */
1133
1134                 if (copybuf)
1135                 {
1136                         WriteData(fout, copybuf, ret);
1137                         PQfreemem(copybuf);
1138                 }
1139
1140                 /* ----------
1141                  * THROTTLE:
1142                  *
1143                  * There was considerable discussion in late July, 2000 regarding
1144                  * slowing down pg_dump when backing up large tables. Users with both
1145                  * slow & fast (multi-processor) machines experienced performance
1146                  * degradation when doing a backup.
1147                  *
1148                  * Initial attempts based on sleeping for a number of ms for each ms
1149                  * of work were deemed too complex, then a simple 'sleep in each loop'
1150                  * implementation was suggested. The latter failed because the loop
1151                  * was too tight. Finally, the following was implemented:
1152                  *
1153                  * If throttle is non-zero, then
1154                  *              See how long since the last sleep.
1155                  *              Work out how long to sleep (based on ratio).
1156                  *              If sleep is more than 100ms, then
1157                  *                      sleep
1158                  *                      reset timer
1159                  *              EndIf
1160                  * EndIf
1161                  *
1162                  * where the throttle value was the number of ms to sleep per ms of
1163                  * work. The calculation was done in each loop.
1164                  *
1165                  * Most of the hard work is done in the backend, and this solution
1166                  * still did not work particularly well: on slow machines, the ratio
1167                  * was 50:1, and on medium paced machines, 1:1, and on fast
1168                  * multi-processor machines, it had little or no effect, for reasons
1169                  * that were unclear.
1170                  *
1171                  * Further discussion ensued, and the proposal was dropped.
1172                  *
1173                  * For those people who want this feature, it can be implemented using
1174                  * gettimeofday in each loop, calculating the time since last sleep,
1175                  * multiplying that by the sleep ratio, then if the result is more
1176                  * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1177                  * function to sleep for a subsecond period ie.
1178                  *
1179                  * select(0, NULL, NULL, NULL, &tvi);
1180                  *
1181                  * This will return after the interval specified in the structure tvi.
1182                  * Finally, call gettimeofday again to save the 'last sleep time'.
1183                  * ----------
1184                  */
1185         }
1186         archprintf(fout, "\\.\n\n\n");
1187
1188         if (ret == -2)
1189         {
1190                 /* copy data transfer failed */
1191                 write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1192                 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1193                 write_msg(NULL, "The command was: %s\n", q->data);
1194                 exit_nicely();
1195         }
1196
1197         /* Check command status and return to normal libpq state */
1198         res = PQgetResult(g_conn);
1199         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1200         PQclear(res);
1201
1202         destroyPQExpBuffer(q);
1203         return 1;
1204 }
1205
1206 static int
1207 dumpTableData_insert(Archive *fout, void *dcontext)
1208 {
1209         TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1210         TableInfo  *tbinfo = tdinfo->tdtable;
1211         const char *classname = tbinfo->dobj.name;
1212         PQExpBuffer q = createPQExpBuffer();
1213         PGresult   *res;
1214         int                     tuple;
1215         int                     nfields;
1216         int                     field;
1217
1218         /*
1219          * Make sure we are in proper schema.  We will qualify the table name
1220          * below anyway (in case its name conflicts with a pg_catalog table); but
1221          * this ensures reproducible results in case the table contains regproc,
1222          * regclass, etc columns.
1223          */
1224         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1225
1226         if (fout->remoteVersion >= 70100)
1227         {
1228                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1229                                                   "SELECT * FROM ONLY %s",
1230                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1231                                                                                  classname));
1232         }
1233         else
1234         {
1235                 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1236                                                   "SELECT * FROM %s",
1237                                                   fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1238                                                                                  classname));
1239         }
1240
1241         res = PQexec(g_conn, q->data);
1242         check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1243
1244         do
1245         {
1246                 PQclear(res);
1247
1248                 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1249                 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1250                                                  PGRES_TUPLES_OK);
1251                 nfields = PQnfields(res);
1252                 for (tuple = 0; tuple < PQntuples(res); tuple++)
1253                 {
1254                         archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1255                         if (nfields == 0)
1256                         {
1257                                 /* corner case for zero-column table */
1258                                 archprintf(fout, "DEFAULT VALUES;\n");
1259                                 continue;
1260                         }
1261                         if (column_inserts)
1262                         {
1263                                 resetPQExpBuffer(q);
1264                                 appendPQExpBuffer(q, "(");
1265                                 for (field = 0; field < nfields; field++)
1266                                 {
1267                                         if (field > 0)
1268                                                 appendPQExpBuffer(q, ", ");
1269                                         appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1270                                 }
1271                                 appendPQExpBuffer(q, ") ");
1272                                 archputs(q->data, fout);
1273                         }
1274                         archprintf(fout, "VALUES (");
1275                         for (field = 0; field < nfields; field++)
1276                         {
1277                                 if (field > 0)
1278                                         archprintf(fout, ", ");
1279                                 if (PQgetisnull(res, tuple, field))
1280                                 {
1281                                         archprintf(fout, "NULL");
1282                                         continue;
1283                                 }
1284
1285                                 /* XXX This code is partially duplicated in ruleutils.c */
1286                                 switch (PQftype(res, field))
1287                                 {
1288                                         case INT2OID:
1289                                         case INT4OID:
1290                                         case INT8OID:
1291                                         case OIDOID:
1292                                         case FLOAT4OID:
1293                                         case FLOAT8OID:
1294                                         case NUMERICOID:
1295                                                 {
1296                                                         /*
1297                                                          * These types are printed without quotes unless
1298                                                          * they contain values that aren't accepted by the
1299                                                          * scanner unquoted (e.g., 'NaN').      Note that
1300                                                          * strtod() and friends might accept NaN, so we
1301                                                          * can't use that to test.
1302                                                          *
1303                                                          * In reality we only need to defend against
1304                                                          * infinity and NaN, so we need not get too crazy
1305                                                          * about pattern matching here.
1306                                                          */
1307                                                         const char *s = PQgetvalue(res, tuple, field);
1308
1309                                                         if (strspn(s, "0123456789 +-eE.") == strlen(s))
1310                                                                 archprintf(fout, "%s", s);
1311                                                         else
1312                                                                 archprintf(fout, "'%s'", s);
1313                                                 }
1314                                                 break;
1315
1316                                         case BITOID:
1317                                         case VARBITOID:
1318                                                 archprintf(fout, "B'%s'",
1319                                                                    PQgetvalue(res, tuple, field));
1320                                                 break;
1321
1322                                         case BOOLOID:
1323                                                 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1324                                                         archprintf(fout, "true");
1325                                                 else
1326                                                         archprintf(fout, "false");
1327                                                 break;
1328
1329                                         default:
1330                                                 /* All other types are printed as string literals. */
1331                                                 resetPQExpBuffer(q);
1332                                                 appendStringLiteralAH(q,
1333                                                                                           PQgetvalue(res, tuple, field),
1334                                                                                           fout);
1335                                                 archputs(q->data, fout);
1336                                                 break;
1337                                 }
1338                         }
1339                         archprintf(fout, ");\n");
1340                 }
1341         } while (PQntuples(res) > 0);
1342
1343         PQclear(res);
1344
1345         archprintf(fout, "\n\n");
1346
1347         do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1348
1349         destroyPQExpBuffer(q);
1350         return 1;
1351 }
1352
1353
1354 /*
1355  * dumpTableData -
1356  *        dump the contents of a single table
1357  *
1358  * Actually, this just makes an ArchiveEntry for the table contents.
1359  */
1360 static void
1361 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1362 {
1363         TableInfo  *tbinfo = tdinfo->tdtable;
1364         PQExpBuffer copyBuf = createPQExpBuffer();
1365         DataDumperPtr dumpFn;
1366         char       *copyStmt;
1367
1368         if (!dump_inserts)
1369         {
1370                 /* Dump/restore using COPY */
1371                 dumpFn = dumpTableData_copy;
1372                 /* must use 2 steps here 'cause fmtId is nonreentrant */
1373                 appendPQExpBuffer(copyBuf, "COPY %s ",
1374                                                   fmtId(tbinfo->dobj.name));
1375                 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1376                                                   fmtCopyColumnList(tbinfo),
1377                                           (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
1378                 copyStmt = copyBuf->data;
1379         }
1380         else
1381         {
1382                 /* Restore using INSERT */
1383                 dumpFn = dumpTableData_insert;
1384                 copyStmt = NULL;
1385         }
1386
1387         ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
1388                                  tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
1389                                  NULL, tbinfo->rolname,
1390                                  false, "TABLE DATA", SECTION_DATA,
1391                                  "", "", copyStmt,
1392                                  tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1393                                  dumpFn, tdinfo);
1394
1395         destroyPQExpBuffer(copyBuf);
1396 }
1397
1398 /*
1399  * getTableData -
1400  *        set up dumpable objects representing the contents of tables
1401  */
1402 static void
1403 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1404 {
1405         int                     i;
1406
1407         for (i = 0; i < numTables; i++)
1408         {
1409                 /* Skip VIEWs (no data to dump) */
1410                 if (tblinfo[i].relkind == RELKIND_VIEW)
1411                         continue;
1412                 /* Skip SEQUENCEs (handled elsewhere) */
1413                 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1414                         continue;
1415
1416                 if (tblinfo[i].dobj.dump)
1417                 {
1418                         TableDataInfo *tdinfo;
1419
1420                         tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1421
1422                         tdinfo->dobj.objType = DO_TABLE_DATA;
1423
1424                         /*
1425                          * Note: use tableoid 0 so that this object won't be mistaken for
1426                          * something that pg_depend entries apply to.
1427                          */
1428                         tdinfo->dobj.catId.tableoid = 0;
1429                         tdinfo->dobj.catId.oid = tblinfo[i].dobj.catId.oid;
1430                         AssignDumpId(&tdinfo->dobj);
1431                         tdinfo->dobj.name = tblinfo[i].dobj.name;
1432                         tdinfo->dobj.namespace = tblinfo[i].dobj.namespace;
1433                         tdinfo->tdtable = &(tblinfo[i]);
1434                         tdinfo->oids = oids;
1435                         addObjectDependency(&tdinfo->dobj, tblinfo[i].dobj.dumpId);
1436
1437                         tblinfo[i].dataObj = tdinfo;
1438                 }
1439         }
1440 }
1441
1442 /*
1443  * getTableDataFKConstraints -
1444  *        add dump-order dependencies reflecting foreign key constraints
1445  *
1446  * This code is executed only in a data-only dump --- in schema+data dumps
1447  * we handle foreign key issues by not creating the FK constraints until
1448  * after the data is loaded.  In a data-only dump, however, we want to
1449  * order the table data objects in such a way that a table's referenced
1450  * tables are restored first.  (In the presence of circular references or
1451  * self-references this may be impossible; we'll detect and complain about
1452  * that during the dependency sorting step.)
1453  */
1454 static void
1455 getTableDataFKConstraints(void)
1456 {
1457         DumpableObject **dobjs;
1458         int                     numObjs;
1459         int                     i;
1460
1461         /* Search through all the dumpable objects for FK constraints */
1462         getDumpableObjects(&dobjs, &numObjs);
1463         for (i = 0; i < numObjs; i++)
1464         {
1465                 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1466                 {
1467                         ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1468                         TableInfo *ftable;
1469
1470                         /* Not interesting unless both tables are to be dumped */
1471                         if (cinfo->contable == NULL ||
1472                                 cinfo->contable->dataObj == NULL)
1473                                 continue;
1474                         ftable = findTableByOid(cinfo->confrelid);
1475                         if (ftable == NULL ||
1476                                 ftable->dataObj == NULL)
1477                                 continue;
1478                         /*
1479                          * Okay, make referencing table's TABLE_DATA object depend on
1480                          * the referenced table's TABLE_DATA object.
1481                          */
1482                         addObjectDependency(&cinfo->contable->dataObj->dobj,
1483                                                                 ftable->dataObj->dobj.dumpId);
1484                 }
1485         }
1486         free(dobjs);
1487 }
1488
1489
1490 /*
1491  * guessConstraintInheritance:
1492  *      In pre-8.4 databases, we can't tell for certain which constraints
1493  *      are inherited.  We assume a CHECK constraint is inherited if its name
1494  *      matches the name of any constraint in the parent.  Originally this code
1495  *      tried to compare the expression texts, but that can fail for various
1496  *      reasons --- for example, if the parent and child tables are in different
1497  *      schemas, reverse-listing of function calls may produce different text
1498  *      (schema-qualified or not) depending on search path.
1499  *
1500  *      In 8.4 and up we can rely on the conislocal field to decide which
1501  *      constraints must be dumped; much safer.
1502  *
1503  *      This function assumes all conislocal flags were initialized to TRUE.
1504  *      It clears the flag on anything that seems to be inherited.
1505  */
1506 static void
1507 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1508 {
1509         int                     i,
1510                                 j,
1511                                 k;
1512
1513         for (i = 0; i < numTables; i++)
1514         {
1515                 TableInfo  *tbinfo = &(tblinfo[i]);
1516                 int                     numParents;
1517                 TableInfo **parents;
1518                 TableInfo  *parent;
1519
1520                 /* Sequences and views never have parents */
1521                 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1522                         tbinfo->relkind == RELKIND_VIEW)
1523                         continue;
1524
1525                 /* Don't bother computing anything for non-target tables, either */
1526                 if (!tbinfo->dobj.dump)
1527                         continue;
1528
1529                 numParents = tbinfo->numParents;
1530                 parents = tbinfo->parents;
1531
1532                 if (numParents == 0)
1533                         continue;                       /* nothing to see here, move along */
1534
1535                 /* scan for inherited CHECK constraints */
1536                 for (j = 0; j < tbinfo->ncheck; j++)
1537                 {
1538                         ConstraintInfo *constr;
1539
1540                         constr = &(tbinfo->checkexprs[j]);
1541
1542                         for (k = 0; k < numParents; k++)
1543                         {
1544                                 int                     l;
1545
1546                                 parent = parents[k];
1547                                 for (l = 0; l < parent->ncheck; l++)
1548                                 {
1549                                         ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1550
1551                                         if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1552                                         {
1553                                                 constr->conislocal = false;
1554                                                 break;
1555                                         }
1556                                 }
1557                                 if (!constr->conislocal)
1558                                         break;
1559                         }
1560                 }
1561         }
1562 }
1563
1564
1565 /*
1566  * dumpDatabase:
1567  *      dump the database definition
1568  */
1569 static void
1570 dumpDatabase(Archive *AH)
1571 {
1572         PQExpBuffer dbQry = createPQExpBuffer();
1573         PQExpBuffer delQry = createPQExpBuffer();
1574         PQExpBuffer creaQry = createPQExpBuffer();
1575         PGresult   *res;
1576         int                     ntups;
1577         int                     i_tableoid,
1578                                 i_oid,
1579                                 i_dba,
1580                                 i_encoding,
1581                                 i_collate,
1582                                 i_ctype,
1583                                 i_frozenxid,
1584                                 i_tablespace;
1585         CatalogId       dbCatId;
1586         DumpId          dbDumpId;
1587         const char *datname,
1588                            *dba,
1589                            *encoding,
1590                            *collate,
1591                            *ctype,
1592                            *tablespace;
1593         uint32          frozenxid;
1594
1595         datname = PQdb(g_conn);
1596
1597         if (g_verbose)
1598                 write_msg(NULL, "saving database definition\n");
1599
1600         /* Make sure we are in proper schema */
1601         selectSourceSchema("pg_catalog");
1602
1603         /* Get the database owner and parameters from pg_database */
1604         if (g_fout->remoteVersion >= 80400)
1605         {
1606                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1607                                                   "(%s datdba) AS dba, "
1608                                                   "pg_encoding_to_char(encoding) AS encoding, "
1609                                                   "datcollate, datctype, datfrozenxid, "
1610                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1611                                           "shobj_description(oid, 'pg_database') AS description "
1612
1613                                                   "FROM pg_database "
1614                                                   "WHERE datname = ",
1615                                                   username_subquery);
1616                 appendStringLiteralAH(dbQry, datname, AH);
1617         }
1618         else if (g_fout->remoteVersion >= 80200)
1619         {
1620                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1621                                                   "(%s datdba) AS dba, "
1622                                                   "pg_encoding_to_char(encoding) AS encoding, "
1623                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1624                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
1625                                           "shobj_description(oid, 'pg_database') AS description "
1626
1627                                                   "FROM pg_database "
1628                                                   "WHERE datname = ",
1629                                                   username_subquery);
1630                 appendStringLiteralAH(dbQry, datname, AH);
1631         }
1632         else if (g_fout->remoteVersion >= 80000)
1633         {
1634                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1635                                                   "(%s datdba) AS dba, "
1636                                                   "pg_encoding_to_char(encoding) AS encoding, "
1637                                                   "NULL AS datcollate, NULL AS datctype, datfrozenxid, "
1638                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
1639                                                   "FROM pg_database "
1640                                                   "WHERE datname = ",
1641                                                   username_subquery);
1642                 appendStringLiteralAH(dbQry, datname, AH);
1643         }
1644         else if (g_fout->remoteVersion >= 70100)
1645         {
1646                 appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
1647                                                   "(%s datdba) AS dba, "
1648                                                   "pg_encoding_to_char(encoding) AS encoding, "
1649                                                   "NULL AS datcollate, NULL AS datctype, "
1650                                                   "0 AS datfrozenxid, "
1651                                                   "NULL AS tablespace "
1652                                                   "FROM pg_database "
1653                                                   "WHERE datname = ",
1654                                                   username_subquery);
1655                 appendStringLiteralAH(dbQry, datname, AH);
1656         }
1657         else
1658         {
1659                 appendPQExpBuffer(dbQry, "SELECT "
1660                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
1661                                                   "oid, "
1662                                                   "(%s datdba) AS dba, "
1663                                                   "pg_encoding_to_char(encoding) AS encoding, "
1664                                                   "NULL AS datcollate, NULL AS datctype, "
1665                                                   "0 AS datfrozenxid, "
1666                                                   "NULL AS tablespace "
1667                                                   "FROM pg_database "
1668                                                   "WHERE datname = ",
1669                                                   username_subquery);
1670                 appendStringLiteralAH(dbQry, datname, AH);
1671         }
1672
1673         res = PQexec(g_conn, dbQry->data);
1674         check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1675
1676         ntups = PQntuples(res);
1677
1678         if (ntups <= 0)
1679         {
1680                 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1681                                   datname);
1682                 exit_nicely();
1683         }
1684
1685         if (ntups != 1)
1686         {
1687                 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1688                                   ntups, datname);
1689                 exit_nicely();
1690         }
1691
1692         i_tableoid = PQfnumber(res, "tableoid");
1693         i_oid = PQfnumber(res, "oid");
1694         i_dba = PQfnumber(res, "dba");
1695         i_encoding = PQfnumber(res, "encoding");
1696         i_collate = PQfnumber(res, "datcollate");
1697         i_ctype = PQfnumber(res, "datctype");
1698         i_frozenxid = PQfnumber(res, "datfrozenxid");
1699         i_tablespace = PQfnumber(res, "tablespace");
1700
1701         dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
1702         dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
1703         dba = PQgetvalue(res, 0, i_dba);
1704         encoding = PQgetvalue(res, 0, i_encoding);
1705         collate = PQgetvalue(res, 0, i_collate);
1706         ctype = PQgetvalue(res, 0, i_ctype);
1707         frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
1708         tablespace = PQgetvalue(res, 0, i_tablespace);
1709
1710         appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1711                                           fmtId(datname));
1712         if (strlen(encoding) > 0)
1713         {
1714                 appendPQExpBuffer(creaQry, " ENCODING = ");
1715                 appendStringLiteralAH(creaQry, encoding, AH);
1716         }
1717         if (strlen(collate) > 0)
1718         {
1719                 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1720                 appendStringLiteralAH(creaQry, collate, AH);
1721         }
1722         if (strlen(ctype) > 0)
1723         {
1724                 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1725                 appendStringLiteralAH(creaQry, ctype, AH);
1726         }
1727         if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1728                 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1729                                                   fmtId(tablespace));
1730         appendPQExpBuffer(creaQry, ";\n");
1731
1732         if (binary_upgrade)
1733         {
1734                 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1735                 appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
1736                                                          "SET datfrozenxid = '%u'\n"
1737                                                          "WHERE datname = ",
1738                                                          frozenxid);
1739                 appendStringLiteralAH(creaQry, datname, AH);
1740                 appendPQExpBuffer(creaQry, ";\n");
1741         }
1742         
1743         appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1744                                           fmtId(datname));
1745
1746         dbDumpId = createDumpId();
1747
1748         ArchiveEntry(AH,
1749                                  dbCatId,               /* catalog ID */
1750                                  dbDumpId,              /* dump ID */
1751                                  datname,               /* Name */
1752                                  NULL,                  /* Namespace */
1753                                  NULL,                  /* Tablespace */
1754                                  dba,                   /* Owner */
1755                                  false,                 /* with oids */
1756                                  "DATABASE",    /* Desc */
1757                                  SECTION_PRE_DATA, /* Section */
1758                                  creaQry->data, /* Create */
1759                                  delQry->data,  /* Del */
1760                                  NULL,                  /* Copy */
1761                                  NULL,                  /* Deps */
1762                                  0,                             /* # Deps */
1763                                  NULL,                  /* Dumper */
1764                                  NULL);                 /* Dumper Arg */
1765
1766         /* Dump DB comment if any */
1767         if (g_fout->remoteVersion >= 80200)
1768         {
1769                 /*
1770                  * 8.2 keeps comments on shared objects in a shared table, so we
1771                  * cannot use the dumpComment used for other database objects.
1772                  */
1773                 char       *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1774
1775                 if (comment && strlen(comment))
1776                 {
1777                         resetPQExpBuffer(dbQry);
1778                         /* Generates warning when loaded into a differently-named database.*/
1779                         appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", fmtId(datname));
1780                         appendStringLiteralAH(dbQry, comment, AH);
1781                         appendPQExpBuffer(dbQry, ";\n");
1782
1783                         ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1784                                                  dba, false, "COMMENT", SECTION_NONE,
1785                                                  dbQry->data, "", NULL,
1786                                                  &dbDumpId, 1, NULL, NULL);
1787                 }
1788         }
1789         else
1790         {
1791                 resetPQExpBuffer(dbQry);
1792                 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1793                 dumpComment(AH, dbQry->data, NULL, "",
1794                                         dbCatId, 0, dbDumpId);
1795         }
1796
1797         PQclear(res);
1798
1799         destroyPQExpBuffer(dbQry);
1800         destroyPQExpBuffer(delQry);
1801         destroyPQExpBuffer(creaQry);
1802 }
1803
1804
1805 /*
1806  * dumpEncoding: put the correct encoding into the archive
1807  */
1808 static void
1809 dumpEncoding(Archive *AH)
1810 {
1811         const char *encname = pg_encoding_to_char(AH->encoding);
1812         PQExpBuffer qry = createPQExpBuffer();
1813
1814         if (g_verbose)
1815                 write_msg(NULL, "saving encoding = %s\n", encname);
1816
1817         appendPQExpBuffer(qry, "SET client_encoding = ");
1818         appendStringLiteralAH(qry, encname, AH);
1819         appendPQExpBuffer(qry, ";\n");
1820
1821         ArchiveEntry(AH, nilCatalogId, createDumpId(),
1822                                  "ENCODING", NULL, NULL, "",
1823                                  false, "ENCODING", SECTION_PRE_DATA,
1824                                  qry->data, "", NULL,
1825                                  NULL, 0,
1826                                  NULL, NULL);
1827
1828         destroyPQExpBuffer(qry);
1829 }
1830
1831
1832 /*
1833  * dumpStdStrings: put the correct escape string behavior into the archive
1834  */
1835 static void
1836 dumpStdStrings(Archive *AH)
1837 {
1838         const char *stdstrings = AH->std_strings ? "on" : "off";
1839         PQExpBuffer qry = createPQExpBuffer();
1840
1841         if (g_verbose)
1842                 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1843                                   stdstrings);
1844
1845         appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1846                                           stdstrings);
1847
1848         ArchiveEntry(AH, nilCatalogId, createDumpId(),
1849                                  "STDSTRINGS", NULL, NULL, "",
1850                                  false, "STDSTRINGS", SECTION_PRE_DATA,
1851                                  qry->data, "", NULL,
1852                                  NULL, 0,
1853                                  NULL, NULL);
1854
1855         destroyPQExpBuffer(qry);
1856 }
1857
1858
1859 /*
1860  * hasBlobs:
1861  *      Test whether database contains any large objects
1862  */
1863 static bool
1864 hasBlobs(Archive *AH)
1865 {
1866         bool            result;
1867         const char *blobQry;
1868         PGresult   *res;
1869
1870         /* Make sure we are in proper schema */
1871         selectSourceSchema("pg_catalog");
1872
1873         /* Check for BLOB OIDs */
1874         if (AH->remoteVersion >= 70100)
1875                 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1876         else
1877                 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1878
1879         res = PQexec(g_conn, blobQry);
1880         check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1881
1882         result = PQntuples(res) > 0;
1883
1884         PQclear(res);
1885
1886         return result;
1887 }
1888
1889 /*
1890  * dumpBlobs:
1891  *      dump all blobs
1892  */
1893 static int
1894 dumpBlobs(Archive *AH, void *arg)
1895 {
1896         const char *blobQry;
1897         const char *blobFetchQry;
1898         PGresult   *res;
1899         char            buf[LOBBUFSIZE];
1900         int                     i;
1901         int                     cnt;
1902
1903         if (g_verbose)
1904                 write_msg(NULL, "saving large objects\n");
1905
1906         /* Make sure we are in proper schema */
1907         selectSourceSchema("pg_catalog");
1908
1909         /* Cursor to get all BLOB OIDs */
1910         if (AH->remoteVersion >= 70100)
1911                 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1912         else
1913                 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1914
1915         res = PQexec(g_conn, blobQry);
1916         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1917
1918         /* Command to fetch from cursor */
1919         blobFetchQry = "FETCH 1000 IN bloboid";
1920
1921         do
1922         {
1923                 PQclear(res);
1924
1925                 /* Do a fetch */
1926                 res = PQexec(g_conn, blobFetchQry);
1927                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1928
1929                 /* Process the tuples, if any */
1930                 for (i = 0; i < PQntuples(res); i++)
1931                 {
1932                         Oid                     blobOid;
1933                         int                     loFd;
1934
1935                         blobOid = atooid(PQgetvalue(res, i, 0));
1936                         /* Open the BLOB */
1937                         loFd = lo_open(g_conn, blobOid, INV_READ);
1938                         if (loFd == -1)
1939                         {
1940                                 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1941                                                   PQerrorMessage(g_conn));
1942                                 exit_nicely();
1943                         }
1944
1945                         StartBlob(AH, blobOid);
1946
1947                         /* Now read it in chunks, sending data to archive */
1948                         do
1949                         {
1950                                 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
1951                                 if (cnt < 0)
1952                                 {
1953                                         write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1954                                                           PQerrorMessage(g_conn));
1955                                         exit_nicely();
1956                                 }
1957
1958                                 WriteData(AH, buf, cnt);
1959                         } while (cnt > 0);
1960
1961                         lo_close(g_conn, loFd);
1962
1963                         EndBlob(AH, blobOid);
1964                 }
1965         } while (PQntuples(res) > 0);
1966
1967         PQclear(res);
1968
1969         return 1;
1970 }
1971
1972 /*
1973  * dumpBlobComments
1974  *      dump all blob comments
1975  *
1976  * Since we don't provide any way to be selective about dumping blobs,
1977  * there's no need to be selective about their comments either.  We put
1978  * all the comments into one big TOC entry.
1979  */
1980 static int
1981 dumpBlobComments(Archive *AH, void *arg)
1982 {
1983         const char *blobQry;
1984         const char *blobFetchQry;
1985         PQExpBuffer commentcmd = createPQExpBuffer();
1986         PGresult   *res;
1987         int                     i;
1988
1989         if (g_verbose)
1990                 write_msg(NULL, "saving large object comments\n");
1991
1992         /* Make sure we are in proper schema */
1993         selectSourceSchema("pg_catalog");
1994
1995         /* Cursor to get all BLOB comments */
1996         if (AH->remoteVersion >= 70300)
1997                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
1998                                   "obj_description(loid, 'pg_largeobject') "
1999                                   "FROM (SELECT DISTINCT loid FROM "
2000                                   "pg_description d JOIN pg_largeobject l ON (objoid = loid) "
2001                                   "WHERE classoid = 'pg_largeobject'::regclass) ss";
2002         else if (AH->remoteVersion >= 70200)
2003                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2004                                   "obj_description(loid, 'pg_largeobject') "
2005                                   "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2006         else if (AH->remoteVersion >= 70100)
2007                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT loid, "
2008                                   "obj_description(loid) "
2009                                   "FROM (SELECT DISTINCT loid FROM pg_largeobject) ss";
2010         else
2011                 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2012                                   "     ( "
2013                                   "             SELECT description "
2014                                   "             FROM pg_description pd "
2015                                   "             WHERE pd.objoid=pc.oid "
2016                                   "     ) "
2017                                   "FROM pg_class pc WHERE relkind = 'l'";
2018
2019         res = PQexec(g_conn, blobQry);
2020         check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2021
2022         /* Command to fetch from cursor */
2023         blobFetchQry = "FETCH 100 IN blobcmt";
2024
2025         do
2026         {
2027                 PQclear(res);
2028
2029                 /* Do a fetch */
2030                 res = PQexec(g_conn, blobFetchQry);
2031                 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2032
2033                 /* Process the tuples, if any */
2034                 for (i = 0; i < PQntuples(res); i++)
2035                 {
2036                         Oid                     blobOid;
2037                         char       *comment;
2038
2039                         /* ignore blobs without comments */
2040                         if (PQgetisnull(res, i, 1))
2041                                 continue;
2042
2043                         blobOid = atooid(PQgetvalue(res, i, 0));
2044                         comment = PQgetvalue(res, i, 1);
2045
2046                         printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
2047                                                           blobOid);
2048                         appendStringLiteralAH(commentcmd, comment, AH);
2049                         appendPQExpBuffer(commentcmd, ";\n");
2050
2051                         archputs(commentcmd->data, AH);
2052                 }
2053         } while (PQntuples(res) > 0);
2054
2055         PQclear(res);
2056
2057         archputs("\n", AH);
2058
2059         destroyPQExpBuffer(commentcmd);
2060
2061         return 1;
2062 }
2063
2064 /*
2065  * getNamespaces:
2066  *        read all namespaces in the system catalogs and return them in the
2067  * NamespaceInfo* structure
2068  *
2069  *      numNamespaces is set to the number of namespaces read in
2070  */
2071 NamespaceInfo *
2072 getNamespaces(int *numNamespaces)
2073 {
2074         PGresult   *res;
2075         int                     ntups;
2076         int                     i;
2077         PQExpBuffer query;
2078         NamespaceInfo *nsinfo;
2079         int                     i_tableoid;
2080         int                     i_oid;
2081         int                     i_nspname;
2082         int                     i_rolname;
2083         int                     i_nspacl;
2084
2085         /*
2086          * Before 7.3, there are no real namespaces; create two dummy entries, one
2087          * for user stuff and one for system stuff.
2088          */
2089         if (g_fout->remoteVersion < 70300)
2090         {
2091                 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
2092
2093                 nsinfo[0].dobj.objType = DO_NAMESPACE;
2094                 nsinfo[0].dobj.catId.tableoid = 0;
2095                 nsinfo[0].dobj.catId.oid = 0;
2096                 AssignDumpId(&nsinfo[0].dobj);
2097                 nsinfo[0].dobj.name = strdup("public");
2098                 nsinfo[0].rolname = strdup("");
2099                 nsinfo[0].nspacl = strdup("");
2100
2101                 selectDumpableNamespace(&nsinfo[0]);
2102
2103                 nsinfo[1].dobj.objType = DO_NAMESPACE;
2104                 nsinfo[1].dobj.catId.tableoid = 0;
2105                 nsinfo[1].dobj.catId.oid = 1;
2106                 AssignDumpId(&nsinfo[1].dobj);
2107                 nsinfo[1].dobj.name = strdup("pg_catalog");
2108                 nsinfo[1].rolname = strdup("");
2109                 nsinfo[1].nspacl = strdup("");
2110
2111                 selectDumpableNamespace(&nsinfo[1]);
2112
2113                 g_namespaces = nsinfo;
2114                 g_numNamespaces = *numNamespaces = 2;
2115
2116                 return nsinfo;
2117         }
2118
2119         query = createPQExpBuffer();
2120
2121         /* Make sure we are in proper schema */
2122         selectSourceSchema("pg_catalog");
2123
2124         /*
2125          * we fetch all namespaces including system ones, so that every object we
2126          * read in can be linked to a containing namespace.
2127          */
2128         appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2129                                           "(%s nspowner) AS rolname, "
2130                                           "nspacl FROM pg_namespace",
2131                                           username_subquery);
2132
2133         res = PQexec(g_conn, query->data);
2134         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2135
2136         ntups = PQntuples(res);
2137
2138         nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
2139
2140         i_tableoid = PQfnumber(res, "tableoid");
2141         i_oid = PQfnumber(res, "oid");
2142         i_nspname = PQfnumber(res, "nspname");
2143         i_rolname = PQfnumber(res, "rolname");
2144         i_nspacl = PQfnumber(res, "nspacl");
2145
2146         for (i = 0; i < ntups; i++)
2147         {
2148                 nsinfo[i].dobj.objType = DO_NAMESPACE;
2149                 nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2150                 nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2151                 AssignDumpId(&nsinfo[i].dobj);
2152                 nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
2153                 nsinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2154                 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
2155
2156                 /* Decide whether to dump this namespace */
2157                 selectDumpableNamespace(&nsinfo[i]);
2158
2159                 if (strlen(nsinfo[i].rolname) == 0)
2160                         write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
2161                                           nsinfo[i].dobj.name);
2162         }
2163
2164         PQclear(res);
2165         destroyPQExpBuffer(query);
2166
2167         g_namespaces = nsinfo;
2168         g_numNamespaces = *numNamespaces = ntups;
2169
2170         return nsinfo;
2171 }
2172
2173 /*
2174  * findNamespace:
2175  *              given a namespace OID and an object OID, look up the info read by
2176  *              getNamespaces
2177  *
2178  * NB: for pre-7.3 source database, we use object OID to guess whether it's
2179  * a system object or not.      In 7.3 and later there is no guessing.
2180  */
2181 static NamespaceInfo *
2182 findNamespace(Oid nsoid, Oid objoid)
2183 {
2184         int                     i;
2185
2186         if (g_fout->remoteVersion >= 70300)
2187         {
2188                 for (i = 0; i < g_numNamespaces; i++)
2189                 {
2190                         NamespaceInfo *nsinfo = &g_namespaces[i];
2191
2192                         if (nsoid == nsinfo->dobj.catId.oid)
2193                                 return nsinfo;
2194                 }
2195                 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2196                 exit_nicely();
2197         }
2198         else
2199         {
2200                 /* This code depends on the layout set up by getNamespaces. */
2201                 if (objoid > g_last_builtin_oid)
2202                         i = 0;                          /* user object */
2203                 else
2204                         i = 1;                          /* system object */
2205                 return &g_namespaces[i];
2206         }
2207
2208         return NULL;                            /* keep compiler quiet */
2209 }
2210
2211 /*
2212  * getTypes:
2213  *        read all types in the system catalogs and return them in the
2214  * TypeInfo* structure
2215  *
2216  *      numTypes is set to the number of types read in
2217  *
2218  * NB: this must run after getFuncs() because we assume we can do
2219  * findFuncByOid().
2220  */
2221 TypeInfo *
2222 getTypes(int *numTypes)
2223 {
2224         PGresult   *res;
2225         int                     ntups;
2226         int                     i;
2227         PQExpBuffer query = createPQExpBuffer();
2228         TypeInfo   *tinfo;
2229         ShellTypeInfo *stinfo;
2230         int                     i_tableoid;
2231         int                     i_oid;
2232         int                     i_typname;
2233         int                     i_typnamespace;
2234         int                     i_rolname;
2235         int                     i_typinput;
2236         int                     i_typoutput;
2237         int                     i_typelem;
2238         int                     i_typrelid;
2239         int                     i_typrelkind;
2240         int                     i_typtype;
2241         int                     i_typisdefined;
2242         int                     i_isarray;
2243
2244         /*
2245          * we include even the built-in types because those may be used as array
2246          * elements by user-defined types
2247          *
2248          * we filter out the built-in types when we dump out the types
2249          *
2250          * same approach for undefined (shell) types and array types
2251          *
2252          * Note: as of 8.3 we can reliably detect whether a type is an
2253          * auto-generated array type by checking the element type's typarray.
2254          * (Before that the test is capable of generating false positives.) We
2255          * still check for name beginning with '_', though, so as to avoid the
2256          * cost of the subselect probe for all standard types.  This would have to
2257          * be revisited if the backend ever allows renaming of array types.
2258          */
2259
2260         /* Make sure we are in proper schema */
2261         selectSourceSchema("pg_catalog");
2262
2263         if (g_fout->remoteVersion >= 80300)
2264         {
2265                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2266                                                   "typnamespace, "
2267                                                   "(%s typowner) AS rolname, "
2268                                                   "typinput::oid AS typinput, "
2269                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2270                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2271                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2272                                                   "typtype, typisdefined, "
2273                                                   "typname[0] = '_' AND typelem != 0 AND "
2274                                                   "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
2275                                                   "FROM pg_type",
2276                                                   username_subquery);
2277         }
2278         else if (g_fout->remoteVersion >= 70300)
2279         {
2280                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2281                                                   "typnamespace, "
2282                                                   "(%s typowner) AS rolname, "
2283                                                   "typinput::oid AS typinput, "
2284                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2285                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2286                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2287                                                   "typtype, typisdefined, "
2288                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2289                                                   "FROM pg_type",
2290                                                   username_subquery);
2291         }
2292         else if (g_fout->remoteVersion >= 70100)
2293         {
2294                 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
2295                                                   "0::oid AS typnamespace, "
2296                                                   "(%s typowner) AS rolname, "
2297                                                   "typinput::oid AS typinput, "
2298                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2299                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2300                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2301                                                   "typtype, typisdefined, "
2302                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2303                                                   "FROM pg_type",
2304                                                   username_subquery);
2305         }
2306         else
2307         {
2308                 appendPQExpBuffer(query, "SELECT "
2309                  "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
2310                                                   "oid, typname, "
2311                                                   "0::oid AS typnamespace, "
2312                                                   "(%s typowner) AS rolname, "
2313                                                   "typinput::oid AS typinput, "
2314                                                   "typoutput::oid AS typoutput, typelem, typrelid, "
2315                                                   "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
2316                                                   "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
2317                                                   "typtype, typisdefined, "
2318                                                   "typname[0] = '_' AND typelem != 0 AS isarray "
2319                                                   "FROM pg_type",
2320                                                   username_subquery);
2321         }
2322
2323         res = PQexec(g_conn, query->data);
2324         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2325
2326         ntups = PQntuples(res);
2327
2328         tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
2329
2330         i_tableoid = PQfnumber(res, "tableoid");
2331         i_oid = PQfnumber(res, "oid");
2332         i_typname = PQfnumber(res, "typname");
2333         i_typnamespace = PQfnumber(res, "typnamespace");
2334         i_rolname = PQfnumber(res, "rolname");
2335         i_typinput = PQfnumber(res, "typinput");
2336         i_typoutput = PQfnumber(res, "typoutput");
2337         i_typelem = PQfnumber(res, "typelem");
2338         i_typrelid = PQfnumber(res, "typrelid");
2339         i_typrelkind = PQfnumber(res, "typrelkind");
2340         i_typtype = PQfnumber(res, "typtype");
2341         i_typisdefined = PQfnumber(res, "typisdefined");
2342         i_isarray = PQfnumber(res, "isarray");
2343
2344         for (i = 0; i < ntups; i++)
2345         {
2346                 tinfo[i].dobj.objType = DO_TYPE;
2347                 tinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2348                 tinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2349                 AssignDumpId(&tinfo[i].dobj);
2350                 tinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_typname));
2351                 tinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_typnamespace)),
2352                                                                                                 tinfo[i].dobj.catId.oid);
2353                 tinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2354                 tinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
2355                 tinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
2356                 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
2357                 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
2358                 tinfo[i].shellType = NULL;
2359
2360                 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2361                         tinfo[i].isDefined = true;
2362                 else
2363                         tinfo[i].isDefined = false;
2364
2365                 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2366                         tinfo[i].isArray = true;
2367                 else
2368                         tinfo[i].isArray = false;
2369
2370                 /* Decide whether we want to dump it */
2371                 selectDumpableType(&tinfo[i]);
2372
2373                 /*
2374                  * If it's a domain, fetch info about its constraints, if any
2375                  */
2376                 tinfo[i].nDomChecks = 0;
2377                 tinfo[i].domChecks = NULL;
2378                 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_DOMAIN)
2379                         getDomainConstraints(&(tinfo[i]));
2380
2381                 /*
2382                  * If it's a base type, make a DumpableObject representing a shell
2383                  * definition of the type.      We will need to dump that ahead of the I/O
2384                  * functions for the type.
2385                  *
2386                  * Note: the shell type doesn't have a catId.  You might think it
2387                  * should copy the base type's catId, but then it might capture the
2388                  * pg_depend entries for the type, which we don't want.
2389                  */
2390                 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
2391                 {
2392                         stinfo = (ShellTypeInfo *) malloc(sizeof(ShellTypeInfo));
2393                         stinfo->dobj.objType = DO_SHELL_TYPE;
2394                         stinfo->dobj.catId = nilCatalogId;
2395                         AssignDumpId(&stinfo->dobj);
2396                         stinfo->dobj.name = strdup(tinfo[i].dobj.name);
2397                         stinfo->dobj.namespace = tinfo[i].dobj.namespace;
2398                         stinfo->baseType = &(tinfo[i]);
2399                         tinfo[i].shellType = stinfo;
2400
2401                         /*
2402                          * Initially mark the shell type as not to be dumped.  We'll only
2403                          * dump it if the I/O functions need to be dumped; this is taken
2404                          * care of while sorting dependencies.
2405                          */
2406                         stinfo->dobj.dump = false;
2407
2408                         /*
2409                          * However, if dumping from pre-7.3, there will be no dependency
2410                          * info so we have to fake it here.  We only need to worry about
2411                          * typinput and typoutput since the other functions only exist
2412                          * post-7.3.
2413                          */
2414                         if (g_fout->remoteVersion < 70300)
2415                         {
2416                                 Oid                     typinput;
2417                                 Oid                     typoutput;
2418                                 FuncInfo   *funcInfo;
2419
2420                                 typinput = atooid(PQgetvalue(res, i, i_typinput));
2421                                 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2422
2423                                 funcInfo = findFuncByOid(typinput);
2424                                 if (funcInfo && funcInfo->dobj.dump)
2425                                 {
2426                                         /* base type depends on function */
2427                                         addObjectDependency(&tinfo[i].dobj,
2428                                                                                 funcInfo->dobj.dumpId);
2429                                         /* function depends on shell type */
2430                                         addObjectDependency(&funcInfo->dobj,
2431                                                                                 stinfo->dobj.dumpId);
2432                                         /* mark shell type as to be dumped */
2433                                         stinfo->dobj.dump = true;
2434                                 }
2435
2436                                 funcInfo = findFuncByOid(typoutput);
2437                                 if (funcInfo && funcInfo->dobj.dump)
2438                                 {
2439                                         /* base type depends on function */
2440                                         addObjectDependency(&tinfo[i].dobj,
2441                                                                                 funcInfo->dobj.dumpId);
2442                                         /* function depends on shell type */
2443                                         addObjectDependency(&funcInfo->dobj,
2444                                                                                 stinfo->dobj.dumpId);
2445                                         /* mark shell type as to be dumped */
2446                                         stinfo->dobj.dump = true;
2447                                 }
2448                         }
2449                 }
2450
2451                 if (strlen(tinfo[i].rolname) == 0 && tinfo[i].isDefined)
2452                         write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
2453                                           tinfo[i].dobj.name);
2454         }
2455
2456         *numTypes = ntups;
2457
2458         PQclear(res);
2459
2460         destroyPQExpBuffer(query);
2461
2462         return tinfo;
2463 }
2464
2465 /*
2466  * getOperators:
2467  *        read all operators in the system catalogs and return them in the
2468  * OprInfo* structure
2469  *
2470  *      numOprs is set to the number of operators read in
2471  */
2472 OprInfo *
2473 getOperators(int *numOprs)
2474 {
2475         PGresult   *res;
2476         int                     ntups;
2477         int                     i;
2478         PQExpBuffer query = createPQExpBuffer();
2479         OprInfo    *oprinfo;
2480         int                     i_tableoid;
2481         int                     i_oid;
2482         int                     i_oprname;
2483         int                     i_oprnamespace;
2484         int                     i_rolname;
2485         int                     i_oprcode;
2486
2487         /*
2488          * find all operators, including builtin operators; we filter out
2489          * system-defined operators at dump-out time.
2490          */
2491
2492         /* Make sure we are in proper schema */
2493         selectSourceSchema("pg_catalog");
2494
2495         if (g_fout->remoteVersion >= 70300)
2496         {
2497                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2498                                                   "oprnamespace, "
2499                                                   "(%s oprowner) AS rolname, "
2500                                                   "oprcode::oid AS oprcode "
2501                                                   "FROM pg_operator",
2502                                                   username_subquery);
2503         }
2504         else if (g_fout->remoteVersion >= 70100)
2505         {
2506                 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2507                                                   "0::oid AS oprnamespace, "
2508                                                   "(%s oprowner) AS rolname, "
2509                                                   "oprcode::oid AS oprcode "
2510                                                   "FROM pg_operator",
2511                                                   username_subquery);
2512         }
2513         else
2514         {
2515                 appendPQExpBuffer(query, "SELECT "
2516                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2517                                                   "oid, oprname, "
2518                                                   "0::oid AS oprnamespace, "
2519                                                   "(%s oprowner) AS rolname, "
2520                                                   "oprcode::oid AS oprcode "
2521                                                   "FROM pg_operator",
2522                                                   username_subquery);
2523         }
2524
2525         res = PQexec(g_conn, query->data);
2526         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2527
2528         ntups = PQntuples(res);
2529         *numOprs = ntups;
2530
2531         oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
2532
2533         i_tableoid = PQfnumber(res, "tableoid");
2534         i_oid = PQfnumber(res, "oid");
2535         i_oprname = PQfnumber(res, "oprname");
2536         i_oprnamespace = PQfnumber(res, "oprnamespace");
2537         i_rolname = PQfnumber(res, "rolname");
2538         i_oprcode = PQfnumber(res, "oprcode");
2539
2540         for (i = 0; i < ntups; i++)
2541         {
2542                 oprinfo[i].dobj.objType = DO_OPERATOR;
2543                 oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2544                 oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2545                 AssignDumpId(&oprinfo[i].dobj);
2546                 oprinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_oprname));
2547                 oprinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_oprnamespace)),
2548                                                                                                   oprinfo[i].dobj.catId.oid);
2549                 oprinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2550                 oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
2551
2552                 /* Decide whether we want to dump it */
2553                 selectDumpableObject(&(oprinfo[i].dobj));
2554
2555                 if (strlen(oprinfo[i].rolname) == 0)
2556                         write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
2557                                           oprinfo[i].dobj.name);
2558         }
2559
2560         PQclear(res);
2561
2562         destroyPQExpBuffer(query);
2563
2564         return oprinfo;
2565 }
2566
2567 /*
2568  * getConversions:
2569  *        read all conversions in the system catalogs and return them in the
2570  * ConvInfo* structure
2571  *
2572  *      numConversions is set to the number of conversions read in
2573  */
2574 ConvInfo *
2575 getConversions(int *numConversions)
2576 {
2577         PGresult   *res;
2578         int                     ntups;
2579         int                     i;
2580         PQExpBuffer query = createPQExpBuffer();
2581         ConvInfo   *convinfo;
2582         int                     i_tableoid;
2583         int                     i_oid;
2584         int                     i_conname;
2585         int                     i_connamespace;
2586         int                     i_rolname;
2587
2588         /* Conversions didn't exist pre-7.3 */
2589         if (g_fout->remoteVersion < 70300)
2590         {
2591                 *numConversions = 0;
2592                 return NULL;
2593         }
2594
2595         /*
2596          * find all conversions, including builtin conversions; we filter out
2597          * system-defined conversions at dump-out time.
2598          */
2599
2600         /* Make sure we are in proper schema */
2601         selectSourceSchema("pg_catalog");
2602
2603         appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2604                                           "connamespace, "
2605                                           "(%s conowner) AS rolname "
2606                                           "FROM pg_conversion",
2607                                           username_subquery);
2608
2609         res = PQexec(g_conn, query->data);
2610         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2611
2612         ntups = PQntuples(res);
2613         *numConversions = ntups;
2614
2615         convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
2616
2617         i_tableoid = PQfnumber(res, "tableoid");
2618         i_oid = PQfnumber(res, "oid");
2619         i_conname = PQfnumber(res, "conname");
2620         i_connamespace = PQfnumber(res, "connamespace");
2621         i_rolname = PQfnumber(res, "rolname");
2622
2623         for (i = 0; i < ntups; i++)
2624         {
2625                 convinfo[i].dobj.objType = DO_CONVERSION;
2626                 convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2627                 convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2628                 AssignDumpId(&convinfo[i].dobj);
2629                 convinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
2630                 convinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_connamespace)),
2631                                                                                                  convinfo[i].dobj.catId.oid);
2632                 convinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2633
2634                 /* Decide whether we want to dump it */
2635                 selectDumpableObject(&(convinfo[i].dobj));
2636         }
2637
2638         PQclear(res);
2639
2640         destroyPQExpBuffer(query);
2641
2642         return convinfo;
2643 }
2644
2645 /*
2646  * getOpclasses:
2647  *        read all opclasses in the system catalogs and return them in the
2648  * OpclassInfo* structure
2649  *
2650  *      numOpclasses is set to the number of opclasses read in
2651  */
2652 OpclassInfo *
2653 getOpclasses(int *numOpclasses)
2654 {
2655         PGresult   *res;
2656         int                     ntups;
2657         int                     i;
2658         PQExpBuffer query = createPQExpBuffer();
2659         OpclassInfo *opcinfo;
2660         int                     i_tableoid;
2661         int                     i_oid;
2662         int                     i_opcname;
2663         int                     i_opcnamespace;
2664         int                     i_rolname;
2665
2666         /*
2667          * find all opclasses, including builtin opclasses; we filter out
2668          * system-defined opclasses at dump-out time.
2669          */
2670
2671         /* Make sure we are in proper schema */
2672         selectSourceSchema("pg_catalog");
2673
2674         if (g_fout->remoteVersion >= 70300)
2675         {
2676                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2677                                                   "opcnamespace, "
2678                                                   "(%s opcowner) AS rolname "
2679                                                   "FROM pg_opclass",
2680                                                   username_subquery);
2681         }
2682         else if (g_fout->remoteVersion >= 70100)
2683         {
2684                 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2685                                                   "0::oid AS opcnamespace, "
2686                                                   "''::name AS rolname "
2687                                                   "FROM pg_opclass");
2688         }
2689         else
2690         {
2691                 appendPQExpBuffer(query, "SELECT "
2692                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2693                                                   "oid, opcname, "
2694                                                   "0::oid AS opcnamespace, "
2695                                                   "''::name AS rolname "
2696                                                   "FROM pg_opclass");
2697         }
2698
2699         res = PQexec(g_conn, query->data);
2700         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2701
2702         ntups = PQntuples(res);
2703         *numOpclasses = ntups;
2704
2705         opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
2706
2707         i_tableoid = PQfnumber(res, "tableoid");
2708         i_oid = PQfnumber(res, "oid");
2709         i_opcname = PQfnumber(res, "opcname");
2710         i_opcnamespace = PQfnumber(res, "opcnamespace");
2711         i_rolname = PQfnumber(res, "rolname");
2712
2713         for (i = 0; i < ntups; i++)
2714         {
2715                 opcinfo[i].dobj.objType = DO_OPCLASS;
2716                 opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2717                 opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2718                 AssignDumpId(&opcinfo[i].dobj);
2719                 opcinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opcname));
2720                 opcinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opcnamespace)),
2721                                                                                                   opcinfo[i].dobj.catId.oid);
2722                 opcinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2723
2724                 /* Decide whether we want to dump it */
2725                 selectDumpableObject(&(opcinfo[i].dobj));
2726
2727                 if (g_fout->remoteVersion >= 70300)
2728                 {
2729                         if (strlen(opcinfo[i].rolname) == 0)
2730                                 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
2731                                                   opcinfo[i].dobj.name);
2732                 }
2733         }
2734
2735         PQclear(res);
2736
2737         destroyPQExpBuffer(query);
2738
2739         return opcinfo;
2740 }
2741
2742 /*
2743  * getOpfamilies:
2744  *        read all opfamilies in the system catalogs and return them in the
2745  * OpfamilyInfo* structure
2746  *
2747  *      numOpfamilies is set to the number of opfamilies read in
2748  */
2749 OpfamilyInfo *
2750 getOpfamilies(int *numOpfamilies)
2751 {
2752         PGresult   *res;
2753         int                     ntups;
2754         int                     i;
2755         PQExpBuffer query;
2756         OpfamilyInfo *opfinfo;
2757         int                     i_tableoid;
2758         int                     i_oid;
2759         int                     i_opfname;
2760         int                     i_opfnamespace;
2761         int                     i_rolname;
2762
2763         /* Before 8.3, there is no separate concept of opfamilies */
2764         if (g_fout->remoteVersion < 80300)
2765         {
2766                 *numOpfamilies = 0;
2767                 return NULL;
2768         }
2769
2770         query = createPQExpBuffer();
2771
2772         /*
2773          * find all opfamilies, including builtin opfamilies; we filter out
2774          * system-defined opfamilies at dump-out time.
2775          */
2776
2777         /* Make sure we are in proper schema */
2778         selectSourceSchema("pg_catalog");
2779
2780         appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2781                                           "opfnamespace, "
2782                                           "(%s opfowner) AS rolname "
2783                                           "FROM pg_opfamily",
2784                                           username_subquery);
2785
2786         res = PQexec(g_conn, query->data);
2787         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2788
2789         ntups = PQntuples(res);
2790         *numOpfamilies = ntups;
2791
2792         opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
2793
2794         i_tableoid = PQfnumber(res, "tableoid");
2795         i_oid = PQfnumber(res, "oid");
2796         i_opfname = PQfnumber(res, "opfname");
2797         i_opfnamespace = PQfnumber(res, "opfnamespace");
2798         i_rolname = PQfnumber(res, "rolname");
2799
2800         for (i = 0; i < ntups; i++)
2801         {
2802                 opfinfo[i].dobj.objType = DO_OPFAMILY;
2803                 opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2804                 opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2805                 AssignDumpId(&opfinfo[i].dobj);
2806                 opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
2807                 opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
2808                                                                                                   opfinfo[i].dobj.catId.oid);
2809                 opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
2810
2811                 /* Decide whether we want to dump it */
2812                 selectDumpableObject(&(opfinfo[i].dobj));
2813
2814                 if (g_fout->remoteVersion >= 70300)
2815                 {
2816                         if (strlen(opfinfo[i].rolname) == 0)
2817                                 write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
2818                                                   opfinfo[i].dobj.name);
2819                 }
2820         }
2821
2822         PQclear(res);
2823
2824         destroyPQExpBuffer(query);
2825
2826         return opfinfo;
2827 }
2828
2829 /*
2830  * getAggregates:
2831  *        read all the user-defined aggregates in the system catalogs and
2832  * return them in the AggInfo* structure
2833  *
2834  * numAggs is set to the number of aggregates read in
2835  */
2836 AggInfo *
2837 getAggregates(int *numAggs)
2838 {
2839         PGresult   *res;
2840         int                     ntups;
2841         int                     i;
2842         PQExpBuffer query = createPQExpBuffer();
2843         AggInfo    *agginfo;
2844         int                     i_tableoid;
2845         int                     i_oid;
2846         int                     i_aggname;
2847         int                     i_aggnamespace;
2848         int                     i_pronargs;
2849         int                     i_proargtypes;
2850         int                     i_rolname;
2851         int                     i_aggacl;
2852
2853         /* Make sure we are in proper schema */
2854         selectSourceSchema("pg_catalog");
2855
2856         /* find all user-defined aggregates */
2857
2858         if (g_fout->remoteVersion >= 80200)
2859         {
2860                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2861                                                   "pronamespace AS aggnamespace, "
2862                                                   "pronargs, proargtypes, "
2863                                                   "(%s proowner) AS rolname, "
2864                                                   "proacl AS aggacl "
2865                                                   "FROM pg_proc "
2866                                                   "WHERE proisagg "
2867                                                   "AND pronamespace != "
2868                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2869                                                   username_subquery);
2870         }
2871         else if (g_fout->remoteVersion >= 70300)
2872         {
2873                 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2874                                                   "pronamespace AS aggnamespace, "
2875                                                   "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
2876                                                   "proargtypes, "
2877                                                   "(%s proowner) AS rolname, "
2878                                                   "proacl AS aggacl "
2879                                                   "FROM pg_proc "
2880                                                   "WHERE proisagg "
2881                                                   "AND pronamespace != "
2882                            "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2883                                                   username_subquery);
2884         }
2885         else if (g_fout->remoteVersion >= 70100)
2886         {
2887                 appendPQExpBuffer(query, "SELECT tableoid, oid, aggname, "
2888                                                   "0::oid AS aggnamespace, "
2889                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2890                                                   "aggbasetype AS proargtypes, "
2891                                                   "(%s aggowner) AS rolname, "
2892                                                   "'{=X}' AS aggacl "
2893                                                   "FROM pg_aggregate "
2894                                                   "where oid > '%u'::oid",
2895                                                   username_subquery,
2896                                                   g_last_builtin_oid);
2897         }
2898         else
2899         {
2900                 appendPQExpBuffer(query, "SELECT "
2901                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
2902                                                   "oid, aggname, "
2903                                                   "0::oid AS aggnamespace, "
2904                                   "CASE WHEN aggbasetype = 0 THEN 0 ELSE 1 END AS pronargs, "
2905                                                   "aggbasetype AS proargtypes, "
2906                                                   "(%s aggowner) AS rolname, "
2907                                                   "'{=X}' AS aggacl "
2908                                                   "FROM pg_aggregate "
2909                                                   "where oid > '%u'::oid",
2910                                                   username_subquery,
2911                                                   g_last_builtin_oid);
2912         }
2913
2914         res = PQexec(g_conn, query->data);
2915         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2916
2917         ntups = PQntuples(res);
2918         *numAggs = ntups;
2919
2920         agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
2921
2922         i_tableoid = PQfnumber(res, "tableoid");
2923         i_oid = PQfnumber(res, "oid");
2924         i_aggname = PQfnumber(res, "aggname");
2925         i_aggnamespace = PQfnumber(res, "aggnamespace");
2926         i_pronargs = PQfnumber(res, "pronargs");
2927         i_proargtypes = PQfnumber(res, "proargtypes");
2928         i_rolname = PQfnumber(res, "rolname");
2929         i_aggacl = PQfnumber(res, "aggacl");
2930
2931         for (i = 0; i < ntups; i++)
2932         {
2933                 agginfo[i].aggfn.dobj.objType = DO_AGG;
2934                 agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
2935                 agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
2936                 AssignDumpId(&agginfo[i].aggfn.dobj);
2937                 agginfo[i].aggfn.dobj.name = strdup(PQgetvalue(res, i, i_aggname));
2938                 agginfo[i].aggfn.dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_aggnamespace)),
2939                                                                                         agginfo[i].aggfn.dobj.catId.oid);
2940                 agginfo[i].aggfn.rolname = strdup(PQgetvalue(res, i, i_rolname));
2941                 if (strlen(agginfo[i].aggfn.rolname) == 0)
2942                         write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
2943                                           agginfo[i].aggfn.dobj.name);
2944                 agginfo[i].aggfn.lang = InvalidOid;             /* not currently interesting */
2945                 agginfo[i].aggfn.prorettype = InvalidOid;               /* not saved */
2946                 agginfo[i].aggfn.proacl = strdup(PQgetvalue(res, i, i_aggacl));
2947                 agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
2948                 if (agginfo[i].aggfn.nargs == 0)
2949                         agginfo[i].aggfn.argtypes = NULL;
2950                 else
2951                 {
2952                         agginfo[i].aggfn.argtypes = (Oid *) malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
2953                         if (g_fout->remoteVersion >= 70300)
2954                                 parseOidArray(PQgetvalue(res, i, i_proargtypes),
2955                                                           agginfo[i].aggfn.argtypes,
2956                                                           agginfo[i].aggfn.nargs);
2957                         else
2958                                 /* it's just aggbasetype */
2959                                 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
2960                 }
2961
2962                 /* Decide whether we want to dump it */
2963                 selectDumpableObject(&(agginfo[i].aggfn.dobj));
2964         }
2965
2966         PQclear(res);
2967
2968         destroyPQExpBuffer(query);
2969
2970         return agginfo;
2971 }
2972
2973 /*
2974  * getFuncs:
2975  *        read all the user-defined functions in the system catalogs and
2976  * return them in the FuncInfo* structure
2977  *
2978  * numFuncs is set to the number of functions read in
2979  */
2980 FuncInfo *
2981 getFuncs(int *numFuncs)
2982 {
2983         PGresult   *res;
2984         int                     ntups;
2985         int                     i;
2986         PQExpBuffer query = createPQExpBuffer();
2987         FuncInfo   *finfo;
2988         int                     i_tableoid;
2989         int                     i_oid;
2990         int                     i_proname;
2991         int                     i_pronamespace;
2992         int                     i_rolname;
2993         int                     i_prolang;
2994         int                     i_pronargs;
2995         int                     i_proargtypes;
2996         int                     i_prorettype;
2997         int                     i_proacl;
2998
2999         /* Make sure we are in proper schema */
3000         selectSourceSchema("pg_catalog");
3001
3002         /* find all user-defined funcs */
3003
3004         if (g_fout->remoteVersion >= 70300)
3005         {
3006                 appendPQExpBuffer(query,
3007                                                   "SELECT tableoid, oid, proname, prolang, "
3008                                                   "pronargs, proargtypes, prorettype, proacl, "
3009                                                   "pronamespace, "
3010                                                   "(%s proowner) AS rolname "
3011                                                   "FROM pg_proc "
3012                                                   "WHERE NOT proisagg "
3013                                                   "AND pronamespace != "
3014                                                   "(SELECT oid FROM pg_namespace "
3015                                                   "WHERE nspname = 'pg_catalog')",
3016                                                   username_subquery);
3017         }
3018         else if (g_fout->remoteVersion >= 70100)
3019         {
3020                 appendPQExpBuffer(query,
3021                                                   "SELECT tableoid, oid, proname, prolang, "
3022                                                   "pronargs, proargtypes, prorettype, "
3023                                                   "'{=X}' AS proacl, "
3024                                                   "0::oid AS pronamespace, "
3025                                                   "(%s proowner) AS rolname "
3026                                                   "FROM pg_proc "
3027                                                   "WHERE pg_proc.oid > '%u'::oid",
3028                                                   username_subquery,
3029                                                   g_last_builtin_oid);
3030         }
3031         else
3032         {
3033                 appendPQExpBuffer(query,
3034                                                   "SELECT "
3035                                                   "(SELECT oid FROM pg_class "
3036                                                   " WHERE relname = 'pg_proc') AS tableoid, "
3037                                                   "oid, proname, prolang, "
3038                                                   "pronargs, proargtypes, prorettype, "
3039                                                   "'{=X}' AS proacl, "
3040                                                   "0::oid AS pronamespace, "
3041                                                   "(%s proowner) AS rolname "
3042                                                   "FROM pg_proc "
3043                                                   "where pg_proc.oid > '%u'::oid",
3044                                                   username_subquery,
3045                                                   g_last_builtin_oid);
3046         }
3047
3048         res = PQexec(g_conn, query->data);
3049         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3050
3051         ntups = PQntuples(res);
3052
3053         *numFuncs = ntups;
3054
3055         finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
3056
3057         i_tableoid = PQfnumber(res, "tableoid");
3058         i_oid = PQfnumber(res, "oid");
3059         i_proname = PQfnumber(res, "proname");
3060         i_pronamespace = PQfnumber(res, "pronamespace");
3061         i_rolname = PQfnumber(res, "rolname");
3062         i_prolang = PQfnumber(res, "prolang");
3063         i_pronargs = PQfnumber(res, "pronargs");
3064         i_proargtypes = PQfnumber(res, "proargtypes");
3065         i_prorettype = PQfnumber(res, "prorettype");
3066         i_proacl = PQfnumber(res, "proacl");
3067
3068         for (i = 0; i < ntups; i++)
3069         {
3070                 finfo[i].dobj.objType = DO_FUNC;
3071                 finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
3072                 finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3073                 AssignDumpId(&finfo[i].dobj);
3074                 finfo[i].dobj.name = strdup(PQgetvalue(res, i, i_proname));
3075                 finfo[i].dobj.namespace =
3076                         findNamespace(atooid(PQgetvalue(res, i, i_pronamespace)),
3077                                                   finfo[i].dobj.catId.oid);
3078                 finfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3079                 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
3080                 finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
3081                 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
3082                 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
3083                 if (finfo[i].nargs == 0)
3084                         finfo[i].argtypes = NULL;
3085                 else
3086                 {
3087                         finfo[i].argtypes = (Oid *) malloc(finfo[i].nargs * sizeof(Oid));
3088                         parseOidArray(PQgetvalue(res, i, i_proargtypes),
3089                                                   finfo[i].argtypes, finfo[i].nargs);
3090                 }
3091
3092                 /* Decide whether we want to dump it */
3093                 selectDumpableObject(&(finfo[i].dobj));
3094
3095                 if (strlen(finfo[i].rolname) == 0)
3096                         write_msg(NULL,
3097                                  "WARNING: owner of function \"%s\" appears to be invalid\n",
3098                                           finfo[i].dobj.name);
3099         }
3100
3101         PQclear(res);
3102
3103         destroyPQExpBuffer(query);
3104
3105         return finfo;
3106 }
3107
3108 /*
3109  * getTables
3110  *        read all the user-defined tables (no indexes, no catalogs)
3111  * in the system catalogs return them in the TableInfo* structure
3112  *
3113  * numTables is set to the number of tables read in
3114  */
3115 TableInfo *
3116 getTables(int *numTables)
3117 {
3118         PGresult   *res;
3119         int                     ntups;
3120         int                     i;
3121         PQExpBuffer query = createPQExpBuffer();
3122         TableInfo  *tblinfo;
3123         int                     i_reltableoid;
3124         int                     i_reloid;
3125         int                     i_relname;
3126         int                     i_relnamespace;
3127         int                     i_relkind;
3128         int                     i_relacl;
3129         int                     i_rolname;
3130         int                     i_relchecks;
3131         int                     i_relhastriggers;
3132         int                     i_relhasindex;
3133         int                     i_relhasrules;
3134         int                     i_relhasoids;
3135         int                     i_relfrozenxid;
3136         int                     i_owning_tab;
3137         int                     i_owning_col;
3138         int                     i_reltablespace;
3139         int                     i_reloptions;
3140         int                     i_toastreloptions;
3141
3142         /* Make sure we are in proper schema */
3143         selectSourceSchema("pg_catalog");
3144
3145         /*
3146          * Find all the tables (including views and sequences).
3147          *
3148          * We include system catalogs, so that we can work if a user table is
3149          * defined to inherit from a system catalog (pretty weird, but...)
3150          *
3151          * We ignore tables that are not type 'r' (ordinary relation), 'S'
3152          * (sequence), 'v' (view), or 'c' (composite type).
3153          *
3154          * Composite-type table entries won't be dumped as such, but we have to
3155          * make a DumpableObject for them so that we can track dependencies of the
3156          * composite type (pg_depend entries for columns of the composite type
3157          * link to the pg_class entry not the pg_type entry).
3158          *
3159          * Note: in this phase we should collect only a minimal amount of
3160          * information about each table, basically just enough to decide if it is
3161          * interesting. We must fetch all tables in this phase because otherwise
3162          * we cannot correctly identify inherited columns, owned sequences, etc.
3163          */
3164
3165         if (g_fout->remoteVersion >= 80400)
3166         {
3167                 /*
3168                  * Left join to pick up dependency info linking sequences to their
3169                  * owning column, if any (note this dependency is AUTO as of 8.2)
3170                  */
3171                 appendPQExpBuffer(query,
3172                                                   "SELECT c.tableoid, c.oid, c.relname, "
3173                                                   "c.relacl, c.relkind, c.relnamespace, "
3174                                                   "(%s c.relowner) AS rolname, "
3175                                                   "c.relchecks, c.relhastriggers, "
3176                                                   "c.relhasindex, c.relhasrules, c.relhasoids, "
3177                                                   "c.relfrozenxid, "
3178                                                   "d.refobjid AS owning_tab, "
3179                                                   "d.refobjsubid AS owning_col, "
3180                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3181                                                   "array_to_string(c.reloptions, ', ') AS reloptions, "
3182                                                   "array_to_string(array(SELECT 'toast.' || x FROM unnest(tc.reloptions) x), ', ') AS toast_reloptions "
3183                                                   "FROM pg_class c "
3184                                                   "LEFT JOIN pg_depend d ON "
3185                                                   "(c.relkind = '%c' AND "
3186                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3187                                                   "d.objsubid = 0 AND "
3188                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3189                                                   "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
3190                                                   "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
3191                                                   "ORDER BY c.oid",
3192                                                   username_subquery,
3193                                                   RELKIND_SEQUENCE,
3194                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3195                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3196         }
3197         else if (g_fout->remoteVersion >= 80200)
3198         {
3199                 /*
3200                  * Left join to pick up dependency info linking sequences to their
3201                  * owning column, if any (note this dependency is AUTO as of 8.2)
3202                  */
3203                 appendPQExpBuffer(query,
3204                                                   "SELECT c.tableoid, c.oid, relname, "
3205                                                   "relacl, relkind, relnamespace, "
3206                                                   "(%s relowner) AS rolname, "
3207                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3208                                                   "relhasindex, relhasrules, relhasoids, "
3209                                                   "relfrozenxid, "
3210                                                   "d.refobjid AS owning_tab, "
3211                                                   "d.refobjsubid AS owning_col, "
3212                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3213                                                   "array_to_string(c.reloptions, ', ') AS reloptions, "
3214                                                   "NULL AS toast_reloptions "
3215                                                   "FROM pg_class c "
3216                                                   "LEFT JOIN pg_depend d ON "
3217                                                   "(c.relkind = '%c' AND "
3218                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3219                                                   "d.objsubid = 0 AND "
3220                                                   "d.refclassid = c.tableoid AND d.deptype = 'a') "
3221                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
3222                                                   "ORDER BY c.oid",
3223                                                   username_subquery,
3224                                                   RELKIND_SEQUENCE,
3225                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3226                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3227         }
3228         else if (g_fout->remoteVersion >= 80000)
3229         {
3230                 /*
3231                  * Left join to pick up dependency info linking sequences to their
3232                  * owning column, if any
3233                  */
3234                 appendPQExpBuffer(query,
3235                                                   "SELECT c.tableoid, c.oid, relname, "
3236                                                   "relacl, relkind, relnamespace, "
3237                                                   "(%s relowner) AS rolname, "
3238                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3239                                                   "relhasindex, relhasrules, relhasoids, "
3240                                                   "0 AS relfrozenxid, "
3241                                                   "d.refobjid AS owning_tab, "
3242                                                   "d.refobjsubid AS owning_col, "
3243                                                   "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
3244                                                   "NULL AS reloptions, "
3245                                                   "NULL AS toast_reloptions "
3246                                                   "FROM pg_class c "
3247                                                   "LEFT JOIN pg_depend d ON "
3248                                                   "(c.relkind = '%c' AND "
3249                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3250                                                   "d.objsubid = 0 AND "
3251                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
3252                                                   "WHERE relkind in ('%c', '%c', '%c', '%c') "
3253                                                   "ORDER BY c.oid",
3254                                                   username_subquery,
3255                                                   RELKIND_SEQUENCE,
3256                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3257                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3258         }
3259         else if (g_fout->remoteVersion >= 70300)
3260         {
3261                 /*
3262                  * Left join to pick up dependency info linking sequences to their
3263                  * owning column, if any
3264                  */
3265                 appendPQExpBuffer(query,
3266                                                   "SELECT c.tableoid, c.oid, relname, "
3267                                                   "relacl, relkind, relnamespace, "
3268                                                   "(%s relowner) AS rolname, "
3269                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3270                                                   "relhasindex, relhasrules, relhasoids, "
3271                                                   "0 AS relfrozenxid, "
3272                                                   "d.refobjid AS owning_tab, "
3273                                                   "d.refobjsubid AS owning_col, "
3274                                                   "NULL AS reltablespace, "
3275                                                   "NULL AS reloptions, "
3276                                                   "NULL AS toast_reloptions "
3277                                                   "FROM pg_class c "
3278                                                   "LEFT JOIN pg_depend d ON "
3279                                                   "(c.relkind = '%c' AND "
3280                                                   "d.classid = c.tableoid AND d.objid = c.oid AND "
3281                                                   "d.objsubid = 0 AND "
3282                                                   "d.refclassid = c.tableoid AND d.deptype = 'i') "
3283                                                   "WHERE relkind IN ('%c', '%c', '%c', '%c') "
3284                                                   "ORDER BY c.oid",
3285                                                   username_subquery,
3286                                                   RELKIND_SEQUENCE,
3287                                                   RELKIND_RELATION, RELKIND_SEQUENCE,
3288                                                   RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3289         }
3290         else if (g_fout->remoteVersion >= 70200)
3291         {
3292                 appendPQExpBuffer(query,
3293                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
3294                                                   "0::oid AS relnamespace, "
3295                                                   "(%s relowner) AS rolname, "
3296                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3297                                                   "relhasindex, relhasrules, relhasoids, "
3298                                                   "0 AS relfrozenxid, "
3299                                                   "NULL::oid AS owning_tab, "
3300                                                   "NULL::int4 AS owning_col, "
3301                                                   "NULL AS reltablespace, "
3302                                                   "NULL AS reloptions, "
3303                                                   "NULL AS toast_reloptions "
3304                                                   "FROM pg_class "
3305                                                   "WHERE relkind IN ('%c', '%c', '%c') "
3306                                                   "ORDER BY oid",
3307                                                   username_subquery,
3308                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3309         }
3310         else if (g_fout->remoteVersion >= 70100)
3311         {
3312                 /* all tables have oids in 7.1 */
3313                 appendPQExpBuffer(query,
3314                                                   "SELECT tableoid, oid, relname, relacl, relkind, "
3315                                                   "0::oid AS relnamespace, "
3316                                                   "(%s relowner) AS rolname, "
3317                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3318                                                   "relhasindex, relhasrules, "
3319                                                   "'t'::bool AS relhasoids, "
3320                                                   "0 AS relfrozenxid, "
3321                                                   "NULL::oid AS owning_tab, "
3322                                                   "NULL::int4 AS owning_col, "
3323                                                   "NULL AS reltablespace, "
3324                                                   "NULL AS reloptions, "
3325                                                   "NULL AS toast_reloptions "
3326                                                   "FROM pg_class "
3327                                                   "WHERE relkind IN ('%c', '%c', '%c') "
3328                                                   "ORDER BY oid",
3329                                                   username_subquery,
3330                                                   RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3331         }
3332         else
3333         {
3334                 /*
3335                  * Before 7.1, view relkind was not set to 'v', so we must check if we
3336                  * have a view by looking for a rule in pg_rewrite.
3337                  */
3338                 appendPQExpBuffer(query,
3339                                                   "SELECT "
3340                 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3341                                                   "oid, relname, relacl, "
3342                                                   "CASE WHEN relhasrules and relkind = 'r' "
3343                                           "  and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
3344                                           "             r.ev_class = c.oid AND r.ev_type = '1') "
3345                                                   "THEN '%c'::\"char\" "
3346                                                   "ELSE relkind END AS relkind,"
3347                                                   "0::oid AS relnamespace, "
3348                                                   "(%s relowner) AS rolname, "
3349                                                   "relchecks, (reltriggers <> 0) AS relhastriggers, "
3350                                                   "relhasindex, relhasrules, "
3351                                                   "'t'::bool AS relhasoids, "
3352                                                   "0 as relfrozenxid, "
3353                                                   "NULL::oid AS owning_tab, "
3354                                                   "NULL::int4 AS owning_col, "
3355                                                   "NULL AS reltablespace, "
3356                                                   "NULL AS reloptions, "
3357                                                   "NULL AS toast_reloptions "
3358                                                   "FROM pg_class c "
3359                                                   "WHERE relkind IN ('%c', '%c') "
3360                                                   "ORDER BY oid",
3361                                                   RELKIND_VIEW,
3362                                                   username_subquery,
3363                                                   RELKIND_RELATION, RELKIND_SEQUENCE);
3364         }
3365
3366         res = PQexec(g_conn, query->data);
3367         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3368
3369         ntups = PQntuples(res);
3370
3371         *numTables = ntups;
3372
3373         /*
3374          * Extract data from result and lock dumpable tables.  We do the locking
3375          * before anything else, to minimize the window wherein a table could
3376          * disappear under us.
3377          *
3378          * Note that we have to save info about all tables here, even when dumping
3379          * only one, because we don't yet know which tables might be inheritance
3380          * ancestors of the target table.
3381          */
3382         tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
3383
3384         i_reltableoid = PQfnumber(res, "tableoid");
3385         i_reloid = PQfnumber(res, "oid");
3386         i_relname = PQfnumber(res, "relname");
3387         i_relnamespace = PQfnumber(res, "relnamespace");
3388         i_relacl = PQfnumber(res, "relacl");
3389         i_relkind = PQfnumber(res, "relkind");
3390         i_rolname = PQfnumber(res, "rolname");
3391         i_relchecks = PQfnumber(res, "relchecks");
3392         i_relhastriggers = PQfnumber(res, "relhastriggers");
3393         i_relhasindex = PQfnumber(res, "relhasindex");
3394         i_relhasrules = PQfnumber(res, "relhasrules");
3395         i_relhasoids = PQfnumber(res, "relhasoids");
3396         i_relfrozenxid = PQfnumber(res, "relfrozenxid");
3397         i_owning_tab = PQfnumber(res, "owning_tab");
3398         i_owning_col = PQfnumber(res, "owning_col");
3399         i_reltablespace = PQfnumber(res, "reltablespace");
3400         i_reloptions = PQfnumber(res, "reloptions");
3401         i_toastreloptions = PQfnumber(res, "toast_reloptions");
3402
3403         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3404         {
3405                 /*
3406                  * Arrange to fail instead of waiting forever for a table lock.
3407                  *
3408                  * NB: this coding assumes that the only queries issued within
3409                  * the following loop are LOCK TABLEs; else the timeout may be
3410                  * undesirably applied to other things too.
3411                  */
3412                 resetPQExpBuffer(query);
3413                 appendPQExpBuffer(query, "SET statement_timeout = ");
3414                 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3415                 do_sql_command(g_conn, query->data);
3416         }
3417
3418         for (i = 0; i < ntups; i++)
3419         {
3420                 tblinfo[i].dobj.objType = DO_TABLE;
3421                 tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
3422                 tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
3423                 AssignDumpId(&tblinfo[i].dobj);
3424                 tblinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_relname));
3425                 tblinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_relnamespace)),
3426                                                                                                   tblinfo[i].dobj.catId.oid);
3427                 tblinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
3428                 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
3429                 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
3430                 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
3431                 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
3432                 tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
3433                 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
3434                 tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
3435                 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
3436                 if (PQgetisnull(res, i, i_owning_tab))
3437                 {
3438                         tblinfo[i].owning_tab = InvalidOid;
3439                         tblinfo[i].owning_col = 0;
3440                 }
3441                 else
3442                 {
3443                         tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3444                         tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
3445                 }
3446                 tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
3447                 tblinfo[i].reloptions = strdup(PQgetvalue(res, i, i_reloptions));
3448                 tblinfo[i].toast_reloptions = strdup(PQgetvalue(res, i, i_toastreloptions));
3449
3450                 /* other fields were zeroed above */
3451
3452                 /*
3453                  * Decide whether we want to dump this table.
3454                  */
3455                 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3456                         tblinfo[i].dobj.dump = false;
3457                 else
3458                         selectDumpableTable(&tblinfo[i]);
3459                 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3460
3461                 /*
3462                  * Read-lock target tables to make sure they aren't DROPPED or altered
3463                  * in schema before we get around to dumping them.
3464                  *
3465                  * Note that we don't explicitly lock parents of the target tables; we
3466                  * assume our lock on the child is enough to prevent schema
3467                  * alterations to parent tables.
3468                  *
3469                  * NOTE: it'd be kinda nice to lock views and sequences too, not only
3470                  * plain tables, but the backend doesn't presently allow that.
3471                  */
3472                 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
3473                 {
3474                         resetPQExpBuffer(query);
3475                         appendPQExpBuffer(query,
3476                                                           "LOCK TABLE %s IN ACCESS SHARE MODE",
3477                                                  fmtQualifiedId(tblinfo[i].dobj.namespace->dobj.name,
3478                                                                                 tblinfo[i].dobj.name));
3479                         do_sql_command(g_conn, query->data);
3480                 }
3481
3482                 /* Emit notice if join for owner failed */
3483                 if (strlen(tblinfo[i].rolname) == 0)
3484                         write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
3485                                           tblinfo[i].dobj.name);
3486         }
3487
3488         if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3489         {
3490                 do_sql_command(g_conn, "SET statement_timeout = 0");
3491         }
3492
3493         PQclear(res);
3494
3495         /*
3496          * Force sequences that are "owned" by table columns to be dumped whenever
3497          * their owning table is being dumped.
3498          */
3499         for (i = 0; i < ntups; i++)
3500         {
3501                 TableInfo  *seqinfo = &tblinfo[i];
3502                 int                     j;
3503
3504                 if (!OidIsValid(seqinfo->owning_tab))
3505                         continue;                       /* not an owned sequence */
3506                 if (seqinfo->dobj.dump)
3507                         continue;                       /* no need to search */
3508
3509                 /* can't use findTableByOid yet, unfortunately */
3510                 for (j = 0; j < ntups; j++)
3511                 {
3512                         if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3513                         {
3514                                 if (tblinfo[j].dobj.dump)
3515                                 {
3516                                         seqinfo->interesting = true;
3517                                         seqinfo->dobj.dump = true;
3518                                 }
3519                                 break;
3520                         }
3521                 }
3522         }
3523
3524         destroyPQExpBuffer(query);
3525
3526         return tblinfo;
3527 }
3528
3529 /*
3530  * getInherits
3531  *        read all the inheritance information
3532  * from the system catalogs return them in the InhInfo* structure
3533  *
3534  * numInherits is set to the number of pairs read in
3535  */
3536 InhInfo *
3537 getInherits(int *numInherits)
3538 {
3539         PGresult   *res;
3540         int                     ntups;
3541         int                     i;
3542         PQExpBuffer query = createPQExpBuffer();
3543         InhInfo    *inhinfo;
3544
3545         int                     i_inhrelid;
3546         int                     i_inhparent;
3547
3548         /* Make sure we are in proper schema */
3549         selectSourceSchema("pg_catalog");
3550
3551         /* find all the inheritance information */
3552
3553         appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
3554
3555         res = PQexec(g_conn, query->data);
3556         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3557
3558         ntups = PQntuples(res);
3559
3560         *numInherits = ntups;
3561
3562         inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3563
3564         i_inhrelid = PQfnumber(res, "inhrelid");
3565         i_inhparent = PQfnumber(res, "inhparent");
3566
3567         for (i = 0; i < ntups; i++)
3568         {
3569                 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3570                 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3571         }
3572
3573         PQclear(res);
3574
3575         destroyPQExpBuffer(query);
3576
3577         return inhinfo;
3578 }
3579
3580 /*
3581  * getIndexes
3582  *        get information about every index on a dumpable table
3583  *
3584  * Note: index data is not returned directly to the caller, but it
3585  * does get entered into the DumpableObject tables.
3586  */
3587 void
3588 getIndexes(TableInfo tblinfo[], int numTables)
3589 {
3590         int                     i,
3591                                 j;
3592         PQExpBuffer query = createPQExpBuffer();
3593         PGresult   *res;
3594         IndxInfo   *indxinfo;
3595         ConstraintInfo *constrinfo;
3596         int                     i_tableoid,
3597                                 i_oid,
3598                                 i_indexname,
3599                                 i_indexdef,
3600                                 i_indnkeys,
3601                                 i_indkey,
3602                                 i_indisclustered,
3603                                 i_contype,
3604                                 i_conname,
3605                                 i_contableoid,
3606                                 i_conoid,
3607                                 i_tablespace,
3608                                 i_options;
3609         int                     ntups;
3610
3611         for (i = 0; i < numTables; i++)
3612         {
3613                 TableInfo  *tbinfo = &tblinfo[i];
3614
3615                 /* Only plain tables have indexes */
3616                 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3617                         continue;
3618
3619                 /* Ignore indexes of tables not to be dumped */
3620                 if (!tbinfo->dobj.dump)
3621                         continue;
3622
3623                 if (g_verbose)
3624                         write_msg(NULL, "reading indexes for table \"%s\"\n",
3625                                           tbinfo->dobj.name);
3626
3627                 /* Make sure we are in proper schema so indexdef is right */
3628                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3629
3630                 /*
3631                  * The point of the messy-looking outer join is to find a constraint
3632                  * that is related by an internal dependency link to the index. If we
3633                  * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
3634                  * assume an index won't have more than one internal dependency.
3635                  */
3636                 resetPQExpBuffer(query);
3637                 if (g_fout->remoteVersion >= 80200)
3638                 {
3639                         appendPQExpBuffer(query,
3640                                                           "SELECT t.tableoid, t.oid, "
3641                                                           "t.relname AS indexname, "
3642                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3643                                                           "t.relnatts AS indnkeys, "
3644                                                           "i.indkey, i.indisclustered, "
3645                                                           "c.contype, c.conname, "
3646                                                           "c.tableoid AS contableoid, "
3647                                                           "c.oid AS conoid, "
3648                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3649                                                         "array_to_string(t.reloptions, ', ') AS options "
3650                                                           "FROM pg_catalog.pg_index i "
3651                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3652                                                           "LEFT JOIN pg_catalog.pg_depend d "
3653                                                           "ON (d.classid = t.tableoid "
3654                                                           "AND d.objid = t.oid "
3655                                                           "AND d.deptype = 'i') "
3656                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3657                                                           "ON (d.refclassid = c.tableoid "
3658                                                           "AND d.refobjid = c.oid) "
3659                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3660                                                           "ORDER BY indexname",
3661                                                           tbinfo->dobj.catId.oid);
3662                 }
3663                 else if (g_fout->remoteVersion >= 80000)
3664                 {
3665                         appendPQExpBuffer(query,
3666                                                           "SELECT t.tableoid, t.oid, "
3667                                                           "t.relname AS indexname, "
3668                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3669                                                           "t.relnatts AS indnkeys, "
3670                                                           "i.indkey, i.indisclustered, "
3671                                                           "c.contype, c.conname, "
3672                                                           "c.tableoid AS contableoid, "
3673                                                           "c.oid AS conoid, "
3674                                                           "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
3675                                                           "null AS options "
3676                                                           "FROM pg_catalog.pg_index i "
3677                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3678                                                           "LEFT JOIN pg_catalog.pg_depend d "
3679                                                           "ON (d.classid = t.tableoid "
3680                                                           "AND d.objid = t.oid "
3681                                                           "AND d.deptype = 'i') "
3682                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3683                                                           "ON (d.refclassid = c.tableoid "
3684                                                           "AND d.refobjid = c.oid) "
3685                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3686                                                           "ORDER BY indexname",
3687                                                           tbinfo->dobj.catId.oid);
3688                 }
3689                 else if (g_fout->remoteVersion >= 70300)
3690                 {
3691                         appendPQExpBuffer(query,
3692                                                           "SELECT t.tableoid, t.oid, "
3693                                                           "t.relname AS indexname, "
3694                                          "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
3695                                                           "t.relnatts AS indnkeys, "
3696                                                           "i.indkey, i.indisclustered, "
3697                                                           "c.contype, c.conname, "
3698                                                           "c.tableoid AS contableoid, "
3699                                                           "c.oid AS conoid, "
3700                                                           "NULL AS tablespace, "
3701                                                           "null AS options "
3702                                                           "FROM pg_catalog.pg_index i "
3703                                           "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
3704                                                           "LEFT JOIN pg_catalog.pg_depend d "
3705                                                           "ON (d.classid = t.tableoid "
3706                                                           "AND d.objid = t.oid "
3707                                                           "AND d.deptype = 'i') "
3708                                                           "LEFT JOIN pg_catalog.pg_constraint c "
3709                                                           "ON (d.refclassid = c.tableoid "
3710                                                           "AND d.refobjid = c.oid) "
3711                                                           "WHERE i.indrelid = '%u'::pg_catalog.oid "
3712                                                           "ORDER BY indexname",
3713                                                           tbinfo->dobj.catId.oid);
3714                 }
3715                 else if (g_fout->remoteVersion >= 70100)
3716                 {
3717                         appendPQExpBuffer(query,
3718                                                           "SELECT t.tableoid, t.oid, "
3719                                                           "t.relname AS indexname, "
3720                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
3721                                                           "t.relnatts AS indnkeys, "
3722                                                           "i.indkey, false AS indisclustered, "
3723                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
3724                                                           "ELSE '0'::char END AS contype, "
3725                                                           "t.relname AS conname, "
3726                                                           "0::oid AS contableoid, "
3727                                                           "t.oid AS conoid, "
3728                                                           "NULL AS tablespace, "
3729                                                           "null AS options "
3730                                                           "FROM pg_index i, pg_class t "
3731                                                           "WHERE t.oid = i.indexrelid "
3732                                                           "AND i.indrelid = '%u'::oid "
3733                                                           "ORDER BY indexname",
3734                                                           tbinfo->dobj.catId.oid);
3735                 }
3736                 else
3737                 {
3738                         appendPQExpBuffer(query,
3739                                                           "SELECT "
3740                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
3741                                                           "t.oid, "
3742                                                           "t.relname AS indexname, "
3743                                                           "pg_get_indexdef(i.indexrelid) AS indexdef, "
3744                                                           "t.relnatts AS indnkeys, "
3745                                                           "i.indkey, false AS indisclustered, "
3746                                                           "CASE WHEN i.indisprimary THEN 'p'::char "
3747                                                           "ELSE '0'::char END AS contype, "
3748                                                           "t.relname AS conname, "
3749                                                           "0::oid AS contableoid, "
3750                                                           "t.oid AS conoid, "
3751                                                           "NULL AS tablespace, "
3752                                                           "null AS options "
3753                                                           "FROM pg_index i, pg_class t "
3754                                                           "WHERE t.oid = i.indexrelid "
3755                                                           "AND i.indrelid = '%u'::oid "
3756                                                           "ORDER BY indexname",
3757                                                           tbinfo->dobj.catId.oid);
3758                 }
3759
3760                 res = PQexec(g_conn, query->data);
3761                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3762
3763                 ntups = PQntuples(res);
3764
3765                 i_tableoid = PQfnumber(res, "tableoid");
3766                 i_oid = PQfnumber(res, "oid");
3767                 i_indexname = PQfnumber(res, "indexname");
3768                 i_indexdef = PQfnumber(res, "indexdef");
3769                 i_indnkeys = PQfnumber(res, "indnkeys");
3770                 i_indkey = PQfnumber(res, "indkey");
3771                 i_indisclustered = PQfnumber(res, "indisclustered");
3772                 i_contype = PQfnumber(res, "contype");
3773                 i_conname = PQfnumber(res, "conname");
3774                 i_contableoid = PQfnumber(res, "contableoid");
3775                 i_conoid = PQfnumber(res, "conoid");
3776                 i_tablespace = PQfnumber(res, "tablespace");
3777                 i_options = PQfnumber(res, "options");
3778
3779                 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3780                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3781
3782                 for (j = 0; j < ntups; j++)
3783                 {
3784                         char            contype;
3785
3786                         indxinfo[j].dobj.objType = DO_INDEX;
3787                         indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
3788                         indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3789                         AssignDumpId(&indxinfo[j].dobj);
3790                         indxinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_indexname));
3791                         indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3792                         indxinfo[j].indextable = tbinfo;
3793                         indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
3794                         indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
3795                         indxinfo[j].tablespace = strdup(PQgetvalue(res, j, i_tablespace));
3796                         indxinfo[j].options = strdup(PQgetvalue(res, j, i_options));
3797
3798                         /*
3799                          * In pre-7.4 releases, indkeys may contain more entries than
3800                          * indnkeys says (since indnkeys will be 1 for a functional
3801                          * index).      We don't actually care about this case since we don't
3802                          * examine indkeys except for indexes associated with PRIMARY and
3803                          * UNIQUE constraints, which are never functional indexes. But we
3804                          * have to allocate enough space to keep parseOidArray from
3805                          * complaining.
3806                          */
3807                         indxinfo[j].indkeys = (Oid *) malloc(INDEX_MAX_KEYS * sizeof(Oid));
3808                         parseOidArray(PQgetvalue(res, j, i_indkey),
3809                                                   indxinfo[j].indkeys, INDEX_MAX_KEYS);
3810                         indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
3811                         contype = *(PQgetvalue(res, j, i_contype));
3812
3813                         if (contype == 'p' || contype == 'u')
3814                         {
3815                                 /*
3816                                  * If we found a constraint matching the index, create an
3817                                  * entry for it.
3818                                  *
3819                                  * In a pre-7.3 database, we take this path iff the index was
3820                                  * marked indisprimary.
3821                                  */
3822                                 constrinfo[j].dobj.objType = DO_CONSTRAINT;
3823                                 constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3824                                 constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3825                                 AssignDumpId(&constrinfo[j].dobj);
3826                                 constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3827                                 constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3828                                 constrinfo[j].contable = tbinfo;
3829                                 constrinfo[j].condomain = NULL;
3830                                 constrinfo[j].contype = contype;
3831                                 constrinfo[j].condef = NULL;
3832                                 constrinfo[j].confrelid = InvalidOid;
3833                                 constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
3834                                 constrinfo[j].conislocal = true;
3835                                 constrinfo[j].separate = true;
3836
3837                                 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
3838
3839                                 /* If pre-7.3 DB, better make sure table comes first */
3840                                 addObjectDependency(&constrinfo[j].dobj,
3841                                                                         tbinfo->dobj.dumpId);
3842                         }
3843                         else
3844                         {
3845                                 /* Plain secondary index */
3846                                 indxinfo[j].indexconstraint = 0;
3847                         }
3848                 }
3849
3850                 PQclear(res);
3851         }
3852
3853         destroyPQExpBuffer(query);
3854 }
3855
3856 /*
3857  * getConstraints
3858  *
3859  * Get info about constraints on dumpable tables.
3860  *
3861  * Currently handles foreign keys only.
3862  * Unique and primary key constraints are handled with indexes,
3863  * while check constraints are processed in getTableAttrs().
3864  */
3865 void
3866 getConstraints(TableInfo tblinfo[], int numTables)
3867 {
3868         int                     i,
3869                                 j;
3870         ConstraintInfo *constrinfo;
3871         PQExpBuffer query;
3872         PGresult   *res;
3873         int                     i_contableoid,
3874                                 i_conoid,
3875                                 i_conname,
3876                                 i_confrelid,
3877                                 i_condef;
3878         int                     ntups;
3879
3880         /* pg_constraint was created in 7.3, so nothing to do if older */
3881         if (g_fout->remoteVersion < 70300)
3882                 return;
3883
3884         query = createPQExpBuffer();
3885
3886         for (i = 0; i < numTables; i++)
3887         {
3888                 TableInfo  *tbinfo = &tblinfo[i];
3889
3890                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
3891                         continue;
3892
3893                 if (g_verbose)
3894                         write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
3895                                           tbinfo->dobj.name);
3896
3897                 /*
3898                  * select table schema to ensure constraint expr is qualified if
3899                  * needed
3900                  */
3901                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
3902
3903                 resetPQExpBuffer(query);
3904                 appendPQExpBuffer(query,
3905                                                   "SELECT tableoid, oid, conname, confrelid, "
3906                                                   "pg_catalog.pg_get_constraintdef(oid) AS condef "
3907                                                   "FROM pg_catalog.pg_constraint "
3908                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
3909                                                   "AND contype = 'f'",
3910                                                   tbinfo->dobj.catId.oid);
3911                 res = PQexec(g_conn, query->data);
3912                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3913
3914                 ntups = PQntuples(res);
3915
3916                 i_contableoid = PQfnumber(res, "tableoid");
3917                 i_conoid = PQfnumber(res, "oid");
3918                 i_conname = PQfnumber(res, "conname");
3919                 i_confrelid = PQfnumber(res, "confrelid");
3920                 i_condef = PQfnumber(res, "condef");
3921
3922                 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3923
3924                 for (j = 0; j < ntups; j++)
3925                 {
3926                         constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
3927                         constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
3928                         constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
3929                         AssignDumpId(&constrinfo[j].dobj);
3930                         constrinfo[j].dobj.name = strdup(PQgetvalue(res, j, i_conname));
3931                         constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3932                         constrinfo[j].contable = tbinfo;
3933                         constrinfo[j].condomain = NULL;
3934                         constrinfo[j].contype = 'f';
3935                         constrinfo[j].condef = strdup(PQgetvalue(res, j, i_condef));
3936                         constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
3937                         constrinfo[j].conindex = 0;
3938                         constrinfo[j].conislocal = true;
3939                         constrinfo[j].separate = true;
3940                 }
3941
3942                 PQclear(res);
3943         }
3944
3945         destroyPQExpBuffer(query);
3946 }
3947
3948 /*
3949  * getDomainConstraints
3950  *
3951  * Get info about constraints on a domain.
3952  */
3953 static void
3954 getDomainConstraints(TypeInfo *tinfo)
3955 {
3956         int                     i;
3957         ConstraintInfo *constrinfo;
3958         PQExpBuffer query;
3959         PGresult   *res;
3960         int                     i_tableoid,
3961                                 i_oid,
3962                                 i_conname,
3963                                 i_consrc;
3964         int                     ntups;
3965
3966         /* pg_constraint was created in 7.3, so nothing to do if older */
3967         if (g_fout->remoteVersion < 70300)
3968                 return;
3969
3970         /*
3971          * select appropriate schema to ensure names in constraint are properly
3972          * qualified
3973          */
3974         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
3975
3976         query = createPQExpBuffer();
3977
3978         if (g_fout->remoteVersion >= 70400)
3979                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3980                                                   "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3981                                                   "FROM pg_catalog.pg_constraint "
3982                                                   "WHERE contypid = '%u'::pg_catalog.oid "
3983                                                   "ORDER BY conname",
3984                                                   tinfo->dobj.catId.oid);
3985         else
3986                 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
3987                                                   "'CHECK (' || consrc || ')' AS consrc "
3988                                                   "FROM pg_catalog.pg_constraint "
3989                                                   "WHERE contypid = '%u'::pg_catalog.oid "
3990                                                   "ORDER BY conname",
3991                                                   tinfo->dobj.catId.oid);
3992
3993         res = PQexec(g_conn, query->data);
3994         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3995
3996         ntups = PQntuples(res);
3997
3998         i_tableoid = PQfnumber(res, "tableoid");
3999         i_oid = PQfnumber(res, "oid");
4000         i_conname = PQfnumber(res, "conname");
4001         i_consrc = PQfnumber(res, "consrc");
4002
4003         constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4004
4005         tinfo->nDomChecks = ntups;
4006         tinfo->domChecks = constrinfo;
4007
4008         for (i = 0; i < ntups; i++)
4009         {
4010                 constrinfo[i].dobj.objType = DO_CONSTRAINT;
4011                 constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4012                 constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4013                 AssignDumpId(&constrinfo[i].dobj);
4014                 constrinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_conname));
4015                 constrinfo[i].dobj.namespace = tinfo->dobj.namespace;
4016                 constrinfo[i].contable = NULL;
4017                 constrinfo[i].condomain = tinfo;
4018                 constrinfo[i].contype = 'c';
4019                 constrinfo[i].condef = strdup(PQgetvalue(res, i, i_consrc));
4020                 constrinfo[i].confrelid = InvalidOid;
4021                 constrinfo[i].conindex = 0;
4022                 constrinfo[i].conislocal = true;
4023                 constrinfo[i].separate = false;
4024
4025                 /*
4026                  * Make the domain depend on the constraint, ensuring it won't be
4027                  * output till any constraint dependencies are OK.
4028                  */
4029                 addObjectDependency(&tinfo->dobj,
4030                                                         constrinfo[i].dobj.dumpId);
4031         }
4032
4033         PQclear(res);
4034
4035         destroyPQExpBuffer(query);
4036 }
4037
4038 /*
4039  * getRules
4040  *        get basic information about every rule in the system
4041  *
4042  * numRules is set to the number of rules read in
4043  */
4044 RuleInfo *
4045 getRules(int *numRules)
4046 {
4047         PGresult   *res;
4048         int                     ntups;
4049         int                     i;
4050         PQExpBuffer query = createPQExpBuffer();
4051         RuleInfo   *ruleinfo;
4052         int                     i_tableoid;
4053         int                     i_oid;
4054         int                     i_rulename;
4055         int                     i_ruletable;
4056         int                     i_ev_type;
4057         int                     i_is_instead;
4058         int                     i_ev_enabled;
4059
4060         /* Make sure we are in proper schema */
4061         selectSourceSchema("pg_catalog");
4062
4063         if (g_fout->remoteVersion >= 80300)
4064         {
4065                 appendPQExpBuffer(query, "SELECT "
4066                                                   "tableoid, oid, rulename, "
4067                                                   "ev_class AS ruletable, ev_type, is_instead, "
4068                                                   "ev_enabled "
4069                                                   "FROM pg_rewrite "
4070                                                   "ORDER BY oid");
4071         }
4072         else if (g_fout->remoteVersion >= 70100)
4073         {
4074                 appendPQExpBuffer(query, "SELECT "
4075                                                   "tableoid, oid, rulename, "
4076                                                   "ev_class AS ruletable, ev_type, is_instead, "
4077                                                   "'O'::char AS ev_enabled "
4078                                                   "FROM pg_rewrite "
4079                                                   "ORDER BY oid");
4080         }
4081         else
4082         {
4083                 appendPQExpBuffer(query, "SELECT "
4084                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4085                                                   "oid, rulename, "
4086                                                   "ev_class AS ruletable, ev_type, is_instead, "
4087                                                   "'O'::char AS ev_enabled "
4088                                                   "FROM pg_rewrite "
4089                                                   "ORDER BY oid");
4090         }
4091
4092         res = PQexec(g_conn, query->data);
4093         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4094
4095         ntups = PQntuples(res);
4096
4097         *numRules = ntups;
4098
4099         ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
4100
4101         i_tableoid = PQfnumber(res, "tableoid");
4102         i_oid = PQfnumber(res, "oid");
4103         i_rulename = PQfnumber(res, "rulename");
4104         i_ruletable = PQfnumber(res, "ruletable");
4105         i_ev_type = PQfnumber(res, "ev_type");
4106         i_is_instead = PQfnumber(res, "is_instead");
4107         i_ev_enabled = PQfnumber(res, "ev_enabled");
4108
4109         for (i = 0; i < ntups; i++)
4110         {
4111                 Oid                     ruletableoid;
4112
4113                 ruleinfo[i].dobj.objType = DO_RULE;
4114                 ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4115                 ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4116                 AssignDumpId(&ruleinfo[i].dobj);
4117                 ruleinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_rulename));
4118                 ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
4119                 ruleinfo[i].ruletable = findTableByOid(ruletableoid);
4120                 if (ruleinfo[i].ruletable == NULL)
4121                 {
4122                         write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4123                                           ruletableoid,
4124                                           ruleinfo[i].dobj.catId.oid);
4125                         exit_nicely();
4126                 }
4127                 ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
4128                 ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
4129                 ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
4130                 ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
4131                 ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
4132                 if (ruleinfo[i].ruletable)
4133                 {
4134                         /*
4135                          * If the table is a view, force its ON SELECT rule to be sorted
4136                          * before the view itself --- this ensures that any dependencies
4137                          * for the rule affect the table's positioning. Other rules are
4138                          * forced to appear after their table.
4139                          */
4140                         if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4141                                 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
4142                         {
4143                                 addObjectDependency(&ruleinfo[i].ruletable->dobj,
4144                                                                         ruleinfo[i].dobj.dumpId);
4145                                 /* We'll merge the rule into CREATE VIEW, if possible */
4146                                 ruleinfo[i].separate = false;
4147                         }
4148                         else
4149                         {
4150                                 addObjectDependency(&ruleinfo[i].dobj,
4151                                                                         ruleinfo[i].ruletable->dobj.dumpId);
4152                                 ruleinfo[i].separate = true;
4153                         }
4154                 }
4155                 else
4156                         ruleinfo[i].separate = true;
4157         }
4158
4159         PQclear(res);
4160
4161         destroyPQExpBuffer(query);
4162
4163         return ruleinfo;
4164 }
4165
4166 /*
4167  * getTriggers
4168  *        get information about every trigger on a dumpable table
4169  *
4170  * Note: trigger data is not returned directly to the caller, but it
4171  * does get entered into the DumpableObject tables.
4172  */
4173 void
4174 getTriggers(TableInfo tblinfo[], int numTables)
4175 {
4176         int                     i,
4177                                 j;
4178         PQExpBuffer query = createPQExpBuffer();
4179         PGresult   *res;
4180         TriggerInfo *tginfo;
4181         int                     i_tableoid,
4182                                 i_oid,
4183                                 i_tgname,
4184                                 i_tgfname,
4185                                 i_tgtype,
4186                                 i_tgnargs,
4187                                 i_tgargs,
4188                                 i_tgisconstraint,
4189                                 i_tgconstrname,
4190                                 i_tgconstrrelid,
4191                                 i_tgconstrrelname,
4192                                 i_tgenabled,
4193                                 i_tgdeferrable,
4194                                 i_tginitdeferred;
4195         int                     ntups;
4196
4197         for (i = 0; i < numTables; i++)
4198         {
4199                 TableInfo  *tbinfo = &tblinfo[i];
4200
4201                 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4202                         continue;
4203
4204                 if (g_verbose)
4205                         write_msg(NULL, "reading triggers for table \"%s\"\n",
4206                                           tbinfo->dobj.name);
4207
4208                 /*
4209                  * select table schema to ensure regproc name is qualified if needed
4210                  */
4211                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4212
4213                 resetPQExpBuffer(query);
4214                 if (g_fout->remoteVersion >= 80300)
4215                 {
4216                         /*
4217                          * We ignore triggers that are tied to a foreign-key constraint
4218                          */
4219                         appendPQExpBuffer(query,
4220                                                           "SELECT tgname, "
4221                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
4222                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4223                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4224                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4225                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4226                                                           "FROM pg_catalog.pg_trigger t "
4227                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
4228                                                           "AND tgconstraint = 0",
4229                                                           tbinfo->dobj.catId.oid);
4230                 }
4231                 else if (g_fout->remoteVersion >= 70300)
4232                 {
4233                         /*
4234                          * We ignore triggers that are tied to a foreign-key constraint,
4235                          * but in these versions we have to grovel through pg_constraint
4236                          * to find out
4237                          */
4238                         appendPQExpBuffer(query,
4239                                                           "SELECT tgname, "
4240                                                           "tgfoid::pg_catalog.regproc AS tgfname, "
4241                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4242                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4243                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4244                                          "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
4245                                                           "FROM pg_catalog.pg_trigger t "
4246                                                           "WHERE tgrelid = '%u'::pg_catalog.oid "
4247                                                           "AND (NOT tgisconstraint "
4248                                                           " OR NOT EXISTS"
4249                                                           "  (SELECT 1 FROM pg_catalog.pg_depend d "
4250                                                           "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
4251                                                           "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
4252                                                           tbinfo->dobj.catId.oid);
4253                 }
4254                 else if (g_fout->remoteVersion >= 70100)
4255                 {
4256                         appendPQExpBuffer(query,
4257                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
4258                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4259                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4260                                                           "tgconstrrelid, tginitdeferred, tableoid, oid, "
4261                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4262                                                           "             AS tgconstrrelname "
4263                                                           "FROM pg_trigger "
4264                                                           "WHERE tgrelid = '%u'::oid",
4265                                                           tbinfo->dobj.catId.oid);
4266                 }
4267                 else
4268                 {
4269                         appendPQExpBuffer(query,
4270                                                           "SELECT tgname, tgfoid::regproc AS tgfname, "
4271                                                           "tgtype, tgnargs, tgargs, tgenabled, "
4272                                                           "tgisconstraint, tgconstrname, tgdeferrable, "
4273                                                           "tgconstrrelid, tginitdeferred, "
4274                                                           "(SELECT oid FROM pg_class WHERE relname = 'pg_trigger') AS tableoid, "
4275                                                           "oid, "
4276                                   "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4277                                                           "             AS tgconstrrelname "
4278                                                           "FROM pg_trigger "
4279                                                           "WHERE tgrelid = '%u'::oid",
4280                                                           tbinfo->dobj.catId.oid);
4281                 }
4282                 res = PQexec(g_conn, query->data);
4283                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4284
4285                 ntups = PQntuples(res);
4286
4287                 i_tableoid = PQfnumber(res, "tableoid");
4288                 i_oid = PQfnumber(res, "oid");
4289                 i_tgname = PQfnumber(res, "tgname");
4290                 i_tgfname = PQfnumber(res, "tgfname");
4291                 i_tgtype = PQfnumber(res, "tgtype");
4292                 i_tgnargs = PQfnumber(res, "tgnargs");
4293                 i_tgargs = PQfnumber(res, "tgargs");
4294                 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
4295                 i_tgconstrname = PQfnumber(res, "tgconstrname");
4296                 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
4297                 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
4298                 i_tgenabled = PQfnumber(res, "tgenabled");
4299                 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
4300                 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
4301
4302                 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4303
4304                 for (j = 0; j < ntups; j++)
4305                 {
4306                         tginfo[j].dobj.objType = DO_TRIGGER;
4307                         tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
4308                         tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
4309                         AssignDumpId(&tginfo[j].dobj);
4310                         tginfo[j].dobj.name = strdup(PQgetvalue(res, j, i_tgname));
4311                         tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
4312                         tginfo[j].tgtable = tbinfo;
4313                         tginfo[j].tgfname = strdup(PQgetvalue(res, j, i_tgfname));
4314                         tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
4315                         tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
4316                         tginfo[j].tgargs = strdup(PQgetvalue(res, j, i_tgargs));
4317                         tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
4318                         tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
4319                         tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
4320                         tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
4321
4322                         if (tginfo[j].tgisconstraint)
4323                         {
4324                                 tginfo[j].tgconstrname = strdup(PQgetvalue(res, j, i_tgconstrname));
4325                                 tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
4326                                 if (OidIsValid(tginfo[j].tgconstrrelid))
4327                                 {
4328                                         if (PQgetisnull(res, j, i_tgconstrrelname))
4329                                         {
4330                                                 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
4331                                                                   tginfo[j].dobj.name, tbinfo->dobj.name,
4332                                                                   tginfo[j].tgconstrrelid);
4333                                                 exit_nicely();
4334                                         }
4335                                         tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4336                                 }
4337                                 else
4338                                         tginfo[j].tgconstrrelname = NULL;
4339                         }
4340                         else
4341                         {
4342                                 tginfo[j].tgconstrname = NULL;
4343                                 tginfo[j].tgconstrrelid = InvalidOid;
4344                                 tginfo[j].tgconstrrelname = NULL;
4345                         }
4346                 }
4347
4348                 PQclear(res);
4349         }
4350
4351         destroyPQExpBuffer(query);
4352 }
4353
4354 /*
4355  * getProcLangs
4356  *        get basic information about every procedural language in the system
4357  *
4358  * numProcLangs is set to the number of langs read in
4359  *
4360  * NB: this must run after getFuncs() because we assume we can do
4361  * findFuncByOid().
4362  */
4363 ProcLangInfo *
4364 getProcLangs(int *numProcLangs)
4365 {
4366         PGresult   *res;
4367         int                     ntups;
4368         int                     i;
4369         PQExpBuffer query = createPQExpBuffer();
4370         ProcLangInfo *planginfo;
4371         int                     i_tableoid;
4372         int                     i_oid;
4373         int                     i_lanname;
4374         int                     i_lanpltrusted;
4375         int                     i_lanplcallfoid;
4376         int                     i_lanvalidator;
4377         int                     i_lanacl;
4378         int                     i_lanowner;
4379
4380         /* Make sure we are in proper schema */
4381         selectSourceSchema("pg_catalog");
4382
4383         if (g_fout->remoteVersion >= 80300)
4384         {
4385                 /* pg_language has a lanowner column */
4386                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4387                                                   "lanname, lanpltrusted, lanplcallfoid, "
4388                                                   "lanvalidator,  lanacl, "
4389                                                   "(%s lanowner) AS lanowner "
4390                                                   "FROM pg_language "
4391                                                   "WHERE lanispl "
4392                                                   "ORDER BY oid",
4393                                                   username_subquery);
4394         }
4395         else if (g_fout->remoteVersion >= 80100)
4396         {
4397                 /* Languages are owned by the bootstrap superuser, OID 10 */
4398                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4399                                                   "(%s '10') AS lanowner "
4400                                                   "FROM pg_language "
4401                                                   "WHERE lanispl "
4402                                                   "ORDER BY oid",
4403                                                   username_subquery);
4404         }
4405         else if (g_fout->remoteVersion >= 70400)
4406         {
4407                 /* Languages are owned by the bootstrap superuser, sysid 1 */
4408                 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4409                                                   "(%s '1') AS lanowner "
4410                                                   "FROM pg_language "
4411                                                   "WHERE lanispl "
4412                                                   "ORDER BY oid",
4413                                                   username_subquery);
4414         }
4415         else if (g_fout->remoteVersion >= 70100)
4416         {
4417                 /* No clear notion of an owner at all before 7.4 ... */
4418                 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4419                                                   "WHERE lanispl "
4420                                                   "ORDER BY oid");
4421         }
4422         else
4423         {
4424                 appendPQExpBuffer(query, "SELECT "
4425                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4426                                                   "oid, * FROM pg_language "
4427                                                   "WHERE lanispl "
4428                                                   "ORDER BY oid");
4429         }
4430
4431         res = PQexec(g_conn, query->data);
4432         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4433
4434         ntups = PQntuples(res);
4435
4436         *numProcLangs = ntups;
4437
4438         planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
4439
4440         i_tableoid = PQfnumber(res, "tableoid");
4441         i_oid = PQfnumber(res, "oid");
4442         i_lanname = PQfnumber(res, "lanname");
4443         i_lanpltrusted = PQfnumber(res, "lanpltrusted");
4444         i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
4445         /* these may fail and return -1: */
4446         i_lanvalidator = PQfnumber(res, "lanvalidator");
4447         i_lanacl = PQfnumber(res, "lanacl");
4448         i_lanowner = PQfnumber(res, "lanowner");
4449
4450         for (i = 0; i < ntups; i++)
4451         {
4452                 planginfo[i].dobj.objType = DO_PROCLANG;
4453                 planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4454                 planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4455                 AssignDumpId(&planginfo[i].dobj);
4456
4457                 planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
4458                 planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
4459                 planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
4460                 if (i_lanvalidator >= 0)
4461                         planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
4462                 else
4463                         planginfo[i].lanvalidator = InvalidOid;
4464                 if (i_lanacl >= 0)
4465                         planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4466                 else
4467                         planginfo[i].lanacl = strdup("{=U}");
4468                 if (i_lanowner >= 0)
4469                         planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4470                 else
4471                         planginfo[i].lanowner = strdup("");
4472
4473                 if (g_fout->remoteVersion < 70300)
4474                 {
4475                         /*
4476                          * We need to make a dependency to ensure the function will be
4477                          * dumped first.  (In 7.3 and later the regular dependency
4478                          * mechanism will handle this for us.)
4479                          */
4480                         FuncInfo   *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4481
4482                         if (funcInfo)
4483                                 addObjectDependency(&planginfo[i].dobj,
4484                                                                         funcInfo->dobj.dumpId);
4485                 }
4486         }
4487
4488         PQclear(res);
4489
4490         destroyPQExpBuffer(query);
4491
4492         return planginfo;
4493 }
4494
4495 /*
4496  * getCasts
4497  *        get basic information about every cast in the system
4498  *
4499  * numCasts is set to the number of casts read in
4500  */
4501 CastInfo *
4502 getCasts(int *numCasts)
4503 {
4504         PGresult   *res;
4505         int                     ntups;
4506         int                     i;
4507         PQExpBuffer query = createPQExpBuffer();
4508         CastInfo   *castinfo;
4509         int                     i_tableoid;
4510         int                     i_oid;
4511         int                     i_castsource;
4512         int                     i_casttarget;
4513         int                     i_castfunc;
4514         int                     i_castcontext;
4515         int                     i_castmethod;
4516
4517         /* Make sure we are in proper schema */
4518         selectSourceSchema("pg_catalog");
4519
4520         if (g_fout->remoteVersion >= 80400)
4521         {
4522                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4523                                                   "castsource, casttarget, castfunc, castcontext, "
4524                                                   "castmethod "
4525                                                   "FROM pg_cast ORDER BY 3,4");
4526         }
4527         else if (g_fout->remoteVersion >= 70300)
4528         {
4529                 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4530                                                   "castsource, casttarget, castfunc, castcontext, "
4531                                                   "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
4532                                                   "FROM pg_cast ORDER BY 3,4");
4533         }
4534         else
4535         {
4536                 appendPQExpBuffer(query, "SELECT 0 AS tableoid, p.oid, "
4537                                                   "t1.oid AS castsource, t2.oid AS casttarget, "
4538                                                   "p.oid AS castfunc, 'e' AS castcontext, "
4539                                                   "'f' AS castmethod "
4540                                                   "FROM pg_type t1, pg_type t2, pg_proc p "
4541                                                   "WHERE p.pronargs = 1 AND "
4542                                                   "p.proargtypes[0] = t1.oid AND "
4543                                                   "p.prorettype = t2.oid AND p.proname = t2.typname "
4544                                                   "ORDER BY 3,4");
4545         }
4546
4547         res = PQexec(g_conn, query->data);
4548         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4549
4550         ntups = PQntuples(res);
4551
4552         *numCasts = ntups;
4553
4554         castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
4555
4556         i_tableoid = PQfnumber(res, "tableoid");
4557         i_oid = PQfnumber(res, "oid");
4558         i_castsource = PQfnumber(res, "castsource");
4559         i_casttarget = PQfnumber(res, "casttarget");
4560         i_castfunc = PQfnumber(res, "castfunc");
4561         i_castcontext = PQfnumber(res, "castcontext");
4562         i_castmethod = PQfnumber(res, "castmethod");
4563
4564         for (i = 0; i < ntups; i++)
4565         {
4566                 PQExpBufferData namebuf;
4567                 TypeInfo   *sTypeInfo;
4568                 TypeInfo   *tTypeInfo;
4569
4570                 castinfo[i].dobj.objType = DO_CAST;
4571                 castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4572                 castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4573                 AssignDumpId(&castinfo[i].dobj);
4574                 castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
4575                 castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
4576                 castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
4577                 castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
4578                 castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
4579
4580                 /*
4581                  * Try to name cast as concatenation of typnames.  This is only used
4582                  * for purposes of sorting.  If we fail to find either type, the name
4583                  * will be an empty string.
4584                  */
4585                 initPQExpBuffer(&namebuf);
4586                 sTypeInfo = findTypeByOid(castinfo[i].castsource);
4587                 tTypeInfo = findTypeByOid(castinfo[i].casttarget);
4588                 if (sTypeInfo && tTypeInfo)
4589                         appendPQExpBuffer(&namebuf, "%s %s",
4590                                                           sTypeInfo->dobj.name, tTypeInfo->dobj.name);
4591                 castinfo[i].dobj.name = namebuf.data;
4592
4593                 if (OidIsValid(castinfo[i].castfunc))
4594                 {
4595                         /*
4596                          * We need to make a dependency to ensure the function will be
4597                          * dumped first.  (In 7.3 and later the regular dependency
4598                          * mechanism will handle this for us.)
4599                          */
4600                         FuncInfo   *funcInfo;
4601
4602                         funcInfo = findFuncByOid(castinfo[i].castfunc);
4603                         if (funcInfo)
4604                                 addObjectDependency(&castinfo[i].dobj,
4605                                                                         funcInfo->dobj.dumpId);
4606                 }
4607         }
4608
4609         PQclear(res);
4610
4611         destroyPQExpBuffer(query);
4612
4613         return castinfo;
4614 }
4615
4616 /*
4617  * getTableAttrs -
4618  *        for each interesting table, read info about its attributes
4619  *        (names, types, default values, CHECK constraints, etc)
4620  *
4621  * This is implemented in a very inefficient way right now, looping
4622  * through the tblinfo and doing a join per table to find the attrs and their
4623  * types.  However, because we want type names and so forth to be named
4624  * relative to the schema of each table, we couldn't do it in just one
4625  * query.  (Maybe one query per schema?)
4626  *
4627  *      modifies tblinfo
4628  */
4629 void
4630 getTableAttrs(TableInfo *tblinfo, int numTables)
4631 {
4632         int                     i,
4633                                 j;
4634         PQExpBuffer q = createPQExpBuffer();
4635         int                     i_attnum;
4636         int                     i_attname;
4637         int                     i_atttypname;
4638         int                     i_atttypmod;
4639         int                     i_attstattarget;
4640         int                     i_attstorage;
4641         int                     i_typstorage;
4642         int                     i_attnotnull;
4643         int                     i_atthasdef;
4644         int                     i_attisdropped;
4645         int                     i_attlen;
4646         int                     i_attalign;
4647         int                     i_attislocal;
4648         PGresult   *res;
4649         int                     ntups;
4650         bool            hasdefaults;
4651
4652         for (i = 0; i < numTables; i++)
4653         {
4654                 TableInfo  *tbinfo = &tblinfo[i];
4655
4656                 /* Don't bother to collect info for sequences */
4657                 if (tbinfo->relkind == RELKIND_SEQUENCE)
4658                         continue;
4659
4660                 /* Don't bother with uninteresting tables, either */
4661                 if (!tbinfo->interesting)
4662                         continue;
4663
4664                 /*
4665                  * Make sure we are in proper schema for this table; this allows
4666                  * correct retrieval of formatted type names and default exprs
4667                  */
4668                 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4669
4670                 /* find all the user attributes and their types */
4671
4672                 /*
4673                  * we must read the attribute names in attribute number order! because
4674                  * we will use the attnum to index into the attnames array later.  We
4675                  * actually ask to order by "attrelid, attnum" because (at least up to
4676                  * 7.3) the planner is not smart enough to realize it needn't re-sort
4677                  * the output of an indexscan on pg_attribute_relid_attnum_index.
4678                  */
4679                 if (g_verbose)
4680                         write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4681                                           tbinfo->dobj.name);
4682
4683                 resetPQExpBuffer(q);
4684
4685                 if (g_fout->remoteVersion >= 70300)
4686                 {
4687                         /* need left join here to not fail on dropped columns ... */
4688                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
4689                                                                  "a.attstattarget, a.attstorage, t.typstorage, "
4690                                                                  "a.attnotnull, a.atthasdef, a.attisdropped, "
4691                                                                  "a.attlen, a.attalign, a.attislocal, "
4692                                    "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname "
4693                          "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
4694                                                           "ON a.atttypid = t.oid "
4695                                                           "WHERE a.attrelid = '%u'::pg_catalog.oid "
4696                                                           "AND a.attnum > 0::pg_catalog.int2 "
4697                                                           "ORDER BY a.attrelid, a.attnum",
4698                                                           tbinfo->dobj.catId.oid);
4699                 }
4700                 else if (g_fout->remoteVersion >= 70100)
4701                 {
4702                         /*
4703                          * attstattarget doesn't exist in 7.1.  It does exist in 7.2, but
4704                          * we don't dump it because we can't tell whether it's been
4705                          * explicitly set or was just a default.
4706                          */
4707                         appendPQExpBuffer(q, "SELECT a.attnum, a.attname, "
4708                                                           "a.atttypmod, -1 AS attstattarget, a.attstorage, "
4709                                                           "t.typstorage, a.attnotnull, a.atthasdef, "
4710                                                           "false AS attisdropped, 0 AS attlen, "
4711                                                           "' ' AS attalign, false AS attislocal, "
4712                                                           "format_type(t.oid,a.atttypmod) AS atttypname "
4713                                                           "FROM pg_attribute a LEFT JOIN pg_type t "
4714                                                           "ON a.atttypid = t.oid "
4715                                                           "WHERE a.attrelid = '%u'::oid "
4716                                                           "AND a.attnum > 0::int2 "
4717                                                           "ORDER BY a.attrelid, a.attnum",
4718                                                           tbinfo->dobj.catId.oid);
4719                 }
4720                 else
4721                 {
4722                         /* format_type not available before 7.1 */
4723                         appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, "
4724                                                           "-1 AS attstattarget, attstorage, "
4725                                                           "attstorage AS typstorage, "
4726                                                           "attnotnull, atthasdef, false AS attisdropped, "
4727                                                           "0 AS attlen, ' ' AS attalign, "
4728                                                           "false AS attislocal, "
4729                                                           "(SELECT typname FROM pg_type WHERE oid = atttypid) AS atttypname "
4730                                                           "FROM pg_attribute a "
4731                                                           "WHERE attrelid = '%u'::oid "
4732                                                           "AND attnum > 0::int2 "
4733                                                           "ORDER BY attrelid, attnum",
4734                                                           tbinfo->dobj.catId.oid);
4735                 }
4736
4737                 res = PQexec(g_conn, q->data);
4738                 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4739
4740                 ntups = PQntuples(res);
4741
4742                 i_attnum = PQfnumber(res, "attnum");
4743                 i_attname = PQfnumber(res, "attname");
4744                 i_atttypname = PQfnumber(res, "atttypname");
4745                 i_atttypmod = PQfnumber(res, "atttypmod");
4746                 i_attstattarget = PQfnumber(res, "attstattarget");
4747                 i_attstorage = PQfnumber(res, "attstorage");
4748                 i_typstorage = PQfnumber(res, "typstorage");
4749                 i_attnotnull = PQfnumber(res, "attnotnull");
4750                 i_atthasdef = PQfnumber(res, "atthasdef");
4751                 i_attisdropped = PQfnumber(res, "attisdropped");
4752                 i_attlen = PQfnumber(res, "attlen");
4753                 i_attalign = PQfnumber(res, "attalign");
4754                 i_attislocal = PQfnumber(res, "attislocal");
4755
4756                 tbinfo->numatts = ntups;
4757                 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
4758                 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
4759                 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
4760                 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
4761                 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
4762                 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
4763                 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
4764                 tbinfo->attlen = (int *) malloc(ntups * sizeof(int));
4765                 tbinfo->attalign = (char *) malloc(ntups * sizeof(char));
4766                 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
4767                 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
4768                 tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *));
4769                 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
4770                 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
4771                 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
4772                 hasdefaults = false;
4773
4774                 for (j = 0; j < ntups; j++)
4775                 {
4776                         if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
4777                         {
4778                                 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
4779                                                   tbinfo->dobj.name);
4780                                 exit_nicely();
4781                         }
4782                         tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
4783                         tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
4784                         tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
4785                         tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
4786                         tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
4787                         tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
4788                         tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
4789                         tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
4790                         tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
4791                         tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
4792                         tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
4793                         tbinfo->attrdefs[j] = NULL; /* fix below */
4794                         if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
4795                                 hasdefaults = true;
4796                         /* these flags will be set in flagInhAttrs() */
4797                         tbinfo->inhAttrs[j] = false;
4798                         tbinfo->inhAttrDef[j] = false;
4799                         tbinfo->inhNotNull[j] = false;
4800                 }
4801
4802                 PQclear(res);
4803
4804
4805                 /*
4806                  *      ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we
4807                  *      set the column data type to 'TEXT;  we will later drop the
4808                  *      column.
4809                  */
4810                 if (binary_upgrade)
4811                 {
4812                         for (j = 0; j < ntups; j++)
4813                         {
4814                                 if (tbinfo->attisdropped[j])
4815                                         tbinfo->atttypnames[j] = strdup("TEXT");
4816                         }
4817                 }
4818                         
4819                 /*
4820                  * Get info about column defaults
4821                  */
4822                 if (hasdefaults)
4823                 {
4824                         AttrDefInfo *attrdefs;
4825                         int                     numDefaults;
4826
4827                         if (g_verbose)
4828                                 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4829                                                   tbinfo->dobj.name);
4830
4831                         resetPQExpBuffer(q);
4832                         if (g_fout->remoteVersion >= 70300)
4833                         {
4834                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
4835                                                    "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
4836                                                                   "FROM pg_catalog.pg_attrdef "
4837                                                                   "WHERE adrelid = '%u'::pg_catalog.oid",
4838                                                                   tbinfo->dobj.catId.oid);
4839                         }
4840                         else if (g_fout->remoteVersion >= 70200)
4841                         {
4842                                 /* 7.2 did not have OIDs in pg_attrdef */
4843                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, adnum, "
4844                                                                   "pg_get_expr(adbin, adrelid) AS adsrc "
4845                                                                   "FROM pg_attrdef "
4846                                                                   "WHERE adrelid = '%u'::oid",
4847                                                                   tbinfo->dobj.catId.oid);
4848                         }
4849                         else if (g_fout->remoteVersion >= 70100)
4850                         {
4851                                 /* no pg_get_expr, so must rely on adsrc */
4852                                 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4853                                                                   "FROM pg_attrdef "
4854                                                                   "WHERE adrelid = '%u'::oid",
4855                                                                   tbinfo->dobj.catId.oid);
4856                         }
4857                         else
4858                         {
4859                                 /* no pg_get_expr, no tableoid either */
4860                                 appendPQExpBuffer(q, "SELECT "
4861                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_attrdef') AS tableoid, "
4862                                                                   "oid, adnum, adsrc "
4863                                                                   "FROM pg_attrdef "
4864                                                                   "WHERE adrelid = '%u'::oid",
4865                                                                   tbinfo->dobj.catId.oid);
4866                         }
4867                         res = PQexec(g_conn, q->data);
4868                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4869
4870                         numDefaults = PQntuples(res);
4871                         attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4872
4873                         for (j = 0; j < numDefaults; j++)
4874                         {
4875                                 int                     adnum;
4876
4877                                 attrdefs[j].dobj.objType = DO_ATTRDEF;
4878                                 attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
4879                                 attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
4880                                 AssignDumpId(&attrdefs[j].dobj);
4881                                 attrdefs[j].adtable = tbinfo;
4882                                 attrdefs[j].adnum = adnum = atoi(PQgetvalue(res, j, 2));
4883                                 attrdefs[j].adef_expr = strdup(PQgetvalue(res, j, 3));
4884
4885                                 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4886                                 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4887
4888                                 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
4889
4890                                 /*
4891                                  * Defaults on a VIEW must always be dumped as separate ALTER
4892                                  * TABLE commands.      Defaults on regular tables are dumped as
4893                                  * part of the CREATE TABLE if possible.  To check if it's
4894                                  * safe, we mark the default as needing to appear before the
4895                                  * CREATE.
4896                                  */
4897                                 if (tbinfo->relkind == RELKIND_VIEW)
4898                                 {
4899                                         attrdefs[j].separate = true;
4900                                         /* needed in case pre-7.3 DB: */
4901                                         addObjectDependency(&attrdefs[j].dobj,
4902                                                                                 tbinfo->dobj.dumpId);
4903                                 }
4904                                 else
4905                                 {
4906                                         attrdefs[j].separate = false;
4907                                         addObjectDependency(&tbinfo->dobj,
4908                                                                                 attrdefs[j].dobj.dumpId);
4909                                 }
4910
4911                                 if (adnum <= 0 || adnum > ntups)
4912                                 {
4913                                         write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4914                                                           adnum, tbinfo->dobj.name);
4915                                         exit_nicely();
4916                                 }
4917                                 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4918                         }
4919                         PQclear(res);
4920                 }
4921
4922                 /*
4923                  * Get info about table CHECK constraints
4924                  */
4925                 if (tbinfo->ncheck > 0)
4926                 {
4927                         ConstraintInfo *constrs;
4928                         int                     numConstrs;
4929
4930                         if (g_verbose)
4931                                 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4932                                                   tbinfo->dobj.name);
4933
4934                         resetPQExpBuffer(q);
4935                         if (g_fout->remoteVersion >= 80400)
4936                         {
4937                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4938                                                         "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4939                                                                   "conislocal "
4940                                                                   "FROM pg_catalog.pg_constraint "
4941                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4942                                                                   "   AND contype = 'c' "
4943                                                                   "ORDER BY conname",
4944                                                                   tbinfo->dobj.catId.oid);
4945                         }
4946                         else if (g_fout->remoteVersion >= 70400)
4947                         {
4948                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4949                                                         "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4950                                                                   "true AS conislocal "
4951                                                                   "FROM pg_catalog.pg_constraint "
4952                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4953                                                                   "   AND contype = 'c' "
4954                                                                   "ORDER BY conname",
4955                                                                   tbinfo->dobj.catId.oid);
4956                         }
4957                         else if (g_fout->remoteVersion >= 70300)
4958                         {
4959                                 /* no pg_get_constraintdef, must use consrc */
4960                                 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4961                                                                   "'CHECK (' || consrc || ')' AS consrc, "
4962                                                                   "true AS conislocal "
4963                                                                   "FROM pg_catalog.pg_constraint "
4964                                                                   "WHERE conrelid = '%u'::pg_catalog.oid "
4965                                                                   "   AND contype = 'c' "
4966                                                                   "ORDER BY conname",
4967                                                                   tbinfo->dobj.catId.oid);
4968                         }
4969                         else if (g_fout->remoteVersion >= 70200)
4970                         {
4971                                 /* 7.2 did not have OIDs in pg_relcheck */
4972                                 appendPQExpBuffer(q, "SELECT tableoid, 0 AS oid, "
4973                                                                   "rcname AS conname, "
4974                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
4975                                                                   "true AS conislocal "
4976                                                                   "FROM pg_relcheck "
4977                                                                   "WHERE rcrelid = '%u'::oid "
4978                                                                   "ORDER BY rcname",
4979                                                                   tbinfo->dobj.catId.oid);
4980                         }
4981                         else if (g_fout->remoteVersion >= 70100)
4982                         {
4983                                 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4984                                                                   "rcname AS conname, "
4985                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
4986                                                                   "true AS conislocal "
4987                                                                   "FROM pg_relcheck "
4988                                                                   "WHERE rcrelid = '%u'::oid "
4989                                                                   "ORDER BY rcname",
4990                                                                   tbinfo->dobj.catId.oid);
4991                         }
4992                         else
4993                         {
4994                                 /* no tableoid in 7.0 */
4995                                 appendPQExpBuffer(q, "SELECT "
4996                                                                   "(SELECT oid FROM pg_class WHERE relname = 'pg_relcheck') AS tableoid, "
4997                                                                   "oid, rcname AS conname, "
4998                                                                   "'CHECK (' || rcsrc || ')' AS consrc, "
4999                                                                   "true AS conislocal "
5000                                                                   "FROM pg_relcheck "
5001                                                                   "WHERE rcrelid = '%u'::oid "
5002                                                                   "ORDER BY rcname",
5003                                                                   tbinfo->dobj.catId.oid);
5004                         }
5005                         res = PQexec(g_conn, q->data);
5006                         check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5007
5008                         numConstrs = PQntuples(res);
5009                         if (numConstrs != tbinfo->ncheck)
5010                         {
5011                                 write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
5012                                                                                  "expected %d check constraints on table \"%s\" but found %d\n",
5013                                                                                  tbinfo->ncheck),
5014                                                   tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5015                                 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5016                                 exit_nicely();
5017                         }
5018
5019                         constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5020                         tbinfo->checkexprs = constrs;
5021
5022                         for (j = 0; j < numConstrs; j++)
5023                         {
5024                                 constrs[j].dobj.objType = DO_CONSTRAINT;
5025                                 constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
5026                                 constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
5027                                 AssignDumpId(&constrs[j].dobj);
5028                                 constrs[j].dobj.name = strdup(PQgetvalue(res, j, 2));
5029                                 constrs[j].dobj.namespace = tbinfo->dobj.namespace;
5030                                 constrs[j].contable = tbinfo;
5031                                 constrs[j].condomain = NULL;
5032                                 constrs[j].contype = 'c';
5033                                 constrs[j].condef = strdup(PQgetvalue(res, j, 3));
5034                                 constrs[j].confrelid = InvalidOid;
5035                                 constrs[j].conindex = 0;
5036                                 constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
5037                                 constrs[j].separate = false;
5038
5039                                 constrs[j].dobj.dump = tbinfo->dobj.dump;
5040
5041                                 /*
5042                                  * Mark the constraint as needing to appear before the table
5043                                  * --- this is so that any other dependencies of the
5044                                  * constraint will be emitted before we try to create the
5045                                  * table.
5046                                  */
5047                                 addObjectDependency(&tbinfo->dobj,
5048                                                                         constrs[j].dobj.dumpId);
5049
5050                                 /*
5051                                  * If the constraint is inherited, this will be detected
5052                                  * later (in pre-8.4 databases).  We also detect later if the
5053                                  * constraint must be split out from the table definition.
5054                                  */
5055                         }
5056                         PQclear(res);
5057                 }
5058         }
5059
5060         destroyPQExpBuffer(q);
5061 }
5062
5063
5064 /*
5065  * getTSParsers:
5066  *        read all text search parsers in the system catalogs and return them
5067  *        in the TSParserInfo* structure
5068  *
5069  *      numTSParsers is set to the number of parsers read in
5070  */
5071 TSParserInfo *
5072 getTSParsers(int *numTSParsers)
5073 {
5074         PGresult   *res;
5075         int                     ntups;
5076         int                     i;
5077         PQExpBuffer query = createPQExpBuffer();
5078         TSParserInfo *prsinfo;
5079         int                     i_tableoid;
5080         int                     i_oid;
5081         int                     i_prsname;
5082         int                     i_prsnamespace;
5083         int                     i_prsstart;
5084         int                     i_prstoken;
5085         int                     i_prsend;
5086         int                     i_prsheadline;
5087         int                     i_prslextype;
5088
5089         /* Before 8.3, there is no built-in text search support */
5090         if (g_fout->remoteVersion < 80300)
5091         {
5092                 *numTSParsers = 0;
5093                 return NULL;
5094         }
5095
5096         /*
5097          * find all text search objects, including builtin ones; we filter out
5098          * system-defined objects at dump-out time.
5099          */
5100
5101         /* Make sure we are in proper schema */
5102         selectSourceSchema("pg_catalog");
5103
5104         appendPQExpBuffer(query, "SELECT tableoid, oid, prsname, prsnamespace, "
5105                                           "prsstart::oid, prstoken::oid, "
5106                                           "prsend::oid, prsheadline::oid, prslextype::oid "
5107                                           "FROM pg_ts_parser");
5108
5109         res = PQexec(g_conn, query->data);
5110         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5111
5112         ntups = PQntuples(res);
5113         *numTSParsers = ntups;
5114
5115         prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
5116
5117         i_tableoid = PQfnumber(res, "tableoid");
5118         i_oid = PQfnumber(res, "oid");
5119         i_prsname = PQfnumber(res, "prsname");
5120         i_prsnamespace = PQfnumber(res, "prsnamespace");
5121         i_prsstart = PQfnumber(res, "prsstart");
5122         i_prstoken = PQfnumber(res, "prstoken");
5123         i_prsend = PQfnumber(res, "prsend");
5124         i_prsheadline = PQfnumber(res, "prsheadline");
5125         i_prslextype = PQfnumber(res, "prslextype");
5126
5127         for (i = 0; i < ntups; i++)
5128         {
5129                 prsinfo[i].dobj.objType = DO_TSPARSER;
5130                 prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5131                 prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5132                 AssignDumpId(&prsinfo[i].dobj);
5133                 prsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_prsname));
5134                 prsinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_prsnamespace)),
5135                                                                                                   prsinfo[i].dobj.catId.oid);
5136                 prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
5137                 prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
5138                 prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
5139                 prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
5140                 prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
5141
5142                 /* Decide whether we want to dump it */
5143                 selectDumpableObject(&(prsinfo[i].dobj));
5144         }
5145
5146         PQclear(res);
5147
5148         destroyPQExpBuffer(query);
5149
5150         return prsinfo;
5151 }
5152
5153 /*
5154  * getTSDictionaries:
5155  *        read all text search dictionaries in the system catalogs and return them
5156  *        in the TSDictInfo* structure
5157  *
5158  *      numTSDicts is set to the number of dictionaries read in
5159  */
5160 TSDictInfo *
5161 getTSDictionaries(int *numTSDicts)
5162 {
5163         PGresult   *res;
5164         int                     ntups;
5165         int                     i;
5166         PQExpBuffer query = createPQExpBuffer();
5167         TSDictInfo *dictinfo;
5168         int                     i_tableoid;
5169         int                     i_oid;
5170         int                     i_dictname;
5171         int                     i_dictnamespace;
5172         int                     i_rolname;
5173         int                     i_dicttemplate;
5174         int                     i_dictinitoption;
5175
5176         /* Before 8.3, there is no built-in text search support */
5177         if (g_fout->remoteVersion < 80300)
5178         {
5179                 *numTSDicts = 0;
5180                 return NULL;
5181         }
5182
5183         /* Make sure we are in proper schema */
5184         selectSourceSchema("pg_catalog");
5185
5186         appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5187                                           "dictnamespace, (%s dictowner) AS rolname, "
5188                                           "dicttemplate, dictinitoption "
5189                                           "FROM pg_ts_dict",
5190                                           username_subquery);
5191
5192         res = PQexec(g_conn, query->data);
5193         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5194
5195         ntups = PQntuples(res);
5196         *numTSDicts = ntups;
5197
5198         dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
5199
5200         i_tableoid = PQfnumber(res, "tableoid");
5201         i_oid = PQfnumber(res, "oid");
5202         i_dictname = PQfnumber(res, "dictname");
5203         i_dictnamespace = PQfnumber(res, "dictnamespace");
5204         i_rolname = PQfnumber(res, "rolname");
5205         i_dictinitoption = PQfnumber(res, "dictinitoption");
5206         i_dicttemplate = PQfnumber(res, "dicttemplate");
5207
5208         for (i = 0; i < ntups; i++)
5209         {
5210                 dictinfo[i].dobj.objType = DO_TSDICT;
5211                 dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5212                 dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5213                 AssignDumpId(&dictinfo[i].dobj);
5214                 dictinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_dictname));
5215                 dictinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_dictnamespace)),
5216                                                                                                  dictinfo[i].dobj.catId.oid);
5217                 dictinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5218                 dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
5219                 if (PQgetisnull(res, i, i_dictinitoption))
5220                         dictinfo[i].dictinitoption = NULL;
5221                 else
5222                         dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5223
5224                 /* Decide whether we want to dump it */
5225                 selectDumpableObject(&(dictinfo[i].dobj));
5226         }
5227
5228         PQclear(res);
5229
5230         destroyPQExpBuffer(query);
5231
5232         return dictinfo;
5233 }
5234
5235 /*
5236  * getTSTemplates:
5237  *        read all text search templates in the system catalogs and return them
5238  *        in the TSTemplateInfo* structure
5239  *
5240  *      numTSTemplates is set to the number of templates read in
5241  */
5242 TSTemplateInfo *
5243 getTSTemplates(int *numTSTemplates)
5244 {
5245         PGresult   *res;
5246         int                     ntups;
5247         int                     i;
5248         PQExpBuffer query = createPQExpBuffer();
5249         TSTemplateInfo *tmplinfo;
5250         int                     i_tableoid;
5251         int                     i_oid;
5252         int                     i_tmplname;
5253         int                     i_tmplnamespace;
5254         int                     i_tmplinit;
5255         int                     i_tmpllexize;
5256
5257         /* Before 8.3, there is no built-in text search support */
5258         if (g_fout->remoteVersion < 80300)
5259         {
5260                 *numTSTemplates = 0;
5261                 return NULL;
5262         }
5263
5264         /* Make sure we are in proper schema */
5265         selectSourceSchema("pg_catalog");
5266
5267         appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5268                                           "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5269                                           "FROM pg_ts_template");
5270
5271         res = PQexec(g_conn, query->data);
5272         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5273
5274         ntups = PQntuples(res);
5275         *numTSTemplates = ntups;
5276
5277         tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
5278
5279         i_tableoid = PQfnumber(res, "tableoid");
5280         i_oid = PQfnumber(res, "oid");
5281         i_tmplname = PQfnumber(res, "tmplname");
5282         i_tmplnamespace = PQfnumber(res, "tmplnamespace");
5283         i_tmplinit = PQfnumber(res, "tmplinit");
5284         i_tmpllexize = PQfnumber(res, "tmpllexize");
5285
5286         for (i = 0; i < ntups; i++)
5287         {
5288                 tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
5289                 tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5290                 tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5291                 AssignDumpId(&tmplinfo[i].dobj);
5292                 tmplinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_tmplname));
5293                 tmplinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_tmplnamespace)),
5294                                                                                                  tmplinfo[i].dobj.catId.oid);
5295                 tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
5296                 tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
5297
5298                 /* Decide whether we want to dump it */
5299                 selectDumpableObject(&(tmplinfo[i].dobj));
5300         }
5301
5302         PQclear(res);
5303
5304         destroyPQExpBuffer(query);
5305
5306         return tmplinfo;
5307 }
5308
5309 /*
5310  * getTSConfigurations:
5311  *        read all text search configurations in the system catalogs and return
5312  *        them in the TSConfigInfo* structure
5313  *
5314  *      numTSConfigs is set to the number of configurations read in
5315  */
5316 TSConfigInfo *
5317 getTSConfigurations(int *numTSConfigs)
5318 {
5319         PGresult   *res;
5320         int                     ntups;
5321         int                     i;
5322         PQExpBuffer query = createPQExpBuffer();
5323         TSConfigInfo *cfginfo;
5324         int                     i_tableoid;
5325         int                     i_oid;
5326         int                     i_cfgname;
5327         int                     i_cfgnamespace;
5328         int                     i_rolname;
5329         int                     i_cfgparser;
5330
5331         /* Before 8.3, there is no built-in text search support */
5332         if (g_fout->remoteVersion < 80300)
5333         {
5334                 *numTSConfigs = 0;
5335                 return NULL;
5336         }
5337
5338         /* Make sure we are in proper schema */
5339         selectSourceSchema("pg_catalog");
5340
5341         appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5342                                           "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5343                                           "FROM pg_ts_config",
5344                                           username_subquery);
5345
5346         res = PQexec(g_conn, query->data);
5347         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5348
5349         ntups = PQntuples(res);
5350         *numTSConfigs = ntups;
5351
5352         cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
5353
5354         i_tableoid = PQfnumber(res, "tableoid");
5355         i_oid = PQfnumber(res, "oid");
5356         i_cfgname = PQfnumber(res, "cfgname");
5357         i_cfgnamespace = PQfnumber(res, "cfgnamespace");
5358         i_rolname = PQfnumber(res, "rolname");
5359         i_cfgparser = PQfnumber(res, "cfgparser");
5360
5361         for (i = 0; i < ntups; i++)
5362         {
5363                 cfginfo[i].dobj.objType = DO_TSCONFIG;
5364                 cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5365                 cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5366                 AssignDumpId(&cfginfo[i].dobj);
5367                 cfginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_cfgname));
5368                 cfginfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_cfgnamespace)),
5369                                                                                                   cfginfo[i].dobj.catId.oid);
5370                 cfginfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5371                 cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
5372
5373                 /* Decide whether we want to dump it */
5374                 selectDumpableObject(&(cfginfo[i].dobj));
5375         }
5376
5377         PQclear(res);
5378
5379         destroyPQExpBuffer(query);
5380
5381         return cfginfo;
5382 }
5383
5384 /*
5385  * getForeignDataWrappers:
5386  *        read all foreign-data wrappers in the system catalogs and return
5387  *        them in the FdwInfo* structure
5388  *
5389  *      numForeignDataWrappers is set to the number of fdws read in
5390  */
5391 FdwInfo *
5392 getForeignDataWrappers(int *numForeignDataWrappers)
5393 {
5394         PGresult   *res;
5395         int                     ntups;
5396         int                     i;
5397         PQExpBuffer query = createPQExpBuffer();
5398         FdwInfo    *fdwinfo;
5399         int                     i_oid;
5400         int                     i_fdwname;
5401         int                     i_rolname;
5402         int                     i_fdwvalidator;
5403         int                     i_fdwacl;
5404         int                     i_fdwoptions;
5405
5406         /* Before 8.4, there are no foreign-data wrappers */
5407         if (g_fout->remoteVersion < 80400)
5408         {
5409                 *numForeignDataWrappers = 0;
5410                 return NULL;
5411         }
5412
5413         /* Make sure we are in proper schema */
5414         selectSourceSchema("pg_catalog");
5415
5416         appendPQExpBuffer(query, "SELECT oid, fdwname, "
5417                                           "(%s fdwowner) AS rolname, fdwvalidator::pg_catalog.regproc, fdwacl,"
5418                                           "array_to_string(ARRAY("
5419                                           "             SELECT option_name || ' ' || quote_literal(option_value) "
5420                                           "             FROM pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
5421                                           "FROM pg_foreign_data_wrapper",
5422                                           username_subquery);
5423
5424         res = PQexec(g_conn, query->data);
5425         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5426
5427         ntups = PQntuples(res);
5428         *numForeignDataWrappers = ntups;
5429
5430         fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
5431
5432         i_oid = PQfnumber(res, "oid");
5433         i_fdwname = PQfnumber(res, "fdwname");
5434         i_rolname = PQfnumber(res, "rolname");
5435         i_fdwvalidator = PQfnumber(res, "fdwvalidator");
5436         i_fdwacl = PQfnumber(res, "fdwacl");
5437         i_fdwoptions = PQfnumber(res, "fdwoptions");
5438
5439         for (i = 0; i < ntups; i++)
5440         {
5441                 fdwinfo[i].dobj.objType = DO_FDW;
5442                 fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5443                 AssignDumpId(&fdwinfo[i].dobj);
5444                 fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
5445                 fdwinfo[i].dobj.namespace = NULL;
5446                 fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5447                 fdwinfo[i].fdwvalidator = strdup(PQgetvalue(res, i, i_fdwvalidator));
5448                 fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
5449                 fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
5450
5451
5452                 /* Decide whether we want to dump it */
5453                 selectDumpableObject(&(fdwinfo[i].dobj));
5454         }
5455
5456         PQclear(res);
5457
5458         destroyPQExpBuffer(query);
5459
5460         return fdwinfo;
5461 }
5462
5463 /*
5464  * getForeignServers:
5465  *        read all foreign servers in the system catalogs and return
5466  *        them in the ForeignServerInfo * structure
5467  *
5468  *      numForeignServers is set to the number of servers read in
5469  */
5470 ForeignServerInfo *
5471 getForeignServers(int *numForeignServers)
5472 {
5473         PGresult   *res;
5474         int                     ntups;
5475         int                     i;
5476         PQExpBuffer query = createPQExpBuffer();
5477         ForeignServerInfo *srvinfo;
5478         int                     i_oid;
5479         int                     i_srvname;
5480         int                     i_rolname;
5481         int                     i_srvfdw;
5482         int                     i_srvtype;
5483         int                     i_srvversion;
5484         int                     i_srvacl;
5485         int                     i_srvoptions;
5486
5487         /* Before 8.4, there are no foreign servers */
5488         if (g_fout->remoteVersion < 80400)
5489         {
5490                 *numForeignServers = 0;
5491                 return NULL;
5492         }
5493
5494         /* Make sure we are in proper schema */
5495         selectSourceSchema("pg_catalog");
5496
5497         appendPQExpBuffer(query, "SELECT oid, srvname, "
5498                                           "(%s srvowner) AS rolname, "
5499                                           "srvfdw, srvtype, srvversion, srvacl,"
5500                                           "array_to_string(ARRAY("
5501                                           "             SELECT option_name || ' ' || quote_literal(option_value) "
5502                                           "             FROM pg_options_to_table(srvoptions)), ', ') AS srvoptions "
5503                                           "FROM pg_foreign_server",
5504                                           username_subquery);
5505
5506         res = PQexec(g_conn, query->data);
5507         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5508
5509         ntups = PQntuples(res);
5510         *numForeignServers = ntups;
5511
5512         srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
5513
5514         i_oid = PQfnumber(res, "oid");
5515         i_srvname = PQfnumber(res, "srvname");
5516         i_rolname = PQfnumber(res, "rolname");
5517         i_srvfdw = PQfnumber(res, "srvfdw");
5518         i_srvtype = PQfnumber(res, "srvtype");
5519         i_srvversion = PQfnumber(res, "srvversion");
5520         i_srvacl = PQfnumber(res, "srvacl");
5521         i_srvoptions = PQfnumber(res, "srvoptions");
5522
5523         for (i = 0; i < ntups; i++)
5524         {
5525                 srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
5526                 srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5527                 AssignDumpId(&srvinfo[i].dobj);
5528                 srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
5529                 srvinfo[i].dobj.namespace = NULL;
5530                 srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
5531                 srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
5532                 srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
5533                 srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
5534                 srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
5535                 srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
5536
5537                 /* Decide whether we want to dump it */
5538                 selectDumpableObject(&(srvinfo[i].dobj));
5539         }
5540
5541         PQclear(res);
5542
5543         destroyPQExpBuffer(query);
5544
5545         return srvinfo;
5546 }
5547
5548 /*
5549  * dumpComment --
5550  *
5551  * This routine is used to dump any comments associated with the
5552  * object handed to this routine. The routine takes a constant character
5553  * string for the target part of the comment-creation command, plus
5554  * the namespace and owner of the object (for labeling the ArchiveEntry),
5555  * plus catalog ID and subid which are the lookup key for pg_description,
5556  * plus the dump ID for the object (for setting a dependency).
5557  * If a matching pg_description entry is found, it is dumped.
5558  *
5559  * Note: although this routine takes a dumpId for dependency purposes,
5560  * that purpose is just to mark the dependency in the emitted dump file
5561  * for possible future use by pg_restore.  We do NOT use it for determining
5562  * ordering of the comment in the dump file, because this routine is called
5563  * after dependency sorting occurs.  This routine should be called just after
5564  * calling ArchiveEntry() for the specified object.
5565  */
5566 static void
5567 dumpComment(Archive *fout, const char *target,
5568                         const char *namespace, const char *owner,
5569                         CatalogId catalogId, int subid, DumpId dumpId)
5570 {
5571         CommentItem *comments;
5572         int                     ncomments;
5573
5574         /* Comments are SCHEMA not data */
5575         if (dataOnly)
5576                 return;
5577
5578         /* Search for comments associated with catalogId, using table */
5579         ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5580                                                          &comments);
5581
5582         /* Is there one matching the subid? */
5583         while (ncomments > 0)
5584         {
5585                 if (comments->objsubid == subid)
5586                         break;
5587                 comments++;
5588                 ncomments--;
5589         }
5590
5591         /* If a comment exists, build COMMENT ON statement */
5592         if (ncomments > 0)
5593         {
5594                 PQExpBuffer query = createPQExpBuffer();
5595
5596                 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5597                 appendStringLiteralAH(query, comments->descr, fout);
5598                 appendPQExpBuffer(query, ";\n");
5599
5600                 /*
5601                  * We mark comments as SECTION_NONE because they really belong
5602                  * in the same section as their parent, whether that is
5603                  * pre-data or post-data.
5604                  */
5605                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5606                                          target, namespace, NULL, owner,
5607                                          false, "COMMENT", SECTION_NONE,
5608                                          query->data, "", NULL,
5609                                          &(dumpId), 1,
5610                                          NULL, NULL);
5611
5612                 destroyPQExpBuffer(query);
5613         }
5614 }
5615
5616 /*
5617  * dumpTableComment --
5618  *
5619  * As above, but dump comments for both the specified table (or view)
5620  * and its columns.
5621  */
5622 static void
5623 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5624                                  const char *reltypename)
5625 {
5626         CommentItem *comments;
5627         int                     ncomments;
5628         PQExpBuffer query;
5629         PQExpBuffer target;
5630
5631         /* Comments are SCHEMA not data */
5632         if (dataOnly)
5633                 return;
5634
5635         /* Search for comments associated with relation, using table */
5636         ncomments = findComments(fout,
5637                                                          tbinfo->dobj.catId.tableoid,
5638                                                          tbinfo->dobj.catId.oid,
5639                                                          &comments);
5640
5641         /* If comments exist, build COMMENT ON statements */
5642         if (ncomments <= 0)
5643                 return;
5644
5645         query = createPQExpBuffer();
5646         target = createPQExpBuffer();
5647
5648         while (ncomments > 0)
5649         {
5650                 const char *descr = comments->descr;
5651                 int                     objsubid = comments->objsubid;
5652
5653                 if (objsubid == 0)
5654                 {
5655                         resetPQExpBuffer(target);
5656                         appendPQExpBuffer(target, "%s %s", reltypename,
5657                                                           fmtId(tbinfo->dobj.name));
5658
5659                         resetPQExpBuffer(query);
5660                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5661                         appendStringLiteralAH(query, descr, fout);
5662                         appendPQExpBuffer(query, ";\n");
5663
5664                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
5665                                                  target->data,
5666                                                  tbinfo->dobj.namespace->dobj.name,
5667                                                  NULL, tbinfo->rolname,
5668                                                  false, "COMMENT", SECTION_NONE,
5669                                                  query->data, "", NULL,
5670                                                  &(tbinfo->dobj.dumpId), 1,
5671                                                  NULL, NULL);
5672                 }
5673                 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5674                 {
5675                         resetPQExpBuffer(target);
5676                         appendPQExpBuffer(target, "COLUMN %s.",
5677                                                           fmtId(tbinfo->dobj.name));
5678                         appendPQExpBuffer(target, "%s",
5679                                                           fmtId(tbinfo->attnames[objsubid - 1]));
5680
5681                         resetPQExpBuffer(query);
5682                         appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5683                         appendStringLiteralAH(query, descr, fout);
5684                         appendPQExpBuffer(query, ";\n");
5685
5686                         ArchiveEntry(fout, nilCatalogId, createDumpId(),
5687                                                  target->data,
5688                                                  tbinfo->dobj.namespace->dobj.name,
5689                                                  NULL, tbinfo->rolname,
5690                                                  false, "COMMENT", SECTION_NONE,
5691                                                  query->data, "", NULL,
5692                                                  &(tbinfo->dobj.dumpId), 1,
5693                                                  NULL, NULL);
5694                 }
5695
5696                 comments++;
5697                 ncomments--;
5698         }
5699
5700         destroyPQExpBuffer(query);
5701         destroyPQExpBuffer(target);
5702 }
5703
5704 /*
5705  * findComments --
5706  *
5707  * Find the comment(s), if any, associated with the given object.  All the
5708  * objsubid values associated with the given classoid/objoid are found with
5709  * one search.
5710  */
5711 static int
5712 findComments(Archive *fout, Oid classoid, Oid objoid,
5713                          CommentItem **items)
5714 {
5715         /* static storage for table of comments */
5716         static CommentItem *comments = NULL;
5717         static int      ncomments = -1;
5718
5719         CommentItem *middle = NULL;
5720         CommentItem *low;
5721         CommentItem *high;
5722         int                     nmatch;
5723
5724         /* Get comments if we didn't already */
5725         if (ncomments < 0)
5726                 ncomments = collectComments(fout, &comments);
5727
5728         /*
5729          * Pre-7.2, pg_description does not contain classoid, so collectComments
5730          * just stores a zero.  If there's a collision on object OID, well, you
5731          * get duplicate comments.
5732          */
5733         if (fout->remoteVersion < 70200)
5734                 classoid = 0;
5735
5736         /*
5737          * Do binary search to find some item matching the object.
5738          */
5739         low = &comments[0];
5740         high = &comments[ncomments - 1];
5741         while (low <= high)
5742         {
5743                 middle = low + (high - low) / 2;
5744
5745                 if (classoid < middle->classoid)
5746                         high = middle - 1;
5747                 else if (classoid > middle->classoid)
5748                         low = middle + 1;
5749                 else if (objoid < middle->objoid)
5750                         high = middle - 1;
5751                 else if (objoid > middle->objoid)
5752                         low = middle + 1;
5753                 else
5754                         break;                          /* found a match */
5755         }
5756
5757         if (low > high)                         /* no matches */
5758         {
5759                 *items = NULL;
5760                 return 0;
5761         }
5762
5763         /*
5764          * Now determine how many items match the object.  The search loop
5765          * invariant still holds: only items between low and high inclusive could
5766          * match.
5767          */
5768         nmatch = 1;
5769         while (middle > low)
5770         {
5771                 if (classoid != middle[-1].classoid ||
5772                         objoid != middle[-1].objoid)
5773                         break;
5774                 middle--;
5775                 nmatch++;
5776         }
5777
5778         *items = middle;
5779
5780         middle += nmatch;
5781         while (middle <= high)
5782         {
5783                 if (classoid != middle->classoid ||
5784                         objoid != middle->objoid)
5785                         break;
5786                 middle++;
5787                 nmatch++;
5788         }
5789
5790         return nmatch;
5791 }
5792
5793 /*
5794  * collectComments --
5795  *
5796  * Construct a table of all comments available for database objects.
5797  * We used to do per-object queries for the comments, but it's much faster
5798  * to pull them all over at once, and on most databases the memory cost
5799  * isn't high.
5800  *
5801  * The table is sorted by classoid/objid/objsubid for speed in lookup.
5802  */
5803 static int
5804 collectComments(Archive *fout, CommentItem **items)
5805 {
5806         PGresult   *res;
5807         PQExpBuffer query;
5808         int                     i_description;
5809         int                     i_classoid;
5810         int                     i_objoid;
5811         int                     i_objsubid;
5812         int                     ntups;
5813         int                     i;
5814         CommentItem *comments;
5815
5816         /*
5817          * Note we do NOT change source schema here; preserve the caller's
5818          * setting, instead.
5819          */
5820
5821         query = createPQExpBuffer();
5822
5823         if (fout->remoteVersion >= 70300)
5824         {
5825                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5826                                                   "FROM pg_catalog.pg_description "
5827                                                   "ORDER BY classoid, objoid, objsubid");
5828         }
5829         else if (fout->remoteVersion >= 70200)
5830         {
5831                 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5832                                                   "FROM pg_description "
5833                                                   "ORDER BY classoid, objoid, objsubid");
5834         }
5835         else
5836         {
5837                 /* Note: this will fail to find attribute comments in pre-7.2... */
5838                 appendPQExpBuffer(query, "SELECT description, 0 AS classoid, objoid, 0 AS objsubid "
5839                                                   "FROM pg_description "
5840                                                   "ORDER BY objoid");
5841         }
5842
5843         res = PQexec(g_conn, query->data);
5844         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5845
5846         /* Construct lookup table containing OIDs in numeric form */
5847
5848         i_description = PQfnumber(res, "description");
5849         i_classoid = PQfnumber(res, "classoid");
5850         i_objoid = PQfnumber(res, "objoid");
5851         i_objsubid = PQfnumber(res, "objsubid");
5852
5853         ntups = PQntuples(res);
5854
5855         comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5856
5857         for (i = 0; i < ntups; i++)
5858         {
5859                 comments[i].descr = PQgetvalue(res, i, i_description);
5860                 comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
5861                 comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
5862                 comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
5863         }
5864
5865         /* Do NOT free the PGresult since we are keeping pointers into it */
5866         destroyPQExpBuffer(query);
5867
5868         *items = comments;
5869         return ntups;
5870 }
5871
5872 /*
5873  * dumpDumpableObject
5874  *
5875  * This routine and its subsidiaries are responsible for creating
5876  * ArchiveEntries (TOC objects) for each object to be dumped.
5877  */
5878 static void
5879 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5880 {
5881         switch (dobj->objType)
5882         {
5883                 case DO_NAMESPACE:
5884                         dumpNamespace(fout, (NamespaceInfo *) dobj);
5885                         break;
5886                 case DO_TYPE:
5887                         dumpType(fout, (TypeInfo *) dobj);
5888                         break;
5889                 case DO_SHELL_TYPE:
5890                         dumpShellType(fout, (ShellTypeInfo *) dobj);
5891                         break;
5892                 case DO_FUNC:
5893                         dumpFunc(fout, (FuncInfo *) dobj);
5894                         break;
5895                 case DO_AGG:
5896                         dumpAgg(fout, (AggInfo *) dobj);
5897                         break;
5898                 case DO_OPERATOR:
5899                         dumpOpr(fout, (OprInfo *) dobj);
5900                         break;
5901                 case DO_OPCLASS:
5902                         dumpOpclass(fout, (OpclassInfo *) dobj);
5903                         break;
5904                 case DO_OPFAMILY:
5905                         dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5906                         break;
5907                 case DO_CONVERSION:
5908                         dumpConversion(fout, (ConvInfo *) dobj);
5909                         break;
5910                 case DO_TABLE:
5911                         dumpTable(fout, (TableInfo *) dobj);
5912                         break;
5913                 case DO_ATTRDEF:
5914                         dumpAttrDef(fout, (AttrDefInfo *) dobj);
5915                         break;
5916                 case DO_INDEX:
5917                         dumpIndex(fout, (IndxInfo *) dobj);
5918                         break;
5919                 case DO_RULE:
5920                         dumpRule(fout, (RuleInfo *) dobj);
5921                         break;
5922                 case DO_TRIGGER:
5923                         dumpTrigger(fout, (TriggerInfo *) dobj);
5924                         break;
5925                 case DO_CONSTRAINT:
5926                         dumpConstraint(fout, (ConstraintInfo *) dobj);
5927                         break;
5928                 case DO_FK_CONSTRAINT:
5929                         dumpConstraint(fout, (ConstraintInfo *) dobj);
5930                         break;
5931                 case DO_PROCLANG:
5932                         dumpProcLang(fout, (ProcLangInfo *) dobj);
5933                         break;
5934                 case DO_CAST:
5935                         dumpCast(fout, (CastInfo *) dobj);
5936                         break;
5937                 case DO_TABLE_DATA:
5938                         dumpTableData(fout, (TableDataInfo *) dobj);
5939                         break;
5940                 case DO_DUMMY_TYPE:
5941                         /* table rowtypes and array types are never dumped separately */
5942                         break;
5943                 case DO_TSPARSER:
5944                         dumpTSParser(fout, (TSParserInfo *) dobj);
5945                         break;
5946                 case DO_TSDICT:
5947                         dumpTSDictionary(fout, (TSDictInfo *) dobj);
5948                         break;
5949                 case DO_TSTEMPLATE:
5950                         dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5951                         break;
5952                 case DO_TSCONFIG:
5953                         dumpTSConfig(fout, (TSConfigInfo *) dobj);
5954                         break;
5955                 case DO_FDW:
5956                         dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
5957                         break;
5958                 case DO_FOREIGN_SERVER:
5959                         dumpForeignServer(fout, (ForeignServerInfo *) dobj);
5960                         break;
5961                 case DO_BLOBS:
5962                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5963                                                  dobj->name, NULL, NULL, "",
5964                                                  false, "BLOBS", SECTION_DATA,
5965                                                  "", "", NULL,
5966                                                  dobj->dependencies, dobj->nDeps,
5967                                                  dumpBlobs, NULL);
5968                         break;
5969                 case DO_BLOB_COMMENTS:
5970                         ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5971                                                  dobj->name, NULL, NULL, "",
5972                                                  false, "BLOB COMMENTS", SECTION_DATA,
5973                                                  "", "", NULL,
5974                                                  dobj->dependencies, dobj->nDeps,
5975                                                  dumpBlobComments, NULL);
5976                         break;
5977         }
5978 }
5979
5980 /*
5981  * dumpNamespace
5982  *        writes out to fout the queries to recreate a user-defined namespace
5983  */
5984 static void
5985 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5986 {
5987         PQExpBuffer q;
5988         PQExpBuffer delq;
5989         char       *qnspname;
5990
5991         /* Skip if not to be dumped */
5992         if (!nspinfo->dobj.dump || dataOnly)
5993                 return;
5994
5995         /* don't dump dummy namespace from pre-7.3 source */
5996         if (strlen(nspinfo->dobj.name) == 0)
5997                 return;
5998
5999         q = createPQExpBuffer();
6000         delq = createPQExpBuffer();
6001
6002         qnspname = strdup(fmtId(nspinfo->dobj.name));
6003
6004         appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
6005
6006         appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
6007
6008         ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
6009                                  nspinfo->dobj.name,
6010                                  NULL, NULL,
6011                                  nspinfo->rolname,
6012                                  false, "SCHEMA", SECTION_PRE_DATA,
6013                                  q->data, delq->data, NULL,
6014                                  nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
6015                                  NULL, NULL);
6016
6017         /* Dump Schema Comments */
6018         resetPQExpBuffer(q);
6019         appendPQExpBuffer(q, "SCHEMA %s", qnspname);
6020         dumpComment(fout, q->data,
6021                                 NULL, nspinfo->rolname,
6022                                 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
6023
6024         dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6025                         qnspname, NULL, nspinfo->dobj.name, NULL,
6026                         nspinfo->rolname, nspinfo->nspacl);
6027
6028         free(qnspname);
6029
6030         destroyPQExpBuffer(q);
6031         destroyPQExpBuffer(delq);
6032 }
6033
6034 /*
6035  * dumpType
6036  *        writes out to fout the queries to recreate a user-defined type
6037  */
6038 static void
6039 dumpType(Archive *fout, TypeInfo *tinfo)
6040 {
6041         /* Skip if not to be dumped */
6042         if (!tinfo->dobj.dump || dataOnly)
6043                 return;
6044
6045         /* Dump out in proper style */
6046         if (tinfo->typtype == TYPTYPE_BASE)
6047                 dumpBaseType(fout, tinfo);
6048         else if (tinfo->typtype == TYPTYPE_DOMAIN)
6049                 dumpDomain(fout, tinfo);
6050         else if (tinfo->typtype == TYPTYPE_COMPOSITE)
6051                 dumpCompositeType(fout, tinfo);
6052         else if (tinfo->typtype == TYPTYPE_ENUM)
6053                 dumpEnumType(fout, tinfo);
6054 }
6055
6056 /*
6057  * dumpEnumType
6058  *        writes out to fout the queries to recreate a user-defined enum type
6059  */
6060 static void
6061 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6062 {
6063         PQExpBuffer q = createPQExpBuffer();
6064         PQExpBuffer delq = createPQExpBuffer();
6065         PQExpBuffer query = createPQExpBuffer();
6066         PGresult   *res;
6067         int                     num,
6068                                 i;
6069         char       *label;
6070
6071         /* Set proper schema search path so regproc references list correctly */
6072         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6073
6074         appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6075                                           "WHERE enumtypid = '%u'"
6076                                           "ORDER BY oid",
6077                                           tinfo->dobj.catId.oid);
6078
6079         res = PQexec(g_conn, query->data);
6080         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6081
6082         num = PQntuples(res);
6083         /* should be at least 1 value */
6084         if (num == 0)
6085         {
6086                 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
6087                 exit_nicely();
6088         }
6089
6090         /*
6091          * DROP must be fully qualified in case same name appears in pg_catalog.
6092          * CASCADE shouldn't be required here as for normal types since the I/O
6093          * functions are generic and do not get dropped.
6094          */
6095         appendPQExpBuffer(delq, "DROP TYPE %s.",
6096                                           fmtId(tinfo->dobj.namespace->dobj.name));
6097         appendPQExpBuffer(delq, "%s;\n",
6098                                           fmtId(tinfo->dobj.name));
6099         appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (\n",
6100                                           fmtId(tinfo->dobj.name));
6101         for (i = 0; i < num; i++)
6102         {
6103                 label = PQgetvalue(res, i, 0);
6104                 if (i > 0)
6105                         appendPQExpBuffer(q, ",\n");
6106                 appendPQExpBuffer(q, "    ");
6107                 appendStringLiteralAH(q, label, fout);
6108         }
6109         appendPQExpBuffer(q, "\n);\n");
6110
6111         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6112                                  tinfo->dobj.name,
6113                                  tinfo->dobj.namespace->dobj.name,
6114                                  NULL,
6115                                  tinfo->rolname, false,
6116                                  "TYPE", SECTION_PRE_DATA,
6117                                  q->data, delq->data, NULL,
6118                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6119                                  NULL, NULL);
6120
6121         /* Dump Type Comments */
6122         resetPQExpBuffer(q);
6123
6124         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6125         dumpComment(fout, q->data,
6126                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6127                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6128
6129         PQclear(res);
6130         destroyPQExpBuffer(q);
6131         destroyPQExpBuffer(delq);
6132         destroyPQExpBuffer(query);
6133 }
6134
6135 /*
6136  * dumpBaseType
6137  *        writes out to fout the queries to recreate a user-defined base type
6138  */
6139 static void
6140 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6141 {
6142         PQExpBuffer q = createPQExpBuffer();
6143         PQExpBuffer delq = createPQExpBuffer();
6144         PQExpBuffer query = createPQExpBuffer();
6145         PGresult   *res;
6146         int                     ntups;
6147         char       *typlen;
6148         char       *typinput;
6149         char       *typoutput;
6150         char       *typreceive;
6151         char       *typsend;
6152         char       *typmodin;
6153         char       *typmodout;
6154         char       *typanalyze;
6155         Oid                     typinputoid;
6156         Oid                     typoutputoid;
6157         Oid                     typreceiveoid;
6158         Oid                     typsendoid;
6159         Oid                     typmodinoid;
6160         Oid                     typmodoutoid;
6161         Oid                     typanalyzeoid;
6162         char       *typcategory;
6163         char       *typispreferred;
6164         char       *typdelim;
6165         char       *typbyval;
6166         char       *typalign;
6167         char       *typstorage;
6168         char       *typdefault;
6169         bool            typdefault_is_literal = false;
6170
6171         /* Set proper schema search path so regproc references list correctly */
6172         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6173
6174         /* Fetch type-specific details */
6175         if (fout->remoteVersion >= 80400)
6176         {
6177                 appendPQExpBuffer(query, "SELECT typlen, "
6178                                                   "typinput, typoutput, typreceive, typsend, "
6179                                                   "typmodin, typmodout, typanalyze, "
6180                                                   "typinput::pg_catalog.oid AS typinputoid, "
6181                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6182                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6183                                                   "typsend::pg_catalog.oid AS typsendoid, "
6184                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
6185                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
6186                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6187                                                   "typcategory, typispreferred, "
6188                                                   "typdelim, typbyval, typalign, typstorage, "
6189                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6190                                                   "FROM pg_catalog.pg_type "
6191                                                   "WHERE oid = '%u'::pg_catalog.oid",
6192                                                   tinfo->dobj.catId.oid);
6193         }
6194         else if (fout->remoteVersion >= 80300)
6195         {
6196                 appendPQExpBuffer(query, "SELECT typlen, "
6197                                                   "typinput, typoutput, typreceive, typsend, "
6198                                                   "typmodin, typmodout, typanalyze, "
6199                                                   "typinput::pg_catalog.oid AS typinputoid, "
6200                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6201                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6202                                                   "typsend::pg_catalog.oid AS typsendoid, "
6203                                                   "typmodin::pg_catalog.oid AS typmodinoid, "
6204                                                   "typmodout::pg_catalog.oid AS typmodoutoid, "
6205                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6206                                                   "'U' AS typcategory, false AS typispreferred, "
6207                                                   "typdelim, typbyval, typalign, typstorage, "
6208                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6209                                                   "FROM pg_catalog.pg_type "
6210                                                   "WHERE oid = '%u'::pg_catalog.oid",
6211                                                   tinfo->dobj.catId.oid);
6212         }
6213         else if (fout->remoteVersion >= 80000)
6214         {
6215                 appendPQExpBuffer(query, "SELECT typlen, "
6216                                                   "typinput, typoutput, typreceive, typsend, "
6217                                                   "'-' AS typmodin, '-' AS typmodout, "
6218                                                   "typanalyze, "
6219                                                   "typinput::pg_catalog.oid AS typinputoid, "
6220                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6221                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6222                                                   "typsend::pg_catalog.oid AS typsendoid, "
6223                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6224                                                   "typanalyze::pg_catalog.oid AS typanalyzeoid, "
6225                                                   "'U' AS typcategory, false AS typispreferred, "
6226                                                   "typdelim, typbyval, typalign, typstorage, "
6227                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6228                                                   "FROM pg_catalog.pg_type "
6229                                                   "WHERE oid = '%u'::pg_catalog.oid",
6230                                                   tinfo->dobj.catId.oid);
6231         }
6232         else if (fout->remoteVersion >= 70400)
6233         {
6234                 appendPQExpBuffer(query, "SELECT typlen, "
6235                                                   "typinput, typoutput, typreceive, typsend, "
6236                                                   "'-' AS typmodin, '-' AS typmodout, "
6237                                                   "'-' AS typanalyze, "
6238                                                   "typinput::pg_catalog.oid AS typinputoid, "
6239                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6240                                                   "typreceive::pg_catalog.oid AS typreceiveoid, "
6241                                                   "typsend::pg_catalog.oid AS typsendoid, "
6242                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6243                                                   "0 AS typanalyzeoid, "
6244                                                   "'U' AS typcategory, false AS typispreferred, "
6245                                                   "typdelim, typbyval, typalign, typstorage, "
6246                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6247                                                   "FROM pg_catalog.pg_type "
6248                                                   "WHERE oid = '%u'::pg_catalog.oid",
6249                                                   tinfo->dobj.catId.oid);
6250         }
6251         else if (fout->remoteVersion >= 70300)
6252         {
6253                 appendPQExpBuffer(query, "SELECT typlen, "
6254                                                   "typinput, typoutput, "
6255                                                   "'-' AS typreceive, '-' AS typsend, "
6256                                                   "'-' AS typmodin, '-' AS typmodout, "
6257                                                   "'-' AS typanalyze, "
6258                                                   "typinput::pg_catalog.oid AS typinputoid, "
6259                                                   "typoutput::pg_catalog.oid AS typoutputoid, "
6260                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6261                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6262                                                   "0 AS typanalyzeoid, "
6263                                                   "'U' AS typcategory, false AS typispreferred, "
6264                                                   "typdelim, typbyval, typalign, typstorage, "
6265                                                   "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6266                                                   "FROM pg_catalog.pg_type "
6267                                                   "WHERE oid = '%u'::pg_catalog.oid",
6268                                                   tinfo->dobj.catId.oid);
6269         }
6270         else if (fout->remoteVersion >= 70200)
6271         {
6272                 /*
6273                  * Note: although pre-7.3 catalogs contain typreceive and typsend,
6274                  * ignore them because they are not right.
6275                  */
6276                 appendPQExpBuffer(query, "SELECT typlen, "
6277                                                   "typinput, typoutput, "
6278                                                   "'-' AS typreceive, '-' AS typsend, "
6279                                                   "'-' AS typmodin, '-' AS typmodout, "
6280                                                   "'-' AS typanalyze, "
6281                                                   "typinput::oid AS typinputoid, "
6282                                                   "typoutput::oid AS typoutputoid, "
6283                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6284                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6285                                                   "0 AS typanalyzeoid, "
6286                                                   "'U' AS typcategory, false AS typispreferred, "
6287                                                   "typdelim, typbyval, typalign, typstorage, "
6288                                                   "NULL AS typdefaultbin, typdefault "
6289                                                   "FROM pg_type "
6290                                                   "WHERE oid = '%u'::oid",
6291                                                   tinfo->dobj.catId.oid);
6292         }
6293         else if (fout->remoteVersion >= 70100)
6294         {
6295                 /*
6296                  * Ignore pre-7.2 typdefault; the field exists but has an unusable
6297                  * representation.
6298                  */
6299                 appendPQExpBuffer(query, "SELECT typlen, "
6300                                                   "typinput, typoutput, "
6301                                                   "'-' AS typreceive, '-' AS typsend, "
6302                                                   "'-' AS typmodin, '-' AS typmodout, "
6303                                                   "'-' AS typanalyze, "
6304                                                   "typinput::oid AS typinputoid, "
6305                                                   "typoutput::oid AS typoutputoid, "
6306                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6307                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6308                                                   "0 AS typanalyzeoid, "
6309                                                   "'U' AS typcategory, false AS typispreferred, "
6310                                                   "typdelim, typbyval, typalign, typstorage, "
6311                                                   "NULL AS typdefaultbin, NULL AS typdefault "
6312                                                   "FROM pg_type "
6313                                                   "WHERE oid = '%u'::oid",
6314                                                   tinfo->dobj.catId.oid);
6315         }
6316         else
6317         {
6318                 appendPQExpBuffer(query, "SELECT typlen, "
6319                                                   "typinput, typoutput, "
6320                                                   "'-' AS typreceive, '-' AS typsend, "
6321                                                   "'-' AS typmodin, '-' AS typmodout, "
6322                                                   "'-' AS typanalyze, "
6323                                                   "typinput::oid AS typinputoid, "
6324                                                   "typoutput::oid AS typoutputoid, "
6325                                                   "0 AS typreceiveoid, 0 AS typsendoid, "
6326                                                   "0 AS typmodinoid, 0 AS typmodoutoid, "
6327                                                   "0 AS typanalyzeoid, "
6328                                                   "'U' AS typcategory, false AS typispreferred, "
6329                                                   "typdelim, typbyval, typalign, "
6330                                                   "'p'::char AS typstorage, "
6331                                                   "NULL AS typdefaultbin, NULL AS typdefault "
6332                                                   "FROM pg_type "
6333                                                   "WHERE oid = '%u'::oid",
6334                                                   tinfo->dobj.catId.oid);
6335         }
6336
6337         res = PQexec(g_conn, query->data);
6338         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6339
6340         /* Expecting a single result only */
6341         ntups = PQntuples(res);
6342         if (ntups != 1)
6343         {
6344                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6345                                                                  "query returned %d rows instead of one: %s\n",
6346                                                                  ntups),
6347                                   ntups, query->data);
6348                 exit_nicely();
6349         }
6350
6351         typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
6352         typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
6353         typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
6354         typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
6355         typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
6356         typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
6357         typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
6358         typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
6359         typinputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typinputoid")));
6360         typoutputoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typoutputoid")));
6361         typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
6362         typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
6363         typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
6364         typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
6365         typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
6366         typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
6367         typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
6368         typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
6369         typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
6370         typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
6371         typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
6372         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6373                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6374         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6375         {
6376                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6377                 typdefault_is_literal = true;   /* it needs quotes */
6378         }
6379         else
6380                 typdefault = NULL;
6381
6382         /*
6383          * DROP must be fully qualified in case same name appears in pg_catalog.
6384          * The reason we include CASCADE is that the circular dependency between
6385          * the type and its I/O functions makes it impossible to drop the type any
6386          * other way.
6387          */
6388         appendPQExpBuffer(delq, "DROP TYPE %s.",
6389                                           fmtId(tinfo->dobj.namespace->dobj.name));
6390         appendPQExpBuffer(delq, "%s CASCADE;\n",
6391                                           fmtId(tinfo->dobj.name));
6392
6393         appendPQExpBuffer(q,
6394                                           "CREATE TYPE %s (\n"
6395                                           "    INTERNALLENGTH = %s",
6396                                           fmtId(tinfo->dobj.name),
6397                                           (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6398
6399         if (fout->remoteVersion >= 70300)
6400         {
6401                 /* regproc result is correctly quoted as of 7.3 */
6402                 appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
6403                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
6404                 if (OidIsValid(typreceiveoid))
6405                         appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
6406                 if (OidIsValid(typsendoid))
6407                         appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
6408                 if (OidIsValid(typmodinoid))
6409                         appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
6410                 if (OidIsValid(typmodoutoid))
6411                         appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
6412                 if (OidIsValid(typanalyzeoid))
6413                         appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
6414         }
6415         else
6416         {
6417                 /* regproc delivers an unquoted name before 7.3 */
6418                 /* cannot combine these because fmtId uses static result area */
6419                 appendPQExpBuffer(q, ",\n    INPUT = %s", fmtId(typinput));
6420                 appendPQExpBuffer(q, ",\n    OUTPUT = %s", fmtId(typoutput));
6421                 /* receive/send/typmodin/typmodout/analyze need not be printed */
6422         }
6423
6424         if (typdefault != NULL)
6425         {
6426                 appendPQExpBuffer(q, ",\n    DEFAULT = ");
6427                 if (typdefault_is_literal)
6428                         appendStringLiteralAH(q, typdefault, fout);
6429                 else
6430                         appendPQExpBufferStr(q, typdefault);
6431         }
6432
6433         if (OidIsValid(tinfo->typelem))
6434         {
6435                 char       *elemType;
6436
6437                 /* reselect schema in case changed by function dump */
6438                 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6439                 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
6440                 appendPQExpBuffer(q, ",\n    ELEMENT = %s", elemType);
6441                 free(elemType);
6442         }
6443
6444         if (strcmp(typcategory, "U") != 0)
6445         {
6446                 appendPQExpBuffer(q, ",\n    CATEGORY = ");
6447                 appendStringLiteralAH(q, typcategory, fout);
6448         }
6449
6450         if (strcmp(typispreferred, "t") == 0)
6451                 appendPQExpBuffer(q, ",\n    PREFERRED = true");
6452
6453         if (typdelim && strcmp(typdelim, ",") != 0)
6454         {
6455                 appendPQExpBuffer(q, ",\n    DELIMITER = ");
6456                 appendStringLiteralAH(q, typdelim, fout);
6457         }
6458
6459         if (strcmp(typalign, "c") == 0)
6460                 appendPQExpBuffer(q, ",\n    ALIGNMENT = char");
6461         else if (strcmp(typalign, "s") == 0)
6462                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int2");
6463         else if (strcmp(typalign, "i") == 0)
6464                 appendPQExpBuffer(q, ",\n    ALIGNMENT = int4");
6465         else if (strcmp(typalign, "d") == 0)
6466                 appendPQExpBuffer(q, ",\n    ALIGNMENT = double");
6467
6468         if (strcmp(typstorage, "p") == 0)
6469                 appendPQExpBuffer(q, ",\n    STORAGE = plain");
6470         else if (strcmp(typstorage, "e") == 0)
6471                 appendPQExpBuffer(q, ",\n    STORAGE = external");
6472         else if (strcmp(typstorage, "x") == 0)
6473                 appendPQExpBuffer(q, ",\n    STORAGE = extended");
6474         else if (strcmp(typstorage, "m") == 0)
6475                 appendPQExpBuffer(q, ",\n    STORAGE = main");
6476
6477         if (strcmp(typbyval, "t") == 0)
6478                 appendPQExpBuffer(q, ",\n    PASSEDBYVALUE");
6479
6480         appendPQExpBuffer(q, "\n);\n");
6481
6482         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6483                                  tinfo->dobj.name,
6484                                  tinfo->dobj.namespace->dobj.name,
6485                                  NULL,
6486                                  tinfo->rolname, false,
6487                                  "TYPE", SECTION_PRE_DATA,
6488                                  q->data, delq->data, NULL,
6489                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6490                                  NULL, NULL);
6491
6492         /* Dump Type Comments */
6493         resetPQExpBuffer(q);
6494
6495         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6496         dumpComment(fout, q->data,
6497                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6498                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6499
6500         PQclear(res);
6501         destroyPQExpBuffer(q);
6502         destroyPQExpBuffer(delq);
6503         destroyPQExpBuffer(query);
6504 }
6505
6506 /*
6507  * dumpDomain
6508  *        writes out to fout the queries to recreate a user-defined domain
6509  */
6510 static void
6511 dumpDomain(Archive *fout, TypeInfo *tinfo)
6512 {
6513         PQExpBuffer q = createPQExpBuffer();
6514         PQExpBuffer delq = createPQExpBuffer();
6515         PQExpBuffer query = createPQExpBuffer();
6516         PGresult   *res;
6517         int                     ntups;
6518         int                     i;
6519         char       *typnotnull;
6520         char       *typdefn;
6521         char       *typdefault;
6522         bool            typdefault_is_literal = false;
6523
6524         /* Set proper schema search path so type references list correctly */
6525         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6526
6527         /* Fetch domain specific details */
6528         /* We assume here that remoteVersion must be at least 70300 */
6529         appendPQExpBuffer(query, "SELECT typnotnull, "
6530                                 "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
6531                                           "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
6532                                           "FROM pg_catalog.pg_type "
6533                                           "WHERE oid = '%u'::pg_catalog.oid",
6534                                           tinfo->dobj.catId.oid);
6535
6536         res = PQexec(g_conn, query->data);
6537         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6538
6539         /* Expecting a single result only */
6540         ntups = PQntuples(res);
6541         if (ntups != 1)
6542         {
6543                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6544                                                                  "query returned %d rows instead of one: %s\n",
6545                                                                  ntups),
6546                                   ntups, query->data);
6547                 exit_nicely();
6548         }
6549
6550         typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
6551         typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
6552         if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
6553                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
6554         else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
6555         {
6556                 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6557                 typdefault_is_literal = true;   /* it needs quotes */
6558         }
6559         else
6560                 typdefault = NULL;
6561
6562         appendPQExpBuffer(q,
6563                                           "CREATE DOMAIN %s AS %s",
6564                                           fmtId(tinfo->dobj.name),
6565                                           typdefn);
6566
6567         if (typnotnull[0] == 't')
6568                 appendPQExpBuffer(q, " NOT NULL");
6569
6570         if (typdefault != NULL)
6571         {
6572                 appendPQExpBuffer(q, " DEFAULT ");
6573                 if (typdefault_is_literal)
6574                         appendStringLiteralAH(q, typdefault, fout);
6575                 else
6576                         appendPQExpBufferStr(q, typdefault);
6577         }
6578
6579         PQclear(res);
6580
6581         /*
6582          * Add any CHECK constraints for the domain
6583          */
6584         for (i = 0; i < tinfo->nDomChecks; i++)
6585         {
6586                 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6587
6588                 if (!domcheck->separate)
6589                         appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6590                                                           fmtId(domcheck->dobj.name), domcheck->condef);
6591         }
6592
6593         appendPQExpBuffer(q, ";\n");
6594
6595         /*
6596          * DROP must be fully qualified in case same name appears in pg_catalog
6597          */
6598         appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6599                                           fmtId(tinfo->dobj.namespace->dobj.name));
6600         appendPQExpBuffer(delq, "%s;\n",
6601                                           fmtId(tinfo->dobj.name));
6602
6603         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6604                                  tinfo->dobj.name,
6605                                  tinfo->dobj.namespace->dobj.name,
6606                                  NULL,
6607                                  tinfo->rolname, false,
6608                                  "DOMAIN", SECTION_PRE_DATA,
6609                                  q->data, delq->data, NULL,
6610                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6611                                  NULL, NULL);
6612
6613         /* Dump Domain Comments */
6614         resetPQExpBuffer(q);
6615
6616         appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->dobj.name));
6617         dumpComment(fout, q->data,
6618                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6619                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6620
6621         destroyPQExpBuffer(q);
6622         destroyPQExpBuffer(delq);
6623         destroyPQExpBuffer(query);
6624 }
6625
6626 /*
6627  * dumpCompositeType
6628  *        writes out to fout the queries to recreate a user-defined stand-alone
6629  *        composite type
6630  */
6631 static void
6632 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6633 {
6634         PQExpBuffer q = createPQExpBuffer();
6635         PQExpBuffer delq = createPQExpBuffer();
6636         PQExpBuffer query = createPQExpBuffer();
6637         PGresult   *res;
6638         int                     ntups;
6639         int                     i_attname;
6640         int                     i_atttypdefn;
6641         int                     i;
6642
6643         /* Set proper schema search path so type references list correctly */
6644         selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6645
6646         /* Fetch type specific details */
6647         /* We assume here that remoteVersion must be at least 70300 */
6648
6649         appendPQExpBuffer(query, "SELECT a.attname, "
6650                          "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn "
6651                                           "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
6652                                           "WHERE t.oid = '%u'::pg_catalog.oid "
6653                                           "AND a.attrelid = t.typrelid "
6654                                           "AND NOT a.attisdropped "
6655                                           "ORDER BY a.attnum ",
6656                                           tinfo->dobj.catId.oid);
6657
6658         res = PQexec(g_conn, query->data);
6659         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6660
6661         /* Expecting at least a single result */
6662         ntups = PQntuples(res);
6663         if (ntups < 1)
6664         {
6665                 write_msg(NULL, "query returned no rows: %s\n", query->data);
6666                 exit_nicely();
6667         }
6668
6669         i_attname = PQfnumber(res, "attname");
6670         i_atttypdefn = PQfnumber(res, "atttypdefn");
6671
6672         appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6673                                           fmtId(tinfo->dobj.name));
6674
6675         for (i = 0; i < ntups; i++)
6676         {
6677                 char       *attname;
6678                 char       *atttypdefn;
6679
6680                 attname = PQgetvalue(res, i, i_attname);
6681                 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6682
6683                 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6684                 if (i < ntups - 1)
6685                         appendPQExpBuffer(q, ",");
6686         }
6687         appendPQExpBuffer(q, "\n);\n");
6688
6689         /*
6690          * DROP must be fully qualified in case same name appears in pg_catalog
6691          */
6692         appendPQExpBuffer(delq, "DROP TYPE %s.",
6693                                           fmtId(tinfo->dobj.namespace->dobj.name));
6694         appendPQExpBuffer(delq, "%s;\n",
6695                                           fmtId(tinfo->dobj.name));
6696
6697         ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6698                                  tinfo->dobj.name,
6699                                  tinfo->dobj.namespace->dobj.name,
6700                                  NULL,
6701                                  tinfo->rolname, false,
6702                                  "TYPE", SECTION_PRE_DATA,
6703                                  q->data, delq->data, NULL,
6704                                  tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6705                                  NULL, NULL);
6706
6707
6708         /* Dump Type Comments */
6709         resetPQExpBuffer(q);
6710
6711         appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->dobj.name));
6712         dumpComment(fout, q->data,
6713                                 tinfo->dobj.namespace->dobj.name, tinfo->rolname,
6714                                 tinfo->dobj.catId, 0, tinfo->dobj.dumpId);
6715
6716         PQclear(res);
6717         destroyPQExpBuffer(q);
6718         destroyPQExpBuffer(delq);
6719         destroyPQExpBuffer(query);
6720 }
6721
6722 /*
6723  * dumpShellType
6724  *        writes out to fout the queries to create a shell type
6725  *
6726  * We dump a shell definition in advance of the I/O functions for the type.
6727  */
6728 static void
6729 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6730 {
6731         PQExpBuffer q;
6732
6733         /* Skip if not to be dumped */
6734         if (!stinfo->dobj.dump || dataOnly)
6735                 return;
6736
6737         q = createPQExpBuffer();
6738
6739         /*
6740          * Note the lack of a DROP command for the shell type; any required DROP
6741          * is driven off the base type entry, instead.  This interacts with
6742          * _printTocEntry()'s use of the presence of a DROP command to decide
6743          * whether an entry needs an ALTER OWNER command.  We don't want to alter
6744          * the shell type's owner immediately on creation; that should happen only
6745          * after it's filled in, otherwise the backend complains.
6746          */
6747
6748         appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6749                                           fmtId(stinfo->dobj.name));
6750
6751         ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6752                                  stinfo->dobj.name,
6753                                  stinfo->dobj.namespace->dobj.name,
6754                                  NULL,
6755                                  stinfo->baseType->rolname, false,
6756                                  "SHELL TYPE", SECTION_PRE_DATA,
6757                                  q->data, "", NULL,
6758                                  stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6759                                  NULL, NULL);
6760
6761         destroyPQExpBuffer(q);
6762 }
6763
6764 /*
6765  * Determine whether we want to dump definitions for procedural languages.
6766  * Since the languages themselves don't have schemas, we can't rely on
6767  * the normal schema-based selection mechanism.  We choose to dump them
6768  * whenever neither --schema nor --table was given.  (Before 8.1, we used
6769  * the dump flag of the PL's call handler function, but in 8.1 this will
6770  * probably always be false since call handlers are created in pg_catalog.)
6771  *
6772  * For some backwards compatibility with the older behavior, we forcibly
6773  * dump a PL if its handler function (and validator if any) are in a
6774  * dumpable namespace.  That case is not checked here.
6775  */
6776 static bool
6777 shouldDumpProcLangs(void)
6778 {
6779         if (!include_everything)
6780                 return false;
6781         /* And they're schema not data */
6782         if (dataOnly)
6783                 return false;
6784         return true;
6785 }
6786
6787 /*
6788  * dumpProcLang
6789  *                writes out to fout the queries to recreate a user-defined
6790  *                procedural language
6791  */
6792 static void
6793 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6794 {
6795         PQExpBuffer defqry;
6796         PQExpBuffer delqry;
6797         bool            useParams;
6798         char       *qlanname;
6799         char       *lanschema;
6800         FuncInfo   *funcInfo;
6801         FuncInfo   *validatorInfo = NULL;
6802
6803         if (dataOnly)
6804                 return;
6805
6806         /*
6807          * Try to find the support function(s).  It is not an error if we don't
6808          * find them --- if the functions are in the pg_catalog schema, as is
6809          * standard in 8.1 and up, then we won't have loaded them. (In this case
6810          * we will emit a parameterless CREATE LANGUAGE command, which will
6811          * require PL template knowledge in the backend to reload.)
6812          */
6813
6814         funcInfo = findFuncByOid(plang->lanplcallfoid);
6815         if (funcInfo != NULL && !funcInfo->dobj.dump)
6816                 funcInfo = NULL;                /* treat not-dumped same as not-found */
6817
6818         if (OidIsValid(plang->lanvalidator))
6819         {
6820                 validatorInfo = findFuncByOid(plang->lanvalidator);
6821                 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6822                         validatorInfo = NULL;
6823         }
6824
6825         /*
6826          * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6827          * with parameters.  Otherwise, dump only if shouldDumpProcLangs() says to
6828          * dump it.
6829          */
6830         useParams = (funcInfo != NULL &&
6831                                  (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6832
6833         if (!useParams && !shouldDumpProcLangs())
6834                 return;
6835
6836         defqry = createPQExpBuffer();
6837         delqry = createPQExpBuffer();
6838
6839         qlanname = strdup(fmtId(plang->dobj.name));
6840
6841         /*
6842          * If dumping a HANDLER clause, treat the language as being in the handler
6843          * function's schema; this avoids cluttering the HANDLER clause. Otherwise
6844          * it doesn't really have a schema.
6845          */
6846         if (useParams)
6847                 lanschema = funcInfo->dobj.namespace->dobj.name;
6848         else
6849                 lanschema = NULL;
6850
6851         appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6852                                           qlanname);
6853
6854         appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6855                                           (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6856                                           qlanname);
6857         if (useParams)
6858         {
6859                 appendPQExpBuffer(defqry, " HANDLER %s",
6860                                                   fmtId(funcInfo->dobj.name));
6861                 if (OidIsValid(plang->lanvalidator))
6862                 {
6863                         appendPQExpBuffer(defqry, " VALIDATOR ");
6864                         /* Cope with possibility that validator is in different schema */
6865                         if (validatorInfo->dobj.namespace != funcInfo->dobj.namespace)
6866                                 appendPQExpBuffer(defqry, "%s.",
6867                                                         fmtId(validatorInfo->dobj.namespace->dobj.name));
6868                         appendPQExpBuffer(defqry, "%s",
6869                                                           fmtId(validatorInfo->dobj.name));
6870                 }
6871         }
6872         appendPQExpBuffer(defqry, ";\n");
6873
6874         ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
6875                                  plang->dobj.name,
6876                                  lanschema, NULL, plang->lanowner,
6877                                  false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
6878                                  defqry->data, delqry->data, NULL,
6879                                  plang->dobj.dependencies, plang->dobj.nDeps,
6880                                  NULL, NULL);
6881
6882         /* Dump Proc Lang Comments */
6883         resetPQExpBuffer(defqry);
6884         appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6885         dumpComment(fout, defqry->data,
6886                                 NULL, "",
6887                                 plang->dobj.catId, 0, plang->dobj.dumpId);
6888
6889         if (plang->lanpltrusted)
6890                 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6891                                 qlanname, NULL, plang->dobj.name,
6892                                 lanschema,
6893                                 plang->lanowner, plang->lanacl);
6894
6895         free(qlanname);
6896
6897         destroyPQExpBuffer(defqry);
6898         destroyPQExpBuffer(delqry);
6899 }
6900
6901 /*
6902  * format_function_arguments: generate function name and argument list
6903  *
6904  * This is used when we can rely on pg_get_function_arguments to format
6905  * the argument list.
6906  */
6907 static char *format_function_arguments(FuncInfo *finfo, char *funcargs)
6908 {
6909         PQExpBufferData fn;
6910
6911         initPQExpBuffer(&fn);
6912         appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6913         return fn.data;
6914 }
6915
6916 /*
6917  * format_function_arguments_old: generate function name and argument list
6918  *
6919  * The argument type names are qualified if needed.  The function name
6920  * is never qualified.
6921  *
6922  * This is used only with pre-8.4 servers, so we aren't expecting to see
6923  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
6924  *
6925  * Any or all of allargtypes, argmodes, argnames may be NULL.
6926  */
6927 static char *
6928 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6929                                                           char **allargtypes,
6930                                                           char **argmodes,
6931                                                           char **argnames)
6932 {
6933         PQExpBufferData fn;
6934         int                     j;
6935
6936         initPQExpBuffer(&fn);
6937         appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6938         for (j = 0; j < nallargs; j++)
6939         {
6940                 Oid                     typid;
6941                 char       *typname;
6942                 const char *argmode;
6943                 const char *argname;
6944
6945                 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6946                 typname = getFormattedTypeName(typid, zeroAsOpaque);
6947
6948                 if (argmodes)
6949                 {
6950                         switch (argmodes[j][0])
6951                         {
6952                                 case PROARGMODE_IN:
6953                                         argmode = "";
6954                                         break;
6955                                 case PROARGMODE_OUT:
6956                                         argmode = "OUT ";
6957                                         break;
6958                                 case PROARGMODE_INOUT:
6959                                         argmode = "INOUT ";
6960                                         break;
6961                                 default:
6962                                         write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6963                                         argmode = "";
6964                                         break;
6965                         }
6966                 }
6967                 else
6968                         argmode = "";
6969
6970                 argname = argnames ? argnames[j] : (char *) NULL;
6971                 if (argname && argname[0] == '\0')
6972                         argname = NULL;
6973
6974                 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6975                                                   (j > 0) ? ", " : "",
6976                                                   argmode,
6977                                                   argname ? fmtId(argname) : "",
6978                                                   argname ? " " : "",
6979                                                   typname);
6980                 free(typname);
6981         }
6982         appendPQExpBuffer(&fn, ")");
6983         return fn.data;
6984 }
6985
6986 /*
6987  * format_function_signature: generate function name and argument list
6988  *
6989  * This is like format_function_arguments_old except that only a minimal
6990  * list of input argument types is generated; this is sufficient to
6991  * reference the function, but not to define it.
6992  *
6993  * If honor_quotes is false then the function name is never quoted.
6994  * This is appropriate for use in TOC tags, but not in SQL commands.
6995  */
6996 static char *
6997 format_function_signature(FuncInfo *finfo, bool honor_quotes)
6998 {
6999         PQExpBufferData fn;
7000         int                     j;
7001
7002         initPQExpBuffer(&fn);
7003         if (honor_quotes)
7004                 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
7005         else
7006                 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
7007         for (j = 0; j < finfo->nargs; j++)
7008         {
7009                 char       *typname;
7010
7011                 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7012
7013                 appendPQExpBuffer(&fn, "%s%s",
7014                                                   (j > 0) ? ", " : "",
7015                                                   typname);
7016                 free(typname);
7017         }
7018         appendPQExpBuffer(&fn, ")");
7019         return fn.data;
7020 }
7021
7022
7023 /*
7024  * dumpFunc:
7025  *        dump out one function
7026  */
7027 static void
7028 dumpFunc(Archive *fout, FuncInfo *finfo)
7029 {
7030         PQExpBuffer query;
7031         PQExpBuffer q;
7032         PQExpBuffer delqry;
7033         PQExpBuffer asPart;
7034         PGresult   *res;
7035         char       *funcsig;                            /* identity signature */
7036         char       *funcfullsig;                        /* full signature */
7037         char       *funcsig_tag;
7038         int                     ntups;
7039         char       *proretset;
7040         char       *prosrc;
7041         char       *probin;
7042         char       *funcargs;
7043         char       *funciargs;
7044         char       *funcresult;
7045         char       *proallargtypes;
7046         char       *proargmodes;
7047         char       *proargnames;
7048         char       *proiswindow;
7049         char       *provolatile;
7050         char       *proisstrict;
7051         char       *prosecdef;
7052         char       *proconfig;
7053         char       *procost;
7054         char       *prorows;
7055         char       *lanname;
7056         char       *rettypename;
7057         int                     nallargs;
7058         char      **allargtypes = NULL;
7059         char      **argmodes = NULL;
7060         char      **argnames = NULL;
7061         char      **configitems = NULL;
7062         int                     nconfigitems = 0;
7063         int                     i;
7064
7065         /* Skip if not to be dumped */
7066         if (!finfo->dobj.dump || dataOnly)
7067                 return;
7068
7069         query = createPQExpBuffer();
7070         q = createPQExpBuffer();
7071         delqry = createPQExpBuffer();
7072         asPart = createPQExpBuffer();
7073
7074         /* Set proper schema search path so type references list correctly */
7075         selectSourceSchema(finfo->dobj.namespace->dobj.name);
7076
7077         /* Fetch function-specific details */
7078         if (g_fout->remoteVersion >= 80400)
7079         {
7080                 /*
7081                  * In 8.4 and up we rely on pg_get_function_arguments and
7082                  * pg_get_function_result instead of examining proallargtypes etc.
7083                  */
7084                 appendPQExpBuffer(query,
7085                                                   "SELECT proretset, prosrc, probin, "
7086                                                   "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
7087                                                   "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
7088                                                   "pg_catalog.pg_get_function_result(oid) AS funcresult, "
7089                                                   "proiswindow, provolatile, proisstrict, prosecdef, "
7090                                                   "proconfig, procost, prorows, "
7091                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7092                                                   "FROM pg_catalog.pg_proc "
7093                                                   "WHERE oid = '%u'::pg_catalog.oid",
7094                                                   finfo->dobj.catId.oid);
7095         }
7096         else if (g_fout->remoteVersion >= 80300)
7097         {
7098                 appendPQExpBuffer(query,
7099                                                   "SELECT proretset, prosrc, probin, "
7100                                                   "proallargtypes, proargmodes, proargnames, "
7101                                                   "false AS proiswindow, "
7102                                                   "provolatile, proisstrict, prosecdef, "
7103                                                   "proconfig, procost, prorows, "
7104                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7105                                                   "FROM pg_catalog.pg_proc "
7106                                                   "WHERE oid = '%u'::pg_catalog.oid",
7107                                                   finfo->dobj.catId.oid);
7108         }
7109         else if (g_fout->remoteVersion >= 80100)
7110         {
7111                 appendPQExpBuffer(query,
7112                                                   "SELECT proretset, prosrc, probin, "
7113                                                   "proallargtypes, proargmodes, proargnames, "
7114                                                   "false AS proiswindow, "
7115                                                   "provolatile, proisstrict, prosecdef, "
7116                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7117                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7118                                                   "FROM pg_catalog.pg_proc "
7119                                                   "WHERE oid = '%u'::pg_catalog.oid",
7120                                                   finfo->dobj.catId.oid);
7121         }
7122         else if (g_fout->remoteVersion >= 80000)
7123         {
7124                 appendPQExpBuffer(query,
7125                                                   "SELECT proretset, prosrc, probin, "
7126                                                   "null AS proallargtypes, "
7127                                                   "null AS proargmodes, "
7128                                                   "proargnames, "
7129                                                   "false AS proiswindow, "
7130                                                   "provolatile, proisstrict, prosecdef, "
7131                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7132                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7133                                                   "FROM pg_catalog.pg_proc "
7134                                                   "WHERE oid = '%u'::pg_catalog.oid",
7135                                                   finfo->dobj.catId.oid);
7136         }
7137         else if (g_fout->remoteVersion >= 70300)
7138         {
7139                 appendPQExpBuffer(query,
7140                                                   "SELECT proretset, prosrc, probin, "
7141                                                   "null AS proallargtypes, "
7142                                                   "null AS proargmodes, "
7143                                                   "null AS proargnames, "
7144                                                   "false AS proiswindow, "
7145                                                   "provolatile, proisstrict, prosecdef, "
7146                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7147                                                   "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
7148                                                   "FROM pg_catalog.pg_proc "
7149                                                   "WHERE oid = '%u'::pg_catalog.oid",
7150                                                   finfo->dobj.catId.oid);
7151         }
7152         else if (g_fout->remoteVersion >= 70100)
7153         {
7154                 appendPQExpBuffer(query,
7155                                                   "SELECT proretset, prosrc, probin, "
7156                                                   "null AS proallargtypes, "
7157                                                   "null AS proargmodes, "
7158                                                   "null AS proargnames, "
7159                                                   "false AS proiswindow, "
7160                          "case when proiscachable then 'i' else 'v' end AS provolatile, "
7161                                                   "proisstrict, "
7162                                                   "false AS prosecdef, "
7163                                                   "null AS proconfig, 0 AS procost, 0 AS prorows, "
7164                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7165                                                   "FROM pg_proc "
7166                                                   "WHERE oid = '%u'::oid",
7167                                                   finfo->dobj.catId.oid);
7168         }
7169         else
7170         {
7171                 appendPQExpBuffer(query,
7172                                                   "SELECT proretset, prosrc, probin, "
7173                                                   "null AS proallargtypes, "
7174                                                   "null AS proargmodes, "
7175                                                   "null AS proargnames, "
7176                                                   "false AS proiswindow, "
7177                          "CASE WHEN proiscachable THEN 'i' ELSE 'v' END AS provolatile, "
7178                                                   "false AS proisstrict, "
7179                                                   "false AS prosecdef, "
7180                                                   "NULL AS proconfig, 0 AS procost, 0 AS prorows, "
7181                   "(SELECT lanname FROM pg_language WHERE oid = prolang) AS lanname "
7182                                                   "FROM pg_proc "
7183                                                   "WHERE oid = '%u'::oid",
7184                                                   finfo->dobj.catId.oid);
7185         }
7186
7187         res = PQexec(g_conn, query->data);
7188         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7189
7190         /* Expecting a single result only */
7191         ntups = PQntuples(res);
7192         if (ntups != 1)
7193         {
7194                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7195                                                                  "query returned %d rows instead of one: %s\n",
7196                                                                  ntups),
7197                                   ntups, query->data);
7198                 exit_nicely();
7199         }
7200
7201         proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
7202         prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
7203         probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
7204         if (g_fout->remoteVersion >= 80400)
7205         {
7206                 funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
7207                 funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
7208                 funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
7209                 proallargtypes = proargmodes = proargnames = NULL;
7210         }
7211         else
7212         {
7213                 proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
7214                 proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
7215                 proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
7216                 funcargs = funciargs = funcresult = NULL;
7217         }
7218         proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
7219         provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
7220         proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
7221         prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
7222         proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
7223         procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
7224         prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
7225         lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
7226
7227         /*
7228          * See backend/commands/functioncmds.c for details of how the 'AS' clause
7229          * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
7230          * versions would set it to "-".  There are no known cases in which prosrc
7231          * is unused, so the tests below for "-" are probably useless.
7232          */
7233         if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7234         {
7235                 appendPQExpBuffer(asPart, "AS ");
7236                 appendStringLiteralAH(asPart, probin, fout);
7237                 if (strcmp(prosrc, "-") != 0)
7238                 {
7239                         appendPQExpBuffer(asPart, ", ");
7240
7241                         /*
7242                          * where we have bin, use dollar quoting if allowed and src
7243                          * contains quote or backslash; else use regular quoting.
7244                          */
7245                         if (disable_dollar_quoting ||
7246                           (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7247                                 appendStringLiteralAH(asPart, prosrc, fout);
7248                         else
7249                                 appendStringLiteralDQ(asPart, prosrc, NULL);
7250                 }
7251         }
7252         else
7253         {
7254                 if (strcmp(prosrc, "-") != 0)
7255                 {
7256                         appendPQExpBuffer(asPart, "AS ");
7257                         /* with no bin, dollar quote src unconditionally if allowed */
7258                         if (disable_dollar_quoting)
7259                                 appendStringLiteralAH(asPart, prosrc, fout);
7260                         else
7261                                 appendStringLiteralDQ(asPart, prosrc, NULL);
7262                 }
7263         }
7264
7265         nallargs = finfo->nargs;        /* unless we learn different from allargs */
7266
7267         if (proallargtypes && *proallargtypes)
7268         {
7269                 int                     nitems = 0;
7270
7271                 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7272                         nitems < finfo->nargs)
7273                 {
7274                         write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7275                         if (allargtypes)
7276                                 free(allargtypes);
7277                         allargtypes = NULL;
7278                 }
7279                 else
7280                         nallargs = nitems;
7281         }
7282
7283         if (proargmodes && *proargmodes)
7284         {
7285                 int                     nitems = 0;
7286
7287                 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7288                         nitems != nallargs)
7289                 {
7290                         write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7291                         if (argmodes)
7292                                 free(argmodes);
7293                         argmodes = NULL;
7294                 }
7295         }
7296
7297         if (proargnames && *proargnames)
7298         {
7299                 int                     nitems = 0;
7300
7301                 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7302                         nitems != nallargs)
7303                 {
7304                         write_msg(NULL, "WARNING: could not parse proargnames array\n");
7305                         if (argnames)
7306                                 free(argnames);
7307                         argnames = NULL;
7308                 }
7309         }
7310
7311         if (proconfig && *proconfig)
7312         {
7313                 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7314                 {
7315                         write_msg(NULL, "WARNING: could not parse proconfig array\n");
7316                         if (configitems)
7317                                 free(configitems);
7318                         configitems = NULL;
7319                         nconfigitems = 0;
7320                 }
7321         }
7322
7323         if (funcargs)
7324         {
7325                 /* 8.4 or later; we rely on server-side code for most of the work */
7326                 funcfullsig = format_function_arguments(finfo, funcargs);
7327                 funcsig = format_function_arguments(finfo, funciargs);
7328         }
7329         else
7330         {
7331                 /* pre-8.4, do it ourselves */
7332                 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7333                                                                                                 argmodes, argnames);
7334                 funcfullsig = funcsig;
7335         }
7336
7337         funcsig_tag = format_function_signature(finfo, false);
7338
7339         /*
7340          * DROP must be fully qualified in case same name appears in pg_catalog
7341          */
7342         appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7343                                           fmtId(finfo->dobj.namespace->dobj.name),
7344                                           funcsig);
7345
7346         appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7347         if (funcresult)
7348                 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7349         else
7350         {
7351                 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7352                 appendPQExpBuffer(q, "RETURNS %s%s",
7353                                                   (proretset[0] == 't') ? "SETOF " : "",
7354                                                   rettypename);
7355                 free(rettypename);
7356         }
7357
7358         appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
7359
7360         if (proiswindow[0] == 't')
7361                 appendPQExpBuffer(q, " WINDOW");
7362
7363         if (provolatile[0] != PROVOLATILE_VOLATILE)
7364         {
7365                 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
7366                         appendPQExpBuffer(q, " IMMUTABLE");
7367                 else if (provolatile[0] == PROVOLATILE_STABLE)
7368                         appendPQExpBuffer(q, " STABLE");
7369                 else if (provolatile[0] != PROVOLATILE_VOLATILE)
7370                 {
7371                         write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7372                                           finfo->dobj.name);
7373                         exit_nicely();
7374                 }
7375         }
7376
7377         if (proisstrict[0] == 't')
7378                 appendPQExpBuffer(q, " STRICT");
7379
7380         if (prosecdef[0] == 't')
7381                 appendPQExpBuffer(q, " SECURITY DEFINER");
7382
7383         /*
7384          * COST and ROWS are emitted only if present and not default, so as not to
7385          * break backwards-compatibility of the dump without need.      Keep this code
7386          * in sync with the defaults in functioncmds.c.
7387          */
7388         if (strcmp(procost, "0") != 0)
7389         {
7390                 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7391                 {
7392                         /* default cost is 1 */
7393                         if (strcmp(procost, "1") != 0)
7394                                 appendPQExpBuffer(q, " COST %s", procost);
7395                 }
7396                 else
7397                 {
7398                         /* default cost is 100 */
7399                         if (strcmp(procost, "100") != 0)
7400                                 appendPQExpBuffer(q, " COST %s", procost);
7401                 }
7402         }
7403         if (proretset[0] == 't' &&
7404                 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7405                 appendPQExpBuffer(q, " ROWS %s", prorows);
7406
7407         for (i = 0; i < nconfigitems; i++)
7408         {
7409                 /* we feel free to scribble on configitems[] here */
7410                 char       *configitem = configitems[i];
7411                 char       *pos;
7412
7413                 pos = strchr(configitem, '=');
7414                 if (pos == NULL)
7415                         continue;
7416                 *pos++ = '\0';
7417                 appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
7418
7419                 /*
7420                  * Some GUC variable names are 'LIST' type and hence must not be
7421                  * quoted.
7422                  */
7423                 if (pg_strcasecmp(configitem, "DateStyle") == 0
7424                         || pg_strcasecmp(configitem, "search_path") == 0)
7425                         appendPQExpBuffer(q, "%s", pos);
7426                 else
7427                         appendStringLiteralAH(q, pos, fout);
7428         }
7429
7430         appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
7431
7432         ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7433                                  funcsig_tag,
7434                                  finfo->dobj.namespace->dobj.name,
7435                                  NULL,
7436                                  finfo->rolname, false,
7437                                  "FUNCTION", SECTION_PRE_DATA,
7438                                  q->data, delqry->data, NULL,
7439                                  finfo->dobj.dependencies, finfo->dobj.nDeps,
7440                                  NULL, NULL);
7441
7442         /* Dump Function Comments */
7443         resetPQExpBuffer(q);
7444         appendPQExpBuffer(q, "FUNCTION %s", funcsig);
7445         dumpComment(fout, q->data,
7446                                 finfo->dobj.namespace->dobj.name, finfo->rolname,
7447                                 finfo->dobj.catId, 0, finfo->dobj.dumpId);
7448
7449         dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
7450                         funcsig, NULL, funcsig_tag,
7451                         finfo->dobj.namespace->dobj.name,
7452                         finfo->rolname, finfo->proacl);
7453
7454         PQclear(res);
7455
7456         destroyPQExpBuffer(query);
7457         destroyPQExpBuffer(q);
7458         destroyPQExpBuffer(delqry);
7459         destroyPQExpBuffer(asPart);
7460         free(funcsig);
7461         free(funcsig_tag);
7462         if (allargtypes)
7463                 free(allargtypes);
7464         if (argmodes)
7465                 free(argmodes);
7466         if (argnames)
7467                 free(argnames);
7468         if (configitems)
7469                 free(configitems);
7470 }
7471
7472
7473 /*
7474  * Dump a user-defined cast
7475  */
7476 static void
7477 dumpCast(Archive *fout, CastInfo *cast)
7478 {
7479         PQExpBuffer defqry;
7480         PQExpBuffer delqry;
7481         PQExpBuffer castsig;
7482         FuncInfo   *funcInfo = NULL;
7483         TypeInfo   *sourceInfo;
7484         TypeInfo   *targetInfo;
7485
7486         if (dataOnly)
7487                 return;
7488
7489         if (OidIsValid(cast->castfunc))
7490         {
7491                 funcInfo = findFuncByOid(cast->castfunc);
7492                 if (funcInfo == NULL)
7493                         return;
7494         }
7495
7496         /*
7497          * As per discussion we dump casts if one or more of the underlying
7498          * objects (the conversion function and the two data types) are not
7499          * builtin AND if all of the non-builtin objects are included in the dump.
7500          * Builtin meaning, the namespace name does not start with "pg_".
7501          */
7502         sourceInfo = findTypeByOid(cast->castsource);
7503         targetInfo = findTypeByOid(cast->casttarget);
7504
7505         if (sourceInfo == NULL || targetInfo == NULL)
7506                 return;
7507
7508         /*
7509          * Skip this cast if all objects are from pg_
7510          */
7511         if ((funcInfo == NULL ||
7512                  strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) == 0) &&
7513                 strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) == 0 &&
7514                 strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) == 0)
7515                 return;
7516
7517         /*
7518          * Skip cast if function isn't from pg_ and is not to be dumped.
7519          */
7520         if (funcInfo &&
7521                 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7522                 !funcInfo->dobj.dump)
7523                 return;
7524
7525         /*
7526          * Same for the source type
7527          */
7528         if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7529                 !sourceInfo->dobj.dump)
7530                 return;
7531
7532         /*
7533          * and the target type.
7534          */
7535         if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7536                 !targetInfo->dobj.dump)
7537                 return;
7538
7539         /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7540         selectSourceSchema("pg_catalog");
7541
7542         defqry = createPQExpBuffer();
7543         delqry = createPQExpBuffer();
7544         castsig = createPQExpBuffer();
7545
7546         appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7547                                           getFormattedTypeName(cast->castsource, zeroAsNone),
7548                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
7549
7550         appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7551                                           getFormattedTypeName(cast->castsource, zeroAsNone),
7552                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
7553
7554         switch(cast->castmethod)
7555         {
7556                 case COERCION_METHOD_BINARY:
7557                         appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7558                         break;
7559                 case COERCION_METHOD_INOUT:
7560                         appendPQExpBuffer(defqry, "WITH INOUT");
7561                         break;
7562                 case COERCION_METHOD_FUNCTION:
7563                         /*
7564                          * Always qualify the function name, in case it is not in
7565                          * pg_catalog schema (format_function_signature won't qualify it).
7566                          */
7567                         appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7568                                                           fmtId(funcInfo->dobj.namespace->dobj.name));
7569                         appendPQExpBuffer(defqry, "%s",
7570                                                           format_function_signature(funcInfo, true));
7571                         break;
7572                 default:
7573                         write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
7574         }
7575
7576         if (cast->castcontext == 'a')
7577                 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
7578         else if (cast->castcontext == 'i')
7579                 appendPQExpBuffer(defqry, " AS IMPLICIT");
7580         appendPQExpBuffer(defqry, ";\n");
7581
7582         appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7583                                           getFormattedTypeName(cast->castsource, zeroAsNone),
7584                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
7585
7586         ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7587                                  castsig->data,
7588                                  "pg_catalog", NULL, "",
7589                                  false, "CAST", SECTION_PRE_DATA,
7590                                  defqry->data, delqry->data, NULL,
7591                                  cast->dobj.dependencies, cast->dobj.nDeps,
7592                                  NULL, NULL);
7593
7594         /* Dump Cast Comments */
7595         resetPQExpBuffer(defqry);
7596         appendPQExpBuffer(defqry, "CAST (%s AS %s)",
7597                                           getFormattedTypeName(cast->castsource, zeroAsNone),
7598                                           getFormattedTypeName(cast->casttarget, zeroAsNone));
7599         dumpComment(fout, defqry->data,
7600                                 NULL, "",
7601                                 cast->dobj.catId, 0, cast->dobj.dumpId);
7602
7603         destroyPQExpBuffer(defqry);
7604         destroyPQExpBuffer(delqry);
7605         destroyPQExpBuffer(castsig);
7606 }
7607
7608 /*
7609  * dumpOpr
7610  *        write out a single operator definition
7611  */
7612 static void
7613 dumpOpr(Archive *fout, OprInfo *oprinfo)
7614 {
7615         PQExpBuffer query;
7616         PQExpBuffer q;
7617         PQExpBuffer delq;
7618         PQExpBuffer oprid;
7619         PQExpBuffer details;
7620         const char *name;
7621         PGresult   *res;
7622         int                     ntups;
7623         int                     i_oprkind;
7624         int                     i_oprcode;
7625         int                     i_oprleft;
7626         int                     i_oprright;
7627         int                     i_oprcom;
7628         int                     i_oprnegate;
7629         int                     i_oprrest;
7630         int                     i_oprjoin;
7631         int                     i_oprcanmerge;
7632         int                     i_oprcanhash;
7633         char       *oprkind;
7634         char       *oprcode;
7635         char       *oprleft;
7636         char       *oprright;
7637         char       *oprcom;
7638         char       *oprnegate;
7639         char       *oprrest;
7640         char       *oprjoin;
7641         char       *oprcanmerge;
7642         char       *oprcanhash;
7643
7644         /* Skip if not to be dumped */
7645         if (!oprinfo->dobj.dump || dataOnly)
7646                 return;
7647
7648         /*
7649          * some operators are invalid because they were the result of user
7650          * defining operators before commutators exist
7651          */
7652         if (!OidIsValid(oprinfo->oprcode))
7653                 return;
7654
7655         query = createPQExpBuffer();
7656         q = createPQExpBuffer();
7657         delq = createPQExpBuffer();
7658         oprid = createPQExpBuffer();
7659         details = createPQExpBuffer();
7660
7661         /* Make sure we are in proper schema so regoperator works correctly */
7662         selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7663
7664         if (g_fout->remoteVersion >= 80300)
7665         {
7666                 appendPQExpBuffer(query, "SELECT oprkind, "
7667                                                   "oprcode::pg_catalog.regprocedure, "
7668                                                   "oprleft::pg_catalog.regtype, "
7669                                                   "oprright::pg_catalog.regtype, "
7670                                                   "oprcom::pg_catalog.regoperator, "
7671                                                   "oprnegate::pg_catalog.regoperator, "
7672                                                   "oprrest::pg_catalog.regprocedure, "
7673                                                   "oprjoin::pg_catalog.regprocedure, "
7674                                                   "oprcanmerge, oprcanhash "
7675                                                   "FROM pg_catalog.pg_operator "
7676                                                   "WHERE oid = '%u'::pg_catalog.oid",
7677                                                   oprinfo->dobj.catId.oid);
7678         }
7679         else if (g_fout->remoteVersion >= 70300)
7680         {
7681                 appendPQExpBuffer(query, "SELECT oprkind, "
7682                                                   "oprcode::pg_catalog.regprocedure, "
7683                                                   "oprleft::pg_catalog.regtype, "
7684                                                   "oprright::pg_catalog.regtype, "
7685                                                   "oprcom::pg_catalog.regoperator, "
7686                                                   "oprnegate::pg_catalog.regoperator, "
7687                                                   "oprrest::pg_catalog.regprocedure, "
7688                                                   "oprjoin::pg_catalog.regprocedure, "
7689                                                   "(oprlsortop != 0) AS oprcanmerge, "
7690                                                   "oprcanhash "
7691                                                   "FROM pg_catalog.pg_operator "
7692                                                   "WHERE oid = '%u'::pg_catalog.oid",
7693                                                   oprinfo->dobj.catId.oid);
7694         }
7695         else if (g_fout->remoteVersion >= 70100)
7696         {
7697                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7698                                                   "CASE WHEN oprleft = 0 THEN '-' "
7699                                                   "ELSE format_type(oprleft, NULL) END AS oprleft, "
7700                                                   "CASE WHEN oprright = 0 THEN '-' "
7701                                                   "ELSE format_type(oprright, NULL) END AS oprright, "
7702                                                   "oprcom, oprnegate, oprrest, oprjoin, "
7703                                                   "(oprlsortop != 0) AS oprcanmerge, "
7704                                                   "oprcanhash "
7705                                                   "FROM pg_operator "
7706                                                   "WHERE oid = '%u'::oid",
7707                                                   oprinfo->dobj.catId.oid);
7708         }
7709         else
7710         {
7711                 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
7712                                                   "CASE WHEN oprleft = 0 THEN '-'::name "
7713                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprleft) END AS oprleft, "
7714                                                   "CASE WHEN oprright = 0 THEN '-'::name "
7715                                                   "ELSE (SELECT typname FROM pg_type WHERE oid = oprright) END AS oprright, "
7716                                                   "oprcom, oprnegate, oprrest, oprjoin, "
7717                                                   "(oprlsortop != 0) AS oprcanmerge, "
7718                                                   "oprcanhash "
7719                                                   "FROM pg_operator "
7720                                                   "WHERE oid = '%u'::oid",
7721                                                   oprinfo->dobj.catId.oid);
7722         }
7723
7724         res = PQexec(g_conn, query->data);
7725         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7726
7727         /* Expecting a single result only */
7728         ntups = PQntuples(res);
7729         if (ntups != 1)
7730         {
7731                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7732                                                                  "query returned %d rows instead of one: %s\n",
7733                                                                  ntups),
7734                                   ntups, query->data);
7735                 exit_nicely();
7736         }
7737
7738         i_oprkind = PQfnumber(res, "oprkind");
7739         i_oprcode = PQfnumber(res, "oprcode");
7740         i_oprleft = PQfnumber(res, "oprleft");
7741         i_oprright = PQfnumber(res, "oprright");
7742         i_oprcom = PQfnumber(res, "oprcom");
7743         i_oprnegate = PQfnumber(res, "oprnegate");
7744         i_oprrest = PQfnumber(res, "oprrest");
7745         i_oprjoin = PQfnumber(res, "oprjoin");
7746         i_oprcanmerge = PQfnumber(res, "oprcanmerge");
7747         i_oprcanhash = PQfnumber(res, "oprcanhash");
7748
7749         oprkind = PQgetvalue(res, 0, i_oprkind);
7750         oprcode = PQgetvalue(res, 0, i_oprcode);
7751         oprleft = PQgetvalue(res, 0, i_oprleft);
7752         oprright = PQgetvalue(res, 0, i_oprright);
7753         oprcom = PQgetvalue(res, 0, i_oprcom);
7754         oprnegate = PQgetvalue(res, 0, i_oprnegate);
7755         oprrest = PQgetvalue(res, 0, i_oprrest);
7756         oprjoin = PQgetvalue(res, 0, i_oprjoin);
7757         oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
7758         oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
7759
7760         appendPQExpBuffer(details, "    PROCEDURE = %s",
7761                                           convertRegProcReference(oprcode));
7762
7763         appendPQExpBuffer(oprid, "%s (",
7764                                           oprinfo->dobj.name);
7765
7766         /*
7767          * right unary means there's a left arg and left unary means there's a
7768          * right arg
7769          */
7770         if (strcmp(oprkind, "r") == 0 ||
7771                 strcmp(oprkind, "b") == 0)
7772         {
7773                 if (g_fout->remoteVersion >= 70100)
7774                         name = oprleft;
7775                 else
7776                         name = fmtId(oprleft);
7777                 appendPQExpBuffer(details, ",\n    LEFTARG = %s", name);
7778                 appendPQExpBuffer(oprid, "%s", name);
7779         }
7780         else
7781                 appendPQExpBuffer(oprid, "NONE");
7782
7783         if (strcmp(oprkind, "l") == 0 ||
7784                 strcmp(oprkind, "b") == 0)
7785         {
7786                 if (g_fout->remoteVersion >= 70100)
7787                         name = oprright;
7788                 else
7789                         name = fmtId(oprright);
7790                 appendPQExpBuffer(details, ",\n    RIGHTARG = %s", name);
7791                 appendPQExpBuffer(oprid, ", %s)", name);
7792         }
7793         else
7794                 appendPQExpBuffer(oprid, ", NONE)");
7795
7796         name = convertOperatorReference(oprcom);
7797         if (name)
7798                 appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", name);
7799
7800         name = convertOperatorReference(oprnegate);
7801         if (name)
7802                 appendPQExpBuffer(details, ",\n    NEGATOR = %s", name);
7803
7804         if (strcmp(oprcanmerge, "t") == 0)
7805                 appendPQExpBuffer(details, ",\n    MERGES");
7806
7807         if (strcmp(oprcanhash, "t") == 0)
7808                 appendPQExpBuffer(details, ",\n    HASHES");
7809
7810         name = convertRegProcReference(oprrest);
7811         if (name)
7812                 appendPQExpBuffer(details, ",\n    RESTRICT = %s", name);
7813
7814         name = convertRegProcReference(oprjoin);
7815         if (name)
7816                 appendPQExpBuffer(details, ",\n    JOIN = %s", name);
7817
7818         /*
7819          * DROP must be fully qualified in case same name appears in pg_catalog
7820          */
7821         appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7822                                           fmtId(oprinfo->dobj.namespace->dobj.name),
7823                                           oprid->data);
7824
7825         appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7826                                           oprinfo->dobj.name, details->data);
7827
7828         ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7829                                  oprinfo->dobj.name,
7830                                  oprinfo->dobj.namespace->dobj.name,
7831                                  NULL,
7832                                  oprinfo->rolname,
7833                                  false, "OPERATOR", SECTION_PRE_DATA,
7834                                  q->data, delq->data, NULL,
7835                                  oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
7836                                  NULL, NULL);
7837
7838         /* Dump Operator Comments */
7839         resetPQExpBuffer(q);
7840         appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
7841         dumpComment(fout, q->data,
7842                                 oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
7843                                 oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
7844
7845         PQclear(res);
7846
7847         destroyPQExpBuffer(query);
7848         destroyPQExpBuffer(q);
7849         destroyPQExpBuffer(delq);
7850         destroyPQExpBuffer(oprid);
7851         destroyPQExpBuffer(details);
7852 }
7853
7854 /*
7855  * Convert a function reference obtained from pg_operator
7856  *
7857  * Returns what to print, or NULL if function references is InvalidOid
7858  *
7859  * In 7.3 the input is a REGPROCEDURE display; we have to strip the
7860  * argument-types part.  In prior versions, the input is a REGPROC display.
7861  */
7862 static const char *
7863 convertRegProcReference(const char *proc)
7864 {
7865         /* In all cases "-" means a null reference */
7866         if (strcmp(proc, "-") == 0)
7867                 return NULL;
7868
7869         if (g_fout->remoteVersion >= 70300)
7870         {
7871                 char       *name;
7872                 char       *paren;
7873                 bool            inquote;
7874
7875                 name = strdup(proc);
7876                 /* find non-double-quoted left paren */
7877                 inquote = false;
7878                 for (paren = name; *paren; paren++)
7879                 {
7880                         if (*paren == '(' && !inquote)
7881                         {
7882                                 *paren = '\0';
7883                                 break;
7884                         }
7885                         if (*paren == '"')
7886                                 inquote = !inquote;
7887                 }
7888                 return name;
7889         }
7890
7891         /* REGPROC before 7.3 does not quote its result */
7892         return fmtId(proc);
7893 }
7894
7895 /*
7896  * Convert an operator cross-reference obtained from pg_operator
7897  *
7898  * Returns what to print, or NULL to print nothing
7899  *
7900  * In 7.3 and up the input is a REGOPERATOR display; we have to strip the
7901  * argument-types part, and add OPERATOR() decoration if the name is
7902  * schema-qualified.  In older versions, the input is just a numeric OID,
7903  * which we search our operator list for.
7904  */
7905 static const char *
7906 convertOperatorReference(const char *opr)
7907 {
7908         OprInfo    *oprInfo;
7909
7910         /* In all cases "0" means a null reference */
7911         if (strcmp(opr, "0") == 0)
7912                 return NULL;
7913
7914         if (g_fout->remoteVersion >= 70300)
7915         {
7916                 char       *name;
7917                 char       *oname;
7918                 char       *ptr;
7919                 bool            inquote;
7920                 bool            sawdot;
7921
7922                 name = strdup(opr);
7923                 /* find non-double-quoted left paren, and check for non-quoted dot */
7924                 inquote = false;
7925                 sawdot = false;
7926                 for (ptr = name; *ptr; ptr++)
7927                 {
7928                         if (*ptr == '"')
7929                                 inquote = !inquote;
7930                         else if (*ptr == '.' && !inquote)
7931                                 sawdot = true;
7932                         else if (*ptr == '(' && !inquote)
7933                         {
7934                                 *ptr = '\0';
7935                                 break;
7936                         }
7937                 }
7938                 /* If not schema-qualified, don't need to add OPERATOR() */
7939                 if (!sawdot)
7940                         return name;
7941                 oname = malloc(strlen(name) + 11);
7942                 sprintf(oname, "OPERATOR(%s)", name);
7943                 free(name);
7944                 return oname;
7945         }
7946
7947         oprInfo = findOprByOid(atooid(opr));
7948         if (oprInfo == NULL)
7949         {
7950                 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7951                                   opr);
7952                 return NULL;
7953         }
7954         return oprInfo->dobj.name;
7955 }
7956
7957 /*
7958  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
7959  *
7960  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
7961  * argument lists of these functions are predetermined.  Note that the
7962  * caller should ensure we are in the proper schema, because the results
7963  * are search path dependent!
7964  */
7965 static const char *
7966 convertTSFunction(Oid funcOid)
7967 {
7968         char       *result;
7969         char            query[128];
7970         PGresult   *res;
7971         int                     ntups;
7972
7973         snprintf(query, sizeof(query),
7974                          "SELECT '%u'::pg_catalog.regproc", funcOid);
7975         res = PQexec(g_conn, query);
7976         check_sql_result(res, g_conn, query, PGRES_TUPLES_OK);
7977
7978         ntups = PQntuples(res);
7979         if (ntups != 1)
7980         {
7981                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7982                                                                  "query returned %d rows instead of one: %s\n",
7983                                                                  ntups),
7984                                   ntups, query);
7985                 exit_nicely();
7986         }
7987
7988         result = strdup(PQgetvalue(res, 0, 0));
7989
7990         PQclear(res);
7991
7992         return result;
7993 }
7994
7995
7996 /*
7997  * dumpOpclass
7998  *        write out a single operator class definition
7999  */
8000 static void
8001 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
8002 {
8003         PQExpBuffer query;
8004         PQExpBuffer q;
8005         PQExpBuffer delq;
8006         PGresult   *res;
8007         int                     ntups;
8008         int                     i_opcintype;
8009         int                     i_opckeytype;
8010         int                     i_opcdefault;
8011         int                     i_opcfamily;
8012         int                     i_opcfamilynsp;
8013         int                     i_amname;
8014         int                     i_amopstrategy;
8015         int                     i_amopreqcheck;
8016         int                     i_amopopr;
8017         int                     i_amprocnum;
8018         int                     i_amproc;
8019         char       *opcintype;
8020         char       *opckeytype;
8021         char       *opcdefault;
8022         char       *opcfamily;
8023         char       *opcfamilynsp;
8024         char       *amname;
8025         char       *amopstrategy;
8026         char       *amopreqcheck;
8027         char       *amopopr;
8028         char       *amprocnum;
8029         char       *amproc;
8030         bool            needComma;
8031         int                     i;
8032
8033         /* Skip if not to be dumped */
8034         if (!opcinfo->dobj.dump || dataOnly)
8035                 return;
8036
8037         /*
8038          * XXX currently we do not implement dumping of operator classes from
8039          * pre-7.3 databases.  This could be done but it seems not worth the
8040          * trouble.
8041          */
8042         if (g_fout->remoteVersion < 70300)
8043                 return;
8044
8045         query = createPQExpBuffer();
8046         q = createPQExpBuffer();
8047         delq = createPQExpBuffer();
8048
8049         /* Make sure we are in proper schema so regoperator works correctly */
8050         selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8051
8052         /* Get additional fields from the pg_opclass row */
8053         if (g_fout->remoteVersion >= 80300)
8054         {
8055                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8056                                                   "opckeytype::pg_catalog.regtype, "
8057                                                   "opcdefault, "
8058                                                   "opfname AS opcfamily, "
8059                                                   "nspname AS opcfamilynsp, "
8060                                                   "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
8061                                                   "FROM pg_catalog.pg_opclass c "
8062                                    "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
8063                            "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
8064                                                   "WHERE c.oid = '%u'::pg_catalog.oid",
8065                                                   opcinfo->dobj.catId.oid);
8066         }
8067         else
8068         {
8069                 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8070                                                   "opckeytype::pg_catalog.regtype, "
8071                                                   "opcdefault, "
8072                                                   "NULL AS opcfamily, "
8073                                                   "NULL AS opcfamilynsp, "
8074                 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
8075                                                   "FROM pg_catalog.pg_opclass "
8076                                                   "WHERE oid = '%u'::pg_catalog.oid",
8077                                                   opcinfo->dobj.catId.oid);
8078         }
8079
8080         res = PQexec(g_conn, query->data);
8081         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8082
8083         /* Expecting a single result only */
8084         ntups = PQntuples(res);
8085         if (ntups != 1)
8086         {
8087                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8088                                                                  "query returned %d rows instead of one: %s\n",
8089                                                                  ntups),
8090                                   ntups, query->data);
8091                 exit_nicely();
8092         }
8093
8094         i_opcintype = PQfnumber(res, "opcintype");
8095         i_opckeytype = PQfnumber(res, "opckeytype");
8096         i_opcdefault = PQfnumber(res, "opcdefault");
8097         i_opcfamily = PQfnumber(res, "opcfamily");
8098         i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
8099         i_amname = PQfnumber(res, "amname");
8100
8101         opcintype = PQgetvalue(res, 0, i_opcintype);
8102         opckeytype = PQgetvalue(res, 0, i_opckeytype);
8103         opcdefault = PQgetvalue(res, 0, i_opcdefault);
8104         opcfamily = PQgetvalue(res, 0, i_opcfamily);
8105         opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
8106         /* amname will still be needed after we PQclear res */
8107         amname = strdup(PQgetvalue(res, 0, i_amname));
8108
8109         /*
8110          * DROP must be fully qualified in case same name appears in pg_catalog
8111          */
8112         appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
8113                                           fmtId(opcinfo->dobj.namespace->dobj.name));
8114         appendPQExpBuffer(delq, ".%s",
8115                                           fmtId(opcinfo->dobj.name));
8116         appendPQExpBuffer(delq, " USING %s;\n",
8117                                           fmtId(amname));
8118
8119         /* Build the fixed portion of the CREATE command */
8120         appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
8121                                           fmtId(opcinfo->dobj.name));
8122         if (strcmp(opcdefault, "t") == 0)
8123                 appendPQExpBuffer(q, "DEFAULT ");
8124         appendPQExpBuffer(q, "FOR TYPE %s USING %s",
8125                                           opcintype,
8126                                           fmtId(amname));
8127         if (strlen(opcfamily) > 0 &&
8128                 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8129                  strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
8130         {
8131                 appendPQExpBuffer(q, " FAMILY ");
8132                 if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
8133                         appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
8134                 appendPQExpBuffer(q, "%s", fmtId(opcfamily));
8135         }
8136         appendPQExpBuffer(q, " AS\n    ");
8137
8138         needComma = false;
8139
8140         if (strcmp(opckeytype, "-") != 0)
8141         {
8142                 appendPQExpBuffer(q, "STORAGE %s",
8143                                                   opckeytype);
8144                 needComma = true;
8145         }
8146
8147         PQclear(res);
8148
8149         /*
8150          * Now fetch and print the OPERATOR entries (pg_amop rows).
8151          */
8152         resetPQExpBuffer(query);
8153
8154         if (g_fout->remoteVersion >= 80400)
8155         {
8156                 /*
8157                  * Print only those opfamily members that are tied to the opclass by
8158                  * pg_depend entries.
8159                  *
8160                  * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8161                  * an older server's table in which it is used.  Would it be better
8162                  * to silently ignore it?
8163                  */
8164                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8165                                                   "amopopr::pg_catalog.regoperator "
8166                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8167                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8168                                                   "AND refobjid = '%u'::pg_catalog.oid "
8169                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8170                                                   "AND objid = ao.oid "
8171                                                   "ORDER BY amopstrategy",
8172                                                   opcinfo->dobj.catId.oid);
8173         }
8174         else if (g_fout->remoteVersion >= 80300)
8175         {
8176                 /*
8177                  * Print only those opfamily members that are tied to the opclass by
8178                  * pg_depend entries.
8179                  */
8180                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8181                                                   "amopopr::pg_catalog.regoperator "
8182                                                   "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8183                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8184                                                   "AND refobjid = '%u'::pg_catalog.oid "
8185                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8186                                                   "AND objid = ao.oid "
8187                                                   "ORDER BY amopstrategy",
8188                                                   opcinfo->dobj.catId.oid);
8189         }
8190         else
8191         {
8192                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8193                                                   "amopopr::pg_catalog.regoperator "
8194                                                   "FROM pg_catalog.pg_amop "
8195                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
8196                                                   "ORDER BY amopstrategy",
8197                                                   opcinfo->dobj.catId.oid);
8198         }
8199
8200         res = PQexec(g_conn, query->data);
8201         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8202
8203         ntups = PQntuples(res);
8204
8205         i_amopstrategy = PQfnumber(res, "amopstrategy");
8206         i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8207         i_amopopr = PQfnumber(res, "amopopr");
8208
8209         for (i = 0; i < ntups; i++)
8210         {
8211                 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8212                 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8213                 amopopr = PQgetvalue(res, i, i_amopopr);
8214
8215                 if (needComma)
8216                         appendPQExpBuffer(q, " ,\n    ");
8217
8218                 appendPQExpBuffer(q, "OPERATOR %s %s",
8219                                                   amopstrategy, amopopr);
8220                 if (strcmp(amopreqcheck, "t") == 0)
8221                         appendPQExpBuffer(q, " RECHECK");
8222
8223                 needComma = true;
8224         }
8225
8226         PQclear(res);
8227
8228         /*
8229          * Now fetch and print the FUNCTION entries (pg_amproc rows).
8230          */
8231         resetPQExpBuffer(query);
8232
8233         if (g_fout->remoteVersion >= 80300)
8234         {
8235                 /*
8236                  * Print only those opfamily members that are tied to the opclass by
8237                  * pg_depend entries.
8238                  */
8239                 appendPQExpBuffer(query, "SELECT amprocnum, "
8240                                                   "amproc::pg_catalog.regprocedure "
8241                                                 "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8242                    "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8243                                                   "AND refobjid = '%u'::pg_catalog.oid "
8244                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8245                                                   "AND objid = ap.oid "
8246                                                   "ORDER BY amprocnum",
8247                                                   opcinfo->dobj.catId.oid);
8248         }
8249         else
8250         {
8251                 appendPQExpBuffer(query, "SELECT amprocnum, "
8252                                                   "amproc::pg_catalog.regprocedure "
8253                                                   "FROM pg_catalog.pg_amproc "
8254                                                   "WHERE amopclaid = '%u'::pg_catalog.oid "
8255                                                   "ORDER BY amprocnum",
8256                                                   opcinfo->dobj.catId.oid);
8257         }
8258
8259         res = PQexec(g_conn, query->data);
8260         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8261
8262         ntups = PQntuples(res);
8263
8264         i_amprocnum = PQfnumber(res, "amprocnum");
8265         i_amproc = PQfnumber(res, "amproc");
8266
8267         for (i = 0; i < ntups; i++)
8268         {
8269                 amprocnum = PQgetvalue(res, i, i_amprocnum);
8270                 amproc = PQgetvalue(res, i, i_amproc);
8271
8272                 if (needComma)
8273                         appendPQExpBuffer(q, " ,\n    ");
8274
8275                 appendPQExpBuffer(q, "FUNCTION %s %s",
8276                                                   amprocnum, amproc);
8277
8278                 needComma = true;
8279         }
8280
8281         PQclear(res);
8282
8283         appendPQExpBuffer(q, ";\n");
8284
8285         ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8286                                  opcinfo->dobj.name,
8287                                  opcinfo->dobj.namespace->dobj.name,
8288                                  NULL,
8289                                  opcinfo->rolname,
8290                                  false, "OPERATOR CLASS", SECTION_PRE_DATA,
8291                                  q->data, delq->data, NULL,
8292                                  opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8293                                  NULL, NULL);
8294
8295         /* Dump Operator Class Comments */
8296         resetPQExpBuffer(q);
8297         appendPQExpBuffer(q, "OPERATOR CLASS %s",
8298                                           fmtId(opcinfo->dobj.name));
8299         appendPQExpBuffer(q, " USING %s",
8300                                           fmtId(amname));
8301         dumpComment(fout, q->data,
8302                                 NULL, opcinfo->rolname,
8303                                 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8304
8305         free(amname);
8306         destroyPQExpBuffer(query);
8307         destroyPQExpBuffer(q);
8308         destroyPQExpBuffer(delq);
8309 }
8310
8311 /*
8312  * dumpOpfamily
8313  *        write out a single operator family definition
8314  */
8315 static void
8316 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8317 {
8318         PQExpBuffer query;
8319         PQExpBuffer q;
8320         PQExpBuffer delq;
8321         PGresult   *res;
8322         PGresult   *res_ops;
8323         PGresult   *res_procs;
8324         int                     ntups;
8325         int                     i_amname;
8326         int                     i_amopstrategy;
8327         int                     i_amopreqcheck;
8328         int                     i_amopopr;
8329         int                     i_amprocnum;
8330         int                     i_amproc;
8331         int                     i_amproclefttype;
8332         int                     i_amprocrighttype;
8333         char       *amname;
8334         char       *amopstrategy;
8335         char       *amopreqcheck;
8336         char       *amopopr;
8337         char       *amprocnum;
8338         char       *amproc;
8339         char       *amproclefttype;
8340         char       *amprocrighttype;
8341         bool            needComma;
8342         int                     i;
8343
8344         /* Skip if not to be dumped */
8345         if (!opfinfo->dobj.dump || dataOnly)
8346                 return;
8347
8348         /*
8349          * We want to dump the opfamily only if (1) it contains "loose" operators
8350          * or functions, or (2) it contains an opclass with a different name or
8351          * owner.  Otherwise it's sufficient to let it be created during creation
8352          * of the contained opclass, and not dumping it improves portability of
8353          * the dump.  Since we have to fetch the loose operators/funcs anyway, do
8354          * that first.
8355          */
8356
8357         query = createPQExpBuffer();
8358         q = createPQExpBuffer();
8359         delq = createPQExpBuffer();
8360
8361         /* Make sure we are in proper schema so regoperator works correctly */
8362         selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8363
8364         /*
8365          * Fetch only those opfamily members that are tied directly to the
8366          * opfamily by pg_depend entries.
8367          */
8368         if (g_fout->remoteVersion >= 80400)
8369         {
8370                 /*
8371                  * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping
8372                  * an older server's table in which it is used.  Would it be better
8373                  * to silently ignore it?
8374                  */
8375                 appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
8376                                           "amopopr::pg_catalog.regoperator "
8377                                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8378                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8379                                           "AND refobjid = '%u'::pg_catalog.oid "
8380                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8381                                           "AND objid = ao.oid "
8382                                           "ORDER BY amopstrategy",
8383                                           opfinfo->dobj.catId.oid);
8384         }
8385         else
8386         {
8387                 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
8388                                           "amopopr::pg_catalog.regoperator "
8389                                           "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
8390                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8391                                           "AND refobjid = '%u'::pg_catalog.oid "
8392                                    "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
8393                                           "AND objid = ao.oid "
8394                                           "ORDER BY amopstrategy",
8395                                           opfinfo->dobj.catId.oid);
8396         }
8397
8398         res_ops = PQexec(g_conn, query->data);
8399         check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8400
8401         resetPQExpBuffer(query);
8402
8403         appendPQExpBuffer(query, "SELECT amprocnum, "
8404                                           "amproc::pg_catalog.regprocedure, "
8405                                           "amproclefttype::pg_catalog.regtype, "
8406                                           "amprocrighttype::pg_catalog.regtype "
8407                                           "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
8408                   "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8409                                           "AND refobjid = '%u'::pg_catalog.oid "
8410                                  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
8411                                           "AND objid = ap.oid "
8412                                           "ORDER BY amprocnum",
8413                                           opfinfo->dobj.catId.oid);
8414
8415         res_procs = PQexec(g_conn, query->data);
8416         check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8417
8418         if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8419         {
8420                 /* No loose members, so check contained opclasses */
8421                 resetPQExpBuffer(query);
8422
8423                 appendPQExpBuffer(query, "SELECT 1 "
8424                                                   "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
8425                                                   "WHERE f.oid = '%u'::pg_catalog.oid "
8426                         "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
8427                                                   "AND refobjid = f.oid "
8428                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
8429                                                   "AND objid = c.oid "
8430                                                   "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
8431                                                   "LIMIT 1",
8432                                                   opfinfo->dobj.catId.oid);
8433
8434                 res = PQexec(g_conn, query->data);
8435                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8436
8437                 if (PQntuples(res) == 0)
8438                 {
8439                         /* no need to dump it, so bail out */
8440                         PQclear(res);
8441                         PQclear(res_ops);
8442                         PQclear(res_procs);
8443                         destroyPQExpBuffer(query);
8444                         destroyPQExpBuffer(q);
8445                         destroyPQExpBuffer(delq);
8446                         return;
8447                 }
8448
8449                 PQclear(res);
8450         }
8451
8452         /* Get additional fields from the pg_opfamily row */
8453         resetPQExpBuffer(query);
8454
8455         appendPQExpBuffer(query, "SELECT "
8456          "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
8457                                           "FROM pg_catalog.pg_opfamily "
8458                                           "WHERE oid = '%u'::pg_catalog.oid",
8459                                           opfinfo->dobj.catId.oid);
8460
8461         res = PQexec(g_conn, query->data);
8462         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8463
8464         /* Expecting a single result only */
8465         ntups = PQntuples(res);
8466         if (ntups != 1)
8467         {
8468                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8469                                                                  "query returned %d rows instead of one: %s\n",
8470                                                                  ntups),
8471                                   ntups, query->data);
8472                 exit_nicely();
8473         }
8474
8475         i_amname = PQfnumber(res, "amname");
8476
8477         /* amname will still be needed after we PQclear res */
8478         amname = strdup(PQgetvalue(res, 0, i_amname));
8479
8480         /*
8481          * DROP must be fully qualified in case same name appears in pg_catalog
8482          */
8483         appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
8484                                           fmtId(opfinfo->dobj.namespace->dobj.name));
8485         appendPQExpBuffer(delq, ".%s",
8486                                           fmtId(opfinfo->dobj.name));
8487         appendPQExpBuffer(delq, " USING %s;\n",
8488                                           fmtId(amname));
8489
8490         /* Build the fixed portion of the CREATE command */
8491         appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
8492                                           fmtId(opfinfo->dobj.name));
8493         appendPQExpBuffer(q, " USING %s;\n",
8494                                           fmtId(amname));
8495
8496         PQclear(res);
8497
8498         /* Do we need an ALTER to add loose members? */
8499         if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8500         {
8501                 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8502                                                   fmtId(opfinfo->dobj.name));
8503                 appendPQExpBuffer(q, " USING %s ADD\n    ",
8504                                                   fmtId(amname));
8505
8506                 needComma = false;
8507
8508                 /*
8509                  * Now fetch and print the OPERATOR entries (pg_amop rows).
8510                  */
8511                 ntups = PQntuples(res_ops);
8512
8513                 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8514                 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8515                 i_amopopr = PQfnumber(res_ops, "amopopr");
8516
8517                 for (i = 0; i < ntups; i++)
8518                 {
8519                         amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8520                         amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8521                         amopopr = PQgetvalue(res_ops, i, i_amopopr);
8522
8523                         if (needComma)
8524                                 appendPQExpBuffer(q, " ,\n    ");
8525
8526                         appendPQExpBuffer(q, "OPERATOR %s %s",
8527                                                           amopstrategy, amopopr);
8528                         if (strcmp(amopreqcheck, "t") == 0)
8529                                 appendPQExpBuffer(q, " RECHECK");
8530
8531                         needComma = true;
8532                 }
8533
8534                 /*
8535                  * Now fetch and print the FUNCTION entries (pg_amproc rows).
8536                  */
8537                 ntups = PQntuples(res_procs);
8538
8539                 i_amprocnum = PQfnumber(res_procs, "amprocnum");
8540                 i_amproc = PQfnumber(res_procs, "amproc");
8541                 i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
8542                 i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
8543
8544                 for (i = 0; i < ntups; i++)
8545                 {
8546                         amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
8547                         amproc = PQgetvalue(res_procs, i, i_amproc);
8548                         amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
8549                         amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
8550
8551                         if (needComma)
8552                                 appendPQExpBuffer(q, " ,\n    ");
8553
8554                         appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8555                                                           amprocnum, amproclefttype, amprocrighttype,
8556                                                           amproc);
8557
8558                         needComma = true;
8559                 }
8560
8561                 appendPQExpBuffer(q, ";\n");
8562         }
8563
8564         ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8565                                  opfinfo->dobj.name,
8566                                  opfinfo->dobj.namespace->dobj.name,
8567                                  NULL,
8568                                  opfinfo->rolname,
8569                                  false, "OPERATOR FAMILY", SECTION_PRE_DATA,
8570                                  q->data, delq->data, NULL,
8571                                  opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8572                                  NULL, NULL);
8573
8574         /* Dump Operator Family Comments */
8575         resetPQExpBuffer(q);
8576         appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8577                                           fmtId(opfinfo->dobj.name));
8578         appendPQExpBuffer(q, " USING %s",
8579                                           fmtId(amname));
8580         dumpComment(fout, q->data,
8581                                 NULL, opfinfo->rolname,
8582                                 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8583
8584         free(amname);
8585         PQclear(res_ops);
8586         PQclear(res_procs);
8587         destroyPQExpBuffer(query);
8588         destroyPQExpBuffer(q);
8589         destroyPQExpBuffer(delq);
8590 }
8591
8592 /*
8593  * dumpConversion
8594  *        write out a single conversion definition
8595  */
8596 static void
8597 dumpConversion(Archive *fout, ConvInfo *convinfo)
8598 {
8599         PQExpBuffer query;
8600         PQExpBuffer q;
8601         PQExpBuffer delq;
8602         PQExpBuffer details;
8603         PGresult   *res;
8604         int                     ntups;
8605         int                     i_conname;
8606         int                     i_conforencoding;
8607         int                     i_contoencoding;
8608         int                     i_conproc;
8609         int                     i_condefault;
8610         const char *conname;
8611         const char *conforencoding;
8612         const char *contoencoding;
8613         const char *conproc;
8614         bool            condefault;
8615
8616         /* Skip if not to be dumped */
8617         if (!convinfo->dobj.dump || dataOnly)
8618                 return;
8619
8620         query = createPQExpBuffer();
8621         q = createPQExpBuffer();
8622         delq = createPQExpBuffer();
8623         details = createPQExpBuffer();
8624
8625         /* Make sure we are in proper schema */
8626         selectSourceSchema(convinfo->dobj.namespace->dobj.name);
8627
8628         /* Get conversion-specific details */
8629         appendPQExpBuffer(query, "SELECT conname, "
8630                  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
8631                    "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
8632                                           "conproc, condefault "
8633                                           "FROM pg_catalog.pg_conversion c "
8634                                           "WHERE c.oid = '%u'::pg_catalog.oid",
8635                                           convinfo->dobj.catId.oid);
8636
8637         res = PQexec(g_conn, query->data);
8638         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8639
8640         /* Expecting a single result only */
8641         ntups = PQntuples(res);
8642         if (ntups != 1)
8643         {
8644                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8645                                                                  "query returned %d rows instead of one: %s\n",
8646                                                                  ntups),
8647                                   ntups, query->data);
8648                 exit_nicely();
8649         }
8650
8651         i_conname = PQfnumber(res, "conname");
8652         i_conforencoding = PQfnumber(res, "conforencoding");
8653         i_contoencoding = PQfnumber(res, "contoencoding");
8654         i_conproc = PQfnumber(res, "conproc");
8655         i_condefault = PQfnumber(res, "condefault");
8656
8657         conname = PQgetvalue(res, 0, i_conname);
8658         conforencoding = PQgetvalue(res, 0, i_conforencoding);
8659         contoencoding = PQgetvalue(res, 0, i_contoencoding);
8660         conproc = PQgetvalue(res, 0, i_conproc);
8661         condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
8662
8663         /*
8664          * DROP must be fully qualified in case same name appears in pg_catalog
8665          */
8666         appendPQExpBuffer(delq, "DROP CONVERSION %s",
8667                                           fmtId(convinfo->dobj.namespace->dobj.name));
8668         appendPQExpBuffer(delq, ".%s;\n",
8669                                           fmtId(convinfo->dobj.name));
8670
8671         appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
8672                                           (condefault) ? "DEFAULT " : "",
8673                                           fmtId(convinfo->dobj.name));
8674         appendStringLiteralAH(q, conforencoding, fout);
8675         appendPQExpBuffer(q, " TO ");
8676         appendStringLiteralAH(q, contoencoding, fout);
8677         /* regproc is automatically quoted in 7.3 and above */
8678         appendPQExpBuffer(q, " FROM %s;\n", conproc);
8679
8680         ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8681                                  convinfo->dobj.name,
8682                                  convinfo->dobj.namespace->dobj.name,
8683                                  NULL,
8684                                  convinfo->rolname,
8685                                  false, "CONVERSION", SECTION_PRE_DATA,
8686                                  q->data, delq->data, NULL,
8687                                  convinfo->dobj.dependencies, convinfo->dobj.nDeps,
8688                                  NULL, NULL);
8689
8690         /* Dump Conversion Comments */
8691         resetPQExpBuffer(q);
8692         appendPQExpBuffer(q, "CONVERSION %s", fmtId(convinfo->dobj.name));
8693         dumpComment(fout, q->data,
8694                                 convinfo->dobj.namespace->dobj.name, convinfo->rolname,
8695                                 convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
8696
8697         PQclear(res);
8698
8699         destroyPQExpBuffer(query);
8700         destroyPQExpBuffer(q);
8701         destroyPQExpBuffer(delq);
8702         destroyPQExpBuffer(details);
8703 }
8704
8705 /*
8706  * format_aggregate_signature: generate aggregate name and argument list
8707  *
8708  * The argument type names are qualified if needed.  The aggregate name
8709  * is never qualified.
8710  */
8711 static char *
8712 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8713 {
8714         PQExpBufferData buf;
8715         int                     j;
8716
8717         initPQExpBuffer(&buf);
8718         if (honor_quotes)
8719                 appendPQExpBuffer(&buf, "%s",
8720                                                   fmtId(agginfo->aggfn.dobj.name));
8721         else
8722                 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8723
8724         if (agginfo->aggfn.nargs == 0)
8725                 appendPQExpBuffer(&buf, "(*)");
8726         else
8727         {
8728                 appendPQExpBuffer(&buf, "(");
8729                 for (j = 0; j < agginfo->aggfn.nargs; j++)
8730                 {
8731                         char       *typname;
8732
8733                         typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8734
8735                         appendPQExpBuffer(&buf, "%s%s",
8736                                                           (j > 0) ? ", " : "",
8737                                                           typname);
8738                         free(typname);
8739                 }
8740                 appendPQExpBuffer(&buf, ")");
8741         }
8742         return buf.data;
8743 }
8744
8745 /*
8746  * dumpAgg
8747  *        write out a single aggregate definition
8748  */
8749 static void
8750 dumpAgg(Archive *fout, AggInfo *agginfo)
8751 {
8752         PQExpBuffer query;
8753         PQExpBuffer q;
8754         PQExpBuffer delq;
8755         PQExpBuffer details;
8756         char       *aggsig;
8757         char       *aggsig_tag;
8758         PGresult   *res;
8759         int                     ntups;
8760         int                     i_aggtransfn;
8761         int                     i_aggfinalfn;
8762         int                     i_aggsortop;
8763         int                     i_aggtranstype;
8764         int                     i_agginitval;
8765         int                     i_convertok;
8766         const char *aggtransfn;
8767         const char *aggfinalfn;
8768         const char *aggsortop;
8769         const char *aggtranstype;
8770         const char *agginitval;
8771         bool            convertok;
8772
8773         /* Skip if not to be dumped */
8774         if (!agginfo->aggfn.dobj.dump || dataOnly)
8775                 return;
8776
8777         query = createPQExpBuffer();
8778         q = createPQExpBuffer();
8779         delq = createPQExpBuffer();
8780         details = createPQExpBuffer();
8781
8782         /* Make sure we are in proper schema */
8783         selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8784
8785         /* Get aggregate-specific details */
8786         if (g_fout->remoteVersion >= 80100)
8787         {
8788                 appendPQExpBuffer(query, "SELECT aggtransfn, "
8789                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8790                                                   "aggsortop::pg_catalog.regoperator, "
8791                                                   "agginitval, "
8792                                                   "'t'::boolean AS convertok "
8793                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8794                                                   "WHERE a.aggfnoid = p.oid "
8795                                                   "AND p.oid = '%u'::pg_catalog.oid",
8796                                                   agginfo->aggfn.dobj.catId.oid);
8797         }
8798         else if (g_fout->remoteVersion >= 70300)
8799         {
8800                 appendPQExpBuffer(query, "SELECT aggtransfn, "
8801                                                   "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8802                                                   "0 AS aggsortop, "
8803                                                   "agginitval, "
8804                                                   "'t'::boolean AS convertok "
8805                                           "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
8806                                                   "WHERE a.aggfnoid = p.oid "
8807                                                   "AND p.oid = '%u'::pg_catalog.oid",
8808                                                   agginfo->aggfn.dobj.catId.oid);
8809         }
8810         else if (g_fout->remoteVersion >= 70100)
8811         {
8812                 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8813                                                   "format_type(aggtranstype, NULL) AS aggtranstype, "
8814                                                   "0 AS aggsortop, "
8815                                                   "agginitval, "
8816                                                   "'t'::boolean AS convertok "
8817                                                   "FROM pg_aggregate "
8818                                                   "WHERE oid = '%u'::oid",
8819                                                   agginfo->aggfn.dobj.catId.oid);
8820         }
8821         else
8822         {
8823                 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
8824                                                   "aggfinalfn, "
8825                                                   "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
8826                                                   "0 AS aggsortop, "
8827                                                   "agginitval1 AS agginitval, "
8828                                                   "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) AS convertok "
8829                                                   "FROM pg_aggregate "
8830                                                   "WHERE oid = '%u'::oid",
8831                                                   agginfo->aggfn.dobj.catId.oid);
8832         }
8833
8834         res = PQexec(g_conn, query->data);
8835         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8836
8837         /* Expecting a single result only */
8838         ntups = PQntuples(res);
8839         if (ntups != 1)
8840         {
8841                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8842                                                                  "query returned %d rows instead of one: %s\n",
8843                                                                  ntups),
8844                                   ntups, query->data);
8845                 exit_nicely();
8846         }
8847
8848         i_aggtransfn = PQfnumber(res, "aggtransfn");
8849         i_aggfinalfn = PQfnumber(res, "aggfinalfn");
8850         i_aggsortop = PQfnumber(res, "aggsortop");
8851         i_aggtranstype = PQfnumber(res, "aggtranstype");
8852         i_agginitval = PQfnumber(res, "agginitval");
8853         i_convertok = PQfnumber(res, "convertok");
8854
8855         aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
8856         aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
8857         aggsortop = PQgetvalue(res, 0, i_aggsortop);
8858         aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
8859         agginitval = PQgetvalue(res, 0, i_agginitval);
8860         convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
8861
8862         aggsig = format_aggregate_signature(agginfo, fout, true);
8863         aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8864
8865         if (!convertok)
8866         {
8867                 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8868                                   aggsig);
8869                 return;
8870         }
8871
8872         if (g_fout->remoteVersion >= 70300)
8873         {
8874                 /* If using 7.3's regproc or regtype, data is already quoted */
8875                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
8876                                                   aggtransfn,
8877                                                   aggtranstype);
8878         }
8879         else if (g_fout->remoteVersion >= 70100)
8880         {
8881                 /* format_type quotes, regproc does not */
8882                 appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
8883                                                   fmtId(aggtransfn),
8884                                                   aggtranstype);
8885         }
8886         else
8887         {
8888                 /* need quotes all around */
8889                 appendPQExpBuffer(details, "    SFUNC = %s,\n",
8890                                                   fmtId(aggtransfn));
8891                 appendPQExpBuffer(details, "    STYPE = %s",
8892                                                   fmtId(aggtranstype));
8893         }
8894
8895         if (!PQgetisnull(res, 0, i_agginitval))
8896         {
8897                 appendPQExpBuffer(details, ",\n    INITCOND = ");
8898                 appendStringLiteralAH(details, agginitval, fout);
8899         }
8900
8901         if (strcmp(aggfinalfn, "-") != 0)
8902         {
8903                 appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
8904                                                   aggfinalfn);
8905         }
8906
8907         aggsortop = convertOperatorReference(aggsortop);
8908         if (aggsortop)
8909         {
8910                 appendPQExpBuffer(details, ",\n    SORTOP = %s",
8911                                                   aggsortop);
8912         }
8913
8914         /*
8915          * DROP must be fully qualified in case same name appears in pg_catalog
8916          */
8917         appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8918                                           fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8919                                           aggsig);
8920
8921         appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8922                                           aggsig, details->data);
8923
8924         ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8925                                  aggsig_tag,
8926                                  agginfo->aggfn.dobj.namespace->dobj.name,
8927                                  NULL,
8928                                  agginfo->aggfn.rolname,
8929                                  false, "AGGREGATE", SECTION_PRE_DATA,
8930                                  q->data, delq->data, NULL,
8931                                  agginfo->aggfn.dobj.dependencies, agginfo->aggfn.dobj.nDeps,
8932                                  NULL, NULL);
8933
8934         /* Dump Aggregate Comments */
8935         resetPQExpBuffer(q);
8936         appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
8937         dumpComment(fout, q->data,
8938                         agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
8939                                 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
8940
8941         /*
8942          * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
8943          * command look like a function's GRANT; in particular this affects the
8944          * syntax for zero-argument aggregates.
8945          */
8946         free(aggsig);
8947         free(aggsig_tag);
8948
8949         aggsig = format_function_signature(&agginfo->aggfn, true);
8950         aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8951
8952         dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8953                         "FUNCTION",
8954                         aggsig, NULL, aggsig_tag,
8955                         agginfo->aggfn.dobj.namespace->dobj.name,
8956                         agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8957
8958         free(aggsig);
8959         free(aggsig_tag);
8960
8961         PQclear(res);
8962
8963         destroyPQExpBuffer(query);
8964         destroyPQExpBuffer(q);
8965         destroyPQExpBuffer(delq);
8966         destroyPQExpBuffer(details);
8967 }
8968
8969 /*
8970  * dumpTSParser
8971  *        write out a single text search parser
8972  */
8973 static void
8974 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8975 {
8976         PQExpBuffer q;
8977         PQExpBuffer delq;
8978
8979         /* Skip if not to be dumped */
8980         if (!prsinfo->dobj.dump || dataOnly)
8981                 return;
8982
8983         q = createPQExpBuffer();
8984         delq = createPQExpBuffer();
8985
8986         /* Make sure we are in proper schema */
8987         selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
8988
8989         appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
8990                                           fmtId(prsinfo->dobj.name));
8991
8992         appendPQExpBuffer(q, "    START = %s,\n",
8993                                           convertTSFunction(prsinfo->prsstart));
8994         appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
8995                                           convertTSFunction(prsinfo->prstoken));
8996         appendPQExpBuffer(q, "    END = %s,\n",
8997                                           convertTSFunction(prsinfo->prsend));
8998         if (prsinfo->prsheadline != InvalidOid)
8999                 appendPQExpBuffer(q, "    HEADLINE = %s,\n",
9000                                                   convertTSFunction(prsinfo->prsheadline));
9001         appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
9002                                           convertTSFunction(prsinfo->prslextype));
9003
9004         /*
9005          * DROP must be fully qualified in case same name appears in pg_catalog
9006          */
9007         appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s",
9008                                           fmtId(prsinfo->dobj.namespace->dobj.name));
9009         appendPQExpBuffer(delq, ".%s;\n",
9010                                           fmtId(prsinfo->dobj.name));
9011
9012         ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
9013                                  prsinfo->dobj.name,
9014                                  prsinfo->dobj.namespace->dobj.name,
9015                                  NULL,
9016                                  "",
9017                                  false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
9018                                  q->data, delq->data, NULL,
9019                                  prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
9020                                  NULL, NULL);
9021
9022         /* Dump Parser Comments */
9023         resetPQExpBuffer(q);
9024         appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9025                                           fmtId(prsinfo->dobj.name));
9026         dumpComment(fout, q->data,
9027                                 NULL, "",
9028                                 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9029
9030         destroyPQExpBuffer(q);
9031         destroyPQExpBuffer(delq);
9032 }
9033
9034 /*
9035  * dumpTSDictionary
9036  *        write out a single text search dictionary
9037  */
9038 static void
9039 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9040 {
9041         PQExpBuffer q;
9042         PQExpBuffer delq;
9043         PQExpBuffer query;
9044         PGresult   *res;
9045         int                     ntups;
9046         char       *nspname;
9047         char       *tmplname;
9048
9049         /* Skip if not to be dumped */
9050         if (!dictinfo->dobj.dump || dataOnly)
9051                 return;
9052
9053         q = createPQExpBuffer();
9054         delq = createPQExpBuffer();
9055         query = createPQExpBuffer();
9056
9057         /* Fetch name and namespace of the dictionary's template */
9058         selectSourceSchema("pg_catalog");
9059         appendPQExpBuffer(query, "SELECT nspname, tmplname "
9060                                           "FROM pg_ts_template p, pg_namespace n "
9061                                           "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
9062                                           dictinfo->dicttemplate);
9063         res = PQexec(g_conn, query->data);
9064         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9065         ntups = PQntuples(res);
9066         if (ntups != 1)
9067         {
9068                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9069                                                                  "query returned %d rows instead of one: %s\n",
9070                                                                  ntups),
9071                                   ntups, query->data);
9072                 exit_nicely();
9073         }
9074         nspname = PQgetvalue(res, 0, 0);
9075         tmplname = PQgetvalue(res, 0, 1);
9076
9077         /* Make sure we are in proper schema */
9078         selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9079
9080         appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9081                                           fmtId(dictinfo->dobj.name));
9082
9083         appendPQExpBuffer(q, "    TEMPLATE = ");
9084         if (strcmp(nspname, dictinfo->dobj.namespace->dobj.name) != 0)
9085                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9086         appendPQExpBuffer(q, "%s", fmtId(tmplname));
9087
9088         PQclear(res);
9089
9090         /* the dictinitoption can be dumped straight into the command */
9091         if (dictinfo->dictinitoption)
9092                 appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
9093
9094         appendPQExpBuffer(q, " );\n");
9095
9096         /*
9097          * DROP must be fully qualified in case same name appears in pg_catalog
9098          */
9099         appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s",
9100                                           fmtId(dictinfo->dobj.namespace->dobj.name));
9101         appendPQExpBuffer(delq, ".%s;\n",
9102                                           fmtId(dictinfo->dobj.name));
9103
9104         ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9105                                  dictinfo->dobj.name,
9106                                  dictinfo->dobj.namespace->dobj.name,
9107                                  NULL,
9108                                  dictinfo->rolname,
9109                                  false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9110                                  q->data, delq->data, NULL,
9111                                  dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
9112                                  NULL, NULL);
9113
9114         /* Dump Dictionary Comments */
9115         resetPQExpBuffer(q);
9116         appendPQExpBuffer(q, "TEXT SEARCH DICTIONARY %s",
9117                                           fmtId(dictinfo->dobj.name));
9118         dumpComment(fout, q->data,
9119                                 NULL, dictinfo->rolname,
9120                                 dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
9121
9122         destroyPQExpBuffer(q);
9123         destroyPQExpBuffer(delq);
9124         destroyPQExpBuffer(query);
9125 }
9126
9127 /*
9128  * dumpTSTemplate
9129  *        write out a single text search template
9130  */
9131 static void
9132 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9133 {
9134         PQExpBuffer q;
9135         PQExpBuffer delq;
9136
9137         /* Skip if not to be dumped */
9138         if (!tmplinfo->dobj.dump || dataOnly)
9139                 return;
9140
9141         q = createPQExpBuffer();
9142         delq = createPQExpBuffer();
9143
9144         /* Make sure we are in proper schema */
9145         selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9146
9147         appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9148                                           fmtId(tmplinfo->dobj.name));
9149
9150         if (tmplinfo->tmplinit != InvalidOid)
9151                 appendPQExpBuffer(q, "    INIT = %s,\n",
9152                                                   convertTSFunction(tmplinfo->tmplinit));
9153         appendPQExpBuffer(q, "    LEXIZE = %s );\n",
9154                                           convertTSFunction(tmplinfo->tmpllexize));
9155
9156         /*
9157          * DROP must be fully qualified in case same name appears in pg_catalog
9158          */
9159         appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s",
9160                                           fmtId(tmplinfo->dobj.namespace->dobj.name));
9161         appendPQExpBuffer(delq, ".%s;\n",
9162                                           fmtId(tmplinfo->dobj.name));
9163
9164         ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9165                                  tmplinfo->dobj.name,
9166                                  tmplinfo->dobj.namespace->dobj.name,
9167                                  NULL,
9168                                  "",
9169                                  false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9170                                  q->data, delq->data, NULL,
9171                                  tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9172                                  NULL, NULL);
9173
9174         /* Dump Template Comments */
9175         resetPQExpBuffer(q);
9176         appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9177                                           fmtId(tmplinfo->dobj.name));
9178         dumpComment(fout, q->data,
9179                                 NULL, "",
9180                                 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9181
9182         destroyPQExpBuffer(q);
9183         destroyPQExpBuffer(delq);
9184 }
9185
9186 /*
9187  * dumpTSConfig
9188  *        write out a single text search configuration
9189  */
9190 static void
9191 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9192 {
9193         PQExpBuffer q;
9194         PQExpBuffer delq;
9195         PQExpBuffer query;
9196         PGresult   *res;
9197         char       *nspname;
9198         char       *prsname;
9199         int                     ntups,
9200                                 i;
9201         int                     i_tokenname;
9202         int                     i_dictname;
9203
9204         /* Skip if not to be dumped */
9205         if (!cfginfo->dobj.dump || dataOnly)
9206                 return;
9207
9208         q = createPQExpBuffer();
9209         delq = createPQExpBuffer();
9210         query = createPQExpBuffer();
9211
9212         /* Fetch name and namespace of the config's parser */
9213         selectSourceSchema("pg_catalog");
9214         appendPQExpBuffer(query, "SELECT nspname, prsname "
9215                                           "FROM pg_ts_parser p, pg_namespace n "
9216                                           "WHERE p.oid = '%u' AND n.oid = prsnamespace",
9217                                           cfginfo->cfgparser);
9218         res = PQexec(g_conn, query->data);
9219         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9220         ntups = PQntuples(res);
9221         if (ntups != 1)
9222         {
9223                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9224                                                                  "query returned %d rows instead of one: %s\n",
9225                                                                  ntups),
9226                                   ntups, query->data);
9227                 exit_nicely();
9228         }
9229         nspname = PQgetvalue(res, 0, 0);
9230         prsname = PQgetvalue(res, 0, 1);
9231
9232         /* Make sure we are in proper schema */
9233         selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9234
9235         appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9236                                           fmtId(cfginfo->dobj.name));
9237
9238         appendPQExpBuffer(q, "    PARSER = ");
9239         if (strcmp(nspname, cfginfo->dobj.namespace->dobj.name) != 0)
9240                 appendPQExpBuffer(q, "%s.", fmtId(nspname));
9241         appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
9242
9243         PQclear(res);
9244
9245         resetPQExpBuffer(query);
9246         appendPQExpBuffer(query,
9247                                           "SELECT \n"
9248                                           "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t \n"
9249                                           "    WHERE t.tokid = m.maptokentype ) AS tokenname, \n"
9250                                           "  m.mapdict::pg_catalog.regdictionary AS dictname \n"
9251                                           "FROM pg_catalog.pg_ts_config_map AS m \n"
9252                                           "WHERE m.mapcfg = '%u' \n"
9253                                           "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
9254                                           cfginfo->cfgparser, cfginfo->dobj.catId.oid);
9255
9256         res = PQexec(g_conn, query->data);
9257         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9258         ntups = PQntuples(res);
9259
9260         i_tokenname = PQfnumber(res, "tokenname");
9261         i_dictname = PQfnumber(res, "dictname");
9262
9263         for (i = 0; i < ntups; i++)
9264         {
9265                 char       *tokenname = PQgetvalue(res, i, i_tokenname);
9266                 char       *dictname = PQgetvalue(res, i, i_dictname);
9267
9268                 if (i == 0 ||
9269                         strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9270                 {
9271                         /* starting a new token type, so start a new command */
9272                         if (i > 0)
9273                                 appendPQExpBuffer(q, ";\n");
9274                         appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
9275                                                           fmtId(cfginfo->dobj.name));
9276                         /* tokenname needs quoting, dictname does NOT */
9277                         appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
9278                                                           fmtId(tokenname), dictname);
9279                 }
9280                 else
9281                         appendPQExpBuffer(q, ", %s", dictname);
9282         }
9283
9284         if (ntups > 0)
9285                 appendPQExpBuffer(q, ";\n");
9286
9287         PQclear(res);
9288
9289         /*
9290          * DROP must be fully qualified in case same name appears in pg_catalog
9291          */
9292         appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s",
9293                                           fmtId(cfginfo->dobj.namespace->dobj.name));
9294         appendPQExpBuffer(delq, ".%s;\n",
9295                                           fmtId(cfginfo->dobj.name));
9296
9297         ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9298                                  cfginfo->dobj.name,
9299                                  cfginfo->dobj.namespace->dobj.name,
9300                                  NULL,
9301                                  cfginfo->rolname,
9302                                  false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9303                                  q->data, delq->data, NULL,
9304                                  cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
9305                                  NULL, NULL);
9306
9307         /* Dump Configuration Comments */
9308         resetPQExpBuffer(q);
9309         appendPQExpBuffer(q, "TEXT SEARCH CONFIGURATION %s",
9310                                           fmtId(cfginfo->dobj.name));
9311         dumpComment(fout, q->data,
9312                                 NULL, cfginfo->rolname,
9313                                 cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
9314
9315         destroyPQExpBuffer(q);
9316         destroyPQExpBuffer(delq);
9317         destroyPQExpBuffer(query);
9318 }
9319
9320 /*
9321  * dumpForeignDataWrapper
9322  *        write out a single foreign-data wrapper definition
9323  */
9324 static void
9325 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9326 {
9327         PQExpBuffer q;
9328         PQExpBuffer delq;
9329         char       *namecopy;
9330
9331         /* Skip if not to be dumped */
9332         if (!fdwinfo->dobj.dump || dataOnly)
9333                 return;
9334
9335         q = createPQExpBuffer();
9336         delq = createPQExpBuffer();
9337
9338         appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9339                                           fmtId(fdwinfo->dobj.name));
9340
9341         if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9342                 appendPQExpBuffer(q, " VALIDATOR %s",
9343                                                   fdwinfo->fdwvalidator);
9344
9345         if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9346                 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9347
9348         appendPQExpBuffer(q, ";\n");
9349
9350         appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9351                                           fmtId(fdwinfo->dobj.name));
9352
9353         ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9354                                  fdwinfo->dobj.name,
9355                                  NULL,
9356                                  NULL,
9357                                  fdwinfo->rolname,
9358                                  false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9359                                  q->data, delq->data, NULL,
9360                                  fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
9361                                  NULL, NULL);
9362
9363         /* Handle the ACL */
9364         namecopy = strdup(fmtId(fdwinfo->dobj.name));
9365         dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9366                         "FOREIGN DATA WRAPPER",
9367                         namecopy, NULL, fdwinfo->dobj.name,
9368                         NULL, fdwinfo->rolname,
9369                         fdwinfo->fdwacl);
9370         free(namecopy);
9371
9372         destroyPQExpBuffer(q);
9373         destroyPQExpBuffer(delq);
9374 }
9375
9376 /*
9377  * dumpForeignServer
9378  *        write out a foreign server definition
9379  */
9380 static void
9381 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9382 {
9383         PQExpBuffer q;
9384         PQExpBuffer delq;
9385         PQExpBuffer query;
9386         PGresult   *res;
9387         int                     ntups;
9388         char       *namecopy;
9389         char       *fdwname;
9390
9391         /* Skip if not to be dumped */
9392         if (!srvinfo->dobj.dump || dataOnly)
9393                 return;
9394
9395         q = createPQExpBuffer();
9396         delq = createPQExpBuffer();
9397         query = createPQExpBuffer();
9398
9399         /* look up the foreign-data wrapper */
9400         appendPQExpBuffer(query, "SELECT fdwname "
9401                                           "FROM pg_foreign_data_wrapper w "
9402                                           "WHERE w.oid = '%u'",
9403                                           srvinfo->srvfdw);
9404         res = PQexec(g_conn, query->data);
9405         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9406         ntups = PQntuples(res);
9407         if (ntups != 1)
9408         {
9409                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9410                                                                  "query returned %d rows instead of one: %s\n",
9411                                                                  ntups),
9412                                   ntups, query->data);
9413                 exit_nicely();
9414         }
9415         fdwname = PQgetvalue(res, 0, 0);
9416
9417         appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9418         if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9419         {
9420                 appendPQExpBuffer(q, " TYPE ");
9421                 appendStringLiteralAH(q, srvinfo->srvtype, fout);
9422         }
9423         if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9424         {
9425                 appendPQExpBuffer(q, " VERSION ");
9426                 appendStringLiteralAH(q, srvinfo->srvversion, fout);
9427         }
9428
9429         appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9430         appendPQExpBuffer(q, "%s", fmtId(fdwname));
9431
9432         if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9433                 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9434
9435         appendPQExpBuffer(q, ";\n");
9436
9437         appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9438                                           fmtId(srvinfo->dobj.name));
9439
9440         ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9441                                  srvinfo->dobj.name,
9442                                  NULL,
9443                                  NULL,
9444                                  srvinfo->rolname,
9445                                  false, "SERVER", SECTION_PRE_DATA,
9446                                  q->data, delq->data, NULL,
9447                                  srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9448                                  NULL, NULL);
9449
9450         /* Handle the ACL */
9451         namecopy = strdup(fmtId(srvinfo->dobj.name));
9452         dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9453                         "SERVER",
9454                         namecopy, NULL, srvinfo->dobj.name,
9455                         NULL, srvinfo->rolname,
9456                         srvinfo->srvacl);
9457         free(namecopy);
9458
9459         /* Dump user mappings */
9460         resetPQExpBuffer(q);
9461         appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
9462         dumpUserMappings(fout, q->data,
9463                                          srvinfo->dobj.name, NULL,
9464                                          srvinfo->rolname,
9465                                      srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9466
9467         destroyPQExpBuffer(q);
9468         destroyPQExpBuffer(delq);
9469 }
9470
9471 /*
9472  * dumpUserMappings
9473  *
9474  * This routine is used to dump any user mappings associated with the
9475  * server handed to this routine. Should be called after ArchiveEntry()
9476  * for the server.
9477  */
9478 static void
9479 dumpUserMappings(Archive *fout, const char *target,
9480                         const char *servername, const char *namespace,
9481                         const char *owner,
9482                         CatalogId catalogId, DumpId dumpId)
9483 {
9484         PQExpBuffer q;
9485         PQExpBuffer delq;
9486         PQExpBuffer query;
9487         PQExpBuffer tag;
9488         PGresult   *res;
9489         int                     ntups;
9490         int                     i_umuser;
9491         int                     i_umoptions;
9492         int                     i;
9493
9494         q = createPQExpBuffer();
9495         tag = createPQExpBuffer();
9496         delq = createPQExpBuffer();
9497         query = createPQExpBuffer();
9498
9499         appendPQExpBuffer(query,
9500                                           "SELECT (%s umuser) AS umuser, "
9501                                           "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
9502                                           "FROM pg_user_mapping "
9503                                           "WHERE umserver=%u",
9504                                           username_subquery,
9505                                           catalogId.oid);
9506
9507         res = PQexec(g_conn, query->data);
9508         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9509
9510         ntups = PQntuples(res);
9511         i_umuser = PQfnumber(res, "umuser");
9512         i_umoptions = PQfnumber(res, "umoptions");
9513
9514         for (i = 0; i < ntups; i++)
9515         {
9516                 char       *umuser;
9517                 char       *umoptions;
9518
9519                 umuser = PQgetvalue(res, i, i_umuser);
9520                 umoptions = PQgetvalue(res, i, i_umoptions);
9521
9522                 resetPQExpBuffer(q);
9523                 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9524                 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9525
9526                 if (umoptions && strlen(umoptions) > 0)
9527                         appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9528
9529                 appendPQExpBuffer(q, ";\n");
9530
9531                 resetPQExpBuffer(delq);
9532                 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
9533
9534                 resetPQExpBuffer(tag);
9535                 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
9536
9537                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9538                                          tag->data,
9539                                          namespace,
9540                                          NULL,
9541                                          owner, false,
9542                                          "USER MAPPING", SECTION_PRE_DATA,
9543                                          q->data, delq->data, NULL,
9544                                          &dumpId, 1,
9545                                          NULL, NULL);
9546         }
9547
9548         PQclear(res);
9549
9550         destroyPQExpBuffer(query);
9551         destroyPQExpBuffer(delq);
9552         destroyPQExpBuffer(q);
9553 }
9554
9555 /*----------
9556  * Write out grant/revoke information
9557  *
9558  * 'objCatId' is the catalog ID of the underlying object.
9559  * 'objDumpId' is the dump ID of the underlying object.
9560  * 'type' must be TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE.
9561  * 'name' is the formatted name of the object.  Must be quoted etc. already.
9562  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
9563  * 'tag' is the tag for the archive entry (typ. unquoted name of object).
9564  * 'nspname' is the namespace the object is in (NULL if none).
9565  * 'owner' is the owner, NULL if there is no owner (for languages).
9566  * 'acls' is the string read out of the fooacl system catalog field;
9567  * it will be parsed here.
9568  *----------
9569  */
9570 static void
9571 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
9572                 const char *type, const char *name, const char *subname,
9573                 const char *tag, const char *nspname, const char *owner,
9574                 const char *acls)
9575 {
9576         PQExpBuffer sql;
9577
9578         /* Do nothing if ACL dump is not enabled */
9579         if (dataOnly || aclsSkip)
9580                 return;
9581
9582         sql = createPQExpBuffer();
9583
9584         if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
9585         {
9586                 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9587                                   acls, name, type);
9588                 exit_nicely();
9589         }
9590
9591         if (sql->len > 0)
9592                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9593                                          tag, nspname,
9594                                          NULL,
9595                                          owner ? owner : "",
9596                                          false, "ACL", SECTION_NONE,
9597                                          sql->data, "", NULL,
9598                                          &(objDumpId), 1,
9599                                          NULL, NULL);
9600
9601         destroyPQExpBuffer(sql);
9602 }
9603
9604 /*
9605  * dumpTable
9606  *        write out to fout the declarations (not data) of a user-defined table
9607  */
9608 static void
9609 dumpTable(Archive *fout, TableInfo *tbinfo)
9610 {
9611         if (tbinfo->dobj.dump)
9612         {
9613                 char   *namecopy;
9614
9615                 if (tbinfo->relkind == RELKIND_SEQUENCE)
9616                         dumpSequence(fout, tbinfo);
9617                 else if (!dataOnly)
9618                         dumpTableSchema(fout, tbinfo);
9619
9620                 /* Handle the ACL here */
9621                 namecopy = strdup(fmtId(tbinfo->dobj.name));
9622                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9623                                 (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE",
9624                                 namecopy, NULL, tbinfo->dobj.name,
9625                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9626                                 tbinfo->relacl);
9627
9628                 /*
9629                  * Handle column ACLs, if any.  Note: we pull these with a separate
9630                  * query rather than trying to fetch them during getTableAttrs, so
9631                  * that we won't miss ACLs on system columns.
9632                  */
9633                 if (g_fout->remoteVersion >= 80400)
9634                 {
9635                         PQExpBuffer query = createPQExpBuffer();
9636                         PGresult *res;
9637                         int             i;
9638
9639                         appendPQExpBuffer(query,
9640                                                           "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9641                                                           "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9642                                                           "ORDER BY attnum",
9643                                                           tbinfo->dobj.catId.oid);
9644                         res = PQexec(g_conn, query->data);
9645                         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9646
9647                         for (i = 0; i < PQntuples(res); i++)
9648                         {
9649                                 char   *attname = PQgetvalue(res, i, 0);
9650                                 char   *attacl = PQgetvalue(res, i, 1);
9651                                 char   *attnamecopy;
9652                                 char   *acltag;
9653
9654                                 attnamecopy = strdup(fmtId(attname));
9655                                 acltag = malloc(strlen(tbinfo->dobj.name) + strlen(attname) + 2);
9656                                 sprintf(acltag, "%s.%s", tbinfo->dobj.name, attname);
9657                                 /* Column's GRANT type is always TABLE */
9658                                 dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
9659                                                 namecopy, attnamecopy, acltag,
9660                                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
9661                                                 attacl);
9662                                 free(attnamecopy);
9663                                 free(acltag);
9664                         }
9665                         PQclear(res);
9666                         destroyPQExpBuffer(query);
9667                 }
9668
9669                 free(namecopy);
9670         }
9671 }
9672
9673 /*
9674  * dumpTableSchema
9675  *        write the declaration (not data) of one user-defined table or view
9676  */
9677 static void
9678 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9679 {
9680         PQExpBuffer query = createPQExpBuffer();
9681         PQExpBuffer q = createPQExpBuffer();
9682         PQExpBuffer delq = createPQExpBuffer();
9683         PGresult   *res;
9684         int                     numParents;
9685         TableInfo **parents;
9686         int                     actual_atts;    /* number of attrs in this CREATE statment */
9687         char       *reltypename;
9688         char       *storage;
9689         int                     j,
9690                                 k;
9691
9692         /* Make sure we are in proper schema */
9693         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9694
9695         /* Is it a table or a view? */
9696         if (tbinfo->relkind == RELKIND_VIEW)
9697         {
9698                 char       *viewdef;
9699
9700                 reltypename = "VIEW";
9701
9702                 /* Fetch the view definition */
9703                 if (g_fout->remoteVersion >= 70300)
9704                 {
9705                         /* Beginning in 7.3, viewname is not unique; rely on OID */
9706                         appendPQExpBuffer(query,
9707                                                           "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
9708                                                           tbinfo->dobj.catId.oid);
9709                 }
9710                 else
9711                 {
9712                         appendPQExpBuffer(query, "SELECT definition AS viewdef "
9713                                                           "FROM pg_views WHERE viewname = ");
9714                         appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9715                         appendPQExpBuffer(query, ";");
9716                 }
9717
9718                 res = PQexec(g_conn, query->data);
9719                 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9720
9721                 if (PQntuples(res) != 1)
9722                 {
9723                         if (PQntuples(res) < 1)
9724                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9725                                                   tbinfo->dobj.name);
9726                         else
9727                                 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9728                                                   tbinfo->dobj.name);
9729                         exit_nicely();
9730                 }
9731
9732                 viewdef = PQgetvalue(res, 0, 0);
9733
9734                 if (strlen(viewdef) == 0)
9735                 {
9736                         write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9737                                           tbinfo->dobj.name);
9738                         exit_nicely();
9739                 }
9740
9741                 /*
9742                  * DROP must be fully qualified in case same name appears in
9743                  * pg_catalog
9744                  */
9745                 appendPQExpBuffer(delq, "DROP VIEW %s.",
9746                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
9747                 appendPQExpBuffer(delq, "%s;\n",
9748                                                   fmtId(tbinfo->dobj.name));
9749
9750                 appendPQExpBuffer(q, "CREATE VIEW %s AS\n    %s\n",
9751                                                   fmtId(tbinfo->dobj.name), viewdef);
9752
9753                 PQclear(res);
9754         }
9755         else
9756         {
9757                 reltypename = "TABLE";
9758                 numParents = tbinfo->numParents;
9759                 parents = tbinfo->parents;
9760
9761                 /*
9762                  * DROP must be fully qualified in case same name appears in
9763                  * pg_catalog
9764                  */
9765                 appendPQExpBuffer(delq, "DROP TABLE %s.",
9766                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
9767                 appendPQExpBuffer(delq, "%s;\n",
9768                                                   fmtId(tbinfo->dobj.name));
9769
9770                 appendPQExpBuffer(q, "CREATE TABLE %s (",
9771                                                   fmtId(tbinfo->dobj.name));
9772                 actual_atts = 0;
9773                 for (j = 0; j < tbinfo->numatts; j++)
9774                 {
9775                         /* Is this one of the table's own attrs, and not dropped ? */
9776                         if (!tbinfo->inhAttrs[j] &&
9777                                 (!tbinfo->attisdropped[j] || binary_upgrade))
9778                         {
9779                                 /* Format properly if not first attr */
9780                                 if (actual_atts > 0)
9781                                         appendPQExpBuffer(q, ",");
9782                                 appendPQExpBuffer(q, "\n    ");
9783
9784                                 /* Attribute name */
9785                                 appendPQExpBuffer(q, "%s ",
9786                                                                   fmtId(tbinfo->attnames[j]));
9787
9788                                 /* Attribute type */
9789                                 if (g_fout->remoteVersion >= 70100)
9790                                 {
9791                                         appendPQExpBuffer(q, "%s",
9792                                                                           tbinfo->atttypnames[j]);
9793                                 }
9794                                 else
9795                                 {
9796                                         /* If no format_type, fake it */
9797                                         appendPQExpBuffer(q, "%s",
9798                                                                           myFormatType(tbinfo->atttypnames[j],
9799                                                                                                    tbinfo->atttypmod[j]));
9800                                 }
9801
9802                                 /*
9803                                  * Default value --- suppress if inherited or to be printed
9804                                  * separately.
9805                                  */
9806                                 if (tbinfo->attrdefs[j] != NULL &&
9807                                         !tbinfo->inhAttrDef[j] &&
9808                                         !tbinfo->attrdefs[j]->separate)
9809                                         appendPQExpBuffer(q, " DEFAULT %s",
9810                                                                           tbinfo->attrdefs[j]->adef_expr);
9811
9812                                 /*
9813                                  * Not Null constraint --- suppress if inherited
9814                                  */
9815                                 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
9816                                         appendPQExpBuffer(q, " NOT NULL");
9817
9818                                 actual_atts++;
9819                         }
9820                 }
9821
9822                 /*
9823                  * Add non-inherited CHECK constraints, if any.
9824                  */
9825                 for (j = 0; j < tbinfo->ncheck; j++)
9826                 {
9827                         ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9828
9829                         if (constr->separate || !constr->conislocal)
9830                                 continue;
9831
9832                         if (actual_atts > 0)
9833                                 appendPQExpBuffer(q, ",\n    ");
9834
9835                         appendPQExpBuffer(q, "CONSTRAINT %s ",
9836                                                           fmtId(constr->dobj.name));
9837                         appendPQExpBuffer(q, "%s", constr->condef);
9838
9839                         actual_atts++;
9840                 }
9841
9842                 appendPQExpBuffer(q, "\n)");
9843
9844                 if (numParents > 0)
9845                 {
9846                         appendPQExpBuffer(q, "\nINHERITS (");
9847                         for (k = 0; k < numParents; k++)
9848                         {
9849                                 TableInfo  *parentRel = parents[k];
9850
9851                                 if (k > 0)
9852                                         appendPQExpBuffer(q, ", ");
9853                                 if (parentRel->dobj.namespace != tbinfo->dobj.namespace)
9854                                         appendPQExpBuffer(q, "%s.",
9855                                                                 fmtId(parentRel->dobj.namespace->dobj.name));
9856                                 appendPQExpBuffer(q, "%s",
9857                                                                   fmtId(parentRel->dobj.name));
9858                         }
9859                         appendPQExpBuffer(q, ")");
9860                 }
9861
9862                 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
9863                         (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
9864                 {
9865                         bool    addcomma = false;
9866
9867                         appendPQExpBuffer(q, "\nWITH (");
9868                         if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9869                         {
9870                                 addcomma = true;
9871                                 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
9872                         }
9873                         if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
9874                         {
9875                                 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
9876                                                                   tbinfo->toast_reloptions);
9877                         }
9878                         appendPQExpBuffer(q, ")");
9879                 }
9880
9881                 appendPQExpBuffer(q, ";\n");
9882
9883                 /*
9884                  * For binary-compatible heap files, we create dropped columns
9885                  * above and drop them here.
9886                  */
9887                 if (binary_upgrade)
9888                 {
9889                         for (j = 0; j < tbinfo->numatts; j++)
9890                         {
9891                                 if (tbinfo->attisdropped[j])
9892                                 {
9893                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9894                                                                           fmtId(tbinfo->dobj.name));
9895                                         appendPQExpBuffer(q, "DROP COLUMN %s;\n",
9896                                                                           fmtId(tbinfo->attnames[j]));
9897
9898                                         /*
9899                                          *      ALTER TABLE DROP COLUMN clears pg_attribute.atttypid,
9900                                          *      so we have to set pg_attribute.attlen and
9901                                          *      pg_attribute.attalign values because that is what
9902                                          *      is used to skip over dropped columns in the heap tuples.
9903                                          *      We have atttypmod, but it seems impossible to know the
9904                                          *      correct data type that will yield pg_attribute values
9905                                          *      that match the old installation.
9906                                          *      See comment in backend/catalog/heap.c::RemoveAttributeById()
9907                                          */
9908                                         appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
9909                                         appendPQExpBuffer(q, "UPDATE pg_attribute\n"
9910                                                                                  "SET attlen = %d, "
9911                                                                                  "attalign = '%c'\n"
9912                                                                                  "WHERE attname = '%s'\n"
9913                                                                                  "      AND attrelid = \n"
9914                                                                                  "      (\n"
9915                                                                                  "              SELECT oid\n"
9916                                                                                  "              FROM pg_class\n"
9917                                                                                  "              WHERE   relnamespace = "
9918                                                                                  "(SELECT oid FROM pg_namespace "
9919                                                                                  "WHERE nspname = CURRENT_SCHEMA)\n"
9920                                                                                  "                      AND relname = ",
9921                                                                                  tbinfo->attlen[j],
9922                                                                                  tbinfo->attalign[j],
9923                                                                                  tbinfo->attnames[j]);
9924                                         appendStringLiteralAH(q, tbinfo->dobj.name, fout);
9925                                         appendPQExpBuffer(q, "\n        );\n");
9926                                 }
9927                         }
9928                         appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
9929                         appendPQExpBuffer(q, "UPDATE pg_class\n"
9930                                                                  "SET relfrozenxid = '%u'\n"
9931                                                                  "WHERE relname = ",
9932                                                                  tbinfo->frozenxid);
9933                         appendStringLiteralAH(q, tbinfo->dobj.name, fout);
9934                         appendPQExpBuffer(q, "\n        AND relnamespace = "
9935                                                                  "(SELECT oid FROM pg_namespace "
9936                                                                  "WHERE nspname = CURRENT_SCHEMA);\n");
9937                 }
9938         
9939                 /* Loop dumping statistics and storage statements */
9940                 for (j = 0; j < tbinfo->numatts; j++)
9941                 {
9942                         /*
9943                          * Dump per-column statistics information. We only issue an ALTER
9944                          * TABLE statement if the attstattarget entry for this column is
9945                          * non-negative (i.e. it's not the default value)
9946                          */
9947                         if (tbinfo->attstattarget[j] >= 0 &&
9948                                 !tbinfo->attisdropped[j])
9949                         {
9950                                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9951                                                                   fmtId(tbinfo->dobj.name));
9952                                 appendPQExpBuffer(q, "ALTER COLUMN %s ",
9953                                                                   fmtId(tbinfo->attnames[j]));
9954                                 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
9955                                                                   tbinfo->attstattarget[j]);
9956                         }
9957
9958                         /*
9959                          * Dump per-column storage information.  The statement is only
9960                          * dumped if the storage has been changed from the type's default.
9961                          */
9962                         if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
9963                         {
9964                                 switch (tbinfo->attstorage[j])
9965                                 {
9966                                         case 'p':
9967                                                 storage = "PLAIN";
9968                                                 break;
9969                                         case 'e':
9970                                                 storage = "EXTERNAL";
9971                                                 break;
9972                                         case 'm':
9973                                                 storage = "MAIN";
9974                                                 break;
9975                                         case 'x':
9976                                                 storage = "EXTENDED";
9977                                                 break;
9978                                         default:
9979                                                 storage = NULL;
9980                                 }
9981
9982                                 /*
9983                                  * Only dump the statement if it's a storage type we recognize
9984                                  */
9985                                 if (storage != NULL)
9986                                 {
9987                                         appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9988                                                                           fmtId(tbinfo->dobj.name));
9989                                         appendPQExpBuffer(q, "ALTER COLUMN %s ",
9990                                                                           fmtId(tbinfo->attnames[j]));
9991                                         appendPQExpBuffer(q, "SET STORAGE %s;\n",
9992                                                                           storage);
9993                                 }
9994                         }
9995                 }
9996         }
9997
9998         ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
9999                                  tbinfo->dobj.name,
10000                                  tbinfo->dobj.namespace->dobj.name,
10001                         (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
10002                                  tbinfo->rolname,
10003                            (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
10004                                  reltypename, SECTION_PRE_DATA,
10005                                  q->data, delq->data, NULL,
10006                                  tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10007                                  NULL, NULL);
10008
10009         /* Dump Table Comments */
10010         dumpTableComment(fout, tbinfo, reltypename);
10011
10012         /* Dump comments on inlined table constraints */
10013         for (j = 0; j < tbinfo->ncheck; j++)
10014         {
10015                 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10016
10017                 if (constr->separate || !constr->conislocal)
10018                         continue;
10019
10020                 dumpTableConstraintComment(fout, constr);
10021         }
10022
10023         destroyPQExpBuffer(query);
10024         destroyPQExpBuffer(q);
10025         destroyPQExpBuffer(delq);
10026 }
10027
10028 /*
10029  * dumpAttrDef --- dump an attribute's default-value declaration
10030  */
10031 static void
10032 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
10033 {
10034         TableInfo  *tbinfo = adinfo->adtable;
10035         int                     adnum = adinfo->adnum;
10036         PQExpBuffer q;
10037         PQExpBuffer delq;
10038
10039         /* Only print it if "separate" mode is selected */
10040         if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10041                 return;
10042
10043         /* Don't print inherited defaults, either */
10044         if (tbinfo->inhAttrDef[adnum - 1])
10045                 return;
10046
10047         q = createPQExpBuffer();
10048         delq = createPQExpBuffer();
10049
10050         appendPQExpBuffer(q, "ALTER TABLE %s ",
10051                                           fmtId(tbinfo->dobj.name));
10052         appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
10053                                           fmtId(tbinfo->attnames[adnum - 1]),
10054                                           adinfo->adef_expr);
10055
10056         /*
10057          * DROP must be fully qualified in case same name appears in pg_catalog
10058          */
10059         appendPQExpBuffer(delq, "ALTER TABLE %s.",
10060                                           fmtId(tbinfo->dobj.namespace->dobj.name));
10061         appendPQExpBuffer(delq, "%s ",
10062                                           fmtId(tbinfo->dobj.name));
10063         appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
10064                                           fmtId(tbinfo->attnames[adnum - 1]));
10065
10066         ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10067                                  tbinfo->attnames[adnum - 1],
10068                                  tbinfo->dobj.namespace->dobj.name,
10069                                  NULL,
10070                                  tbinfo->rolname,
10071                                  false, "DEFAULT", SECTION_PRE_DATA,
10072                                  q->data, delq->data, NULL,
10073                                  adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10074                                  NULL, NULL);
10075
10076         destroyPQExpBuffer(q);
10077         destroyPQExpBuffer(delq);
10078 }
10079
10080 /*
10081  * getAttrName: extract the correct name for an attribute
10082  *
10083  * The array tblInfo->attnames[] only provides names of user attributes;
10084  * if a system attribute number is supplied, we have to fake it.
10085  * We also do a little bit of bounds checking for safety's sake.
10086  */
10087 static const char *
10088 getAttrName(int attrnum, TableInfo *tblInfo)
10089 {
10090         if (attrnum > 0 && attrnum <= tblInfo->numatts)
10091                 return tblInfo->attnames[attrnum - 1];
10092         switch (attrnum)
10093         {
10094                 case SelfItemPointerAttributeNumber:
10095                         return "ctid";
10096                 case ObjectIdAttributeNumber:
10097                         return "oid";
10098                 case MinTransactionIdAttributeNumber:
10099                         return "xmin";
10100                 case MinCommandIdAttributeNumber:
10101                         return "cmin";
10102                 case MaxTransactionIdAttributeNumber:
10103                         return "xmax";
10104                 case MaxCommandIdAttributeNumber:
10105                         return "cmax";
10106                 case TableOidAttributeNumber:
10107                         return "tableoid";
10108         }
10109         write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10110                           attrnum, tblInfo->dobj.name);
10111         exit_nicely();
10112         return NULL;                            /* keep compiler quiet */
10113 }
10114
10115 /*
10116  * dumpIndex
10117  *        write out to fout a user-defined index
10118  */
10119 static void
10120 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10121 {
10122         TableInfo  *tbinfo = indxinfo->indextable;
10123         PQExpBuffer q;
10124         PQExpBuffer delq;
10125
10126         if (dataOnly)
10127                 return;
10128
10129         q = createPQExpBuffer();
10130         delq = createPQExpBuffer();
10131
10132         /*
10133          * If there's an associated constraint, don't dump the index per se, but
10134          * do dump any comment for it.  (This is safe because dependency ordering
10135          * will have ensured the constraint is emitted first.)
10136          */
10137         if (indxinfo->indexconstraint == 0)
10138         {
10139                 /* Plain secondary index */
10140                 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10141
10142                 /* If the index is clustered, we need to record that. */
10143                 if (indxinfo->indisclustered)
10144                 {
10145                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10146                                                           fmtId(tbinfo->dobj.name));
10147                         appendPQExpBuffer(q, " ON %s;\n",
10148                                                           fmtId(indxinfo->dobj.name));
10149                 }
10150
10151                 /*
10152                  * DROP must be fully qualified in case same name appears in
10153                  * pg_catalog
10154                  */
10155                 appendPQExpBuffer(delq, "DROP INDEX %s.",
10156                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10157                 appendPQExpBuffer(delq, "%s;\n",
10158                                                   fmtId(indxinfo->dobj.name));
10159
10160                 ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
10161                                          indxinfo->dobj.name,
10162                                          tbinfo->dobj.namespace->dobj.name,
10163                                          indxinfo->tablespace,
10164                                          tbinfo->rolname, false,
10165                                          "INDEX", SECTION_POST_DATA,
10166                                          q->data, delq->data, NULL,
10167                                          indxinfo->dobj.dependencies, indxinfo->dobj.nDeps,
10168                                          NULL, NULL);
10169         }
10170
10171         /* Dump Index Comments */
10172         resetPQExpBuffer(q);
10173         appendPQExpBuffer(q, "INDEX %s",
10174                                           fmtId(indxinfo->dobj.name));
10175         dumpComment(fout, q->data,
10176                                 tbinfo->dobj.namespace->dobj.name,
10177                                 tbinfo->rolname,
10178                                 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10179
10180         destroyPQExpBuffer(q);
10181         destroyPQExpBuffer(delq);
10182 }
10183
10184 /*
10185  * dumpConstraint
10186  *        write out to fout a user-defined constraint
10187  */
10188 static void
10189 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10190 {
10191         TableInfo  *tbinfo = coninfo->contable;
10192         PQExpBuffer q;
10193         PQExpBuffer delq;
10194
10195         /* Skip if not to be dumped */
10196         if (!coninfo->dobj.dump || dataOnly)
10197                 return;
10198
10199         q = createPQExpBuffer();
10200         delq = createPQExpBuffer();
10201
10202         if (coninfo->contype == 'p' || coninfo->contype == 'u')
10203         {
10204                 /* Index-related constraint */
10205                 IndxInfo   *indxinfo;
10206                 int                     k;
10207
10208                 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10209
10210                 if (indxinfo == NULL)
10211                 {
10212                         write_msg(NULL, "missing index for constraint \"%s\"\n",
10213                                           coninfo->dobj.name);
10214                         exit_nicely();
10215                 }
10216
10217                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10218                                                   fmtId(tbinfo->dobj.name));
10219                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s (",
10220                                                   fmtId(coninfo->dobj.name),
10221                                                   coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
10222
10223                 for (k = 0; k < indxinfo->indnkeys; k++)
10224                 {
10225                         int                     indkey = (int) indxinfo->indkeys[k];
10226                         const char *attname;
10227
10228                         if (indkey == InvalidAttrNumber)
10229                                 break;
10230                         attname = getAttrName(indkey, tbinfo);
10231
10232                         appendPQExpBuffer(q, "%s%s",
10233                                                           (k == 0) ? "" : ", ",
10234                                                           fmtId(attname));
10235                 }
10236
10237                 appendPQExpBuffer(q, ")");
10238
10239                 if (indxinfo->options && strlen(indxinfo->options) > 0)
10240                         appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10241
10242                 appendPQExpBuffer(q, ";\n");
10243
10244                 /* If the index is clustered, we need to record that. */
10245                 if (indxinfo->indisclustered)
10246                 {
10247                         appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10248                                                           fmtId(tbinfo->dobj.name));
10249                         appendPQExpBuffer(q, " ON %s;\n",
10250                                                           fmtId(indxinfo->dobj.name));
10251                 }
10252
10253                 /*
10254                  * DROP must be fully qualified in case same name appears in
10255                  * pg_catalog
10256                  */
10257                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10258                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10259                 appendPQExpBuffer(delq, "%s ",
10260                                                   fmtId(tbinfo->dobj.name));
10261                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10262                                                   fmtId(coninfo->dobj.name));
10263
10264                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10265                                          coninfo->dobj.name,
10266                                          tbinfo->dobj.namespace->dobj.name,
10267                                          indxinfo->tablespace,
10268                                          tbinfo->rolname, false,
10269                                          "CONSTRAINT", SECTION_POST_DATA,
10270                                          q->data, delq->data, NULL,
10271                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10272                                          NULL, NULL);
10273         }
10274         else if (coninfo->contype == 'f')
10275         {
10276                 /*
10277                  * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10278                  * current table data is not processed
10279                  */
10280                 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
10281                                                   fmtId(tbinfo->dobj.name));
10282                 appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10283                                                   fmtId(coninfo->dobj.name),
10284                                                   coninfo->condef);
10285
10286                 /*
10287                  * DROP must be fully qualified in case same name appears in
10288                  * pg_catalog
10289                  */
10290                 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
10291                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10292                 appendPQExpBuffer(delq, "%s ",
10293                                                   fmtId(tbinfo->dobj.name));
10294                 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10295                                                   fmtId(coninfo->dobj.name));
10296
10297                 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10298                                          coninfo->dobj.name,
10299                                          tbinfo->dobj.namespace->dobj.name,
10300                                          NULL,
10301                                          tbinfo->rolname, false,
10302                                          "FK CONSTRAINT", SECTION_POST_DATA,
10303                                          q->data, delq->data, NULL,
10304                                          coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10305                                          NULL, NULL);
10306         }
10307         else if (coninfo->contype == 'c' && tbinfo)
10308         {
10309                 /* CHECK constraint on a table */
10310
10311                 /* Ignore if not to be dumped separately */
10312                 if (coninfo->separate)
10313                 {
10314                         /* not ONLY since we want it to propagate to children */
10315                         appendPQExpBuffer(q, "ALTER TABLE %s\n",
10316                                                           fmtId(tbinfo->dobj.name));
10317                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10318                                                           fmtId(coninfo->dobj.name),
10319                                                           coninfo->condef);
10320
10321                         /*
10322                          * DROP must be fully qualified in case same name appears in
10323                          * pg_catalog
10324                          */
10325                         appendPQExpBuffer(delq, "ALTER TABLE %s.",
10326                                                           fmtId(tbinfo->dobj.namespace->dobj.name));
10327                         appendPQExpBuffer(delq, "%s ",
10328                                                           fmtId(tbinfo->dobj.name));
10329                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10330                                                           fmtId(coninfo->dobj.name));
10331
10332                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10333                                                  coninfo->dobj.name,
10334                                                  tbinfo->dobj.namespace->dobj.name,
10335                                                  NULL,
10336                                                  tbinfo->rolname, false,
10337                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
10338                                                  q->data, delq->data, NULL,
10339                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10340                                                  NULL, NULL);
10341                 }
10342         }
10343         else if (coninfo->contype == 'c' && tbinfo == NULL)
10344         {
10345                 /* CHECK constraint on a domain */
10346                 TypeInfo   *tinfo = coninfo->condomain;
10347
10348                 /* Ignore if not to be dumped separately */
10349                 if (coninfo->separate)
10350                 {
10351                         appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
10352                                                           fmtId(tinfo->dobj.name));
10353                         appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
10354                                                           fmtId(coninfo->dobj.name),
10355                                                           coninfo->condef);
10356
10357                         /*
10358                          * DROP must be fully qualified in case same name appears in
10359                          * pg_catalog
10360                          */
10361                         appendPQExpBuffer(delq, "ALTER DOMAIN %s.",
10362                                                           fmtId(tinfo->dobj.namespace->dobj.name));
10363                         appendPQExpBuffer(delq, "%s ",
10364                                                           fmtId(tinfo->dobj.name));
10365                         appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
10366                                                           fmtId(coninfo->dobj.name));
10367
10368                         ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10369                                                  coninfo->dobj.name,
10370                                                  tinfo->dobj.namespace->dobj.name,
10371                                                  NULL,
10372                                                  tinfo->rolname, false,
10373                                                  "CHECK CONSTRAINT", SECTION_POST_DATA,
10374                                                  q->data, delq->data, NULL,
10375                                                  coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10376                                                  NULL, NULL);
10377                 }
10378         }
10379         else
10380         {
10381                 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
10382                 exit_nicely();
10383         }
10384
10385         /* Dump Constraint Comments --- only works for table constraints */
10386         if (tbinfo && coninfo->separate)
10387                 dumpTableConstraintComment(fout, coninfo);
10388
10389         destroyPQExpBuffer(q);
10390         destroyPQExpBuffer(delq);
10391 }
10392
10393 /*
10394  * dumpTableConstraintComment --- dump a constraint's comment if any
10395  *
10396  * This is split out because we need the function in two different places
10397  * depending on whether the constraint is dumped as part of CREATE TABLE
10398  * or as a separate ALTER command.
10399  */
10400 static void
10401 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
10402 {
10403         TableInfo  *tbinfo = coninfo->contable;
10404         PQExpBuffer q = createPQExpBuffer();
10405
10406         appendPQExpBuffer(q, "CONSTRAINT %s ",
10407                                           fmtId(coninfo->dobj.name));
10408         appendPQExpBuffer(q, "ON %s",
10409                                           fmtId(tbinfo->dobj.name));
10410         dumpComment(fout, q->data,
10411                                 tbinfo->dobj.namespace->dobj.name,
10412                                 tbinfo->rolname,
10413                                 coninfo->dobj.catId, 0,
10414                          coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
10415
10416         destroyPQExpBuffer(q);
10417 }
10418
10419 /*
10420  * findLastBuiltInOid -
10421  * find the last built in oid
10422  *
10423  * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10424  * pg_database entry for the current database
10425  */
10426 static Oid
10427 findLastBuiltinOid_V71(const char *dbname)
10428 {
10429         PGresult   *res;
10430         int                     ntups;
10431         Oid                     last_oid;
10432         PQExpBuffer query = createPQExpBuffer();
10433
10434         resetPQExpBuffer(query);
10435         appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
10436         appendStringLiteralAH(query, dbname, g_fout);
10437
10438         res = PQexec(g_conn, query->data);
10439         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10440
10441         ntups = PQntuples(res);
10442         if (ntups < 1)
10443         {
10444                 write_msg(NULL, "missing pg_database entry for this database\n");
10445                 exit_nicely();
10446         }
10447         if (ntups > 1)
10448         {
10449                 write_msg(NULL, "found more than one pg_database entry for this database\n");
10450                 exit_nicely();
10451         }
10452         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
10453         PQclear(res);
10454         destroyPQExpBuffer(query);
10455         return last_oid;
10456 }
10457
10458 /*
10459  * findLastBuiltInOid -
10460  * find the last built in oid
10461  *
10462  * For 7.0, we do this by assuming that the last thing that initdb does is to
10463  * create the pg_indexes view.  This sucks in general, but seeing that 7.0.x
10464  * initdb won't be changing anymore, it'll do.
10465  */
10466 static Oid
10467 findLastBuiltinOid_V70(void)
10468 {
10469         PGresult   *res;
10470         int                     ntups;
10471         int                     last_oid;
10472
10473         res = PQexec(g_conn,
10474                                  "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
10475         check_sql_result(res, g_conn,
10476                                          "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'",
10477                                          PGRES_TUPLES_OK);
10478         ntups = PQntuples(res);
10479         if (ntups < 1)
10480         {
10481                 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
10482                 exit_nicely();
10483         }
10484         if (ntups > 1)
10485         {
10486                 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
10487                 exit_nicely();
10488         }
10489         last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
10490         PQclear(res);
10491         return last_oid;
10492 }
10493
10494 static void
10495 dumpSequence(Archive *fout, TableInfo *tbinfo)
10496 {
10497         PGresult   *res;
10498         char       *startv,
10499                            *last,
10500                            *incby,
10501                            *maxv = NULL,
10502                            *minv = NULL,
10503                            *cache;
10504         char            bufm[100],
10505                                 bufx[100];
10506         bool            cycled,
10507                                 called;
10508         PQExpBuffer query = createPQExpBuffer();
10509         PQExpBuffer delqry = createPQExpBuffer();
10510
10511         /* Make sure we are in proper schema */
10512         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10513
10514         snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
10515         snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
10516
10517         if (g_fout->remoteVersion >= 80400)
10518         {
10519                 appendPQExpBuffer(query,
10520                                   "SELECT sequence_name, "
10521                                   "start_value, last_value, increment_by, "
10522                                   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10523                                   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10524                                   "     ELSE max_value "
10525                                   "END AS max_value, "
10526                                   "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10527                                   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
10528                                   "     ELSE min_value "
10529                                   "END AS min_value, "
10530                                   "cache_value, is_cycled, is_called from %s",
10531                                   bufx, bufm,
10532                                   fmtId(tbinfo->dobj.name));
10533         }
10534         else
10535         {
10536                 appendPQExpBuffer(query,
10537                                   "SELECT sequence_name, "
10538                                   "0 AS start_value, last_value, increment_by, "
10539                                   "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
10540                                   "     WHEN increment_by < 0 AND max_value = -1 THEN NULL "
10541                                   "     ELSE max_value "
10542                                   "END AS max_value, "
10543                                   "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
10544                                   "     WHEN increment_by < 0 AND min_value = %s THEN NULL "
10545                                   "     ELSE min_value "
10546                                   "END AS min_value, "
10547                                   "cache_value, is_cycled, is_called from %s",
10548                                   bufx, bufm,
10549                                   fmtId(tbinfo->dobj.name));
10550         }
10551
10552         res = PQexec(g_conn, query->data);
10553         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10554
10555         if (PQntuples(res) != 1)
10556         {
10557                 write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
10558                                                                  "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
10559                                                                  PQntuples(res)),
10560                                   tbinfo->dobj.name, PQntuples(res));
10561                 exit_nicely();
10562         }
10563
10564         /* Disable this check: it fails if sequence has been renamed */
10565 #ifdef NOT_USED
10566         if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
10567         {
10568                 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10569                                   tbinfo->dobj.name, PQgetvalue(res, 0, 0));
10570                 exit_nicely();
10571         }
10572 #endif
10573
10574         startv = PQgetvalue(res, 0, 1);
10575         last = PQgetvalue(res, 0, 2);
10576         incby = PQgetvalue(res, 0, 3);
10577         if (!PQgetisnull(res, 0, 4))
10578                 maxv = PQgetvalue(res, 0, 4);
10579         if (!PQgetisnull(res, 0, 5))
10580                 minv = PQgetvalue(res, 0, 5);
10581         cache = PQgetvalue(res, 0, 6);
10582         cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
10583         called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
10584
10585         /*
10586          * The logic we use for restoring sequences is as follows:
10587          *
10588          * Add a CREATE SEQUENCE statement as part of a "schema" dump (use
10589          * last_val for start if called is false, else use min_val for start_val).
10590          * Also, if the sequence is owned by a column, add an ALTER SEQUENCE OWNED
10591          * BY command for it.
10592          *
10593          * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10594          */
10595         if (!dataOnly)
10596         {
10597                 resetPQExpBuffer(delqry);
10598
10599                 /*
10600                  * DROP must be fully qualified in case same name appears in
10601                  * pg_catalog
10602                  */
10603                 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
10604                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10605                 appendPQExpBuffer(delqry, "%s;\n",
10606                                                   fmtId(tbinfo->dobj.name));
10607
10608                 resetPQExpBuffer(query);
10609                 appendPQExpBuffer(query,
10610                                                   "CREATE SEQUENCE %s\n",
10611                                                   fmtId(tbinfo->dobj.name));
10612
10613                 if (g_fout->remoteVersion >= 80400)
10614                         appendPQExpBuffer(query, "    START WITH %s\n", startv);
10615                 else
10616                 {
10617                         /*
10618                          * Versions before 8.4 did not remember the true start value.  If
10619                          * is_called is false then the sequence has never been incremented
10620                          * so we can use last_val.  Otherwise punt and let it default.
10621                          */
10622                         if (!called)
10623                                 appendPQExpBuffer(query, "    START WITH %s\n", last);
10624                 }
10625
10626                 appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
10627
10628                 if (maxv)
10629                         appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
10630                 else
10631                         appendPQExpBuffer(query, "    NO MAXVALUE\n");
10632
10633                 if (minv)
10634                         appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
10635                 else
10636                         appendPQExpBuffer(query, "    NO MINVALUE\n");
10637
10638                 appendPQExpBuffer(query,
10639                                                   "    CACHE %s%s",
10640                                                   cache, (cycled ? "\n    CYCLE" : ""));
10641
10642                 appendPQExpBuffer(query, ";\n");
10643
10644                 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10645                                          tbinfo->dobj.name,
10646                                          tbinfo->dobj.namespace->dobj.name,
10647                                          NULL,
10648                                          tbinfo->rolname,
10649                                          false, "SEQUENCE", SECTION_PRE_DATA,
10650                                          query->data, delqry->data, NULL,
10651                                          tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
10652                                          NULL, NULL);
10653
10654                 /*
10655                  * If the sequence is owned by a table column, emit the ALTER for it
10656                  * as a separate TOC entry immediately following the sequence's own
10657                  * entry.  It's OK to do this rather than using full sorting logic,
10658                  * because the dependency that tells us it's owned will have forced
10659                  * the table to be created first.  We can't just include the ALTER in
10660                  * the TOC entry because it will fail if we haven't reassigned the
10661                  * sequence owner to match the table's owner.
10662                  *
10663                  * We need not schema-qualify the table reference because both
10664                  * sequence and table must be in the same schema.
10665                  */
10666                 if (OidIsValid(tbinfo->owning_tab))
10667                 {
10668                         TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
10669
10670                         if (owning_tab && owning_tab->dobj.dump)
10671                         {
10672                                 resetPQExpBuffer(query);
10673                                 appendPQExpBuffer(query, "ALTER SEQUENCE %s",
10674                                                                   fmtId(tbinfo->dobj.name));
10675                                 appendPQExpBuffer(query, " OWNED BY %s",
10676                                                                   fmtId(owning_tab->dobj.name));
10677                                 appendPQExpBuffer(query, ".%s;\n",
10678                                                 fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
10679
10680                                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10681                                                          tbinfo->dobj.name,
10682                                                          tbinfo->dobj.namespace->dobj.name,
10683                                                          NULL,
10684                                                          tbinfo->rolname,
10685                                                          false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
10686                                                          query->data, "", NULL,
10687                                                          &(tbinfo->dobj.dumpId), 1,
10688                                                          NULL, NULL);
10689                         }
10690                 }
10691
10692                 /* Dump Sequence Comments */
10693                 resetPQExpBuffer(query);
10694                 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
10695                 dumpComment(fout, query->data,
10696                                         tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10697                                         tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
10698         }
10699
10700         if (!schemaOnly)
10701         {
10702                 resetPQExpBuffer(query);
10703                 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
10704                 appendStringLiteralAH(query, fmtId(tbinfo->dobj.name), fout);
10705                 appendPQExpBuffer(query, ", %s, %s);\n",
10706                                                   last, (called ? "true" : "false"));
10707
10708                 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10709                                          tbinfo->dobj.name,
10710                                          tbinfo->dobj.namespace->dobj.name,
10711                                          NULL,
10712                                          tbinfo->rolname,
10713                                          false, "SEQUENCE SET", SECTION_PRE_DATA,
10714                                          query->data, "", NULL,
10715                                          &(tbinfo->dobj.dumpId), 1,
10716                                          NULL, NULL);
10717         }
10718
10719         PQclear(res);
10720
10721         destroyPQExpBuffer(query);
10722         destroyPQExpBuffer(delqry);
10723 }
10724
10725 static void
10726 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
10727 {
10728         TableInfo  *tbinfo = tginfo->tgtable;
10729         PQExpBuffer query;
10730         PQExpBuffer delqry;
10731         const char *p;
10732         int                     findx;
10733
10734         if (dataOnly)
10735                 return;
10736
10737         query = createPQExpBuffer();
10738         delqry = createPQExpBuffer();
10739
10740         /*
10741          * DROP must be fully qualified in case same name appears in pg_catalog
10742          */
10743         appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
10744                                           fmtId(tginfo->dobj.name));
10745         appendPQExpBuffer(delqry, "ON %s.",
10746                                           fmtId(tbinfo->dobj.namespace->dobj.name));
10747         appendPQExpBuffer(delqry, "%s;\n",
10748                                           fmtId(tbinfo->dobj.name));
10749
10750         if (tginfo->tgisconstraint)
10751         {
10752                 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
10753                 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
10754         }
10755         else
10756         {
10757                 appendPQExpBuffer(query, "CREATE TRIGGER ");
10758                 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10759         }
10760         appendPQExpBuffer(query, "\n    ");
10761
10762         /* Trigger type */
10763         findx = 0;
10764         if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10765                 appendPQExpBuffer(query, "BEFORE");
10766         else
10767                 appendPQExpBuffer(query, "AFTER");
10768         if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10769         {
10770                 appendPQExpBuffer(query, " INSERT");
10771                 findx++;
10772         }
10773         if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10774         {
10775                 if (findx > 0)
10776                         appendPQExpBuffer(query, " OR DELETE");
10777                 else
10778                         appendPQExpBuffer(query, " DELETE");
10779                 findx++;
10780         }
10781         if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10782         {
10783                 if (findx > 0)
10784                         appendPQExpBuffer(query, " OR UPDATE");
10785                 else
10786                         appendPQExpBuffer(query, " UPDATE");
10787         }
10788         if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10789         {
10790                 if (findx > 0)
10791                         appendPQExpBuffer(query, " OR TRUNCATE");
10792                 else
10793                         appendPQExpBuffer(query, " TRUNCATE");
10794         }
10795         appendPQExpBuffer(query, " ON %s\n",
10796                                           fmtId(tbinfo->dobj.name));
10797
10798         if (tginfo->tgisconstraint)
10799         {
10800                 if (OidIsValid(tginfo->tgconstrrelid))
10801                 {
10802                         /* If we are using regclass, name is already quoted */
10803                         if (g_fout->remoteVersion >= 70300)
10804                                 appendPQExpBuffer(query, "    FROM %s\n    ",
10805                                                                   tginfo->tgconstrrelname);
10806                         else
10807                                 appendPQExpBuffer(query, "    FROM %s\n    ",
10808                                                                   fmtId(tginfo->tgconstrrelname));
10809                 }
10810                 if (!tginfo->tgdeferrable)
10811                         appendPQExpBuffer(query, "NOT ");
10812                 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10813                 if (tginfo->tginitdeferred)
10814                         appendPQExpBuffer(query, "DEFERRED\n");
10815                 else
10816                         appendPQExpBuffer(query, "IMMEDIATE\n");
10817         }
10818
10819         if (TRIGGER_FOR_ROW(tginfo->tgtype))
10820                 appendPQExpBuffer(query, "    FOR EACH ROW\n    ");
10821         else
10822                 appendPQExpBuffer(query, "    FOR EACH STATEMENT\n    ");
10823
10824         /* In 7.3, result of regproc is already quoted */
10825         if (g_fout->remoteVersion >= 70300)
10826                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10827                                                   tginfo->tgfname);
10828         else
10829                 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10830                                                   fmtId(tginfo->tgfname));
10831
10832         p = tginfo->tgargs;
10833         for (findx = 0; findx < tginfo->tgnargs; findx++)
10834         {
10835                 const char *s = p;
10836
10837                 /* Set 'p' to end of arg string. marked by '\000' */
10838                 for (;;)
10839                 {
10840                         p = strchr(p, '\\');
10841                         if (p == NULL)
10842                         {
10843                                 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10844                                                   tginfo->tgargs,
10845                                                   tginfo->dobj.name,
10846                                                   tbinfo->dobj.name);
10847                                 exit_nicely();
10848                         }
10849                         p++;
10850                         if (*p == '\\')         /* is it '\\'? */
10851                         {
10852                                 p++;
10853                                 continue;
10854                         }
10855                         if (p[0] == '0' && p[1] == '0' && p[2] == '0')          /* is it '\000'? */
10856                                 break;
10857                 }
10858                 p--;
10859
10860                 appendPQExpBufferChar(query, '\'');
10861                 while (s < p)
10862                 {
10863                         if (*s == '\'')
10864                                 appendPQExpBufferChar(query, '\'');
10865
10866                         /*
10867                          * bytea unconditionally doubles backslashes, so we suppress the
10868                          * doubling for standard_conforming_strings.
10869                          */
10870                         if (fout->std_strings && *s == '\\' && s[1] == '\\')
10871                                 s++;
10872                         appendPQExpBufferChar(query, *s++);
10873                 }
10874                 appendPQExpBufferChar(query, '\'');
10875                 appendPQExpBuffer(query,
10876                                                   (findx < tginfo->tgnargs - 1) ? ", " : "");
10877                 p = p + 4;
10878         }
10879         appendPQExpBuffer(query, ");\n");
10880
10881         if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10882         {
10883                 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10884                                                   fmtId(tbinfo->dobj.name));
10885                 switch (tginfo->tgenabled)
10886                 {
10887                         case 'D':
10888                         case 'f':
10889                                 appendPQExpBuffer(query, "DISABLE");
10890                                 break;
10891                         case 'A':
10892                                 appendPQExpBuffer(query, "ENABLE ALWAYS");
10893                                 break;
10894                         case 'R':
10895                                 appendPQExpBuffer(query, "ENABLE REPLICA");
10896                                 break;
10897                         default:
10898                                 appendPQExpBuffer(query, "ENABLE");
10899                                 break;
10900                 }
10901                 appendPQExpBuffer(query, " TRIGGER %s;\n",
10902                                                   fmtId(tginfo->dobj.name));
10903         }
10904
10905         ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10906                                  tginfo->dobj.name,
10907                                  tbinfo->dobj.namespace->dobj.name,
10908                                  NULL,
10909                                  tbinfo->rolname, false,
10910                                  "TRIGGER", SECTION_POST_DATA,
10911                                  query->data, delqry->data, NULL,
10912                                  tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10913                                  NULL, NULL);
10914
10915         resetPQExpBuffer(query);
10916         appendPQExpBuffer(query, "TRIGGER %s ",
10917                                           fmtId(tginfo->dobj.name));
10918         appendPQExpBuffer(query, "ON %s",
10919                                           fmtId(tbinfo->dobj.name));
10920
10921         dumpComment(fout, query->data,
10922                                 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10923                                 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10924
10925         destroyPQExpBuffer(query);
10926         destroyPQExpBuffer(delqry);
10927 }
10928
10929 /*
10930  * dumpRule
10931  *              Dump a rule
10932  */
10933 static void
10934 dumpRule(Archive *fout, RuleInfo *rinfo)
10935 {
10936         TableInfo  *tbinfo = rinfo->ruletable;
10937         PQExpBuffer query;
10938         PQExpBuffer cmd;
10939         PQExpBuffer delcmd;
10940         PGresult   *res;
10941
10942         /* Skip if not to be dumped */
10943         if (!rinfo->dobj.dump || dataOnly)
10944                 return;
10945
10946         /*
10947          * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
10948          * we do not want to dump it as a separate object.
10949          */
10950         if (!rinfo->separate)
10951                 return;
10952
10953         /*
10954          * Make sure we are in proper schema.
10955          */
10956         selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10957
10958         query = createPQExpBuffer();
10959         cmd = createPQExpBuffer();
10960         delcmd = createPQExpBuffer();
10961
10962         if (g_fout->remoteVersion >= 70300)
10963         {
10964                 appendPQExpBuffer(query,
10965                                                   "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10966                                                   rinfo->dobj.catId.oid);
10967         }
10968         else
10969         {
10970                 /* Rule name was unique before 7.3 ... */
10971                 appendPQExpBuffer(query,
10972                                                   "SELECT pg_get_ruledef('%s') AS definition",
10973                                                   rinfo->dobj.name);
10974         }
10975
10976         res = PQexec(g_conn, query->data);
10977         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10978
10979         if (PQntuples(res) != 1)
10980         {
10981                 write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
10982                                   rinfo->dobj.name, tbinfo->dobj.name);
10983                 exit_nicely();
10984         }
10985
10986         printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
10987
10988         /*
10989          * Add the command to alter the rules replication firing semantics if it
10990          * differs from the default.
10991          */
10992         if (rinfo->ev_enabled != 'O')
10993         {
10994                 appendPQExpBuffer(cmd, "ALTER TABLE %s.",
10995                                                   fmtId(tbinfo->dobj.namespace->dobj.name));
10996                 appendPQExpBuffer(cmd, "%s ",
10997                                                   fmtId(tbinfo->dobj.name));
10998                 switch (rinfo->ev_enabled)
10999                 {
11000                         case 'A':
11001                                 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
11002                                                                   fmtId(rinfo->dobj.name));
11003                                 break;
11004                         case 'R':
11005                                 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
11006                                                                   fmtId(rinfo->dobj.name));
11007                                 break;
11008                         case 'D':
11009                                 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
11010                                                                   fmtId(rinfo->dobj.name));
11011                                 break;
11012                 }
11013         }
11014
11015         /*
11016          * DROP must be fully qualified in case same name appears in pg_catalog
11017          */
11018         appendPQExpBuffer(delcmd, "DROP RULE %s ",
11019                                           fmtId(rinfo->dobj.name));
11020         appendPQExpBuffer(delcmd, "ON %s.",
11021                                           fmtId(tbinfo->dobj.namespace->dobj.name));
11022         appendPQExpBuffer(delcmd, "%s;\n",
11023                                           fmtId(tbinfo->dobj.name));
11024
11025         ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
11026                                  rinfo->dobj.name,
11027                                  tbinfo->dobj.namespace->dobj.name,
11028                                  NULL,
11029                                  tbinfo->rolname, false,
11030                                  "RULE", SECTION_POST_DATA,
11031                                  cmd->data, delcmd->data, NULL,
11032                                  rinfo->dobj.dependencies, rinfo->dobj.nDeps,
11033                                  NULL, NULL);
11034
11035         /* Dump rule comments */
11036         resetPQExpBuffer(query);
11037         appendPQExpBuffer(query, "RULE %s",
11038                                           fmtId(rinfo->dobj.name));
11039         appendPQExpBuffer(query, " ON %s",
11040                                           fmtId(tbinfo->dobj.name));
11041         dumpComment(fout, query->data,
11042                                 tbinfo->dobj.namespace->dobj.name,
11043                                 tbinfo->rolname,
11044                                 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11045
11046         PQclear(res);
11047
11048         destroyPQExpBuffer(query);
11049         destroyPQExpBuffer(cmd);
11050         destroyPQExpBuffer(delcmd);
11051 }
11052
11053 /*
11054  * getDependencies --- obtain available dependency data
11055  */
11056 static void
11057 getDependencies(void)
11058 {
11059         PQExpBuffer query;
11060         PGresult   *res;
11061         int                     ntups,
11062                                 i;
11063         int                     i_classid,
11064                                 i_objid,
11065                                 i_refclassid,
11066                                 i_refobjid,
11067                                 i_deptype;
11068         DumpableObject *dobj,
11069                            *refdobj;
11070
11071         /* No dependency info available before 7.3 */
11072         if (g_fout->remoteVersion < 70300)
11073                 return;
11074
11075         if (g_verbose)
11076                 write_msg(NULL, "reading dependency data\n");
11077
11078         /* Make sure we are in proper schema */
11079         selectSourceSchema("pg_catalog");
11080
11081         query = createPQExpBuffer();
11082
11083         appendPQExpBuffer(query, "SELECT "
11084                                           "classid, objid, refclassid, refobjid, deptype "
11085                                           "FROM pg_depend "
11086                                           "WHERE deptype != 'p' "
11087                                           "ORDER BY 1,2");
11088
11089         res = PQexec(g_conn, query->data);
11090         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11091
11092         ntups = PQntuples(res);
11093
11094         i_classid = PQfnumber(res, "classid");
11095         i_objid = PQfnumber(res, "objid");
11096         i_refclassid = PQfnumber(res, "refclassid");
11097         i_refobjid = PQfnumber(res, "refobjid");
11098         i_deptype = PQfnumber(res, "deptype");
11099
11100         /*
11101          * Since we ordered the SELECT by referencing ID, we can expect that
11102          * multiple entries for the same object will appear together; this saves
11103          * on searches.
11104          */
11105         dobj = NULL;
11106
11107         for (i = 0; i < ntups; i++)
11108         {
11109                 CatalogId       objId;
11110                 CatalogId       refobjId;
11111                 char            deptype;
11112
11113                 objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
11114                 objId.oid = atooid(PQgetvalue(res, i, i_objid));
11115                 refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
11116                 refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
11117                 deptype = *(PQgetvalue(res, i, i_deptype));
11118
11119                 if (dobj == NULL ||
11120                         dobj->catId.tableoid != objId.tableoid ||
11121                         dobj->catId.oid != objId.oid)
11122                         dobj = findObjectByCatalogId(objId);
11123
11124                 /*
11125                  * Failure to find objects mentioned in pg_depend is not unexpected,
11126                  * since for example we don't collect info about TOAST tables.
11127                  */
11128                 if (dobj == NULL)
11129                 {
11130 #ifdef NOT_USED
11131                         fprintf(stderr, "no referencing object %u %u\n",
11132                                         objId.tableoid, objId.oid);
11133 #endif
11134                         continue;
11135                 }
11136
11137                 refdobj = findObjectByCatalogId(refobjId);
11138
11139                 if (refdobj == NULL)
11140                 {
11141 #ifdef NOT_USED
11142                         fprintf(stderr, "no referenced object %u %u\n",
11143                                         refobjId.tableoid, refobjId.oid);
11144 #endif
11145                         continue;
11146                 }
11147
11148                 /*
11149                  * Ordinarily, table rowtypes have implicit dependencies on their
11150                  * tables.      However, for a composite type the implicit dependency goes
11151                  * the other way in pg_depend; which is the right thing for DROP but
11152                  * it doesn't produce the dependency ordering we need. So in that one
11153                  * case, we reverse the direction of the dependency.
11154                  */
11155                 if (deptype == 'i' &&
11156                         dobj->objType == DO_TABLE &&
11157                         refdobj->objType == DO_TYPE)
11158                         addObjectDependency(refdobj, dobj->dumpId);
11159                 else
11160                         /* normal case */
11161                         addObjectDependency(dobj, refdobj->dumpId);
11162         }
11163
11164         PQclear(res);
11165
11166         destroyPQExpBuffer(query);
11167 }
11168
11169
11170 /*
11171  * selectSourceSchema - make the specified schema the active search path
11172  * in the source database.
11173  *
11174  * NB: pg_catalog is explicitly searched after the specified schema;
11175  * so user names are only qualified if they are cross-schema references,
11176  * and system names are only qualified if they conflict with a user name
11177  * in the current schema.
11178  *
11179  * Whenever the selected schema is not pg_catalog, be careful to qualify
11180  * references to system catalogs and types in our emitted commands!
11181  */
11182 static void
11183 selectSourceSchema(const char *schemaName)
11184 {
11185         static char *curSchemaName = NULL;
11186         PQExpBuffer query;
11187
11188         /* Not relevant if fetching from pre-7.3 DB */
11189         if (g_fout->remoteVersion < 70300)
11190                 return;
11191         /* Ignore null schema names */
11192         if (schemaName == NULL || *schemaName == '\0')
11193                 return;
11194         /* Optimize away repeated selection of same schema */
11195         if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
11196                 return;
11197
11198         query = createPQExpBuffer();
11199         appendPQExpBuffer(query, "SET search_path = %s",
11200                                           fmtId(schemaName));
11201         if (strcmp(schemaName, "pg_catalog") != 0)
11202                 appendPQExpBuffer(query, ", pg_catalog");
11203
11204         do_sql_command(g_conn, query->data);
11205
11206         destroyPQExpBuffer(query);
11207         if (curSchemaName)
11208                 free(curSchemaName);
11209         curSchemaName = strdup(schemaName);
11210 }
11211
11212 /*
11213  * getFormattedTypeName - retrieve a nicely-formatted type name for the
11214  * given type name.
11215  *
11216  * NB: in 7.3 and up the result may depend on the currently-selected
11217  * schema; this is why we don't try to cache the names.
11218  */
11219 static char *
11220 getFormattedTypeName(Oid oid, OidOptions opts)
11221 {
11222         char       *result;
11223         PQExpBuffer query;
11224         PGresult   *res;
11225         int                     ntups;
11226
11227         if (oid == 0)
11228         {
11229                 if ((opts & zeroAsOpaque) != 0)
11230                         return strdup(g_opaque_type);
11231                 else if ((opts & zeroAsAny) != 0)
11232                         return strdup("'any'");
11233                 else if ((opts & zeroAsStar) != 0)
11234                         return strdup("*");
11235                 else if ((opts & zeroAsNone) != 0)
11236                         return strdup("NONE");
11237         }
11238
11239         query = createPQExpBuffer();
11240         if (g_fout->remoteVersion >= 70300)
11241         {
11242                 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11243                                                   oid);
11244         }
11245         else if (g_fout->remoteVersion >= 70100)
11246         {
11247                 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11248                                                   oid);
11249         }
11250         else
11251         {
11252                 appendPQExpBuffer(query, "SELECT typname "
11253                                                   "FROM pg_type "
11254                                                   "WHERE oid = '%u'::oid",
11255                                                   oid);
11256         }
11257
11258         res = PQexec(g_conn, query->data);
11259         check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11260
11261         /* Expecting a single result only */
11262         ntups = PQntuples(res);
11263         if (ntups != 1)
11264         {
11265                 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11266                                                                  "query returned %d rows instead of one: %s\n",
11267                                                                  ntups),
11268                                   ntups, query->data);
11269                 exit_nicely();
11270         }
11271
11272         if (g_fout->remoteVersion >= 70100)
11273         {
11274                 /* already quoted */
11275                 result = strdup(PQgetvalue(res, 0, 0));
11276         }
11277         else
11278         {
11279                 /* may need to quote it */
11280                 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11281         }
11282
11283         PQclear(res);
11284         destroyPQExpBuffer(query);
11285
11286         return result;
11287 }
11288
11289 /*
11290  * myFormatType --- local implementation of format_type for use with 7.0.
11291  */
11292 static char *
11293 myFormatType(const char *typname, int32 typmod)
11294 {
11295         char       *result;
11296         bool            isarray = false;
11297         PQExpBuffer buf = createPQExpBuffer();
11298
11299         /* Handle array types */
11300         if (typname[0] == '_')
11301         {
11302                 isarray = true;
11303                 typname++;
11304         }
11305
11306         /* Show lengths on bpchar and varchar */
11307         if (!strcmp(typname, "bpchar"))
11308         {
11309                 int                     len = (typmod - VARHDRSZ);
11310
11311                 appendPQExpBuffer(buf, "character");
11312                 if (len > 1)
11313                         appendPQExpBuffer(buf, "(%d)",
11314                                                           typmod - VARHDRSZ);
11315         }
11316         else if (!strcmp(typname, "varchar"))
11317         {
11318                 appendPQExpBuffer(buf, "character varying");
11319                 if (typmod != -1)
11320                         appendPQExpBuffer(buf, "(%d)",
11321                                                           typmod - VARHDRSZ);
11322         }
11323         else if (!strcmp(typname, "numeric"))
11324         {
11325                 appendPQExpBuffer(buf, "numeric");
11326                 if (typmod != -1)
11327                 {
11328                         int32           tmp_typmod;
11329                         int                     precision;
11330                         int                     scale;
11331
11332                         tmp_typmod = typmod - VARHDRSZ;
11333                         precision = (tmp_typmod >> 16) & 0xffff;
11334                         scale = tmp_typmod & 0xffff;
11335                         appendPQExpBuffer(buf, "(%d,%d)",
11336                                                           precision, scale);
11337                 }
11338         }
11339
11340         /*
11341          * char is an internal single-byte data type; Let's make sure we force it
11342          * through with quotes. - thomas 1998-12-13
11343          */
11344         else if (strcmp(typname, "char") == 0)
11345                 appendPQExpBuffer(buf, "\"char\"");
11346         else
11347                 appendPQExpBuffer(buf, "%s", fmtId(typname));
11348
11349         /* Append array qualifier for array types */
11350         if (isarray)
11351                 appendPQExpBuffer(buf, "[]");
11352
11353         result = strdup(buf->data);
11354         destroyPQExpBuffer(buf);
11355
11356         return result;
11357 }
11358
11359 /*
11360  * fmtQualifiedId - convert a qualified name to the proper format for
11361  * the source database.
11362  *
11363  * Like fmtId, use the result before calling again.
11364  */
11365 static const char *
11366 fmtQualifiedId(const char *schema, const char *id)
11367 {
11368         static PQExpBuffer id_return = NULL;
11369
11370         if (id_return)                          /* first time through? */
11371                 resetPQExpBuffer(id_return);
11372         else
11373                 id_return = createPQExpBuffer();
11374
11375         /* Suppress schema name if fetching from pre-7.3 DB */
11376         if (g_fout->remoteVersion >= 70300 && schema && *schema)
11377         {
11378                 appendPQExpBuffer(id_return, "%s.",
11379                                                   fmtId(schema));
11380         }
11381         appendPQExpBuffer(id_return, "%s",
11382                                           fmtId(id));
11383
11384         return id_return->data;
11385 }
11386
11387 /*
11388  * Return a column list clause for the given relation.
11389  *
11390  * Special case: if there are no undropped columns in the relation, return
11391  * "", not an invalid "()" column list.
11392  */
11393 static const char *
11394 fmtCopyColumnList(const TableInfo *ti)
11395 {
11396         static PQExpBuffer q = NULL;
11397         int                     numatts = ti->numatts;
11398         char      **attnames = ti->attnames;
11399         bool       *attisdropped = ti->attisdropped;
11400         bool            needComma;
11401         int                     i;
11402
11403         if (q)                                          /* first time through? */
11404                 resetPQExpBuffer(q);
11405         else
11406                 q = createPQExpBuffer();
11407
11408         appendPQExpBuffer(q, "(");
11409         needComma = false;
11410         for (i = 0; i < numatts; i++)
11411         {
11412                 if (attisdropped[i])
11413                         continue;
11414                 if (needComma)
11415                         appendPQExpBuffer(q, ", ");
11416                 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
11417                 needComma = true;
11418         }
11419
11420         if (!needComma)
11421                 return "";                              /* no undropped columns */
11422
11423         appendPQExpBuffer(q, ")");
11424         return q->data;
11425 }
11426
11427 /*
11428  * Convenience subroutine to execute a SQL command and check for
11429  * COMMAND_OK status.
11430  */
11431 static void
11432 do_sql_command(PGconn *conn, const char *query)
11433 {
11434         PGresult   *res;
11435
11436         res = PQexec(conn, query);
11437         check_sql_result(res, conn, query, PGRES_COMMAND_OK);
11438         PQclear(res);
11439 }
11440
11441 /*
11442  * Convenience subroutine to verify a SQL command succeeded,
11443  * and exit with a useful error message if not.
11444  */
11445 static void
11446 check_sql_result(PGresult *res, PGconn *conn, const char *query,
11447                                  ExecStatusType expected)
11448 {
11449         const char *err;
11450
11451         if (res && PQresultStatus(res) == expected)
11452                 return;                                 /* A-OK */
11453
11454         write_msg(NULL, "SQL command failed\n");
11455         if (res)
11456                 err = PQresultErrorMessage(res);
11457         else
11458                 err = PQerrorMessage(conn);
11459         write_msg(NULL, "Error message from server: %s", err);
11460         write_msg(NULL, "The command was: %s\n", query);
11461         exit_nicely();
11462 }