1 /*-------------------------------------------------------------------------
4 * pg_dump is a utility for dumping out a postgres database
7 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
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
15 * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.536 2009/05/21 01:08:43 petere Exp $
17 *-------------------------------------------------------------------------
20 #include "postgres_fe.h"
31 #include "getopt_long.h"
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"
42 #include "pg_backup_archiver.h"
43 #include "dumputils.h"
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 #) */
60 bool g_verbose; /* User wants verbose narration of our
62 Archive *g_fout; /* the script file */
63 PGconn *g_conn; /* the database connection */
65 /* various user-settable parameters */
69 const char *lockWaitTimeout;
71 /* subquery used to convert user ID (eg, datdba) to user name */
72 static const char *username_subquery;
74 /* obsolete as of 7.3: */
75 static Oid g_last_builtin_oid; /* value of the last builtin oid */
78 * Object inclusion/exclusion lists
80 * The string lists record the patterns given by command-line switches,
81 * which we then convert to lists of OIDs of matching objects.
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};
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};
93 /* default, if no "inclusion" switches appear, is to dump everything */
94 static bool include_everything = true;
96 char g_opaque_type[10]; /* name for the opaque type */
98 /* placeholders for the delimiters for comments */
99 char g_comment_start[10];
100 char g_comment_end[10];
102 static const CatalogId nilCatalogId = {0, 0};
104 /* these are to avoid passing around info for findNamespace() */
105 static NamespaceInfo *g_namespaces;
106 static int g_numNamespaces;
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;
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);
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,
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,
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);
202 main(int argc, char **argv)
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;
216 DumpableObject **dobjs;
219 enum trivalue prompt_password = TRI_DEFAULT;
220 int compressLevel = -1;
223 int outputCreate = 0;
224 bool outputBlobs = false;
225 int outputNoOwner = 0;
226 char *outputSuperuser = NULL;
227 char *use_role = NULL;
230 RestoreOptions *ropt;
232 static int disable_triggers = 0;
233 static int outputNoTablespaces = 0;
234 static int use_setsessauth = 0;
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'},
267 * the following options don't have an equivalent short option letter
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},
283 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
287 strcpy(g_comment_start, "-- ");
288 g_comment_end[0] = '\0';
289 strcpy(g_opaque_type, "opaque");
291 dataOnly = schemaOnly = false;
292 lockWaitTimeout = NULL;
294 progname = get_progname(argv[0]);
296 /* Set default options based on progname */
297 if (strcmp(progname, "pg_backup") == 0)
302 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
307 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
309 puts("pg_dump (PostgreSQL) " PG_VERSION);
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)
319 case 'a': /* Dump data only */
323 case 'b': /* Dump blobs */
327 case 'c': /* clean (i.e., drop) schema prior to create */
331 case 'C': /* Create DB */
335 case 'E': /* Dump encoding */
336 dumpencoding = optarg;
347 case 'h': /* server host */
352 /* ignored, deprecated option */
355 case 'n': /* include schema(s) */
356 simple_string_list_append(&schema_include_patterns, optarg);
357 include_everything = false;
360 case 'N': /* exclude schema(s) */
361 simple_string_list_append(&schema_exclude_patterns, optarg);
364 case 'o': /* Dump oids */
368 case 'O': /* Don't reconnect to match owner */
372 case 'p': /* server port */
377 /* no-op, still accepted for backwards compatibility */
380 case 's': /* dump schema only */
384 case 'S': /* Username for superuser in plain text output */
385 outputSuperuser = strdup(optarg);
388 case 't': /* include table(s) */
389 simple_string_list_append(&table_include_patterns, optarg);
390 include_everything = false;
393 case 'T': /* exclude table(s) */
394 simple_string_list_append(&table_exclude_patterns, optarg);
401 case 'v': /* verbose */
406 prompt_password = TRI_NO;
410 prompt_password = TRI_YES;
413 case 'x': /* skip ACL dump */
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)
430 _("%s: invalid -X option -- %s\n"),
432 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
437 case 'Z': /* Compression Level */
438 compressLevel = atoi(optarg);
442 /* This covers the long options equivalent to -X xxx. */
445 case 2: /* lock-wait-timeout */
446 lockWaitTimeout = optarg;
449 case 3: /* SET ROLE */
454 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
459 if (optind < (argc - 1))
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"),
468 /* Get database name from command line */
470 dbname = argv[optind];
472 /* --column-inserts implies --inserts */
476 if (dataOnly && schemaOnly)
478 write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
482 if (dataOnly && outputClean)
484 write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
488 if (dump_inserts && oids)
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");
495 /* open the output file */
496 if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
498 /* This is used by pg_dumpall, and is not documented */
500 g_fout = CreateArchive(filename, archNull, 0, archModeAppend);
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)
507 * Dump files into the current directory; for demonstration only, not
510 g_fout = CreateArchive(filename, archFiles, compressLevel, archModeWrite);
512 else if (pg_strcasecmp(format, "p") == 0 || pg_strcasecmp(format, "plain") == 0)
515 g_fout = CreateArchive(filename, archNull, 0, archModeWrite);
517 else if (pg_strcasecmp(format, "t") == 0 || pg_strcasecmp(format, "tar") == 0)
518 g_fout = CreateArchive(filename, archTar, compressLevel, archModeWrite);
521 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
527 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
531 /* Let the archiver know how noisy to be */
532 g_fout->verbose = g_verbose;
534 my_version = parse_version(PG_VERSION);
537 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
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.)
545 g_fout->minRemoteVersion = 70000;
546 g_fout->maxRemoteVersion = (my_version / 100) * 100 + 99;
549 * Open the database using the Archiver, so it knows about it. Errors mean
552 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
553 username, prompt_password);
555 /* Set the client encoding if requested */
558 if (PQsetClientEncoding(g_conn, dumpencoding) < 0)
560 write_msg(NULL, "invalid client encoding \"%s\" specified\n",
567 * Get the active encoding and the standard_conforming_strings setting, so
568 * we know how to escape strings.
570 g_fout->encoding = PQclientEncoding(g_conn);
572 std_strings = PQparameterStatus(g_conn, "standard_conforming_strings");
573 g_fout->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
575 /* Set the role if requested */
576 if (use_role && g_fout->remoteVersion >= 80100)
578 PQExpBuffer query = createPQExpBuffer();
580 appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
581 do_sql_command(g_conn, query->data);
582 destroyPQExpBuffer(query);
585 /* Set the datestyle to ISO to ensure the dump's portability */
586 do_sql_command(g_conn, "SET DATESTYLE = ISO");
588 /* Likewise, avoid using sql_standard intervalstyle */
589 if (g_fout->remoteVersion >= 80400)
590 do_sql_command(g_conn, "SET INTERVALSTYLE = POSTGRES");
593 * If supported, set extra_float_digits so that we can dump float data
594 * exactly (given correctly implemented float I/O code, anyway)
596 if (g_fout->remoteVersion >= 70400)
597 do_sql_command(g_conn, "SET extra_float_digits TO 2");
600 * If synchronized scanning is supported, disable it, to prevent
601 * unpredictable changes in row ordering across a dump and reload.
603 if (g_fout->remoteVersion >= 80300)
604 do_sql_command(g_conn, "SET synchronize_seqscans TO off");
607 * Disable timeouts if supported.
609 if (g_fout->remoteVersion >= 70300)
610 do_sql_command(g_conn, "SET statement_timeout = 0");
613 * Start serializable transaction to dump consistent data.
615 do_sql_command(g_conn, "BEGIN");
617 do_sql_command(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
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 =";
625 username_subquery = "SELECT usename FROM pg_user WHERE usesysid =";
627 /* Find the last built-in OID, if needed */
628 if (g_fout->remoteVersion < 70300)
630 if (g_fout->remoteVersion >= 70100)
631 g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
633 g_last_builtin_oid = findLastBuiltinOid_V70();
635 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
638 /* Expand schema selection patterns into OID lists */
639 if (schema_include_patterns.head != NULL)
641 expand_schema_name_patterns(&schema_include_patterns,
642 &schema_include_oids);
643 if (schema_include_oids.head == NULL)
645 write_msg(NULL, "No matching schemas were found\n");
649 expand_schema_name_patterns(&schema_exclude_patterns,
650 &schema_exclude_oids);
651 /* non-matching exclusion patterns aren't an error */
653 /* Expand table selection patterns into OID lists */
654 if (table_include_patterns.head != NULL)
656 expand_table_name_patterns(&table_include_patterns,
657 &table_include_oids);
658 if (table_include_oids.head == NULL)
660 write_msg(NULL, "No matching tables were found\n");
664 expand_table_name_patterns(&table_exclude_patterns,
665 &table_exclude_oids);
666 /* non-matching exclusion patterns aren't an error */
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.
672 if (include_everything && !schemaOnly)
676 * Now scan the database and create DumpableObject structs for all the
677 * objects we intend to dump.
679 tblinfo = getSchemaData(&numTables);
681 if (g_fout->remoteVersion < 80400)
682 guessConstraintInheritance(tblinfo, numTables);
686 getTableData(tblinfo, numTables, oids);
688 getTableDataFKConstraints();
691 if (outputBlobs && hasBlobs(g_fout))
693 /* Add placeholders to allow correct sorting of blobs */
694 DumpableObject *blobobj;
695 DumpableObject *blobcobj;
697 blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
698 blobobj->objType = DO_BLOBS;
699 blobobj->catId = nilCatalogId;
700 AssignDumpId(blobobj);
701 blobobj->name = strdup("BLOBS");
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);
712 * Collect dependency data to assist in ordering the objects.
717 * Sort the objects into a safe dump order (no forward references).
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.
725 getDumpableObjects(&dobjs, &numObjs);
727 if (g_fout->remoteVersion >= 70300)
728 sortDumpableObjectsByTypeName(dobjs, numObjs);
730 sortDumpableObjectsByTypeOid(dobjs, numObjs);
732 sortDumpableObjects(dobjs, numObjs);
735 * Create archive TOC entries for all the objects to be dumped, in a safe
739 /* First the special ENCODING and STDSTRINGS entries. */
740 dumpEncoding(g_fout);
741 dumpStdStrings(g_fout);
743 /* The database item is always next, unless we don't want it at all */
744 if (include_everything && !dataOnly)
745 dumpDatabase(g_fout);
747 /* Now the rearrangeable objects. */
748 for (i = 0; i < numObjs; i++)
749 dumpDumpableObject(g_fout, dobjs[i]);
752 * And finally we can do the actual output.
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;
768 if (compressLevel == -1)
769 ropt->compression = 0;
771 ropt->compression = compressLevel;
773 ropt->suppressDumpWarnings = true; /* We've already shown them */
775 RestoreArchive(g_fout, ropt);
778 CloseArchive(g_fout);
787 help(const char *progname)
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);
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"));
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"));
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"));
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"));
846 write_msg(NULL, "*** aborted because of error\n");
851 * Find the OIDs of all schemas matching the given list of patterns,
852 * and append them to the given OID list.
855 expand_schema_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
859 SimpleStringListCell *cell;
862 if (patterns->head == NULL)
863 return; /* nothing to do */
865 if (g_fout->remoteVersion < 70300)
867 write_msg(NULL, "server version must be at least 7.3 to use schema selection switches\n");
871 query = createPQExpBuffer();
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.
878 for (cell = patterns->head; cell; cell = cell->next)
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,
889 res = PQexec(g_conn, query->data);
890 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
892 for (i = 0; i < PQntuples(res); i++)
894 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
898 destroyPQExpBuffer(query);
902 * Find the OIDs of all tables matching the given list of patterns,
903 * and append them to the given OID list.
906 expand_table_name_patterns(SimpleStringList *patterns, SimpleOidList *oids)
910 SimpleStringListCell *cell;
913 if (patterns->head == NULL)
914 return; /* nothing to do */
916 query = createPQExpBuffer();
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.
923 for (cell = patterns->head; cell; cell = cell->next)
925 if (cell != patterns->head)
926 appendPQExpBuffer(query, "UNION ALL\n");
927 appendPQExpBuffer(query,
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)");
938 res = PQexec(g_conn, query->data);
939 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
941 for (i = 0; i < PQntuples(res); i++)
943 simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
947 destroyPQExpBuffer(query);
951 * selectDumpableNamespace: policy-setting subroutine
952 * Mark a namespace as to be dumped or not
955 selectDumpableNamespace(NamespaceInfo *nsinfo)
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.
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;
971 nsinfo->dobj.dump = true;
974 * In any case, a namespace can be excluded by an exclusion switch
976 if (nsinfo->dobj.dump &&
977 simple_oid_list_member(&schema_exclude_oids,
978 nsinfo->dobj.catId.oid))
979 nsinfo->dobj.dump = false;
983 * selectDumpableTable: policy-setting subroutine
984 * Mark a table as to be dumped or not
987 selectDumpableTable(TableInfo *tbinfo)
990 * If specific tables are being dumped, dump just those tables; else, dump
991 * according to the parent namespace's dump flag.
993 if (table_include_oids.head != NULL)
994 tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
995 tbinfo->dobj.catId.oid);
997 tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump;
1000 * In any case, a table can be excluded by an exclusion switch
1002 if (tbinfo->dobj.dump &&
1003 simple_oid_list_member(&table_exclude_oids,
1004 tbinfo->dobj.catId.oid))
1005 tbinfo->dobj.dump = false;
1009 * selectDumpableType: policy-setting subroutine
1010 * Mark a type as to be dumped or not
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.
1019 selectDumpableType(TypeInfo *tinfo)
1021 /* skip complex types, except for standalone composite types */
1022 if (OidIsValid(tinfo->typrelid) &&
1023 tinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1025 tinfo->dobj.dump = false;
1026 tinfo->dobj.objType = DO_DUMMY_TYPE;
1029 /* skip auto-generated array types */
1030 else if (tinfo->isArray)
1032 tinfo->dobj.dump = false;
1033 tinfo->dobj.objType = DO_DUMMY_TYPE;
1036 /* dump only types in dumpable namespaces */
1037 else if (!tinfo->dobj.namespace->dobj.dump)
1038 tinfo->dobj.dump = false;
1040 /* skip undefined placeholder types */
1041 else if (!tinfo->isDefined)
1042 tinfo->dobj.dump = false;
1045 tinfo->dobj.dump = true;
1049 * selectDumpableObject: policy-setting subroutine
1050 * Mark a generic dumpable object as to be dumped or not
1052 * Use this only for object types without a special-case routine above.
1055 selectDumpableObject(DumpableObject *dobj)
1058 * Default policy is to dump if parent namespace is dumpable, or always
1059 * for non-namespace-associated items.
1061 if (dobj->namespace)
1062 dobj->dump = dobj->namespace->dobj.dump;
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
1074 dumpTableData_copy(Archive *fout, void *dcontext)
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();
1085 const char *column_list;
1088 write_msg(NULL, "dumping contents of table %s\n", classname);
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.
1096 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
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.)
1104 if (g_fout->remoteVersion >= 70300)
1105 column_list = fmtCopyColumnList(tbinfo);
1107 column_list = ""; /* can't select columns in COPY */
1109 if (oids && hasoids)
1111 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1112 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1118 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1119 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1123 res = PQexec(g_conn, q->data);
1124 check_sql_result(res, g_conn, q->data, PGRES_COPY_OUT);
1129 ret = PQgetCopyData(g_conn, ©buf, 0);
1132 break; /* done or error */
1136 WriteData(fout, copybuf, ret);
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.
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:
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
1162 * where the throttle value was the number of ms to sleep per ms of
1163 * work. The calculation was done in each loop.
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.
1171 * Further discussion ensued, and the proposal was dropped.
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.
1179 * select(0, NULL, NULL, NULL, &tvi);
1181 * This will return after the interval specified in the structure tvi.
1182 * Finally, call gettimeofday again to save the 'last sleep time'.
1186 archprintf(fout, "\\.\n\n\n");
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);
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);
1202 destroyPQExpBuffer(q);
1207 dumpTableData_insert(Archive *fout, void *dcontext)
1209 TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1210 TableInfo *tbinfo = tdinfo->tdtable;
1211 const char *classname = tbinfo->dobj.name;
1212 PQExpBuffer q = createPQExpBuffer();
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.
1224 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
1226 if (fout->remoteVersion >= 70100)
1228 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1229 "SELECT * FROM ONLY %s",
1230 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1235 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1237 fmtQualifiedId(tbinfo->dobj.namespace->dobj.name,
1241 res = PQexec(g_conn, q->data);
1242 check_sql_result(res, g_conn, q->data, PGRES_COMMAND_OK);
1248 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
1249 check_sql_result(res, g_conn, "FETCH 100 FROM _pg_dump_cursor",
1251 nfields = PQnfields(res);
1252 for (tuple = 0; tuple < PQntuples(res); tuple++)
1254 archprintf(fout, "INSERT INTO %s ", fmtId(classname));
1257 /* corner case for zero-column table */
1258 archprintf(fout, "DEFAULT VALUES;\n");
1263 resetPQExpBuffer(q);
1264 appendPQExpBuffer(q, "(");
1265 for (field = 0; field < nfields; field++)
1268 appendPQExpBuffer(q, ", ");
1269 appendPQExpBufferStr(q, fmtId(PQfname(res, field)));
1271 appendPQExpBuffer(q, ") ");
1272 archputs(q->data, fout);
1274 archprintf(fout, "VALUES (");
1275 for (field = 0; field < nfields; field++)
1278 archprintf(fout, ", ");
1279 if (PQgetisnull(res, tuple, field))
1281 archprintf(fout, "NULL");
1285 /* XXX This code is partially duplicated in ruleutils.c */
1286 switch (PQftype(res, field))
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.
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.
1307 const char *s = PQgetvalue(res, tuple, field);
1309 if (strspn(s, "0123456789 +-eE.") == strlen(s))
1310 archprintf(fout, "%s", s);
1312 archprintf(fout, "'%s'", s);
1318 archprintf(fout, "B'%s'",
1319 PQgetvalue(res, tuple, field));
1323 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1324 archprintf(fout, "true");
1326 archprintf(fout, "false");
1330 /* All other types are printed as string literals. */
1331 resetPQExpBuffer(q);
1332 appendStringLiteralAH(q,
1333 PQgetvalue(res, tuple, field),
1335 archputs(q->data, fout);
1339 archprintf(fout, ");\n");
1341 } while (PQntuples(res) > 0);
1345 archprintf(fout, "\n\n");
1347 do_sql_command(g_conn, "CLOSE _pg_dump_cursor");
1349 destroyPQExpBuffer(q);
1356 * dump the contents of a single table
1358 * Actually, this just makes an ArchiveEntry for the table contents.
1361 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
1363 TableInfo *tbinfo = tdinfo->tdtable;
1364 PQExpBuffer copyBuf = createPQExpBuffer();
1365 DataDumperPtr dumpFn;
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;
1382 /* Restore using INSERT */
1383 dumpFn = dumpTableData_insert;
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,
1392 tdinfo->dobj.dependencies, tdinfo->dobj.nDeps,
1395 destroyPQExpBuffer(copyBuf);
1400 * set up dumpable objects representing the contents of tables
1403 getTableData(TableInfo *tblinfo, int numTables, bool oids)
1407 for (i = 0; i < numTables; i++)
1409 /* Skip VIEWs (no data to dump) */
1410 if (tblinfo[i].relkind == RELKIND_VIEW)
1412 /* Skip SEQUENCEs (handled elsewhere) */
1413 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1416 if (tblinfo[i].dobj.dump)
1418 TableDataInfo *tdinfo;
1420 tdinfo = (TableDataInfo *) malloc(sizeof(TableDataInfo));
1422 tdinfo->dobj.objType = DO_TABLE_DATA;
1425 * Note: use tableoid 0 so that this object won't be mistaken for
1426 * something that pg_depend entries apply to.
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);
1437 tblinfo[i].dataObj = tdinfo;
1443 * getTableDataFKConstraints -
1444 * add dump-order dependencies reflecting foreign key constraints
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.)
1455 getTableDataFKConstraints(void)
1457 DumpableObject **dobjs;
1461 /* Search through all the dumpable objects for FK constraints */
1462 getDumpableObjects(&dobjs, &numObjs);
1463 for (i = 0; i < numObjs; i++)
1465 if (dobjs[i]->objType == DO_FK_CONSTRAINT)
1467 ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
1470 /* Not interesting unless both tables are to be dumped */
1471 if (cinfo->contable == NULL ||
1472 cinfo->contable->dataObj == NULL)
1474 ftable = findTableByOid(cinfo->confrelid);
1475 if (ftable == NULL ||
1476 ftable->dataObj == NULL)
1479 * Okay, make referencing table's TABLE_DATA object depend on
1480 * the referenced table's TABLE_DATA object.
1482 addObjectDependency(&cinfo->contable->dataObj->dobj,
1483 ftable->dataObj->dobj.dumpId);
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.
1500 * In 8.4 and up we can rely on the conislocal field to decide which
1501 * constraints must be dumped; much safer.
1503 * This function assumes all conislocal flags were initialized to TRUE.
1504 * It clears the flag on anything that seems to be inherited.
1507 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
1513 for (i = 0; i < numTables; i++)
1515 TableInfo *tbinfo = &(tblinfo[i]);
1517 TableInfo **parents;
1520 /* Sequences and views never have parents */
1521 if (tbinfo->relkind == RELKIND_SEQUENCE ||
1522 tbinfo->relkind == RELKIND_VIEW)
1525 /* Don't bother computing anything for non-target tables, either */
1526 if (!tbinfo->dobj.dump)
1529 numParents = tbinfo->numParents;
1530 parents = tbinfo->parents;
1532 if (numParents == 0)
1533 continue; /* nothing to see here, move along */
1535 /* scan for inherited CHECK constraints */
1536 for (j = 0; j < tbinfo->ncheck; j++)
1538 ConstraintInfo *constr;
1540 constr = &(tbinfo->checkexprs[j]);
1542 for (k = 0; k < numParents; k++)
1546 parent = parents[k];
1547 for (l = 0; l < parent->ncheck; l++)
1549 ConstraintInfo *pconstr = &(parent->checkexprs[l]);
1551 if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
1553 constr->conislocal = false;
1557 if (!constr->conislocal)
1567 * dump the database definition
1570 dumpDatabase(Archive *AH)
1572 PQExpBuffer dbQry = createPQExpBuffer();
1573 PQExpBuffer delQry = createPQExpBuffer();
1574 PQExpBuffer creaQry = createPQExpBuffer();
1587 const char *datname,
1595 datname = PQdb(g_conn);
1598 write_msg(NULL, "saving database definition\n");
1600 /* Make sure we are in proper schema */
1601 selectSourceSchema("pg_catalog");
1603 /* Get the database owner and parameters from pg_database */
1604 if (g_fout->remoteVersion >= 80400)
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 "
1616 appendStringLiteralAH(dbQry, datname, AH);
1618 else if (g_fout->remoteVersion >= 80200)
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 "
1630 appendStringLiteralAH(dbQry, datname, AH);
1632 else if (g_fout->remoteVersion >= 80000)
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 "
1642 appendStringLiteralAH(dbQry, datname, AH);
1644 else if (g_fout->remoteVersion >= 70100)
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 "
1655 appendStringLiteralAH(dbQry, datname, AH);
1659 appendPQExpBuffer(dbQry, "SELECT "
1660 "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
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 "
1670 appendStringLiteralAH(dbQry, datname, AH);
1673 res = PQexec(g_conn, dbQry->data);
1674 check_sql_result(res, g_conn, dbQry->data, PGRES_TUPLES_OK);
1676 ntups = PQntuples(res);
1680 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1687 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
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");
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);
1710 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1712 if (strlen(encoding) > 0)
1714 appendPQExpBuffer(creaQry, " ENCODING = ");
1715 appendStringLiteralAH(creaQry, encoding, AH);
1717 if (strlen(collate) > 0)
1719 appendPQExpBuffer(creaQry, " LC_COLLATE = ");
1720 appendStringLiteralAH(creaQry, collate, AH);
1722 if (strlen(ctype) > 0)
1724 appendPQExpBuffer(creaQry, " LC_CTYPE = ");
1725 appendStringLiteralAH(creaQry, ctype, AH);
1727 if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0)
1728 appendPQExpBuffer(creaQry, " TABLESPACE = %s",
1730 appendPQExpBuffer(creaQry, ";\n");
1734 appendPQExpBuffer(creaQry, "\n-- For binary upgrade, set datfrozenxid.\n");
1735 appendPQExpBuffer(creaQry, "UPDATE pg_database\n"
1736 "SET datfrozenxid = '%u'\n"
1739 appendStringLiteralAH(creaQry, datname, AH);
1740 appendPQExpBuffer(creaQry, ";\n");
1743 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1746 dbDumpId = createDumpId();
1749 dbCatId, /* catalog ID */
1750 dbDumpId, /* dump ID */
1752 NULL, /* Namespace */
1753 NULL, /* Tablespace */
1755 false, /* with oids */
1756 "DATABASE", /* Desc */
1757 SECTION_PRE_DATA, /* Section */
1758 creaQry->data, /* Create */
1759 delQry->data, /* Del */
1764 NULL); /* Dumper Arg */
1766 /* Dump DB comment if any */
1767 if (g_fout->remoteVersion >= 80200)
1770 * 8.2 keeps comments on shared objects in a shared table, so we
1771 * cannot use the dumpComment used for other database objects.
1773 char *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
1775 if (comment && strlen(comment))
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");
1783 ArchiveEntry(AH, dbCatId, createDumpId(), datname, NULL, NULL,
1784 dba, false, "COMMENT", SECTION_NONE,
1785 dbQry->data, "", NULL,
1786 &dbDumpId, 1, NULL, NULL);
1791 resetPQExpBuffer(dbQry);
1792 appendPQExpBuffer(dbQry, "DATABASE %s", fmtId(datname));
1793 dumpComment(AH, dbQry->data, NULL, "",
1794 dbCatId, 0, dbDumpId);
1799 destroyPQExpBuffer(dbQry);
1800 destroyPQExpBuffer(delQry);
1801 destroyPQExpBuffer(creaQry);
1806 * dumpEncoding: put the correct encoding into the archive
1809 dumpEncoding(Archive *AH)
1811 const char *encname = pg_encoding_to_char(AH->encoding);
1812 PQExpBuffer qry = createPQExpBuffer();
1815 write_msg(NULL, "saving encoding = %s\n", encname);
1817 appendPQExpBuffer(qry, "SET client_encoding = ");
1818 appendStringLiteralAH(qry, encname, AH);
1819 appendPQExpBuffer(qry, ";\n");
1821 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1822 "ENCODING", NULL, NULL, "",
1823 false, "ENCODING", SECTION_PRE_DATA,
1824 qry->data, "", NULL,
1828 destroyPQExpBuffer(qry);
1833 * dumpStdStrings: put the correct escape string behavior into the archive
1836 dumpStdStrings(Archive *AH)
1838 const char *stdstrings = AH->std_strings ? "on" : "off";
1839 PQExpBuffer qry = createPQExpBuffer();
1842 write_msg(NULL, "saving standard_conforming_strings = %s\n",
1845 appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
1848 ArchiveEntry(AH, nilCatalogId, createDumpId(),
1849 "STDSTRINGS", NULL, NULL, "",
1850 false, "STDSTRINGS", SECTION_PRE_DATA,
1851 qry->data, "", NULL,
1855 destroyPQExpBuffer(qry);
1861 * Test whether database contains any large objects
1864 hasBlobs(Archive *AH)
1867 const char *blobQry;
1870 /* Make sure we are in proper schema */
1871 selectSourceSchema("pg_catalog");
1873 /* Check for BLOB OIDs */
1874 if (AH->remoteVersion >= 70100)
1875 blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
1877 blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
1879 res = PQexec(g_conn, blobQry);
1880 check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
1882 result = PQntuples(res) > 0;
1894 dumpBlobs(Archive *AH, void *arg)
1896 const char *blobQry;
1897 const char *blobFetchQry;
1899 char buf[LOBBUFSIZE];
1904 write_msg(NULL, "saving large objects\n");
1906 /* Make sure we are in proper schema */
1907 selectSourceSchema("pg_catalog");
1909 /* Cursor to get all BLOB OIDs */
1910 if (AH->remoteVersion >= 70100)
1911 blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
1913 blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
1915 res = PQexec(g_conn, blobQry);
1916 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
1918 /* Command to fetch from cursor */
1919 blobFetchQry = "FETCH 1000 IN bloboid";
1926 res = PQexec(g_conn, blobFetchQry);
1927 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
1929 /* Process the tuples, if any */
1930 for (i = 0; i < PQntuples(res); i++)
1935 blobOid = atooid(PQgetvalue(res, i, 0));
1937 loFd = lo_open(g_conn, blobOid, INV_READ);
1940 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1941 PQerrorMessage(g_conn));
1945 StartBlob(AH, blobOid);
1947 /* Now read it in chunks, sending data to archive */
1950 cnt = lo_read(g_conn, loFd, buf, LOBBUFSIZE);
1953 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1954 PQerrorMessage(g_conn));
1958 WriteData(AH, buf, cnt);
1961 lo_close(g_conn, loFd);
1963 EndBlob(AH, blobOid);
1965 } while (PQntuples(res) > 0);
1974 * dump all blob comments
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.
1981 dumpBlobComments(Archive *AH, void *arg)
1983 const char *blobQry;
1984 const char *blobFetchQry;
1985 PQExpBuffer commentcmd = createPQExpBuffer();
1990 write_msg(NULL, "saving large object comments\n");
1992 /* Make sure we are in proper schema */
1993 selectSourceSchema("pg_catalog");
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";
2011 blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, "
2013 " SELECT description "
2014 " FROM pg_description pd "
2015 " WHERE pd.objoid=pc.oid "
2017 "FROM pg_class pc WHERE relkind = 'l'";
2019 res = PQexec(g_conn, blobQry);
2020 check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
2022 /* Command to fetch from cursor */
2023 blobFetchQry = "FETCH 100 IN blobcmt";
2030 res = PQexec(g_conn, blobFetchQry);
2031 check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
2033 /* Process the tuples, if any */
2034 for (i = 0; i < PQntuples(res); i++)
2039 /* ignore blobs without comments */
2040 if (PQgetisnull(res, i, 1))
2043 blobOid = atooid(PQgetvalue(res, i, 0));
2044 comment = PQgetvalue(res, i, 1);
2046 printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
2048 appendStringLiteralAH(commentcmd, comment, AH);
2049 appendPQExpBuffer(commentcmd, ";\n");
2051 archputs(commentcmd->data, AH);
2053 } while (PQntuples(res) > 0);
2059 destroyPQExpBuffer(commentcmd);
2066 * read all namespaces in the system catalogs and return them in the
2067 * NamespaceInfo* structure
2069 * numNamespaces is set to the number of namespaces read in
2072 getNamespaces(int *numNamespaces)
2078 NamespaceInfo *nsinfo;
2086 * Before 7.3, there are no real namespaces; create two dummy entries, one
2087 * for user stuff and one for system stuff.
2089 if (g_fout->remoteVersion < 70300)
2091 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
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("");
2101 selectDumpableNamespace(&nsinfo[0]);
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("");
2111 selectDumpableNamespace(&nsinfo[1]);
2113 g_namespaces = nsinfo;
2114 g_numNamespaces = *numNamespaces = 2;
2119 query = createPQExpBuffer();
2121 /* Make sure we are in proper schema */
2122 selectSourceSchema("pg_catalog");
2125 * we fetch all namespaces including system ones, so that every object we
2126 * read in can be linked to a containing namespace.
2128 appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
2129 "(%s nspowner) AS rolname, "
2130 "nspacl FROM pg_namespace",
2133 res = PQexec(g_conn, query->data);
2134 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2136 ntups = PQntuples(res);
2138 nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
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");
2146 for (i = 0; i < ntups; i++)
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));
2156 /* Decide whether to dump this namespace */
2157 selectDumpableNamespace(&nsinfo[i]);
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);
2165 destroyPQExpBuffer(query);
2167 g_namespaces = nsinfo;
2168 g_numNamespaces = *numNamespaces = ntups;
2175 * given a namespace OID and an object OID, look up the info read by
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.
2181 static NamespaceInfo *
2182 findNamespace(Oid nsoid, Oid objoid)
2186 if (g_fout->remoteVersion >= 70300)
2188 for (i = 0; i < g_numNamespaces; i++)
2190 NamespaceInfo *nsinfo = &g_namespaces[i];
2192 if (nsoid == nsinfo->dobj.catId.oid)
2195 write_msg(NULL, "schema with OID %u does not exist\n", nsoid);
2200 /* This code depends on the layout set up by getNamespaces. */
2201 if (objoid > g_last_builtin_oid)
2202 i = 0; /* user object */
2204 i = 1; /* system object */
2205 return &g_namespaces[i];
2208 return NULL; /* keep compiler quiet */
2213 * read all types in the system catalogs and return them in the
2214 * TypeInfo* structure
2216 * numTypes is set to the number of types read in
2218 * NB: this must run after getFuncs() because we assume we can do
2222 getTypes(int *numTypes)
2227 PQExpBuffer query = createPQExpBuffer();
2229 ShellTypeInfo *stinfo;
2245 * we include even the built-in types because those may be used as array
2246 * elements by user-defined types
2248 * we filter out the built-in types when we dump out the types
2250 * same approach for undefined (shell) types and array types
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.
2260 /* Make sure we are in proper schema */
2261 selectSourceSchema("pg_catalog");
2263 if (g_fout->remoteVersion >= 80300)
2265 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
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 "
2278 else if (g_fout->remoteVersion >= 70300)
2280 appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
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 "
2292 else if (g_fout->remoteVersion >= 70100)
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 "
2308 appendPQExpBuffer(query, "SELECT "
2309 "(SELECT oid FROM pg_class WHERE relname = 'pg_type') AS tableoid, "
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 "
2323 res = PQexec(g_conn, query->data);
2324 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2326 ntups = PQntuples(res);
2328 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
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");
2344 for (i = 0; i < ntups; i++)
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;
2360 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
2361 tinfo[i].isDefined = true;
2363 tinfo[i].isDefined = false;
2365 if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
2366 tinfo[i].isArray = true;
2368 tinfo[i].isArray = false;
2370 /* Decide whether we want to dump it */
2371 selectDumpableType(&tinfo[i]);
2374 * If it's a domain, fetch info about its constraints, if any
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]));
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.
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.
2390 if (tinfo[i].dobj.dump && tinfo[i].typtype == TYPTYPE_BASE)
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;
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.
2406 stinfo->dobj.dump = false;
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
2414 if (g_fout->remoteVersion < 70300)
2420 typinput = atooid(PQgetvalue(res, i, i_typinput));
2421 typoutput = atooid(PQgetvalue(res, i, i_typoutput));
2423 funcInfo = findFuncByOid(typinput);
2424 if (funcInfo && funcInfo->dobj.dump)
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;
2436 funcInfo = findFuncByOid(typoutput);
2437 if (funcInfo && funcInfo->dobj.dump)
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;
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);
2460 destroyPQExpBuffer(query);
2467 * read all operators in the system catalogs and return them in the
2468 * OprInfo* structure
2470 * numOprs is set to the number of operators read in
2473 getOperators(int *numOprs)
2478 PQExpBuffer query = createPQExpBuffer();
2488 * find all operators, including builtin operators; we filter out
2489 * system-defined operators at dump-out time.
2492 /* Make sure we are in proper schema */
2493 selectSourceSchema("pg_catalog");
2495 if (g_fout->remoteVersion >= 70300)
2497 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2499 "(%s oprowner) AS rolname, "
2500 "oprcode::oid AS oprcode "
2504 else if (g_fout->remoteVersion >= 70100)
2506 appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
2507 "0::oid AS oprnamespace, "
2508 "(%s oprowner) AS rolname, "
2509 "oprcode::oid AS oprcode "
2515 appendPQExpBuffer(query, "SELECT "
2516 "(SELECT oid FROM pg_class WHERE relname = 'pg_operator') AS tableoid, "
2518 "0::oid AS oprnamespace, "
2519 "(%s oprowner) AS rolname, "
2520 "oprcode::oid AS oprcode "
2525 res = PQexec(g_conn, query->data);
2526 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2528 ntups = PQntuples(res);
2531 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
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");
2540 for (i = 0; i < ntups; i++)
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));
2552 /* Decide whether we want to dump it */
2553 selectDumpableObject(&(oprinfo[i].dobj));
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);
2562 destroyPQExpBuffer(query);
2569 * read all conversions in the system catalogs and return them in the
2570 * ConvInfo* structure
2572 * numConversions is set to the number of conversions read in
2575 getConversions(int *numConversions)
2580 PQExpBuffer query = createPQExpBuffer();
2588 /* Conversions didn't exist pre-7.3 */
2589 if (g_fout->remoteVersion < 70300)
2591 *numConversions = 0;
2596 * find all conversions, including builtin conversions; we filter out
2597 * system-defined conversions at dump-out time.
2600 /* Make sure we are in proper schema */
2601 selectSourceSchema("pg_catalog");
2603 appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
2605 "(%s conowner) AS rolname "
2606 "FROM pg_conversion",
2609 res = PQexec(g_conn, query->data);
2610 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2612 ntups = PQntuples(res);
2613 *numConversions = ntups;
2615 convinfo = (ConvInfo *) malloc(ntups * sizeof(ConvInfo));
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");
2623 for (i = 0; i < ntups; i++)
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));
2634 /* Decide whether we want to dump it */
2635 selectDumpableObject(&(convinfo[i].dobj));
2640 destroyPQExpBuffer(query);
2647 * read all opclasses in the system catalogs and return them in the
2648 * OpclassInfo* structure
2650 * numOpclasses is set to the number of opclasses read in
2653 getOpclasses(int *numOpclasses)
2658 PQExpBuffer query = createPQExpBuffer();
2659 OpclassInfo *opcinfo;
2667 * find all opclasses, including builtin opclasses; we filter out
2668 * system-defined opclasses at dump-out time.
2671 /* Make sure we are in proper schema */
2672 selectSourceSchema("pg_catalog");
2674 if (g_fout->remoteVersion >= 70300)
2676 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2678 "(%s opcowner) AS rolname "
2682 else if (g_fout->remoteVersion >= 70100)
2684 appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
2685 "0::oid AS opcnamespace, "
2686 "''::name AS rolname "
2691 appendPQExpBuffer(query, "SELECT "
2692 "(SELECT oid FROM pg_class WHERE relname = 'pg_opclass') AS tableoid, "
2694 "0::oid AS opcnamespace, "
2695 "''::name AS rolname "
2699 res = PQexec(g_conn, query->data);
2700 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2702 ntups = PQntuples(res);
2703 *numOpclasses = ntups;
2705 opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
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");
2713 for (i = 0; i < ntups; i++)
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));
2724 /* Decide whether we want to dump it */
2725 selectDumpableObject(&(opcinfo[i].dobj));
2727 if (g_fout->remoteVersion >= 70300)
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);
2737 destroyPQExpBuffer(query);
2744 * read all opfamilies in the system catalogs and return them in the
2745 * OpfamilyInfo* structure
2747 * numOpfamilies is set to the number of opfamilies read in
2750 getOpfamilies(int *numOpfamilies)
2756 OpfamilyInfo *opfinfo;
2763 /* Before 8.3, there is no separate concept of opfamilies */
2764 if (g_fout->remoteVersion < 80300)
2770 query = createPQExpBuffer();
2773 * find all opfamilies, including builtin opfamilies; we filter out
2774 * system-defined opfamilies at dump-out time.
2777 /* Make sure we are in proper schema */
2778 selectSourceSchema("pg_catalog");
2780 appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
2782 "(%s opfowner) AS rolname "
2786 res = PQexec(g_conn, query->data);
2787 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2789 ntups = PQntuples(res);
2790 *numOpfamilies = ntups;
2792 opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
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");
2800 for (i = 0; i < ntups; i++)
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));
2811 /* Decide whether we want to dump it */
2812 selectDumpableObject(&(opfinfo[i].dobj));
2814 if (g_fout->remoteVersion >= 70300)
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);
2824 destroyPQExpBuffer(query);
2831 * read all the user-defined aggregates in the system catalogs and
2832 * return them in the AggInfo* structure
2834 * numAggs is set to the number of aggregates read in
2837 getAggregates(int *numAggs)
2842 PQExpBuffer query = createPQExpBuffer();
2853 /* Make sure we are in proper schema */
2854 selectSourceSchema("pg_catalog");
2856 /* find all user-defined aggregates */
2858 if (g_fout->remoteVersion >= 80200)
2860 appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
2861 "pronamespace AS aggnamespace, "
2862 "pronargs, proargtypes, "
2863 "(%s proowner) AS rolname, "
2867 "AND pronamespace != "
2868 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2871 else if (g_fout->remoteVersion >= 70300)
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, "
2877 "(%s proowner) AS rolname, "
2881 "AND pronamespace != "
2882 "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
2885 else if (g_fout->remoteVersion >= 70100)
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, "
2893 "FROM pg_aggregate "
2894 "where oid > '%u'::oid",
2896 g_last_builtin_oid);
2900 appendPQExpBuffer(query, "SELECT "
2901 "(SELECT oid FROM pg_class WHERE relname = 'pg_aggregate') AS tableoid, "
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, "
2908 "FROM pg_aggregate "
2909 "where oid > '%u'::oid",
2911 g_last_builtin_oid);
2914 res = PQexec(g_conn, query->data);
2915 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
2917 ntups = PQntuples(res);
2920 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
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");
2931 for (i = 0; i < ntups; i++)
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;
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);
2958 /* it's just aggbasetype */
2959 agginfo[i].aggfn.argtypes[0] = atooid(PQgetvalue(res, i, i_proargtypes));
2962 /* Decide whether we want to dump it */
2963 selectDumpableObject(&(agginfo[i].aggfn.dobj));
2968 destroyPQExpBuffer(query);
2975 * read all the user-defined functions in the system catalogs and
2976 * return them in the FuncInfo* structure
2978 * numFuncs is set to the number of functions read in
2981 getFuncs(int *numFuncs)
2986 PQExpBuffer query = createPQExpBuffer();
2999 /* Make sure we are in proper schema */
3000 selectSourceSchema("pg_catalog");
3002 /* find all user-defined funcs */
3004 if (g_fout->remoteVersion >= 70300)
3006 appendPQExpBuffer(query,
3007 "SELECT tableoid, oid, proname, prolang, "
3008 "pronargs, proargtypes, prorettype, proacl, "
3010 "(%s proowner) AS rolname "
3012 "WHERE NOT proisagg "
3013 "AND pronamespace != "
3014 "(SELECT oid FROM pg_namespace "
3015 "WHERE nspname = 'pg_catalog')",
3018 else if (g_fout->remoteVersion >= 70100)
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 "
3027 "WHERE pg_proc.oid > '%u'::oid",
3029 g_last_builtin_oid);
3033 appendPQExpBuffer(query,
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 "
3043 "where pg_proc.oid > '%u'::oid",
3045 g_last_builtin_oid);
3048 res = PQexec(g_conn, query->data);
3049 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3051 ntups = PQntuples(res);
3055 finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
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");
3068 for (i = 0; i < ntups; i++)
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;
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);
3092 /* Decide whether we want to dump it */
3093 selectDumpableObject(&(finfo[i].dobj));
3095 if (strlen(finfo[i].rolname) == 0)
3097 "WARNING: owner of function \"%s\" appears to be invalid\n",
3098 finfo[i].dobj.name);
3103 destroyPQExpBuffer(query);
3110 * read all the user-defined tables (no indexes, no catalogs)
3111 * in the system catalogs return them in the TableInfo* structure
3113 * numTables is set to the number of tables read in
3116 getTables(int *numTables)
3121 PQExpBuffer query = createPQExpBuffer();
3131 int i_relhastriggers;
3138 int i_reltablespace;
3140 int i_toastreloptions;
3142 /* Make sure we are in proper schema */
3143 selectSourceSchema("pg_catalog");
3146 * Find all the tables (including views and sequences).
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...)
3151 * We ignore tables that are not type 'r' (ordinary relation), 'S'
3152 * (sequence), 'v' (view), or 'c' (composite type).
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).
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.
3165 if (g_fout->remoteVersion >= 80400)
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)
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, "
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 "
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') "
3194 RELKIND_RELATION, RELKIND_SEQUENCE,
3195 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3197 else if (g_fout->remoteVersion >= 80200)
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)
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, "
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 "
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') "
3225 RELKIND_RELATION, RELKIND_SEQUENCE,
3226 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3228 else if (g_fout->remoteVersion >= 80000)
3231 * Left join to pick up dependency info linking sequences to their
3232 * owning column, if any
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 "
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') "
3256 RELKIND_RELATION, RELKIND_SEQUENCE,
3257 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3259 else if (g_fout->remoteVersion >= 70300)
3262 * Left join to pick up dependency info linking sequences to their
3263 * owning column, if any
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 "
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') "
3287 RELKIND_RELATION, RELKIND_SEQUENCE,
3288 RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
3290 else if (g_fout->remoteVersion >= 70200)
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 "
3305 "WHERE relkind IN ('%c', '%c', '%c') "
3308 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
3310 else if (g_fout->remoteVersion >= 70100)
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 "
3327 "WHERE relkind IN ('%c', '%c', '%c') "
3330 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
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.
3338 appendPQExpBuffer(query,
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 "
3359 "WHERE relkind IN ('%c', '%c') "
3363 RELKIND_RELATION, RELKIND_SEQUENCE);
3366 res = PQexec(g_conn, query->data);
3367 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3369 ntups = PQntuples(res);
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.
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.
3382 tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
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");
3403 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3406 * Arrange to fail instead of waiting forever for a table lock.
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.
3412 resetPQExpBuffer(query);
3413 appendPQExpBuffer(query, "SET statement_timeout = ");
3414 appendStringLiteralConn(query, lockWaitTimeout, g_conn);
3415 do_sql_command(g_conn, query->data);
3418 for (i = 0; i < ntups; i++)
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))
3438 tblinfo[i].owning_tab = InvalidOid;
3439 tblinfo[i].owning_col = 0;
3443 tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
3444 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
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));
3450 /* other fields were zeroed above */
3453 * Decide whether we want to dump this table.
3455 if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
3456 tblinfo[i].dobj.dump = false;
3458 selectDumpableTable(&tblinfo[i]);
3459 tblinfo[i].interesting = tblinfo[i].dobj.dump;
3462 * Read-lock target tables to make sure they aren't DROPPED or altered
3463 * in schema before we get around to dumping them.
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.
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.
3472 if (tblinfo[i].dobj.dump && tblinfo[i].relkind == RELKIND_RELATION)
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);
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);
3488 if (lockWaitTimeout && g_fout->remoteVersion >= 70300)
3490 do_sql_command(g_conn, "SET statement_timeout = 0");
3496 * Force sequences that are "owned" by table columns to be dumped whenever
3497 * their owning table is being dumped.
3499 for (i = 0; i < ntups; i++)
3501 TableInfo *seqinfo = &tblinfo[i];
3504 if (!OidIsValid(seqinfo->owning_tab))
3505 continue; /* not an owned sequence */
3506 if (seqinfo->dobj.dump)
3507 continue; /* no need to search */
3509 /* can't use findTableByOid yet, unfortunately */
3510 for (j = 0; j < ntups; j++)
3512 if (tblinfo[j].dobj.catId.oid == seqinfo->owning_tab)
3514 if (tblinfo[j].dobj.dump)
3516 seqinfo->interesting = true;
3517 seqinfo->dobj.dump = true;
3524 destroyPQExpBuffer(query);
3531 * read all the inheritance information
3532 * from the system catalogs return them in the InhInfo* structure
3534 * numInherits is set to the number of pairs read in
3537 getInherits(int *numInherits)
3542 PQExpBuffer query = createPQExpBuffer();
3548 /* Make sure we are in proper schema */
3549 selectSourceSchema("pg_catalog");
3551 /* find all the inheritance information */
3553 appendPQExpBuffer(query, "SELECT inhrelid, inhparent FROM pg_inherits");
3555 res = PQexec(g_conn, query->data);
3556 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3558 ntups = PQntuples(res);
3560 *numInherits = ntups;
3562 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
3564 i_inhrelid = PQfnumber(res, "inhrelid");
3565 i_inhparent = PQfnumber(res, "inhparent");
3567 for (i = 0; i < ntups; i++)
3569 inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
3570 inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
3575 destroyPQExpBuffer(query);
3582 * get information about every index on a dumpable table
3584 * Note: index data is not returned directly to the caller, but it
3585 * does get entered into the DumpableObject tables.
3588 getIndexes(TableInfo tblinfo[], int numTables)
3592 PQExpBuffer query = createPQExpBuffer();
3595 ConstraintInfo *constrinfo;
3611 for (i = 0; i < numTables; i++)
3613 TableInfo *tbinfo = &tblinfo[i];
3615 /* Only plain tables have indexes */
3616 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
3619 /* Ignore indexes of tables not to be dumped */
3620 if (!tbinfo->dobj.dump)
3624 write_msg(NULL, "reading indexes for table \"%s\"\n",
3627 /* Make sure we are in proper schema so indexdef is right */
3628 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
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.
3636 resetPQExpBuffer(query);
3637 if (g_fout->remoteVersion >= 80200)
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, "
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);
3663 else if (g_fout->remoteVersion >= 80000)
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, "
3674 "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
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);
3689 else if (g_fout->remoteVersion >= 70300)
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, "
3700 "NULL AS tablespace, "
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);
3715 else if (g_fout->remoteVersion >= 70100)
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, "
3728 "NULL AS tablespace, "
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);
3738 appendPQExpBuffer(query,
3740 "(SELECT oid FROM pg_class WHERE relname = 'pg_class') AS tableoid, "
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, "
3751 "NULL AS tablespace, "
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);
3760 res = PQexec(g_conn, query->data);
3761 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3763 ntups = PQntuples(res);
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");
3779 indxinfo = (IndxInfo *) malloc(ntups * sizeof(IndxInfo));
3780 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3782 for (j = 0; j < ntups; j++)
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));
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
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));
3813 if (contype == 'p' || contype == 'u')
3816 * If we found a constraint matching the index, create an
3819 * In a pre-7.3 database, we take this path iff the index was
3820 * marked indisprimary.
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;
3837 indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
3839 /* If pre-7.3 DB, better make sure table comes first */
3840 addObjectDependency(&constrinfo[j].dobj,
3841 tbinfo->dobj.dumpId);
3845 /* Plain secondary index */
3846 indxinfo[j].indexconstraint = 0;
3853 destroyPQExpBuffer(query);
3859 * Get info about constraints on dumpable tables.
3861 * Currently handles foreign keys only.
3862 * Unique and primary key constraints are handled with indexes,
3863 * while check constraints are processed in getTableAttrs().
3866 getConstraints(TableInfo tblinfo[], int numTables)
3870 ConstraintInfo *constrinfo;
3880 /* pg_constraint was created in 7.3, so nothing to do if older */
3881 if (g_fout->remoteVersion < 70300)
3884 query = createPQExpBuffer();
3886 for (i = 0; i < numTables; i++)
3888 TableInfo *tbinfo = &tblinfo[i];
3890 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
3894 write_msg(NULL, "reading foreign key constraints for table \"%s\"\n",
3898 * select table schema to ensure constraint expr is qualified if
3901 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
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);
3914 ntups = PQntuples(res);
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");
3922 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
3924 for (j = 0; j < ntups; j++)
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;
3945 destroyPQExpBuffer(query);
3949 * getDomainConstraints
3951 * Get info about constraints on a domain.
3954 getDomainConstraints(TypeInfo *tinfo)
3957 ConstraintInfo *constrinfo;
3966 /* pg_constraint was created in 7.3, so nothing to do if older */
3967 if (g_fout->remoteVersion < 70300)
3971 * select appropriate schema to ensure names in constraint are properly
3974 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
3976 query = createPQExpBuffer();
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 "
3984 tinfo->dobj.catId.oid);
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 "
3991 tinfo->dobj.catId.oid);
3993 res = PQexec(g_conn, query->data);
3994 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
3996 ntups = PQntuples(res);
3998 i_tableoid = PQfnumber(res, "tableoid");
3999 i_oid = PQfnumber(res, "oid");
4000 i_conname = PQfnumber(res, "conname");
4001 i_consrc = PQfnumber(res, "consrc");
4003 constrinfo = (ConstraintInfo *) malloc(ntups * sizeof(ConstraintInfo));
4005 tinfo->nDomChecks = ntups;
4006 tinfo->domChecks = constrinfo;
4008 for (i = 0; i < ntups; i++)
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;
4026 * Make the domain depend on the constraint, ensuring it won't be
4027 * output till any constraint dependencies are OK.
4029 addObjectDependency(&tinfo->dobj,
4030 constrinfo[i].dobj.dumpId);
4035 destroyPQExpBuffer(query);
4040 * get basic information about every rule in the system
4042 * numRules is set to the number of rules read in
4045 getRules(int *numRules)
4050 PQExpBuffer query = createPQExpBuffer();
4060 /* Make sure we are in proper schema */
4061 selectSourceSchema("pg_catalog");
4063 if (g_fout->remoteVersion >= 80300)
4065 appendPQExpBuffer(query, "SELECT "
4066 "tableoid, oid, rulename, "
4067 "ev_class AS ruletable, ev_type, is_instead, "
4072 else if (g_fout->remoteVersion >= 70100)
4074 appendPQExpBuffer(query, "SELECT "
4075 "tableoid, oid, rulename, "
4076 "ev_class AS ruletable, ev_type, is_instead, "
4077 "'O'::char AS ev_enabled "
4083 appendPQExpBuffer(query, "SELECT "
4084 "(SELECT oid FROM pg_class WHERE relname = 'pg_rewrite') AS tableoid, "
4086 "ev_class AS ruletable, ev_type, is_instead, "
4087 "'O'::char AS ev_enabled "
4092 res = PQexec(g_conn, query->data);
4093 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4095 ntups = PQntuples(res);
4099 ruleinfo = (RuleInfo *) malloc(ntups * sizeof(RuleInfo));
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");
4109 for (i = 0; i < ntups; i++)
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)
4122 write_msg(NULL, "failed sanity check, parent table OID %u of pg_rewrite entry OID %u not found\n",
4124 ruleinfo[i].dobj.catId.oid);
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)
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.
4140 if (ruleinfo[i].ruletable->relkind == RELKIND_VIEW &&
4141 ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
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;
4150 addObjectDependency(&ruleinfo[i].dobj,
4151 ruleinfo[i].ruletable->dobj.dumpId);
4152 ruleinfo[i].separate = true;
4156 ruleinfo[i].separate = true;
4161 destroyPQExpBuffer(query);
4168 * get information about every trigger on a dumpable table
4170 * Note: trigger data is not returned directly to the caller, but it
4171 * does get entered into the DumpableObject tables.
4174 getTriggers(TableInfo tblinfo[], int numTables)
4178 PQExpBuffer query = createPQExpBuffer();
4180 TriggerInfo *tginfo;
4197 for (i = 0; i < numTables; i++)
4199 TableInfo *tbinfo = &tblinfo[i];
4201 if (!tbinfo->hastriggers || !tbinfo->dobj.dump)
4205 write_msg(NULL, "reading triggers for table \"%s\"\n",
4209 * select table schema to ensure regproc name is qualified if needed
4211 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4213 resetPQExpBuffer(query);
4214 if (g_fout->remoteVersion >= 80300)
4217 * We ignore triggers that are tied to a foreign-key constraint
4219 appendPQExpBuffer(query,
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);
4231 else if (g_fout->remoteVersion >= 70300)
4234 * We ignore triggers that are tied to a foreign-key constraint,
4235 * but in these versions we have to grovel through pg_constraint
4238 appendPQExpBuffer(query,
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 "
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);
4254 else if (g_fout->remoteVersion >= 70100)
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 "
4264 "WHERE tgrelid = '%u'::oid",
4265 tbinfo->dobj.catId.oid);
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, "
4276 "(SELECT relname FROM pg_class WHERE oid = tgconstrrelid) "
4277 " AS tgconstrrelname "
4279 "WHERE tgrelid = '%u'::oid",
4280 tbinfo->dobj.catId.oid);
4282 res = PQexec(g_conn, query->data);
4283 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4285 ntups = PQntuples(res);
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");
4302 tginfo = (TriggerInfo *) malloc(ntups * sizeof(TriggerInfo));
4304 for (j = 0; j < ntups; j++)
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';
4322 if (tginfo[j].tgisconstraint)
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))
4328 if (PQgetisnull(res, j, i_tgconstrrelname))
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);
4335 tginfo[j].tgconstrrelname = strdup(PQgetvalue(res, j, i_tgconstrrelname));
4338 tginfo[j].tgconstrrelname = NULL;
4342 tginfo[j].tgconstrname = NULL;
4343 tginfo[j].tgconstrrelid = InvalidOid;
4344 tginfo[j].tgconstrrelname = NULL;
4351 destroyPQExpBuffer(query);
4356 * get basic information about every procedural language in the system
4358 * numProcLangs is set to the number of langs read in
4360 * NB: this must run after getFuncs() because we assume we can do
4364 getProcLangs(int *numProcLangs)
4369 PQExpBuffer query = createPQExpBuffer();
4370 ProcLangInfo *planginfo;
4375 int i_lanplcallfoid;
4380 /* Make sure we are in proper schema */
4381 selectSourceSchema("pg_catalog");
4383 if (g_fout->remoteVersion >= 80300)
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 "
4395 else if (g_fout->remoteVersion >= 80100)
4397 /* Languages are owned by the bootstrap superuser, OID 10 */
4398 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4399 "(%s '10') AS lanowner "
4405 else if (g_fout->remoteVersion >= 70400)
4407 /* Languages are owned by the bootstrap superuser, sysid 1 */
4408 appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
4409 "(%s '1') AS lanowner "
4415 else if (g_fout->remoteVersion >= 70100)
4417 /* No clear notion of an owner at all before 7.4 ... */
4418 appendPQExpBuffer(query, "SELECT tableoid, oid, * FROM pg_language "
4424 appendPQExpBuffer(query, "SELECT "
4425 "(SELECT oid FROM pg_class WHERE relname = 'pg_language') AS tableoid, "
4426 "oid, * FROM pg_language "
4431 res = PQexec(g_conn, query->data);
4432 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4434 ntups = PQntuples(res);
4436 *numProcLangs = ntups;
4438 planginfo = (ProcLangInfo *) malloc(ntups * sizeof(ProcLangInfo));
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");
4450 for (i = 0; i < ntups; i++)
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);
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));
4463 planginfo[i].lanvalidator = InvalidOid;
4465 planginfo[i].lanacl = strdup(PQgetvalue(res, i, i_lanacl));
4467 planginfo[i].lanacl = strdup("{=U}");
4468 if (i_lanowner >= 0)
4469 planginfo[i].lanowner = strdup(PQgetvalue(res, i, i_lanowner));
4471 planginfo[i].lanowner = strdup("");
4473 if (g_fout->remoteVersion < 70300)
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.)
4480 FuncInfo *funcInfo = findFuncByOid(planginfo[i].lanplcallfoid);
4483 addObjectDependency(&planginfo[i].dobj,
4484 funcInfo->dobj.dumpId);
4490 destroyPQExpBuffer(query);
4497 * get basic information about every cast in the system
4499 * numCasts is set to the number of casts read in
4502 getCasts(int *numCasts)
4507 PQExpBuffer query = createPQExpBuffer();
4517 /* Make sure we are in proper schema */
4518 selectSourceSchema("pg_catalog");
4520 if (g_fout->remoteVersion >= 80400)
4522 appendPQExpBuffer(query, "SELECT tableoid, oid, "
4523 "castsource, casttarget, castfunc, castcontext, "
4525 "FROM pg_cast ORDER BY 3,4");
4527 else if (g_fout->remoteVersion >= 70300)
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");
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 "
4547 res = PQexec(g_conn, query->data);
4548 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
4550 ntups = PQntuples(res);
4554 castinfo = (CastInfo *) malloc(ntups * sizeof(CastInfo));
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");
4564 for (i = 0; i < ntups; i++)
4566 PQExpBufferData namebuf;
4567 TypeInfo *sTypeInfo;
4568 TypeInfo *tTypeInfo;
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));
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.
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;
4593 if (OidIsValid(castinfo[i].castfunc))
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.)
4602 funcInfo = findFuncByOid(castinfo[i].castfunc);
4604 addObjectDependency(&castinfo[i].dobj,
4605 funcInfo->dobj.dumpId);
4611 destroyPQExpBuffer(query);
4618 * for each interesting table, read info about its attributes
4619 * (names, types, default values, CHECK constraints, etc)
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?)
4630 getTableAttrs(TableInfo *tblinfo, int numTables)
4634 PQExpBuffer q = createPQExpBuffer();
4639 int i_attstattarget;
4652 for (i = 0; i < numTables; i++)
4654 TableInfo *tbinfo = &tblinfo[i];
4656 /* Don't bother to collect info for sequences */
4657 if (tbinfo->relkind == RELKIND_SEQUENCE)
4660 /* Don't bother with uninteresting tables, either */
4661 if (!tbinfo->interesting)
4665 * Make sure we are in proper schema for this table; this allows
4666 * correct retrieval of formatted type names and default exprs
4668 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
4670 /* find all the user attributes and their types */
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.
4680 write_msg(NULL, "finding the columns and types of table \"%s\"\n",
4683 resetPQExpBuffer(q);
4685 if (g_fout->remoteVersion >= 70300)
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);
4700 else if (g_fout->remoteVersion >= 70100)
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.
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);
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);
4737 res = PQexec(g_conn, q->data);
4738 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4740 ntups = PQntuples(res);
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");
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;
4774 for (j = 0; j < ntups; j++)
4776 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
4778 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
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')
4796 /* these flags will be set in flagInhAttrs() */
4797 tbinfo->inhAttrs[j] = false;
4798 tbinfo->inhAttrDef[j] = false;
4799 tbinfo->inhNotNull[j] = false;
4806 * ALTER TABLE DROP COLUMN clears pg_attribute.atttypid, so we
4807 * set the column data type to 'TEXT; we will later drop the
4812 for (j = 0; j < ntups; j++)
4814 if (tbinfo->attisdropped[j])
4815 tbinfo->atttypnames[j] = strdup("TEXT");
4820 * Get info about column defaults
4824 AttrDefInfo *attrdefs;
4828 write_msg(NULL, "finding default expressions of table \"%s\"\n",
4831 resetPQExpBuffer(q);
4832 if (g_fout->remoteVersion >= 70300)
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);
4840 else if (g_fout->remoteVersion >= 70200)
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 "
4846 "WHERE adrelid = '%u'::oid",
4847 tbinfo->dobj.catId.oid);
4849 else if (g_fout->remoteVersion >= 70100)
4851 /* no pg_get_expr, so must rely on adsrc */
4852 appendPQExpBuffer(q, "SELECT tableoid, oid, adnum, adsrc "
4854 "WHERE adrelid = '%u'::oid",
4855 tbinfo->dobj.catId.oid);
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 "
4864 "WHERE adrelid = '%u'::oid",
4865 tbinfo->dobj.catId.oid);
4867 res = PQexec(g_conn, q->data);
4868 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
4870 numDefaults = PQntuples(res);
4871 attrdefs = (AttrDefInfo *) malloc(numDefaults * sizeof(AttrDefInfo));
4873 for (j = 0; j < numDefaults; j++)
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));
4885 attrdefs[j].dobj.name = strdup(tbinfo->dobj.name);
4886 attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
4888 attrdefs[j].dobj.dump = tbinfo->dobj.dump;
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
4897 if (tbinfo->relkind == RELKIND_VIEW)
4899 attrdefs[j].separate = true;
4900 /* needed in case pre-7.3 DB: */
4901 addObjectDependency(&attrdefs[j].dobj,
4902 tbinfo->dobj.dumpId);
4906 attrdefs[j].separate = false;
4907 addObjectDependency(&tbinfo->dobj,
4908 attrdefs[j].dobj.dumpId);
4911 if (adnum <= 0 || adnum > ntups)
4913 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
4914 adnum, tbinfo->dobj.name);
4917 tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
4923 * Get info about table CHECK constraints
4925 if (tbinfo->ncheck > 0)
4927 ConstraintInfo *constrs;
4931 write_msg(NULL, "finding check constraints for table \"%s\"\n",
4934 resetPQExpBuffer(q);
4935 if (g_fout->remoteVersion >= 80400)
4937 appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
4938 "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
4940 "FROM pg_catalog.pg_constraint "
4941 "WHERE conrelid = '%u'::pg_catalog.oid "
4942 " AND contype = 'c' "
4944 tbinfo->dobj.catId.oid);
4946 else if (g_fout->remoteVersion >= 70400)
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' "
4955 tbinfo->dobj.catId.oid);
4957 else if (g_fout->remoteVersion >= 70300)
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' "
4967 tbinfo->dobj.catId.oid);
4969 else if (g_fout->remoteVersion >= 70200)
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 "
4977 "WHERE rcrelid = '%u'::oid "
4979 tbinfo->dobj.catId.oid);
4981 else if (g_fout->remoteVersion >= 70100)
4983 appendPQExpBuffer(q, "SELECT tableoid, oid, "
4984 "rcname AS conname, "
4985 "'CHECK (' || rcsrc || ')' AS consrc, "
4986 "true AS conislocal "
4988 "WHERE rcrelid = '%u'::oid "
4990 tbinfo->dobj.catId.oid);
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 "
5001 "WHERE rcrelid = '%u'::oid "
5003 tbinfo->dobj.catId.oid);
5005 res = PQexec(g_conn, q->data);
5006 check_sql_result(res, g_conn, q->data, PGRES_TUPLES_OK);
5008 numConstrs = PQntuples(res);
5009 if (numConstrs != tbinfo->ncheck)
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",
5014 tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
5015 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5019 constrs = (ConstraintInfo *) malloc(numConstrs * sizeof(ConstraintInfo));
5020 tbinfo->checkexprs = constrs;
5022 for (j = 0; j < numConstrs; j++)
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;
5039 constrs[j].dobj.dump = tbinfo->dobj.dump;
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
5047 addObjectDependency(&tbinfo->dobj,
5048 constrs[j].dobj.dumpId);
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.
5060 destroyPQExpBuffer(q);
5066 * read all text search parsers in the system catalogs and return them
5067 * in the TSParserInfo* structure
5069 * numTSParsers is set to the number of parsers read in
5072 getTSParsers(int *numTSParsers)
5077 PQExpBuffer query = createPQExpBuffer();
5078 TSParserInfo *prsinfo;
5089 /* Before 8.3, there is no built-in text search support */
5090 if (g_fout->remoteVersion < 80300)
5097 * find all text search objects, including builtin ones; we filter out
5098 * system-defined objects at dump-out time.
5101 /* Make sure we are in proper schema */
5102 selectSourceSchema("pg_catalog");
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");
5109 res = PQexec(g_conn, query->data);
5110 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5112 ntups = PQntuples(res);
5113 *numTSParsers = ntups;
5115 prsinfo = (TSParserInfo *) malloc(ntups * sizeof(TSParserInfo));
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");
5127 for (i = 0; i < ntups; i++)
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));
5142 /* Decide whether we want to dump it */
5143 selectDumpableObject(&(prsinfo[i].dobj));
5148 destroyPQExpBuffer(query);
5154 * getTSDictionaries:
5155 * read all text search dictionaries in the system catalogs and return them
5156 * in the TSDictInfo* structure
5158 * numTSDicts is set to the number of dictionaries read in
5161 getTSDictionaries(int *numTSDicts)
5166 PQExpBuffer query = createPQExpBuffer();
5167 TSDictInfo *dictinfo;
5171 int i_dictnamespace;
5174 int i_dictinitoption;
5176 /* Before 8.3, there is no built-in text search support */
5177 if (g_fout->remoteVersion < 80300)
5183 /* Make sure we are in proper schema */
5184 selectSourceSchema("pg_catalog");
5186 appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
5187 "dictnamespace, (%s dictowner) AS rolname, "
5188 "dicttemplate, dictinitoption "
5192 res = PQexec(g_conn, query->data);
5193 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5195 ntups = PQntuples(res);
5196 *numTSDicts = ntups;
5198 dictinfo = (TSDictInfo *) malloc(ntups * sizeof(TSDictInfo));
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");
5208 for (i = 0; i < ntups; i++)
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;
5222 dictinfo[i].dictinitoption = strdup(PQgetvalue(res, i, i_dictinitoption));
5224 /* Decide whether we want to dump it */
5225 selectDumpableObject(&(dictinfo[i].dobj));
5230 destroyPQExpBuffer(query);
5237 * read all text search templates in the system catalogs and return them
5238 * in the TSTemplateInfo* structure
5240 * numTSTemplates is set to the number of templates read in
5243 getTSTemplates(int *numTSTemplates)
5248 PQExpBuffer query = createPQExpBuffer();
5249 TSTemplateInfo *tmplinfo;
5253 int i_tmplnamespace;
5257 /* Before 8.3, there is no built-in text search support */
5258 if (g_fout->remoteVersion < 80300)
5260 *numTSTemplates = 0;
5264 /* Make sure we are in proper schema */
5265 selectSourceSchema("pg_catalog");
5267 appendPQExpBuffer(query, "SELECT tableoid, oid, tmplname, "
5268 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
5269 "FROM pg_ts_template");
5271 res = PQexec(g_conn, query->data);
5272 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5274 ntups = PQntuples(res);
5275 *numTSTemplates = ntups;
5277 tmplinfo = (TSTemplateInfo *) malloc(ntups * sizeof(TSTemplateInfo));
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");
5286 for (i = 0; i < ntups; i++)
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));
5298 /* Decide whether we want to dump it */
5299 selectDumpableObject(&(tmplinfo[i].dobj));
5304 destroyPQExpBuffer(query);
5310 * getTSConfigurations:
5311 * read all text search configurations in the system catalogs and return
5312 * them in the TSConfigInfo* structure
5314 * numTSConfigs is set to the number of configurations read in
5317 getTSConfigurations(int *numTSConfigs)
5322 PQExpBuffer query = createPQExpBuffer();
5323 TSConfigInfo *cfginfo;
5331 /* Before 8.3, there is no built-in text search support */
5332 if (g_fout->remoteVersion < 80300)
5338 /* Make sure we are in proper schema */
5339 selectSourceSchema("pg_catalog");
5341 appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
5342 "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
5343 "FROM pg_ts_config",
5346 res = PQexec(g_conn, query->data);
5347 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5349 ntups = PQntuples(res);
5350 *numTSConfigs = ntups;
5352 cfginfo = (TSConfigInfo *) malloc(ntups * sizeof(TSConfigInfo));
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");
5361 for (i = 0; i < ntups; i++)
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));
5373 /* Decide whether we want to dump it */
5374 selectDumpableObject(&(cfginfo[i].dobj));
5379 destroyPQExpBuffer(query);
5385 * getForeignDataWrappers:
5386 * read all foreign-data wrappers in the system catalogs and return
5387 * them in the FdwInfo* structure
5389 * numForeignDataWrappers is set to the number of fdws read in
5392 getForeignDataWrappers(int *numForeignDataWrappers)
5397 PQExpBuffer query = createPQExpBuffer();
5406 /* Before 8.4, there are no foreign-data wrappers */
5407 if (g_fout->remoteVersion < 80400)
5409 *numForeignDataWrappers = 0;
5413 /* Make sure we are in proper schema */
5414 selectSourceSchema("pg_catalog");
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",
5424 res = PQexec(g_conn, query->data);
5425 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5427 ntups = PQntuples(res);
5428 *numForeignDataWrappers = ntups;
5430 fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
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");
5439 for (i = 0; i < ntups; i++)
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));
5452 /* Decide whether we want to dump it */
5453 selectDumpableObject(&(fdwinfo[i].dobj));
5458 destroyPQExpBuffer(query);
5464 * getForeignServers:
5465 * read all foreign servers in the system catalogs and return
5466 * them in the ForeignServerInfo * structure
5468 * numForeignServers is set to the number of servers read in
5471 getForeignServers(int *numForeignServers)
5476 PQExpBuffer query = createPQExpBuffer();
5477 ForeignServerInfo *srvinfo;
5487 /* Before 8.4, there are no foreign servers */
5488 if (g_fout->remoteVersion < 80400)
5490 *numForeignServers = 0;
5494 /* Make sure we are in proper schema */
5495 selectSourceSchema("pg_catalog");
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",
5506 res = PQexec(g_conn, query->data);
5507 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5509 ntups = PQntuples(res);
5510 *numForeignServers = ntups;
5512 srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
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");
5523 for (i = 0; i < ntups; i++)
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));
5537 /* Decide whether we want to dump it */
5538 selectDumpableObject(&(srvinfo[i].dobj));
5543 destroyPQExpBuffer(query);
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.
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.
5567 dumpComment(Archive *fout, const char *target,
5568 const char *namespace, const char *owner,
5569 CatalogId catalogId, int subid, DumpId dumpId)
5571 CommentItem *comments;
5574 /* Comments are SCHEMA not data */
5578 /* Search for comments associated with catalogId, using table */
5579 ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
5582 /* Is there one matching the subid? */
5583 while (ncomments > 0)
5585 if (comments->objsubid == subid)
5591 /* If a comment exists, build COMMENT ON statement */
5594 PQExpBuffer query = createPQExpBuffer();
5596 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
5597 appendStringLiteralAH(query, comments->descr, fout);
5598 appendPQExpBuffer(query, ";\n");
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.
5605 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5606 target, namespace, NULL, owner,
5607 false, "COMMENT", SECTION_NONE,
5608 query->data, "", NULL,
5612 destroyPQExpBuffer(query);
5617 * dumpTableComment --
5619 * As above, but dump comments for both the specified table (or view)
5623 dumpTableComment(Archive *fout, TableInfo *tbinfo,
5624 const char *reltypename)
5626 CommentItem *comments;
5631 /* Comments are SCHEMA not data */
5635 /* Search for comments associated with relation, using table */
5636 ncomments = findComments(fout,
5637 tbinfo->dobj.catId.tableoid,
5638 tbinfo->dobj.catId.oid,
5641 /* If comments exist, build COMMENT ON statements */
5645 query = createPQExpBuffer();
5646 target = createPQExpBuffer();
5648 while (ncomments > 0)
5650 const char *descr = comments->descr;
5651 int objsubid = comments->objsubid;
5655 resetPQExpBuffer(target);
5656 appendPQExpBuffer(target, "%s %s", reltypename,
5657 fmtId(tbinfo->dobj.name));
5659 resetPQExpBuffer(query);
5660 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5661 appendStringLiteralAH(query, descr, fout);
5662 appendPQExpBuffer(query, ";\n");
5664 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5666 tbinfo->dobj.namespace->dobj.name,
5667 NULL, tbinfo->rolname,
5668 false, "COMMENT", SECTION_NONE,
5669 query->data, "", NULL,
5670 &(tbinfo->dobj.dumpId), 1,
5673 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
5675 resetPQExpBuffer(target);
5676 appendPQExpBuffer(target, "COLUMN %s.",
5677 fmtId(tbinfo->dobj.name));
5678 appendPQExpBuffer(target, "%s",
5679 fmtId(tbinfo->attnames[objsubid - 1]));
5681 resetPQExpBuffer(query);
5682 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
5683 appendStringLiteralAH(query, descr, fout);
5684 appendPQExpBuffer(query, ";\n");
5686 ArchiveEntry(fout, nilCatalogId, createDumpId(),
5688 tbinfo->dobj.namespace->dobj.name,
5689 NULL, tbinfo->rolname,
5690 false, "COMMENT", SECTION_NONE,
5691 query->data, "", NULL,
5692 &(tbinfo->dobj.dumpId), 1,
5700 destroyPQExpBuffer(query);
5701 destroyPQExpBuffer(target);
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
5712 findComments(Archive *fout, Oid classoid, Oid objoid,
5713 CommentItem **items)
5715 /* static storage for table of comments */
5716 static CommentItem *comments = NULL;
5717 static int ncomments = -1;
5719 CommentItem *middle = NULL;
5724 /* Get comments if we didn't already */
5726 ncomments = collectComments(fout, &comments);
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.
5733 if (fout->remoteVersion < 70200)
5737 * Do binary search to find some item matching the object.
5740 high = &comments[ncomments - 1];
5743 middle = low + (high - low) / 2;
5745 if (classoid < middle->classoid)
5747 else if (classoid > middle->classoid)
5749 else if (objoid < middle->objoid)
5751 else if (objoid > middle->objoid)
5754 break; /* found a match */
5757 if (low > high) /* no matches */
5764 * Now determine how many items match the object. The search loop
5765 * invariant still holds: only items between low and high inclusive could
5769 while (middle > low)
5771 if (classoid != middle[-1].classoid ||
5772 objoid != middle[-1].objoid)
5781 while (middle <= high)
5783 if (classoid != middle->classoid ||
5784 objoid != middle->objoid)
5794 * collectComments --
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
5801 * The table is sorted by classoid/objid/objsubid for speed in lookup.
5804 collectComments(Archive *fout, CommentItem **items)
5814 CommentItem *comments;
5817 * Note we do NOT change source schema here; preserve the caller's
5821 query = createPQExpBuffer();
5823 if (fout->remoteVersion >= 70300)
5825 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5826 "FROM pg_catalog.pg_description "
5827 "ORDER BY classoid, objoid, objsubid");
5829 else if (fout->remoteVersion >= 70200)
5831 appendPQExpBuffer(query, "SELECT description, classoid, objoid, objsubid "
5832 "FROM pg_description "
5833 "ORDER BY classoid, objoid, objsubid");
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 "
5843 res = PQexec(g_conn, query->data);
5844 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
5846 /* Construct lookup table containing OIDs in numeric form */
5848 i_description = PQfnumber(res, "description");
5849 i_classoid = PQfnumber(res, "classoid");
5850 i_objoid = PQfnumber(res, "objoid");
5851 i_objsubid = PQfnumber(res, "objsubid");
5853 ntups = PQntuples(res);
5855 comments = (CommentItem *) malloc(ntups * sizeof(CommentItem));
5857 for (i = 0; i < ntups; i++)
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));
5865 /* Do NOT free the PGresult since we are keeping pointers into it */
5866 destroyPQExpBuffer(query);
5873 * dumpDumpableObject
5875 * This routine and its subsidiaries are responsible for creating
5876 * ArchiveEntries (TOC objects) for each object to be dumped.
5879 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
5881 switch (dobj->objType)
5884 dumpNamespace(fout, (NamespaceInfo *) dobj);
5887 dumpType(fout, (TypeInfo *) dobj);
5890 dumpShellType(fout, (ShellTypeInfo *) dobj);
5893 dumpFunc(fout, (FuncInfo *) dobj);
5896 dumpAgg(fout, (AggInfo *) dobj);
5899 dumpOpr(fout, (OprInfo *) dobj);
5902 dumpOpclass(fout, (OpclassInfo *) dobj);
5905 dumpOpfamily(fout, (OpfamilyInfo *) dobj);
5908 dumpConversion(fout, (ConvInfo *) dobj);
5911 dumpTable(fout, (TableInfo *) dobj);
5914 dumpAttrDef(fout, (AttrDefInfo *) dobj);
5917 dumpIndex(fout, (IndxInfo *) dobj);
5920 dumpRule(fout, (RuleInfo *) dobj);
5923 dumpTrigger(fout, (TriggerInfo *) dobj);
5926 dumpConstraint(fout, (ConstraintInfo *) dobj);
5928 case DO_FK_CONSTRAINT:
5929 dumpConstraint(fout, (ConstraintInfo *) dobj);
5932 dumpProcLang(fout, (ProcLangInfo *) dobj);
5935 dumpCast(fout, (CastInfo *) dobj);
5938 dumpTableData(fout, (TableDataInfo *) dobj);
5941 /* table rowtypes and array types are never dumped separately */
5944 dumpTSParser(fout, (TSParserInfo *) dobj);
5947 dumpTSDictionary(fout, (TSDictInfo *) dobj);
5950 dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
5953 dumpTSConfig(fout, (TSConfigInfo *) dobj);
5956 dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
5958 case DO_FOREIGN_SERVER:
5959 dumpForeignServer(fout, (ForeignServerInfo *) dobj);
5962 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5963 dobj->name, NULL, NULL, "",
5964 false, "BLOBS", SECTION_DATA,
5966 dobj->dependencies, dobj->nDeps,
5969 case DO_BLOB_COMMENTS:
5970 ArchiveEntry(fout, dobj->catId, dobj->dumpId,
5971 dobj->name, NULL, NULL, "",
5972 false, "BLOB COMMENTS", SECTION_DATA,
5974 dobj->dependencies, dobj->nDeps,
5975 dumpBlobComments, NULL);
5982 * writes out to fout the queries to recreate a user-defined namespace
5985 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
5991 /* Skip if not to be dumped */
5992 if (!nspinfo->dobj.dump || dataOnly)
5995 /* don't dump dummy namespace from pre-7.3 source */
5996 if (strlen(nspinfo->dobj.name) == 0)
5999 q = createPQExpBuffer();
6000 delq = createPQExpBuffer();
6002 qnspname = strdup(fmtId(nspinfo->dobj.name));
6004 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
6006 appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
6008 ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
6012 false, "SCHEMA", SECTION_PRE_DATA,
6013 q->data, delq->data, NULL,
6014 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
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);
6024 dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
6025 qnspname, NULL, nspinfo->dobj.name, NULL,
6026 nspinfo->rolname, nspinfo->nspacl);
6030 destroyPQExpBuffer(q);
6031 destroyPQExpBuffer(delq);
6036 * writes out to fout the queries to recreate a user-defined type
6039 dumpType(Archive *fout, TypeInfo *tinfo)
6041 /* Skip if not to be dumped */
6042 if (!tinfo->dobj.dump || dataOnly)
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);
6058 * writes out to fout the queries to recreate a user-defined enum type
6061 dumpEnumType(Archive *fout, TypeInfo *tinfo)
6063 PQExpBuffer q = createPQExpBuffer();
6064 PQExpBuffer delq = createPQExpBuffer();
6065 PQExpBuffer query = createPQExpBuffer();
6071 /* Set proper schema search path so regproc references list correctly */
6072 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6074 appendPQExpBuffer(query, "SELECT enumlabel FROM pg_catalog.pg_enum "
6075 "WHERE enumtypid = '%u'"
6077 tinfo->dobj.catId.oid);
6079 res = PQexec(g_conn, query->data);
6080 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6082 num = PQntuples(res);
6083 /* should be at least 1 value */
6086 write_msg(NULL, "no label definitions found for enum ID %u\n", tinfo->dobj.catId.oid);
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.
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++)
6103 label = PQgetvalue(res, i, 0);
6105 appendPQExpBuffer(q, ",\n");
6106 appendPQExpBuffer(q, " ");
6107 appendStringLiteralAH(q, label, fout);
6109 appendPQExpBuffer(q, "\n);\n");
6111 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6113 tinfo->dobj.namespace->dobj.name,
6115 tinfo->rolname, false,
6116 "TYPE", SECTION_PRE_DATA,
6117 q->data, delq->data, NULL,
6118 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6121 /* Dump Type Comments */
6122 resetPQExpBuffer(q);
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);
6130 destroyPQExpBuffer(q);
6131 destroyPQExpBuffer(delq);
6132 destroyPQExpBuffer(query);
6137 * writes out to fout the queries to recreate a user-defined base type
6140 dumpBaseType(Archive *fout, TypeInfo *tinfo)
6142 PQExpBuffer q = createPQExpBuffer();
6143 PQExpBuffer delq = createPQExpBuffer();
6144 PQExpBuffer query = createPQExpBuffer();
6163 char *typispreferred;
6169 bool typdefault_is_literal = false;
6171 /* Set proper schema search path so regproc references list correctly */
6172 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6174 /* Fetch type-specific details */
6175 if (fout->remoteVersion >= 80400)
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);
6194 else if (fout->remoteVersion >= 80300)
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);
6213 else if (fout->remoteVersion >= 80000)
6215 appendPQExpBuffer(query, "SELECT typlen, "
6216 "typinput, typoutput, typreceive, typsend, "
6217 "'-' AS typmodin, '-' AS typmodout, "
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);
6232 else if (fout->remoteVersion >= 70400)
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);
6251 else if (fout->remoteVersion >= 70300)
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);
6270 else if (fout->remoteVersion >= 70200)
6273 * Note: although pre-7.3 catalogs contain typreceive and typsend,
6274 * ignore them because they are not right.
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 "
6290 "WHERE oid = '%u'::oid",
6291 tinfo->dobj.catId.oid);
6293 else if (fout->remoteVersion >= 70100)
6296 * Ignore pre-7.2 typdefault; the field exists but has an unusable
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 "
6313 "WHERE oid = '%u'::oid",
6314 tinfo->dobj.catId.oid);
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 "
6333 "WHERE oid = '%u'::oid",
6334 tinfo->dobj.catId.oid);
6337 res = PQexec(g_conn, query->data);
6338 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6340 /* Expecting a single result only */
6341 ntups = PQntuples(res);
6344 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6345 "query returned %d rows instead of one: %s\n",
6347 ntups, query->data);
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")))
6376 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6377 typdefault_is_literal = true; /* it needs quotes */
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
6388 appendPQExpBuffer(delq, "DROP TYPE %s.",
6389 fmtId(tinfo->dobj.namespace->dobj.name));
6390 appendPQExpBuffer(delq, "%s CASCADE;\n",
6391 fmtId(tinfo->dobj.name));
6393 appendPQExpBuffer(q,
6394 "CREATE TYPE %s (\n"
6395 " INTERNALLENGTH = %s",
6396 fmtId(tinfo->dobj.name),
6397 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
6399 if (fout->remoteVersion >= 70300)
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);
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 */
6424 if (typdefault != NULL)
6426 appendPQExpBuffer(q, ",\n DEFAULT = ");
6427 if (typdefault_is_literal)
6428 appendStringLiteralAH(q, typdefault, fout);
6430 appendPQExpBufferStr(q, typdefault);
6433 if (OidIsValid(tinfo->typelem))
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);
6444 if (strcmp(typcategory, "U") != 0)
6446 appendPQExpBuffer(q, ",\n CATEGORY = ");
6447 appendStringLiteralAH(q, typcategory, fout);
6450 if (strcmp(typispreferred, "t") == 0)
6451 appendPQExpBuffer(q, ",\n PREFERRED = true");
6453 if (typdelim && strcmp(typdelim, ",") != 0)
6455 appendPQExpBuffer(q, ",\n DELIMITER = ");
6456 appendStringLiteralAH(q, typdelim, fout);
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");
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");
6477 if (strcmp(typbyval, "t") == 0)
6478 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
6480 appendPQExpBuffer(q, "\n);\n");
6482 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6484 tinfo->dobj.namespace->dobj.name,
6486 tinfo->rolname, false,
6487 "TYPE", SECTION_PRE_DATA,
6488 q->data, delq->data, NULL,
6489 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6492 /* Dump Type Comments */
6493 resetPQExpBuffer(q);
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);
6501 destroyPQExpBuffer(q);
6502 destroyPQExpBuffer(delq);
6503 destroyPQExpBuffer(query);
6508 * writes out to fout the queries to recreate a user-defined domain
6511 dumpDomain(Archive *fout, TypeInfo *tinfo)
6513 PQExpBuffer q = createPQExpBuffer();
6514 PQExpBuffer delq = createPQExpBuffer();
6515 PQExpBuffer query = createPQExpBuffer();
6522 bool typdefault_is_literal = false;
6524 /* Set proper schema search path so type references list correctly */
6525 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
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);
6536 res = PQexec(g_conn, query->data);
6537 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6539 /* Expecting a single result only */
6540 ntups = PQntuples(res);
6543 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
6544 "query returned %d rows instead of one: %s\n",
6546 ntups, query->data);
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")))
6556 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
6557 typdefault_is_literal = true; /* it needs quotes */
6562 appendPQExpBuffer(q,
6563 "CREATE DOMAIN %s AS %s",
6564 fmtId(tinfo->dobj.name),
6567 if (typnotnull[0] == 't')
6568 appendPQExpBuffer(q, " NOT NULL");
6570 if (typdefault != NULL)
6572 appendPQExpBuffer(q, " DEFAULT ");
6573 if (typdefault_is_literal)
6574 appendStringLiteralAH(q, typdefault, fout);
6576 appendPQExpBufferStr(q, typdefault);
6582 * Add any CHECK constraints for the domain
6584 for (i = 0; i < tinfo->nDomChecks; i++)
6586 ConstraintInfo *domcheck = &(tinfo->domChecks[i]);
6588 if (!domcheck->separate)
6589 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
6590 fmtId(domcheck->dobj.name), domcheck->condef);
6593 appendPQExpBuffer(q, ";\n");
6596 * DROP must be fully qualified in case same name appears in pg_catalog
6598 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
6599 fmtId(tinfo->dobj.namespace->dobj.name));
6600 appendPQExpBuffer(delq, "%s;\n",
6601 fmtId(tinfo->dobj.name));
6603 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6605 tinfo->dobj.namespace->dobj.name,
6607 tinfo->rolname, false,
6608 "DOMAIN", SECTION_PRE_DATA,
6609 q->data, delq->data, NULL,
6610 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6613 /* Dump Domain Comments */
6614 resetPQExpBuffer(q);
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);
6621 destroyPQExpBuffer(q);
6622 destroyPQExpBuffer(delq);
6623 destroyPQExpBuffer(query);
6628 * writes out to fout the queries to recreate a user-defined stand-alone
6632 dumpCompositeType(Archive *fout, TypeInfo *tinfo)
6634 PQExpBuffer q = createPQExpBuffer();
6635 PQExpBuffer delq = createPQExpBuffer();
6636 PQExpBuffer query = createPQExpBuffer();
6643 /* Set proper schema search path so type references list correctly */
6644 selectSourceSchema(tinfo->dobj.namespace->dobj.name);
6646 /* Fetch type specific details */
6647 /* We assume here that remoteVersion must be at least 70300 */
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);
6658 res = PQexec(g_conn, query->data);
6659 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
6661 /* Expecting at least a single result */
6662 ntups = PQntuples(res);
6665 write_msg(NULL, "query returned no rows: %s\n", query->data);
6669 i_attname = PQfnumber(res, "attname");
6670 i_atttypdefn = PQfnumber(res, "atttypdefn");
6672 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
6673 fmtId(tinfo->dobj.name));
6675 for (i = 0; i < ntups; i++)
6680 attname = PQgetvalue(res, i, i_attname);
6681 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
6683 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
6685 appendPQExpBuffer(q, ",");
6687 appendPQExpBuffer(q, "\n);\n");
6690 * DROP must be fully qualified in case same name appears in pg_catalog
6692 appendPQExpBuffer(delq, "DROP TYPE %s.",
6693 fmtId(tinfo->dobj.namespace->dobj.name));
6694 appendPQExpBuffer(delq, "%s;\n",
6695 fmtId(tinfo->dobj.name));
6697 ArchiveEntry(fout, tinfo->dobj.catId, tinfo->dobj.dumpId,
6699 tinfo->dobj.namespace->dobj.name,
6701 tinfo->rolname, false,
6702 "TYPE", SECTION_PRE_DATA,
6703 q->data, delq->data, NULL,
6704 tinfo->dobj.dependencies, tinfo->dobj.nDeps,
6708 /* Dump Type Comments */
6709 resetPQExpBuffer(q);
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);
6717 destroyPQExpBuffer(q);
6718 destroyPQExpBuffer(delq);
6719 destroyPQExpBuffer(query);
6724 * writes out to fout the queries to create a shell type
6726 * We dump a shell definition in advance of the I/O functions for the type.
6729 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
6733 /* Skip if not to be dumped */
6734 if (!stinfo->dobj.dump || dataOnly)
6737 q = createPQExpBuffer();
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.
6748 appendPQExpBuffer(q, "CREATE TYPE %s;\n",
6749 fmtId(stinfo->dobj.name));
6751 ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
6753 stinfo->dobj.namespace->dobj.name,
6755 stinfo->baseType->rolname, false,
6756 "SHELL TYPE", SECTION_PRE_DATA,
6758 stinfo->dobj.dependencies, stinfo->dobj.nDeps,
6761 destroyPQExpBuffer(q);
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.)
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.
6777 shouldDumpProcLangs(void)
6779 if (!include_everything)
6781 /* And they're schema not data */
6789 * writes out to fout the queries to recreate a user-defined
6790 * procedural language
6793 dumpProcLang(Archive *fout, ProcLangInfo *plang)
6801 FuncInfo *validatorInfo = NULL;
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.)
6814 funcInfo = findFuncByOid(plang->lanplcallfoid);
6815 if (funcInfo != NULL && !funcInfo->dobj.dump)
6816 funcInfo = NULL; /* treat not-dumped same as not-found */
6818 if (OidIsValid(plang->lanvalidator))
6820 validatorInfo = findFuncByOid(plang->lanvalidator);
6821 if (validatorInfo != NULL && !validatorInfo->dobj.dump)
6822 validatorInfo = NULL;
6826 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
6827 * with parameters. Otherwise, dump only if shouldDumpProcLangs() says to
6830 useParams = (funcInfo != NULL &&
6831 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
6833 if (!useParams && !shouldDumpProcLangs())
6836 defqry = createPQExpBuffer();
6837 delqry = createPQExpBuffer();
6839 qlanname = strdup(fmtId(plang->dobj.name));
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.
6847 lanschema = funcInfo->dobj.namespace->dobj.name;
6851 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
6854 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
6855 (useParams && plang->lanpltrusted) ? "TRUSTED " : "",
6859 appendPQExpBuffer(defqry, " HANDLER %s",
6860 fmtId(funcInfo->dobj.name));
6861 if (OidIsValid(plang->lanvalidator))
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));
6872 appendPQExpBuffer(defqry, ";\n");
6874 ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
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,
6882 /* Dump Proc Lang Comments */
6883 resetPQExpBuffer(defqry);
6884 appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
6885 dumpComment(fout, defqry->data,
6887 plang->dobj.catId, 0, plang->dobj.dumpId);
6889 if (plang->lanpltrusted)
6890 dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
6891 qlanname, NULL, plang->dobj.name,
6893 plang->lanowner, plang->lanacl);
6897 destroyPQExpBuffer(defqry);
6898 destroyPQExpBuffer(delqry);
6902 * format_function_arguments: generate function name and argument list
6904 * This is used when we can rely on pg_get_function_arguments to format
6905 * the argument list.
6907 static char *format_function_arguments(FuncInfo *finfo, char *funcargs)
6911 initPQExpBuffer(&fn);
6912 appendPQExpBuffer(&fn, "%s(%s)", fmtId(finfo->dobj.name), funcargs);
6917 * format_function_arguments_old: generate function name and argument list
6919 * The argument type names are qualified if needed. The function name
6920 * is never qualified.
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.
6925 * Any or all of allargtypes, argmodes, argnames may be NULL.
6928 format_function_arguments_old(FuncInfo *finfo, int nallargs,
6936 initPQExpBuffer(&fn);
6937 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
6938 for (j = 0; j < nallargs; j++)
6942 const char *argmode;
6943 const char *argname;
6945 typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
6946 typname = getFormattedTypeName(typid, zeroAsOpaque);
6950 switch (argmodes[j][0])
6955 case PROARGMODE_OUT:
6958 case PROARGMODE_INOUT:
6962 write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
6970 argname = argnames ? argnames[j] : (char *) NULL;
6971 if (argname && argname[0] == '\0')
6974 appendPQExpBuffer(&fn, "%s%s%s%s%s",
6975 (j > 0) ? ", " : "",
6977 argname ? fmtId(argname) : "",
6982 appendPQExpBuffer(&fn, ")");
6987 * format_function_signature: generate function name and argument list
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.
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.
6997 format_function_signature(FuncInfo *finfo, bool honor_quotes)
7002 initPQExpBuffer(&fn);
7004 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
7006 appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
7007 for (j = 0; j < finfo->nargs; j++)
7011 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
7013 appendPQExpBuffer(&fn, "%s%s",
7014 (j > 0) ? ", " : "",
7018 appendPQExpBuffer(&fn, ")");
7025 * dump out one function
7028 dumpFunc(Archive *fout, FuncInfo *finfo)
7035 char *funcsig; /* identity signature */
7036 char *funcfullsig; /* full signature */
7045 char *proallargtypes;
7058 char **allargtypes = NULL;
7059 char **argmodes = NULL;
7060 char **argnames = NULL;
7061 char **configitems = NULL;
7062 int nconfigitems = 0;
7065 /* Skip if not to be dumped */
7066 if (!finfo->dobj.dump || dataOnly)
7069 query = createPQExpBuffer();
7070 q = createPQExpBuffer();
7071 delqry = createPQExpBuffer();
7072 asPart = createPQExpBuffer();
7074 /* Set proper schema search path so type references list correctly */
7075 selectSourceSchema(finfo->dobj.namespace->dobj.name);
7077 /* Fetch function-specific details */
7078 if (g_fout->remoteVersion >= 80400)
7081 * In 8.4 and up we rely on pg_get_function_arguments and
7082 * pg_get_function_result instead of examining proallargtypes etc.
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);
7096 else if (g_fout->remoteVersion >= 80300)
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);
7109 else if (g_fout->remoteVersion >= 80100)
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);
7122 else if (g_fout->remoteVersion >= 80000)
7124 appendPQExpBuffer(query,
7125 "SELECT proretset, prosrc, probin, "
7126 "null AS proallargtypes, "
7127 "null AS proargmodes, "
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);
7137 else if (g_fout->remoteVersion >= 70300)
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);
7152 else if (g_fout->remoteVersion >= 70100)
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, "
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 "
7166 "WHERE oid = '%u'::oid",
7167 finfo->dobj.catId.oid);
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 "
7183 "WHERE oid = '%u'::oid",
7184 finfo->dobj.catId.oid);
7187 res = PQexec(g_conn, query->data);
7188 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7190 /* Expecting a single result only */
7191 ntups = PQntuples(res);
7194 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7195 "query returned %d rows instead of one: %s\n",
7197 ntups, query->data);
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)
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;
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;
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"));
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.
7233 if (probin[0] != '\0' && strcmp(probin, "-") != 0)
7235 appendPQExpBuffer(asPart, "AS ");
7236 appendStringLiteralAH(asPart, probin, fout);
7237 if (strcmp(prosrc, "-") != 0)
7239 appendPQExpBuffer(asPart, ", ");
7242 * where we have bin, use dollar quoting if allowed and src
7243 * contains quote or backslash; else use regular quoting.
7245 if (disable_dollar_quoting ||
7246 (strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
7247 appendStringLiteralAH(asPart, prosrc, fout);
7249 appendStringLiteralDQ(asPart, prosrc, NULL);
7254 if (strcmp(prosrc, "-") != 0)
7256 appendPQExpBuffer(asPart, "AS ");
7257 /* with no bin, dollar quote src unconditionally if allowed */
7258 if (disable_dollar_quoting)
7259 appendStringLiteralAH(asPart, prosrc, fout);
7261 appendStringLiteralDQ(asPart, prosrc, NULL);
7265 nallargs = finfo->nargs; /* unless we learn different from allargs */
7267 if (proallargtypes && *proallargtypes)
7271 if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
7272 nitems < finfo->nargs)
7274 write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
7283 if (proargmodes && *proargmodes)
7287 if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
7290 write_msg(NULL, "WARNING: could not parse proargmodes array\n");
7297 if (proargnames && *proargnames)
7301 if (!parsePGArray(proargnames, &argnames, &nitems) ||
7304 write_msg(NULL, "WARNING: could not parse proargnames array\n");
7311 if (proconfig && *proconfig)
7313 if (!parsePGArray(proconfig, &configitems, &nconfigitems))
7315 write_msg(NULL, "WARNING: could not parse proconfig array\n");
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);
7331 /* pre-8.4, do it ourselves */
7332 funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
7333 argmodes, argnames);
7334 funcfullsig = funcsig;
7337 funcsig_tag = format_function_signature(finfo, false);
7340 * DROP must be fully qualified in case same name appears in pg_catalog
7342 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
7343 fmtId(finfo->dobj.namespace->dobj.name),
7346 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
7348 appendPQExpBuffer(q, "RETURNS %s", funcresult);
7351 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
7352 appendPQExpBuffer(q, "RETURNS %s%s",
7353 (proretset[0] == 't') ? "SETOF " : "",
7358 appendPQExpBuffer(q, "\n LANGUAGE %s", fmtId(lanname));
7360 if (proiswindow[0] == 't')
7361 appendPQExpBuffer(q, " WINDOW");
7363 if (provolatile[0] != PROVOLATILE_VOLATILE)
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)
7371 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
7377 if (proisstrict[0] == 't')
7378 appendPQExpBuffer(q, " STRICT");
7380 if (prosecdef[0] == 't')
7381 appendPQExpBuffer(q, " SECURITY DEFINER");
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.
7388 if (strcmp(procost, "0") != 0)
7390 if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
7392 /* default cost is 1 */
7393 if (strcmp(procost, "1") != 0)
7394 appendPQExpBuffer(q, " COST %s", procost);
7398 /* default cost is 100 */
7399 if (strcmp(procost, "100") != 0)
7400 appendPQExpBuffer(q, " COST %s", procost);
7403 if (proretset[0] == 't' &&
7404 strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
7405 appendPQExpBuffer(q, " ROWS %s", prorows);
7407 for (i = 0; i < nconfigitems; i++)
7409 /* we feel free to scribble on configitems[] here */
7410 char *configitem = configitems[i];
7413 pos = strchr(configitem, '=');
7417 appendPQExpBuffer(q, "\n SET %s TO ", fmtId(configitem));
7420 * Some GUC variable names are 'LIST' type and hence must not be
7423 if (pg_strcasecmp(configitem, "DateStyle") == 0
7424 || pg_strcasecmp(configitem, "search_path") == 0)
7425 appendPQExpBuffer(q, "%s", pos);
7427 appendStringLiteralAH(q, pos, fout);
7430 appendPQExpBuffer(q, "\n %s;\n", asPart->data);
7432 ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
7434 finfo->dobj.namespace->dobj.name,
7436 finfo->rolname, false,
7437 "FUNCTION", SECTION_PRE_DATA,
7438 q->data, delqry->data, NULL,
7439 finfo->dobj.dependencies, finfo->dobj.nDeps,
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);
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);
7456 destroyPQExpBuffer(query);
7457 destroyPQExpBuffer(q);
7458 destroyPQExpBuffer(delqry);
7459 destroyPQExpBuffer(asPart);
7474 * Dump a user-defined cast
7477 dumpCast(Archive *fout, CastInfo *cast)
7481 PQExpBuffer castsig;
7482 FuncInfo *funcInfo = NULL;
7483 TypeInfo *sourceInfo;
7484 TypeInfo *targetInfo;
7489 if (OidIsValid(cast->castfunc))
7491 funcInfo = findFuncByOid(cast->castfunc);
7492 if (funcInfo == NULL)
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_".
7502 sourceInfo = findTypeByOid(cast->castsource);
7503 targetInfo = findTypeByOid(cast->casttarget);
7505 if (sourceInfo == NULL || targetInfo == NULL)
7509 * Skip this cast if all objects are from pg_
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)
7518 * Skip cast if function isn't from pg_ and is not to be dumped.
7521 strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7522 !funcInfo->dobj.dump)
7526 * Same for the source type
7528 if (strncmp(sourceInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7529 !sourceInfo->dobj.dump)
7533 * and the target type.
7535 if (strncmp(targetInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
7536 !targetInfo->dobj.dump)
7539 /* Make sure we are in proper schema (needed for getFormattedTypeName) */
7540 selectSourceSchema("pg_catalog");
7542 defqry = createPQExpBuffer();
7543 delqry = createPQExpBuffer();
7544 castsig = createPQExpBuffer();
7546 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
7547 getFormattedTypeName(cast->castsource, zeroAsNone),
7548 getFormattedTypeName(cast->casttarget, zeroAsNone));
7550 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
7551 getFormattedTypeName(cast->castsource, zeroAsNone),
7552 getFormattedTypeName(cast->casttarget, zeroAsNone));
7554 switch(cast->castmethod)
7556 case COERCION_METHOD_BINARY:
7557 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
7559 case COERCION_METHOD_INOUT:
7560 appendPQExpBuffer(defqry, "WITH INOUT");
7562 case COERCION_METHOD_FUNCTION:
7564 * Always qualify the function name, in case it is not in
7565 * pg_catalog schema (format_function_signature won't qualify it).
7567 appendPQExpBuffer(defqry, "WITH FUNCTION %s.",
7568 fmtId(funcInfo->dobj.namespace->dobj.name));
7569 appendPQExpBuffer(defqry, "%s",
7570 format_function_signature(funcInfo, true));
7573 write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
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");
7582 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
7583 getFormattedTypeName(cast->castsource, zeroAsNone),
7584 getFormattedTypeName(cast->casttarget, zeroAsNone));
7586 ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
7588 "pg_catalog", NULL, "",
7589 false, "CAST", SECTION_PRE_DATA,
7590 defqry->data, delqry->data, NULL,
7591 cast->dobj.dependencies, cast->dobj.nDeps,
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,
7601 cast->dobj.catId, 0, cast->dobj.dumpId);
7603 destroyPQExpBuffer(defqry);
7604 destroyPQExpBuffer(delqry);
7605 destroyPQExpBuffer(castsig);
7610 * write out a single operator definition
7613 dumpOpr(Archive *fout, OprInfo *oprinfo)
7619 PQExpBuffer details;
7644 /* Skip if not to be dumped */
7645 if (!oprinfo->dobj.dump || dataOnly)
7649 * some operators are invalid because they were the result of user
7650 * defining operators before commutators exist
7652 if (!OidIsValid(oprinfo->oprcode))
7655 query = createPQExpBuffer();
7656 q = createPQExpBuffer();
7657 delq = createPQExpBuffer();
7658 oprid = createPQExpBuffer();
7659 details = createPQExpBuffer();
7661 /* Make sure we are in proper schema so regoperator works correctly */
7662 selectSourceSchema(oprinfo->dobj.namespace->dobj.name);
7664 if (g_fout->remoteVersion >= 80300)
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);
7679 else if (g_fout->remoteVersion >= 70300)
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, "
7691 "FROM pg_catalog.pg_operator "
7692 "WHERE oid = '%u'::pg_catalog.oid",
7693 oprinfo->dobj.catId.oid);
7695 else if (g_fout->remoteVersion >= 70100)
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, "
7706 "WHERE oid = '%u'::oid",
7707 oprinfo->dobj.catId.oid);
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, "
7720 "WHERE oid = '%u'::oid",
7721 oprinfo->dobj.catId.oid);
7724 res = PQexec(g_conn, query->data);
7725 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
7727 /* Expecting a single result only */
7728 ntups = PQntuples(res);
7731 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7732 "query returned %d rows instead of one: %s\n",
7734 ntups, query->data);
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");
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);
7760 appendPQExpBuffer(details, " PROCEDURE = %s",
7761 convertRegProcReference(oprcode));
7763 appendPQExpBuffer(oprid, "%s (",
7764 oprinfo->dobj.name);
7767 * right unary means there's a left arg and left unary means there's a
7770 if (strcmp(oprkind, "r") == 0 ||
7771 strcmp(oprkind, "b") == 0)
7773 if (g_fout->remoteVersion >= 70100)
7776 name = fmtId(oprleft);
7777 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
7778 appendPQExpBuffer(oprid, "%s", name);
7781 appendPQExpBuffer(oprid, "NONE");
7783 if (strcmp(oprkind, "l") == 0 ||
7784 strcmp(oprkind, "b") == 0)
7786 if (g_fout->remoteVersion >= 70100)
7789 name = fmtId(oprright);
7790 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
7791 appendPQExpBuffer(oprid, ", %s)", name);
7794 appendPQExpBuffer(oprid, ", NONE)");
7796 name = convertOperatorReference(oprcom);
7798 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
7800 name = convertOperatorReference(oprnegate);
7802 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
7804 if (strcmp(oprcanmerge, "t") == 0)
7805 appendPQExpBuffer(details, ",\n MERGES");
7807 if (strcmp(oprcanhash, "t") == 0)
7808 appendPQExpBuffer(details, ",\n HASHES");
7810 name = convertRegProcReference(oprrest);
7812 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
7814 name = convertRegProcReference(oprjoin);
7816 appendPQExpBuffer(details, ",\n JOIN = %s", name);
7819 * DROP must be fully qualified in case same name appears in pg_catalog
7821 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
7822 fmtId(oprinfo->dobj.namespace->dobj.name),
7825 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
7826 oprinfo->dobj.name, details->data);
7828 ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
7830 oprinfo->dobj.namespace->dobj.name,
7833 false, "OPERATOR", SECTION_PRE_DATA,
7834 q->data, delq->data, NULL,
7835 oprinfo->dobj.dependencies, oprinfo->dobj.nDeps,
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);
7847 destroyPQExpBuffer(query);
7848 destroyPQExpBuffer(q);
7849 destroyPQExpBuffer(delq);
7850 destroyPQExpBuffer(oprid);
7851 destroyPQExpBuffer(details);
7855 * Convert a function reference obtained from pg_operator
7857 * Returns what to print, or NULL if function references is InvalidOid
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.
7863 convertRegProcReference(const char *proc)
7865 /* In all cases "-" means a null reference */
7866 if (strcmp(proc, "-") == 0)
7869 if (g_fout->remoteVersion >= 70300)
7875 name = strdup(proc);
7876 /* find non-double-quoted left paren */
7878 for (paren = name; *paren; paren++)
7880 if (*paren == '(' && !inquote)
7891 /* REGPROC before 7.3 does not quote its result */
7896 * Convert an operator cross-reference obtained from pg_operator
7898 * Returns what to print, or NULL to print nothing
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.
7906 convertOperatorReference(const char *opr)
7910 /* In all cases "0" means a null reference */
7911 if (strcmp(opr, "0") == 0)
7914 if (g_fout->remoteVersion >= 70300)
7923 /* find non-double-quoted left paren, and check for non-quoted dot */
7926 for (ptr = name; *ptr; ptr++)
7930 else if (*ptr == '.' && !inquote)
7932 else if (*ptr == '(' && !inquote)
7938 /* If not schema-qualified, don't need to add OPERATOR() */
7941 oname = malloc(strlen(name) + 11);
7942 sprintf(oname, "OPERATOR(%s)", name);
7947 oprInfo = findOprByOid(atooid(opr));
7948 if (oprInfo == NULL)
7950 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
7954 return oprInfo->dobj.name;
7958 * Convert a function OID obtained from pg_ts_parser or pg_ts_template
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!
7966 convertTSFunction(Oid funcOid)
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);
7978 ntups = PQntuples(res);
7981 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
7982 "query returned %d rows instead of one: %s\n",
7988 result = strdup(PQgetvalue(res, 0, 0));
7998 * write out a single operator class definition
8001 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
8033 /* Skip if not to be dumped */
8034 if (!opcinfo->dobj.dump || dataOnly)
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
8042 if (g_fout->remoteVersion < 70300)
8045 query = createPQExpBuffer();
8046 q = createPQExpBuffer();
8047 delq = createPQExpBuffer();
8049 /* Make sure we are in proper schema so regoperator works correctly */
8050 selectSourceSchema(opcinfo->dobj.namespace->dobj.name);
8052 /* Get additional fields from the pg_opclass row */
8053 if (g_fout->remoteVersion >= 80300)
8055 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8056 "opckeytype::pg_catalog.regtype, "
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);
8069 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
8070 "opckeytype::pg_catalog.regtype, "
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);
8080 res = PQexec(g_conn, query->data);
8081 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8083 /* Expecting a single result only */
8084 ntups = PQntuples(res);
8087 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8088 "query returned %d rows instead of one: %s\n",
8090 ntups, query->data);
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");
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));
8110 * DROP must be fully qualified in case same name appears in pg_catalog
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",
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",
8127 if (strlen(opcfamily) > 0 &&
8128 (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
8129 strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
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));
8136 appendPQExpBuffer(q, " AS\n ");
8140 if (strcmp(opckeytype, "-") != 0)
8142 appendPQExpBuffer(q, "STORAGE %s",
8150 * Now fetch and print the OPERATOR entries (pg_amop rows).
8152 resetPQExpBuffer(query);
8154 if (g_fout->remoteVersion >= 80400)
8157 * Print only those opfamily members that are tied to the opclass by
8158 * pg_depend entries.
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?
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);
8174 else if (g_fout->remoteVersion >= 80300)
8177 * Print only those opfamily members that are tied to the opclass by
8178 * pg_depend entries.
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);
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);
8200 res = PQexec(g_conn, query->data);
8201 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8203 ntups = PQntuples(res);
8205 i_amopstrategy = PQfnumber(res, "amopstrategy");
8206 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
8207 i_amopopr = PQfnumber(res, "amopopr");
8209 for (i = 0; i < ntups; i++)
8211 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
8212 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
8213 amopopr = PQgetvalue(res, i, i_amopopr);
8216 appendPQExpBuffer(q, " ,\n ");
8218 appendPQExpBuffer(q, "OPERATOR %s %s",
8219 amopstrategy, amopopr);
8220 if (strcmp(amopreqcheck, "t") == 0)
8221 appendPQExpBuffer(q, " RECHECK");
8229 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8231 resetPQExpBuffer(query);
8233 if (g_fout->remoteVersion >= 80300)
8236 * Print only those opfamily members that are tied to the opclass by
8237 * pg_depend entries.
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);
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);
8259 res = PQexec(g_conn, query->data);
8260 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8262 ntups = PQntuples(res);
8264 i_amprocnum = PQfnumber(res, "amprocnum");
8265 i_amproc = PQfnumber(res, "amproc");
8267 for (i = 0; i < ntups; i++)
8269 amprocnum = PQgetvalue(res, i, i_amprocnum);
8270 amproc = PQgetvalue(res, i, i_amproc);
8273 appendPQExpBuffer(q, " ,\n ");
8275 appendPQExpBuffer(q, "FUNCTION %s %s",
8283 appendPQExpBuffer(q, ";\n");
8285 ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
8287 opcinfo->dobj.namespace->dobj.name,
8290 false, "OPERATOR CLASS", SECTION_PRE_DATA,
8291 q->data, delq->data, NULL,
8292 opcinfo->dobj.dependencies, opcinfo->dobj.nDeps,
8295 /* Dump Operator Class Comments */
8296 resetPQExpBuffer(q);
8297 appendPQExpBuffer(q, "OPERATOR CLASS %s",
8298 fmtId(opcinfo->dobj.name));
8299 appendPQExpBuffer(q, " USING %s",
8301 dumpComment(fout, q->data,
8302 NULL, opcinfo->rolname,
8303 opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
8306 destroyPQExpBuffer(query);
8307 destroyPQExpBuffer(q);
8308 destroyPQExpBuffer(delq);
8313 * write out a single operator family definition
8316 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
8323 PGresult *res_procs;
8331 int i_amproclefttype;
8332 int i_amprocrighttype;
8339 char *amproclefttype;
8340 char *amprocrighttype;
8344 /* Skip if not to be dumped */
8345 if (!opfinfo->dobj.dump || dataOnly)
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
8357 query = createPQExpBuffer();
8358 q = createPQExpBuffer();
8359 delq = createPQExpBuffer();
8361 /* Make sure we are in proper schema so regoperator works correctly */
8362 selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
8365 * Fetch only those opfamily members that are tied directly to the
8366 * opfamily by pg_depend entries.
8368 if (g_fout->remoteVersion >= 80400)
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?
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);
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);
8398 res_ops = PQexec(g_conn, query->data);
8399 check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
8401 resetPQExpBuffer(query);
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);
8415 res_procs = PQexec(g_conn, query->data);
8416 check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
8418 if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
8420 /* No loose members, so check contained opclasses */
8421 resetPQExpBuffer(query);
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) "
8432 opfinfo->dobj.catId.oid);
8434 res = PQexec(g_conn, query->data);
8435 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8437 if (PQntuples(res) == 0)
8439 /* no need to dump it, so bail out */
8443 destroyPQExpBuffer(query);
8444 destroyPQExpBuffer(q);
8445 destroyPQExpBuffer(delq);
8452 /* Get additional fields from the pg_opfamily row */
8453 resetPQExpBuffer(query);
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);
8461 res = PQexec(g_conn, query->data);
8462 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8464 /* Expecting a single result only */
8465 ntups = PQntuples(res);
8468 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8469 "query returned %d rows instead of one: %s\n",
8471 ntups, query->data);
8475 i_amname = PQfnumber(res, "amname");
8477 /* amname will still be needed after we PQclear res */
8478 amname = strdup(PQgetvalue(res, 0, i_amname));
8481 * DROP must be fully qualified in case same name appears in pg_catalog
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",
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",
8498 /* Do we need an ALTER to add loose members? */
8499 if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
8501 appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
8502 fmtId(opfinfo->dobj.name));
8503 appendPQExpBuffer(q, " USING %s ADD\n ",
8509 * Now fetch and print the OPERATOR entries (pg_amop rows).
8511 ntups = PQntuples(res_ops);
8513 i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
8514 i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
8515 i_amopopr = PQfnumber(res_ops, "amopopr");
8517 for (i = 0; i < ntups; i++)
8519 amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
8520 amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
8521 amopopr = PQgetvalue(res_ops, i, i_amopopr);
8524 appendPQExpBuffer(q, " ,\n ");
8526 appendPQExpBuffer(q, "OPERATOR %s %s",
8527 amopstrategy, amopopr);
8528 if (strcmp(amopreqcheck, "t") == 0)
8529 appendPQExpBuffer(q, " RECHECK");
8535 * Now fetch and print the FUNCTION entries (pg_amproc rows).
8537 ntups = PQntuples(res_procs);
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");
8544 for (i = 0; i < ntups; i++)
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);
8552 appendPQExpBuffer(q, " ,\n ");
8554 appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
8555 amprocnum, amproclefttype, amprocrighttype,
8561 appendPQExpBuffer(q, ";\n");
8564 ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
8566 opfinfo->dobj.namespace->dobj.name,
8569 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
8570 q->data, delq->data, NULL,
8571 opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
8574 /* Dump Operator Family Comments */
8575 resetPQExpBuffer(q);
8576 appendPQExpBuffer(q, "OPERATOR FAMILY %s",
8577 fmtId(opfinfo->dobj.name));
8578 appendPQExpBuffer(q, " USING %s",
8580 dumpComment(fout, q->data,
8581 NULL, opfinfo->rolname,
8582 opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
8587 destroyPQExpBuffer(query);
8588 destroyPQExpBuffer(q);
8589 destroyPQExpBuffer(delq);
8594 * write out a single conversion definition
8597 dumpConversion(Archive *fout, ConvInfo *convinfo)
8602 PQExpBuffer details;
8606 int i_conforencoding;
8607 int i_contoencoding;
8610 const char *conname;
8611 const char *conforencoding;
8612 const char *contoencoding;
8613 const char *conproc;
8616 /* Skip if not to be dumped */
8617 if (!convinfo->dobj.dump || dataOnly)
8620 query = createPQExpBuffer();
8621 q = createPQExpBuffer();
8622 delq = createPQExpBuffer();
8623 details = createPQExpBuffer();
8625 /* Make sure we are in proper schema */
8626 selectSourceSchema(convinfo->dobj.namespace->dobj.name);
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);
8637 res = PQexec(g_conn, query->data);
8638 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8640 /* Expecting a single result only */
8641 ntups = PQntuples(res);
8644 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8645 "query returned %d rows instead of one: %s\n",
8647 ntups, query->data);
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");
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');
8664 * DROP must be fully qualified in case same name appears in pg_catalog
8666 appendPQExpBuffer(delq, "DROP CONVERSION %s",
8667 fmtId(convinfo->dobj.namespace->dobj.name));
8668 appendPQExpBuffer(delq, ".%s;\n",
8669 fmtId(convinfo->dobj.name));
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);
8680 ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
8681 convinfo->dobj.name,
8682 convinfo->dobj.namespace->dobj.name,
8685 false, "CONVERSION", SECTION_PRE_DATA,
8686 q->data, delq->data, NULL,
8687 convinfo->dobj.dependencies, convinfo->dobj.nDeps,
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);
8699 destroyPQExpBuffer(query);
8700 destroyPQExpBuffer(q);
8701 destroyPQExpBuffer(delq);
8702 destroyPQExpBuffer(details);
8706 * format_aggregate_signature: generate aggregate name and argument list
8708 * The argument type names are qualified if needed. The aggregate name
8709 * is never qualified.
8712 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
8714 PQExpBufferData buf;
8717 initPQExpBuffer(&buf);
8719 appendPQExpBuffer(&buf, "%s",
8720 fmtId(agginfo->aggfn.dobj.name));
8722 appendPQExpBuffer(&buf, "%s", agginfo->aggfn.dobj.name);
8724 if (agginfo->aggfn.nargs == 0)
8725 appendPQExpBuffer(&buf, "(*)");
8728 appendPQExpBuffer(&buf, "(");
8729 for (j = 0; j < agginfo->aggfn.nargs; j++)
8733 typname = getFormattedTypeName(agginfo->aggfn.argtypes[j], zeroAsOpaque);
8735 appendPQExpBuffer(&buf, "%s%s",
8736 (j > 0) ? ", " : "",
8740 appendPQExpBuffer(&buf, ")");
8747 * write out a single aggregate definition
8750 dumpAgg(Archive *fout, AggInfo *agginfo)
8755 PQExpBuffer details;
8766 const char *aggtransfn;
8767 const char *aggfinalfn;
8768 const char *aggsortop;
8769 const char *aggtranstype;
8770 const char *agginitval;
8773 /* Skip if not to be dumped */
8774 if (!agginfo->aggfn.dobj.dump || dataOnly)
8777 query = createPQExpBuffer();
8778 q = createPQExpBuffer();
8779 delq = createPQExpBuffer();
8780 details = createPQExpBuffer();
8782 /* Make sure we are in proper schema */
8783 selectSourceSchema(agginfo->aggfn.dobj.namespace->dobj.name);
8785 /* Get aggregate-specific details */
8786 if (g_fout->remoteVersion >= 80100)
8788 appendPQExpBuffer(query, "SELECT aggtransfn, "
8789 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
8790 "aggsortop::pg_catalog.regoperator, "
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);
8798 else if (g_fout->remoteVersion >= 70300)
8800 appendPQExpBuffer(query, "SELECT aggtransfn, "
8801 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
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);
8810 else if (g_fout->remoteVersion >= 70100)
8812 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
8813 "format_type(aggtranstype, NULL) AS aggtranstype, "
8816 "'t'::boolean AS convertok "
8817 "FROM pg_aggregate "
8818 "WHERE oid = '%u'::oid",
8819 agginfo->aggfn.dobj.catId.oid);
8823 appendPQExpBuffer(query, "SELECT aggtransfn1 AS aggtransfn, "
8825 "(SELECT typname FROM pg_type WHERE oid = aggtranstype1) AS aggtranstype, "
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);
8834 res = PQexec(g_conn, query->data);
8835 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
8837 /* Expecting a single result only */
8838 ntups = PQntuples(res);
8841 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
8842 "query returned %d rows instead of one: %s\n",
8844 ntups, query->data);
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");
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');
8862 aggsig = format_aggregate_signature(agginfo, fout, true);
8863 aggsig_tag = format_aggregate_signature(agginfo, fout, false);
8867 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
8872 if (g_fout->remoteVersion >= 70300)
8874 /* If using 7.3's regproc or regtype, data is already quoted */
8875 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8879 else if (g_fout->remoteVersion >= 70100)
8881 /* format_type quotes, regproc does not */
8882 appendPQExpBuffer(details, " SFUNC = %s,\n STYPE = %s",
8888 /* need quotes all around */
8889 appendPQExpBuffer(details, " SFUNC = %s,\n",
8891 appendPQExpBuffer(details, " STYPE = %s",
8892 fmtId(aggtranstype));
8895 if (!PQgetisnull(res, 0, i_agginitval))
8897 appendPQExpBuffer(details, ",\n INITCOND = ");
8898 appendStringLiteralAH(details, agginitval, fout);
8901 if (strcmp(aggfinalfn, "-") != 0)
8903 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
8907 aggsortop = convertOperatorReference(aggsortop);
8910 appendPQExpBuffer(details, ",\n SORTOP = %s",
8915 * DROP must be fully qualified in case same name appears in pg_catalog
8917 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
8918 fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
8921 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
8922 aggsig, details->data);
8924 ArchiveEntry(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8926 agginfo->aggfn.dobj.namespace->dobj.name,
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,
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);
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.
8949 aggsig = format_function_signature(&agginfo->aggfn, true);
8950 aggsig_tag = format_function_signature(&agginfo->aggfn, false);
8952 dumpACL(fout, agginfo->aggfn.dobj.catId, agginfo->aggfn.dobj.dumpId,
8954 aggsig, NULL, aggsig_tag,
8955 agginfo->aggfn.dobj.namespace->dobj.name,
8956 agginfo->aggfn.rolname, agginfo->aggfn.proacl);
8963 destroyPQExpBuffer(query);
8964 destroyPQExpBuffer(q);
8965 destroyPQExpBuffer(delq);
8966 destroyPQExpBuffer(details);
8971 * write out a single text search parser
8974 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
8979 /* Skip if not to be dumped */
8980 if (!prsinfo->dobj.dump || dataOnly)
8983 q = createPQExpBuffer();
8984 delq = createPQExpBuffer();
8986 /* Make sure we are in proper schema */
8987 selectSourceSchema(prsinfo->dobj.namespace->dobj.name);
8989 appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
8990 fmtId(prsinfo->dobj.name));
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));
9005 * DROP must be fully qualified in case same name appears in pg_catalog
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));
9012 ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
9014 prsinfo->dobj.namespace->dobj.name,
9017 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
9018 q->data, delq->data, NULL,
9019 prsinfo->dobj.dependencies, prsinfo->dobj.nDeps,
9022 /* Dump Parser Comments */
9023 resetPQExpBuffer(q);
9024 appendPQExpBuffer(q, "TEXT SEARCH PARSER %s",
9025 fmtId(prsinfo->dobj.name));
9026 dumpComment(fout, q->data,
9028 prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
9030 destroyPQExpBuffer(q);
9031 destroyPQExpBuffer(delq);
9036 * write out a single text search dictionary
9039 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
9049 /* Skip if not to be dumped */
9050 if (!dictinfo->dobj.dump || dataOnly)
9053 q = createPQExpBuffer();
9054 delq = createPQExpBuffer();
9055 query = createPQExpBuffer();
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);
9068 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9069 "query returned %d rows instead of one: %s\n",
9071 ntups, query->data);
9074 nspname = PQgetvalue(res, 0, 0);
9075 tmplname = PQgetvalue(res, 0, 1);
9077 /* Make sure we are in proper schema */
9078 selectSourceSchema(dictinfo->dobj.namespace->dobj.name);
9080 appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
9081 fmtId(dictinfo->dobj.name));
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));
9090 /* the dictinitoption can be dumped straight into the command */
9091 if (dictinfo->dictinitoption)
9092 appendPQExpBuffer(q, ",\n %s", dictinfo->dictinitoption);
9094 appendPQExpBuffer(q, " );\n");
9097 * DROP must be fully qualified in case same name appears in pg_catalog
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));
9104 ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
9105 dictinfo->dobj.name,
9106 dictinfo->dobj.namespace->dobj.name,
9109 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
9110 q->data, delq->data, NULL,
9111 dictinfo->dobj.dependencies, dictinfo->dobj.nDeps,
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);
9122 destroyPQExpBuffer(q);
9123 destroyPQExpBuffer(delq);
9124 destroyPQExpBuffer(query);
9129 * write out a single text search template
9132 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
9137 /* Skip if not to be dumped */
9138 if (!tmplinfo->dobj.dump || dataOnly)
9141 q = createPQExpBuffer();
9142 delq = createPQExpBuffer();
9144 /* Make sure we are in proper schema */
9145 selectSourceSchema(tmplinfo->dobj.namespace->dobj.name);
9147 appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
9148 fmtId(tmplinfo->dobj.name));
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));
9157 * DROP must be fully qualified in case same name appears in pg_catalog
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));
9164 ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
9165 tmplinfo->dobj.name,
9166 tmplinfo->dobj.namespace->dobj.name,
9169 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
9170 q->data, delq->data, NULL,
9171 tmplinfo->dobj.dependencies, tmplinfo->dobj.nDeps,
9174 /* Dump Template Comments */
9175 resetPQExpBuffer(q);
9176 appendPQExpBuffer(q, "TEXT SEARCH TEMPLATE %s",
9177 fmtId(tmplinfo->dobj.name));
9178 dumpComment(fout, q->data,
9180 tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
9182 destroyPQExpBuffer(q);
9183 destroyPQExpBuffer(delq);
9188 * write out a single text search configuration
9191 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
9204 /* Skip if not to be dumped */
9205 if (!cfginfo->dobj.dump || dataOnly)
9208 q = createPQExpBuffer();
9209 delq = createPQExpBuffer();
9210 query = createPQExpBuffer();
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);
9223 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9224 "query returned %d rows instead of one: %s\n",
9226 ntups, query->data);
9229 nspname = PQgetvalue(res, 0, 0);
9230 prsname = PQgetvalue(res, 0, 1);
9232 /* Make sure we are in proper schema */
9233 selectSourceSchema(cfginfo->dobj.namespace->dobj.name);
9235 appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
9236 fmtId(cfginfo->dobj.name));
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));
9245 resetPQExpBuffer(query);
9246 appendPQExpBuffer(query,
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);
9256 res = PQexec(g_conn, query->data);
9257 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9258 ntups = PQntuples(res);
9260 i_tokenname = PQfnumber(res, "tokenname");
9261 i_dictname = PQfnumber(res, "dictname");
9263 for (i = 0; i < ntups; i++)
9265 char *tokenname = PQgetvalue(res, i, i_tokenname);
9266 char *dictname = PQgetvalue(res, i, i_dictname);
9269 strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
9271 /* starting a new token type, so start a new command */
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);
9281 appendPQExpBuffer(q, ", %s", dictname);
9285 appendPQExpBuffer(q, ";\n");
9290 * DROP must be fully qualified in case same name appears in pg_catalog
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));
9297 ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
9299 cfginfo->dobj.namespace->dobj.name,
9302 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
9303 q->data, delq->data, NULL,
9304 cfginfo->dobj.dependencies, cfginfo->dobj.nDeps,
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);
9315 destroyPQExpBuffer(q);
9316 destroyPQExpBuffer(delq);
9317 destroyPQExpBuffer(query);
9321 * dumpForeignDataWrapper
9322 * write out a single foreign-data wrapper definition
9325 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
9331 /* Skip if not to be dumped */
9332 if (!fdwinfo->dobj.dump || dataOnly)
9335 q = createPQExpBuffer();
9336 delq = createPQExpBuffer();
9338 appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
9339 fmtId(fdwinfo->dobj.name));
9341 if (fdwinfo->fdwvalidator && strcmp(fdwinfo->fdwvalidator, "-") != 0)
9342 appendPQExpBuffer(q, " VALIDATOR %s",
9343 fdwinfo->fdwvalidator);
9345 if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
9346 appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
9348 appendPQExpBuffer(q, ";\n");
9350 appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
9351 fmtId(fdwinfo->dobj.name));
9353 ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
9358 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
9359 q->data, delq->data, NULL,
9360 fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
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,
9372 destroyPQExpBuffer(q);
9373 destroyPQExpBuffer(delq);
9378 * write out a foreign server definition
9381 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
9391 /* Skip if not to be dumped */
9392 if (!srvinfo->dobj.dump || dataOnly)
9395 q = createPQExpBuffer();
9396 delq = createPQExpBuffer();
9397 query = createPQExpBuffer();
9399 /* look up the foreign-data wrapper */
9400 appendPQExpBuffer(query, "SELECT fdwname "
9401 "FROM pg_foreign_data_wrapper w "
9402 "WHERE w.oid = '%u'",
9404 res = PQexec(g_conn, query->data);
9405 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9406 ntups = PQntuples(res);
9409 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
9410 "query returned %d rows instead of one: %s\n",
9412 ntups, query->data);
9415 fdwname = PQgetvalue(res, 0, 0);
9417 appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
9418 if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
9420 appendPQExpBuffer(q, " TYPE ");
9421 appendStringLiteralAH(q, srvinfo->srvtype, fout);
9423 if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
9425 appendPQExpBuffer(q, " VERSION ");
9426 appendStringLiteralAH(q, srvinfo->srvversion, fout);
9429 appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
9430 appendPQExpBuffer(q, "%s", fmtId(fdwname));
9432 if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
9433 appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
9435 appendPQExpBuffer(q, ";\n");
9437 appendPQExpBuffer(delq, "DROP SERVER %s;\n",
9438 fmtId(srvinfo->dobj.name));
9440 ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9445 false, "SERVER", SECTION_PRE_DATA,
9446 q->data, delq->data, NULL,
9447 srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
9450 /* Handle the ACL */
9451 namecopy = strdup(fmtId(srvinfo->dobj.name));
9452 dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
9454 namecopy, NULL, srvinfo->dobj.name,
9455 NULL, srvinfo->rolname,
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,
9465 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
9467 destroyPQExpBuffer(q);
9468 destroyPQExpBuffer(delq);
9474 * This routine is used to dump any user mappings associated with the
9475 * server handed to this routine. Should be called after ArchiveEntry()
9479 dumpUserMappings(Archive *fout, const char *target,
9480 const char *servername, const char *namespace,
9482 CatalogId catalogId, DumpId dumpId)
9494 q = createPQExpBuffer();
9495 tag = createPQExpBuffer();
9496 delq = createPQExpBuffer();
9497 query = createPQExpBuffer();
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",
9507 res = PQexec(g_conn, query->data);
9508 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9510 ntups = PQntuples(res);
9511 i_umuser = PQfnumber(res, "umuser");
9512 i_umoptions = PQfnumber(res, "umoptions");
9514 for (i = 0; i < ntups; i++)
9519 umuser = PQgetvalue(res, i, i_umuser);
9520 umoptions = PQgetvalue(res, i, i_umoptions);
9522 resetPQExpBuffer(q);
9523 appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
9524 appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
9526 if (umoptions && strlen(umoptions) > 0)
9527 appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
9529 appendPQExpBuffer(q, ";\n");
9531 resetPQExpBuffer(delq);
9532 appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
9534 resetPQExpBuffer(tag);
9535 appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
9537 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9542 "USER MAPPING", SECTION_PRE_DATA,
9543 q->data, delq->data, NULL,
9550 destroyPQExpBuffer(query);
9551 destroyPQExpBuffer(delq);
9552 destroyPQExpBuffer(q);
9556 * Write out grant/revoke information
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.
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,
9578 /* Do nothing if ACL dump is not enabled */
9579 if (dataOnly || aclsSkip)
9582 sql = createPQExpBuffer();
9584 if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
9586 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
9592 ArchiveEntry(fout, nilCatalogId, createDumpId(),
9596 false, "ACL", SECTION_NONE,
9597 sql->data, "", NULL,
9601 destroyPQExpBuffer(sql);
9606 * write out to fout the declarations (not data) of a user-defined table
9609 dumpTable(Archive *fout, TableInfo *tbinfo)
9611 if (tbinfo->dobj.dump)
9615 if (tbinfo->relkind == RELKIND_SEQUENCE)
9616 dumpSequence(fout, tbinfo);
9618 dumpTableSchema(fout, tbinfo);
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,
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.
9633 if (g_fout->remoteVersion >= 80400)
9635 PQExpBuffer query = createPQExpBuffer();
9639 appendPQExpBuffer(query,
9640 "SELECT attname, attacl FROM pg_catalog.pg_attribute "
9641 "WHERE attrelid = '%u' AND NOT attisdropped AND attacl IS NOT NULL "
9643 tbinfo->dobj.catId.oid);
9644 res = PQexec(g_conn, query->data);
9645 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9647 for (i = 0; i < PQntuples(res); i++)
9649 char *attname = PQgetvalue(res, i, 0);
9650 char *attacl = PQgetvalue(res, i, 1);
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,
9666 destroyPQExpBuffer(query);
9675 * write the declaration (not data) of one user-defined table or view
9678 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
9680 PQExpBuffer query = createPQExpBuffer();
9681 PQExpBuffer q = createPQExpBuffer();
9682 PQExpBuffer delq = createPQExpBuffer();
9685 TableInfo **parents;
9686 int actual_atts; /* number of attrs in this CREATE statment */
9692 /* Make sure we are in proper schema */
9693 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
9695 /* Is it a table or a view? */
9696 if (tbinfo->relkind == RELKIND_VIEW)
9700 reltypename = "VIEW";
9702 /* Fetch the view definition */
9703 if (g_fout->remoteVersion >= 70300)
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);
9712 appendPQExpBuffer(query, "SELECT definition AS viewdef "
9713 "FROM pg_views WHERE viewname = ");
9714 appendStringLiteralAH(query, tbinfo->dobj.name, fout);
9715 appendPQExpBuffer(query, ";");
9718 res = PQexec(g_conn, query->data);
9719 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
9721 if (PQntuples(res) != 1)
9723 if (PQntuples(res) < 1)
9724 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
9727 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
9732 viewdef = PQgetvalue(res, 0, 0);
9734 if (strlen(viewdef) == 0)
9736 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
9742 * DROP must be fully qualified in case same name appears in
9745 appendPQExpBuffer(delq, "DROP VIEW %s.",
9746 fmtId(tbinfo->dobj.namespace->dobj.name));
9747 appendPQExpBuffer(delq, "%s;\n",
9748 fmtId(tbinfo->dobj.name));
9750 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
9751 fmtId(tbinfo->dobj.name), viewdef);
9757 reltypename = "TABLE";
9758 numParents = tbinfo->numParents;
9759 parents = tbinfo->parents;
9762 * DROP must be fully qualified in case same name appears in
9765 appendPQExpBuffer(delq, "DROP TABLE %s.",
9766 fmtId(tbinfo->dobj.namespace->dobj.name));
9767 appendPQExpBuffer(delq, "%s;\n",
9768 fmtId(tbinfo->dobj.name));
9770 appendPQExpBuffer(q, "CREATE TABLE %s (",
9771 fmtId(tbinfo->dobj.name));
9773 for (j = 0; j < tbinfo->numatts; j++)
9775 /* Is this one of the table's own attrs, and not dropped ? */
9776 if (!tbinfo->inhAttrs[j] &&
9777 (!tbinfo->attisdropped[j] || binary_upgrade))
9779 /* Format properly if not first attr */
9780 if (actual_atts > 0)
9781 appendPQExpBuffer(q, ",");
9782 appendPQExpBuffer(q, "\n ");
9784 /* Attribute name */
9785 appendPQExpBuffer(q, "%s ",
9786 fmtId(tbinfo->attnames[j]));
9788 /* Attribute type */
9789 if (g_fout->remoteVersion >= 70100)
9791 appendPQExpBuffer(q, "%s",
9792 tbinfo->atttypnames[j]);
9796 /* If no format_type, fake it */
9797 appendPQExpBuffer(q, "%s",
9798 myFormatType(tbinfo->atttypnames[j],
9799 tbinfo->atttypmod[j]));
9803 * Default value --- suppress if inherited or to be printed
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);
9813 * Not Null constraint --- suppress if inherited
9815 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
9816 appendPQExpBuffer(q, " NOT NULL");
9823 * Add non-inherited CHECK constraints, if any.
9825 for (j = 0; j < tbinfo->ncheck; j++)
9827 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
9829 if (constr->separate || !constr->conislocal)
9832 if (actual_atts > 0)
9833 appendPQExpBuffer(q, ",\n ");
9835 appendPQExpBuffer(q, "CONSTRAINT %s ",
9836 fmtId(constr->dobj.name));
9837 appendPQExpBuffer(q, "%s", constr->condef);
9842 appendPQExpBuffer(q, "\n)");
9846 appendPQExpBuffer(q, "\nINHERITS (");
9847 for (k = 0; k < numParents; k++)
9849 TableInfo *parentRel = parents[k];
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));
9859 appendPQExpBuffer(q, ")");
9862 if ((tbinfo->reloptions && strlen(tbinfo->reloptions) > 0) ||
9863 (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0))
9865 bool addcomma = false;
9867 appendPQExpBuffer(q, "\nWITH (");
9868 if (tbinfo->reloptions && strlen(tbinfo->reloptions) > 0)
9871 appendPQExpBuffer(q, "%s", tbinfo->reloptions);
9873 if (tbinfo->toast_reloptions && strlen(tbinfo->toast_reloptions) > 0)
9875 appendPQExpBuffer(q, "%s%s", addcomma ? ", " : "",
9876 tbinfo->toast_reloptions);
9878 appendPQExpBuffer(q, ")");
9881 appendPQExpBuffer(q, ";\n");
9884 * For binary-compatible heap files, we create dropped columns
9885 * above and drop them here.
9889 for (j = 0; j < tbinfo->numatts; j++)
9891 if (tbinfo->attisdropped[j])
9893 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
9894 fmtId(tbinfo->dobj.name));
9895 appendPQExpBuffer(q, "DROP COLUMN %s;\n",
9896 fmtId(tbinfo->attnames[j]));
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()
9908 appendPQExpBuffer(q, "\n-- For binary upgrade, recreate dropped column's length and alignment.\n");
9909 appendPQExpBuffer(q, "UPDATE pg_attribute\n"
9912 "WHERE attname = '%s'\n"
9913 " AND attrelid = \n"
9917 " WHERE relnamespace = "
9918 "(SELECT oid FROM pg_namespace "
9919 "WHERE nspname = CURRENT_SCHEMA)\n"
9922 tbinfo->attalign[j],
9923 tbinfo->attnames[j]);
9924 appendStringLiteralAH(q, tbinfo->dobj.name, fout);
9925 appendPQExpBuffer(q, "\n );\n");
9928 appendPQExpBuffer(q, "\n-- For binary upgrade, set relfrozenxid.\n");
9929 appendPQExpBuffer(q, "UPDATE pg_class\n"
9930 "SET relfrozenxid = '%u'\n"
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");
9939 /* Loop dumping statistics and storage statements */
9940 for (j = 0; j < tbinfo->numatts; j++)
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)
9947 if (tbinfo->attstattarget[j] >= 0 &&
9948 !tbinfo->attisdropped[j])
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]);
9959 * Dump per-column storage information. The statement is only
9960 * dumped if the storage has been changed from the type's default.
9962 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
9964 switch (tbinfo->attstorage[j])
9970 storage = "EXTERNAL";
9976 storage = "EXTENDED";
9983 * Only dump the statement if it's a storage type we recognize
9985 if (storage != NULL)
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",
9998 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10000 tbinfo->dobj.namespace->dobj.name,
10001 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
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,
10009 /* Dump Table Comments */
10010 dumpTableComment(fout, tbinfo, reltypename);
10012 /* Dump comments on inlined table constraints */
10013 for (j = 0; j < tbinfo->ncheck; j++)
10015 ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
10017 if (constr->separate || !constr->conislocal)
10020 dumpTableConstraintComment(fout, constr);
10023 destroyPQExpBuffer(query);
10024 destroyPQExpBuffer(q);
10025 destroyPQExpBuffer(delq);
10029 * dumpAttrDef --- dump an attribute's default-value declaration
10032 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
10034 TableInfo *tbinfo = adinfo->adtable;
10035 int adnum = adinfo->adnum;
10039 /* Only print it if "separate" mode is selected */
10040 if (!tbinfo->dobj.dump || !adinfo->separate || dataOnly)
10043 /* Don't print inherited defaults, either */
10044 if (tbinfo->inhAttrDef[adnum - 1])
10047 q = createPQExpBuffer();
10048 delq = createPQExpBuffer();
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);
10057 * DROP must be fully qualified in case same name appears in pg_catalog
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]));
10066 ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
10067 tbinfo->attnames[adnum - 1],
10068 tbinfo->dobj.namespace->dobj.name,
10071 false, "DEFAULT", SECTION_PRE_DATA,
10072 q->data, delq->data, NULL,
10073 adinfo->dobj.dependencies, adinfo->dobj.nDeps,
10076 destroyPQExpBuffer(q);
10077 destroyPQExpBuffer(delq);
10081 * getAttrName: extract the correct name for an attribute
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.
10087 static const char *
10088 getAttrName(int attrnum, TableInfo *tblInfo)
10090 if (attrnum > 0 && attrnum <= tblInfo->numatts)
10091 return tblInfo->attnames[attrnum - 1];
10094 case SelfItemPointerAttributeNumber:
10096 case ObjectIdAttributeNumber:
10098 case MinTransactionIdAttributeNumber:
10100 case MinCommandIdAttributeNumber:
10102 case MaxTransactionIdAttributeNumber:
10104 case MaxCommandIdAttributeNumber:
10106 case TableOidAttributeNumber:
10109 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
10110 attrnum, tblInfo->dobj.name);
10112 return NULL; /* keep compiler quiet */
10117 * write out to fout a user-defined index
10120 dumpIndex(Archive *fout, IndxInfo *indxinfo)
10122 TableInfo *tbinfo = indxinfo->indextable;
10129 q = createPQExpBuffer();
10130 delq = createPQExpBuffer();
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.)
10137 if (indxinfo->indexconstraint == 0)
10139 /* Plain secondary index */
10140 appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
10142 /* If the index is clustered, we need to record that. */
10143 if (indxinfo->indisclustered)
10145 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10146 fmtId(tbinfo->dobj.name));
10147 appendPQExpBuffer(q, " ON %s;\n",
10148 fmtId(indxinfo->dobj.name));
10152 * DROP must be fully qualified in case same name appears in
10155 appendPQExpBuffer(delq, "DROP INDEX %s.",
10156 fmtId(tbinfo->dobj.namespace->dobj.name));
10157 appendPQExpBuffer(delq, "%s;\n",
10158 fmtId(indxinfo->dobj.name));
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,
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,
10178 indxinfo->dobj.catId, 0, indxinfo->dobj.dumpId);
10180 destroyPQExpBuffer(q);
10181 destroyPQExpBuffer(delq);
10186 * write out to fout a user-defined constraint
10189 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
10191 TableInfo *tbinfo = coninfo->contable;
10195 /* Skip if not to be dumped */
10196 if (!coninfo->dobj.dump || dataOnly)
10199 q = createPQExpBuffer();
10200 delq = createPQExpBuffer();
10202 if (coninfo->contype == 'p' || coninfo->contype == 'u')
10204 /* Index-related constraint */
10205 IndxInfo *indxinfo;
10208 indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
10210 if (indxinfo == NULL)
10212 write_msg(NULL, "missing index for constraint \"%s\"\n",
10213 coninfo->dobj.name);
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");
10223 for (k = 0; k < indxinfo->indnkeys; k++)
10225 int indkey = (int) indxinfo->indkeys[k];
10226 const char *attname;
10228 if (indkey == InvalidAttrNumber)
10230 attname = getAttrName(indkey, tbinfo);
10232 appendPQExpBuffer(q, "%s%s",
10233 (k == 0) ? "" : ", ",
10237 appendPQExpBuffer(q, ")");
10239 if (indxinfo->options && strlen(indxinfo->options) > 0)
10240 appendPQExpBuffer(q, " WITH (%s)", indxinfo->options);
10242 appendPQExpBuffer(q, ";\n");
10244 /* If the index is clustered, we need to record that. */
10245 if (indxinfo->indisclustered)
10247 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
10248 fmtId(tbinfo->dobj.name));
10249 appendPQExpBuffer(q, " ON %s;\n",
10250 fmtId(indxinfo->dobj.name));
10254 * DROP must be fully qualified in case same name appears in
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));
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,
10274 else if (coninfo->contype == 'f')
10277 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
10278 * current table data is not processed
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),
10287 * DROP must be fully qualified in case same name appears in
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));
10297 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10298 coninfo->dobj.name,
10299 tbinfo->dobj.namespace->dobj.name,
10301 tbinfo->rolname, false,
10302 "FK CONSTRAINT", SECTION_POST_DATA,
10303 q->data, delq->data, NULL,
10304 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10307 else if (coninfo->contype == 'c' && tbinfo)
10309 /* CHECK constraint on a table */
10311 /* Ignore if not to be dumped separately */
10312 if (coninfo->separate)
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),
10322 * DROP must be fully qualified in case same name appears in
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));
10332 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10333 coninfo->dobj.name,
10334 tbinfo->dobj.namespace->dobj.name,
10336 tbinfo->rolname, false,
10337 "CHECK CONSTRAINT", SECTION_POST_DATA,
10338 q->data, delq->data, NULL,
10339 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10343 else if (coninfo->contype == 'c' && tbinfo == NULL)
10345 /* CHECK constraint on a domain */
10346 TypeInfo *tinfo = coninfo->condomain;
10348 /* Ignore if not to be dumped separately */
10349 if (coninfo->separate)
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),
10358 * DROP must be fully qualified in case same name appears in
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));
10368 ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
10369 coninfo->dobj.name,
10370 tinfo->dobj.namespace->dobj.name,
10372 tinfo->rolname, false,
10373 "CHECK CONSTRAINT", SECTION_POST_DATA,
10374 q->data, delq->data, NULL,
10375 coninfo->dobj.dependencies, coninfo->dobj.nDeps,
10381 write_msg(NULL, "unrecognized constraint type: %c\n", coninfo->contype);
10385 /* Dump Constraint Comments --- only works for table constraints */
10386 if (tbinfo && coninfo->separate)
10387 dumpTableConstraintComment(fout, coninfo);
10389 destroyPQExpBuffer(q);
10390 destroyPQExpBuffer(delq);
10394 * dumpTableConstraintComment --- dump a constraint's comment if any
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.
10401 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
10403 TableInfo *tbinfo = coninfo->contable;
10404 PQExpBuffer q = createPQExpBuffer();
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,
10413 coninfo->dobj.catId, 0,
10414 coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
10416 destroyPQExpBuffer(q);
10420 * findLastBuiltInOid -
10421 * find the last built in oid
10423 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
10424 * pg_database entry for the current database
10427 findLastBuiltinOid_V71(const char *dbname)
10432 PQExpBuffer query = createPQExpBuffer();
10434 resetPQExpBuffer(query);
10435 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
10436 appendStringLiteralAH(query, dbname, g_fout);
10438 res = PQexec(g_conn, query->data);
10439 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10441 ntups = PQntuples(res);
10444 write_msg(NULL, "missing pg_database entry for this database\n");
10449 write_msg(NULL, "found more than one pg_database entry for this database\n");
10452 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
10454 destroyPQExpBuffer(query);
10459 * findLastBuiltInOid -
10460 * find the last built in oid
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.
10467 findLastBuiltinOid_V70(void)
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'",
10478 ntups = PQntuples(res);
10481 write_msg(NULL, "could not find entry for pg_indexes in pg_class\n");
10486 write_msg(NULL, "found more than one entry for pg_indexes in pg_class\n");
10489 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
10495 dumpSequence(Archive *fout, TableInfo *tbinfo)
10508 PQExpBuffer query = createPQExpBuffer();
10509 PQExpBuffer delqry = createPQExpBuffer();
10511 /* Make sure we are in proper schema */
10512 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10514 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
10515 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
10517 if (g_fout->remoteVersion >= 80400)
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 "
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 "
10529 "END AS min_value, "
10530 "cache_value, is_cycled, is_called from %s",
10532 fmtId(tbinfo->dobj.name));
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 "
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 "
10546 "END AS min_value, "
10547 "cache_value, is_cycled, is_called from %s",
10549 fmtId(tbinfo->dobj.name));
10552 res = PQexec(g_conn, query->data);
10553 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10555 if (PQntuples(res) != 1)
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",
10560 tbinfo->dobj.name, PQntuples(res));
10564 /* Disable this check: it fails if sequence has been renamed */
10566 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->dobj.name) != 0)
10568 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
10569 tbinfo->dobj.name, PQgetvalue(res, 0, 0));
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);
10586 * The logic we use for restoring sequences is as follows:
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.
10593 * Add a 'SETVAL(seq, last_val, iscalled)' as part of a "data" dump.
10597 resetPQExpBuffer(delqry);
10600 * DROP must be fully qualified in case same name appears in
10603 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
10604 fmtId(tbinfo->dobj.namespace->dobj.name));
10605 appendPQExpBuffer(delqry, "%s;\n",
10606 fmtId(tbinfo->dobj.name));
10608 resetPQExpBuffer(query);
10609 appendPQExpBuffer(query,
10610 "CREATE SEQUENCE %s\n",
10611 fmtId(tbinfo->dobj.name));
10613 if (g_fout->remoteVersion >= 80400)
10614 appendPQExpBuffer(query, " START WITH %s\n", startv);
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.
10623 appendPQExpBuffer(query, " START WITH %s\n", last);
10626 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
10629 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
10631 appendPQExpBuffer(query, " NO MAXVALUE\n");
10634 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
10636 appendPQExpBuffer(query, " NO MINVALUE\n");
10638 appendPQExpBuffer(query,
10640 cache, (cycled ? "\n CYCLE" : ""));
10642 appendPQExpBuffer(query, ";\n");
10644 ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
10646 tbinfo->dobj.namespace->dobj.name,
10649 false, "SEQUENCE", SECTION_PRE_DATA,
10650 query->data, delqry->data, NULL,
10651 tbinfo->dobj.dependencies, tbinfo->dobj.nDeps,
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.
10663 * We need not schema-qualify the table reference because both
10664 * sequence and table must be in the same schema.
10666 if (OidIsValid(tbinfo->owning_tab))
10668 TableInfo *owning_tab = findTableByOid(tbinfo->owning_tab);
10670 if (owning_tab && owning_tab->dobj.dump)
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]));
10680 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10682 tbinfo->dobj.namespace->dobj.name,
10685 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
10686 query->data, "", NULL,
10687 &(tbinfo->dobj.dumpId), 1,
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);
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"));
10708 ArchiveEntry(fout, nilCatalogId, createDumpId(),
10710 tbinfo->dobj.namespace->dobj.name,
10713 false, "SEQUENCE SET", SECTION_PRE_DATA,
10714 query->data, "", NULL,
10715 &(tbinfo->dobj.dumpId), 1,
10721 destroyPQExpBuffer(query);
10722 destroyPQExpBuffer(delqry);
10726 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
10728 TableInfo *tbinfo = tginfo->tgtable;
10730 PQExpBuffer delqry;
10737 query = createPQExpBuffer();
10738 delqry = createPQExpBuffer();
10741 * DROP must be fully qualified in case same name appears in pg_catalog
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));
10750 if (tginfo->tgisconstraint)
10752 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
10753 appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
10757 appendPQExpBuffer(query, "CREATE TRIGGER ");
10758 appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
10760 appendPQExpBuffer(query, "\n ");
10764 if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
10765 appendPQExpBuffer(query, "BEFORE");
10767 appendPQExpBuffer(query, "AFTER");
10768 if (TRIGGER_FOR_INSERT(tginfo->tgtype))
10770 appendPQExpBuffer(query, " INSERT");
10773 if (TRIGGER_FOR_DELETE(tginfo->tgtype))
10776 appendPQExpBuffer(query, " OR DELETE");
10778 appendPQExpBuffer(query, " DELETE");
10781 if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
10784 appendPQExpBuffer(query, " OR UPDATE");
10786 appendPQExpBuffer(query, " UPDATE");
10788 if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
10791 appendPQExpBuffer(query, " OR TRUNCATE");
10793 appendPQExpBuffer(query, " TRUNCATE");
10795 appendPQExpBuffer(query, " ON %s\n",
10796 fmtId(tbinfo->dobj.name));
10798 if (tginfo->tgisconstraint)
10800 if (OidIsValid(tginfo->tgconstrrelid))
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);
10807 appendPQExpBuffer(query, " FROM %s\n ",
10808 fmtId(tginfo->tgconstrrelname));
10810 if (!tginfo->tgdeferrable)
10811 appendPQExpBuffer(query, "NOT ");
10812 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
10813 if (tginfo->tginitdeferred)
10814 appendPQExpBuffer(query, "DEFERRED\n");
10816 appendPQExpBuffer(query, "IMMEDIATE\n");
10819 if (TRIGGER_FOR_ROW(tginfo->tgtype))
10820 appendPQExpBuffer(query, " FOR EACH ROW\n ");
10822 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
10824 /* In 7.3, result of regproc is already quoted */
10825 if (g_fout->remoteVersion >= 70300)
10826 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10829 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
10830 fmtId(tginfo->tgfname));
10832 p = tginfo->tgargs;
10833 for (findx = 0; findx < tginfo->tgnargs; findx++)
10837 /* Set 'p' to end of arg string. marked by '\000' */
10840 p = strchr(p, '\\');
10843 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
10846 tbinfo->dobj.name);
10850 if (*p == '\\') /* is it '\\'? */
10855 if (p[0] == '0' && p[1] == '0' && p[2] == '0') /* is it '\000'? */
10860 appendPQExpBufferChar(query, '\'');
10864 appendPQExpBufferChar(query, '\'');
10867 * bytea unconditionally doubles backslashes, so we suppress the
10868 * doubling for standard_conforming_strings.
10870 if (fout->std_strings && *s == '\\' && s[1] == '\\')
10872 appendPQExpBufferChar(query, *s++);
10874 appendPQExpBufferChar(query, '\'');
10875 appendPQExpBuffer(query,
10876 (findx < tginfo->tgnargs - 1) ? ", " : "");
10879 appendPQExpBuffer(query, ");\n");
10881 if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
10883 appendPQExpBuffer(query, "\nALTER TABLE %s ",
10884 fmtId(tbinfo->dobj.name));
10885 switch (tginfo->tgenabled)
10889 appendPQExpBuffer(query, "DISABLE");
10892 appendPQExpBuffer(query, "ENABLE ALWAYS");
10895 appendPQExpBuffer(query, "ENABLE REPLICA");
10898 appendPQExpBuffer(query, "ENABLE");
10901 appendPQExpBuffer(query, " TRIGGER %s;\n",
10902 fmtId(tginfo->dobj.name));
10905 ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
10907 tbinfo->dobj.namespace->dobj.name,
10909 tbinfo->rolname, false,
10910 "TRIGGER", SECTION_POST_DATA,
10911 query->data, delqry->data, NULL,
10912 tginfo->dobj.dependencies, tginfo->dobj.nDeps,
10915 resetPQExpBuffer(query);
10916 appendPQExpBuffer(query, "TRIGGER %s ",
10917 fmtId(tginfo->dobj.name));
10918 appendPQExpBuffer(query, "ON %s",
10919 fmtId(tbinfo->dobj.name));
10921 dumpComment(fout, query->data,
10922 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
10923 tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
10925 destroyPQExpBuffer(query);
10926 destroyPQExpBuffer(delqry);
10934 dumpRule(Archive *fout, RuleInfo *rinfo)
10936 TableInfo *tbinfo = rinfo->ruletable;
10939 PQExpBuffer delcmd;
10942 /* Skip if not to be dumped */
10943 if (!rinfo->dobj.dump || dataOnly)
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.
10950 if (!rinfo->separate)
10954 * Make sure we are in proper schema.
10956 selectSourceSchema(tbinfo->dobj.namespace->dobj.name);
10958 query = createPQExpBuffer();
10959 cmd = createPQExpBuffer();
10960 delcmd = createPQExpBuffer();
10962 if (g_fout->remoteVersion >= 70300)
10964 appendPQExpBuffer(query,
10965 "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid) AS definition",
10966 rinfo->dobj.catId.oid);
10970 /* Rule name was unique before 7.3 ... */
10971 appendPQExpBuffer(query,
10972 "SELECT pg_get_ruledef('%s') AS definition",
10976 res = PQexec(g_conn, query->data);
10977 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
10979 if (PQntuples(res) != 1)
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);
10986 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
10989 * Add the command to alter the rules replication firing semantics if it
10990 * differs from the default.
10992 if (rinfo->ev_enabled != 'O')
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)
11001 appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
11002 fmtId(rinfo->dobj.name));
11005 appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
11006 fmtId(rinfo->dobj.name));
11009 appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
11010 fmtId(rinfo->dobj.name));
11016 * DROP must be fully qualified in case same name appears in pg_catalog
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));
11025 ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
11027 tbinfo->dobj.namespace->dobj.name,
11029 tbinfo->rolname, false,
11030 "RULE", SECTION_POST_DATA,
11031 cmd->data, delcmd->data, NULL,
11032 rinfo->dobj.dependencies, rinfo->dobj.nDeps,
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,
11044 rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
11048 destroyPQExpBuffer(query);
11049 destroyPQExpBuffer(cmd);
11050 destroyPQExpBuffer(delcmd);
11054 * getDependencies --- obtain available dependency data
11057 getDependencies(void)
11068 DumpableObject *dobj,
11071 /* No dependency info available before 7.3 */
11072 if (g_fout->remoteVersion < 70300)
11076 write_msg(NULL, "reading dependency data\n");
11078 /* Make sure we are in proper schema */
11079 selectSourceSchema("pg_catalog");
11081 query = createPQExpBuffer();
11083 appendPQExpBuffer(query, "SELECT "
11084 "classid, objid, refclassid, refobjid, deptype "
11086 "WHERE deptype != 'p' "
11089 res = PQexec(g_conn, query->data);
11090 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11092 ntups = PQntuples(res);
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");
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
11107 for (i = 0; i < ntups; i++)
11110 CatalogId refobjId;
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));
11119 if (dobj == NULL ||
11120 dobj->catId.tableoid != objId.tableoid ||
11121 dobj->catId.oid != objId.oid)
11122 dobj = findObjectByCatalogId(objId);
11125 * Failure to find objects mentioned in pg_depend is not unexpected,
11126 * since for example we don't collect info about TOAST tables.
11131 fprintf(stderr, "no referencing object %u %u\n",
11132 objId.tableoid, objId.oid);
11137 refdobj = findObjectByCatalogId(refobjId);
11139 if (refdobj == NULL)
11142 fprintf(stderr, "no referenced object %u %u\n",
11143 refobjId.tableoid, refobjId.oid);
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.
11155 if (deptype == 'i' &&
11156 dobj->objType == DO_TABLE &&
11157 refdobj->objType == DO_TYPE)
11158 addObjectDependency(refdobj, dobj->dumpId);
11161 addObjectDependency(dobj, refdobj->dumpId);
11166 destroyPQExpBuffer(query);
11171 * selectSourceSchema - make the specified schema the active search path
11172 * in the source database.
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.
11179 * Whenever the selected schema is not pg_catalog, be careful to qualify
11180 * references to system catalogs and types in our emitted commands!
11183 selectSourceSchema(const char *schemaName)
11185 static char *curSchemaName = NULL;
11188 /* Not relevant if fetching from pre-7.3 DB */
11189 if (g_fout->remoteVersion < 70300)
11191 /* Ignore null schema names */
11192 if (schemaName == NULL || *schemaName == '\0')
11194 /* Optimize away repeated selection of same schema */
11195 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
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");
11204 do_sql_command(g_conn, query->data);
11206 destroyPQExpBuffer(query);
11208 free(curSchemaName);
11209 curSchemaName = strdup(schemaName);
11213 * getFormattedTypeName - retrieve a nicely-formatted type name for the
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.
11220 getFormattedTypeName(Oid oid, OidOptions opts)
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");
11239 query = createPQExpBuffer();
11240 if (g_fout->remoteVersion >= 70300)
11242 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
11245 else if (g_fout->remoteVersion >= 70100)
11247 appendPQExpBuffer(query, "SELECT format_type('%u'::oid, NULL)",
11252 appendPQExpBuffer(query, "SELECT typname "
11254 "WHERE oid = '%u'::oid",
11258 res = PQexec(g_conn, query->data);
11259 check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
11261 /* Expecting a single result only */
11262 ntups = PQntuples(res);
11265 write_msg(NULL, ngettext("query returned %d row instead of one: %s\n",
11266 "query returned %d rows instead of one: %s\n",
11268 ntups, query->data);
11272 if (g_fout->remoteVersion >= 70100)
11274 /* already quoted */
11275 result = strdup(PQgetvalue(res, 0, 0));
11279 /* may need to quote it */
11280 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
11284 destroyPQExpBuffer(query);
11290 * myFormatType --- local implementation of format_type for use with 7.0.
11293 myFormatType(const char *typname, int32 typmod)
11296 bool isarray = false;
11297 PQExpBuffer buf = createPQExpBuffer();
11299 /* Handle array types */
11300 if (typname[0] == '_')
11306 /* Show lengths on bpchar and varchar */
11307 if (!strcmp(typname, "bpchar"))
11309 int len = (typmod - VARHDRSZ);
11311 appendPQExpBuffer(buf, "character");
11313 appendPQExpBuffer(buf, "(%d)",
11314 typmod - VARHDRSZ);
11316 else if (!strcmp(typname, "varchar"))
11318 appendPQExpBuffer(buf, "character varying");
11320 appendPQExpBuffer(buf, "(%d)",
11321 typmod - VARHDRSZ);
11323 else if (!strcmp(typname, "numeric"))
11325 appendPQExpBuffer(buf, "numeric");
11332 tmp_typmod = typmod - VARHDRSZ;
11333 precision = (tmp_typmod >> 16) & 0xffff;
11334 scale = tmp_typmod & 0xffff;
11335 appendPQExpBuffer(buf, "(%d,%d)",
11341 * char is an internal single-byte data type; Let's make sure we force it
11342 * through with quotes. - thomas 1998-12-13
11344 else if (strcmp(typname, "char") == 0)
11345 appendPQExpBuffer(buf, "\"char\"");
11347 appendPQExpBuffer(buf, "%s", fmtId(typname));
11349 /* Append array qualifier for array types */
11351 appendPQExpBuffer(buf, "[]");
11353 result = strdup(buf->data);
11354 destroyPQExpBuffer(buf);
11360 * fmtQualifiedId - convert a qualified name to the proper format for
11361 * the source database.
11363 * Like fmtId, use the result before calling again.
11365 static const char *
11366 fmtQualifiedId(const char *schema, const char *id)
11368 static PQExpBuffer id_return = NULL;
11370 if (id_return) /* first time through? */
11371 resetPQExpBuffer(id_return);
11373 id_return = createPQExpBuffer();
11375 /* Suppress schema name if fetching from pre-7.3 DB */
11376 if (g_fout->remoteVersion >= 70300 && schema && *schema)
11378 appendPQExpBuffer(id_return, "%s.",
11381 appendPQExpBuffer(id_return, "%s",
11384 return id_return->data;
11388 * Return a column list clause for the given relation.
11390 * Special case: if there are no undropped columns in the relation, return
11391 * "", not an invalid "()" column list.
11393 static const char *
11394 fmtCopyColumnList(const TableInfo *ti)
11396 static PQExpBuffer q = NULL;
11397 int numatts = ti->numatts;
11398 char **attnames = ti->attnames;
11399 bool *attisdropped = ti->attisdropped;
11403 if (q) /* first time through? */
11404 resetPQExpBuffer(q);
11406 q = createPQExpBuffer();
11408 appendPQExpBuffer(q, "(");
11410 for (i = 0; i < numatts; i++)
11412 if (attisdropped[i])
11415 appendPQExpBuffer(q, ", ");
11416 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
11421 return ""; /* no undropped columns */
11423 appendPQExpBuffer(q, ")");
11428 * Convenience subroutine to execute a SQL command and check for
11429 * COMMAND_OK status.
11432 do_sql_command(PGconn *conn, const char *query)
11436 res = PQexec(conn, query);
11437 check_sql_result(res, conn, query, PGRES_COMMAND_OK);
11442 * Convenience subroutine to verify a SQL command succeeded,
11443 * and exit with a useful error message if not.
11446 check_sql_result(PGresult *res, PGconn *conn, const char *query,
11447 ExecStatusType expected)
11451 if (res && PQresultStatus(res) == expected)
11454 write_msg(NULL, "SQL command failed\n");
11456 err = PQresultErrorMessage(res);
11458 err = PQerrorMessage(conn);
11459 write_msg(NULL, "Error message from server: %s", err);
11460 write_msg(NULL, "The command was: %s\n", query);