1 /*-------------------------------------------------------------------------
4 * pg_dump is a utility for dumping out a postgres database
7 * Portions Copyright (c) 1996-2003, 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 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.355 2003/10/28 21:05:29 tgl Exp $
17 *-------------------------------------------------------------------------
21 * Although this is not a backend module, we must include postgres.h anyway
22 * so that we can include a bunch of backend include files. pg_dump has
23 * never pretended to be very independent of the backend anyhow ...
40 #include "getopt_long.h"
46 #include "access/attnum.h"
47 #include "access/htup.h"
48 #include "catalog/pg_class.h"
49 #include "catalog/pg_proc.h"
50 #include "catalog/pg_trigger.h"
51 #include "catalog/pg_type.h"
53 #include "commands/sequence.h"
56 #include "libpq/libpq-fs.h"
59 #include "pg_backup.h"
60 #include "pg_backup_archiver.h"
61 #include "dumputils.h"
63 #define _(x) gettext((x))
65 typedef struct _dumpContext
72 static void help(const char *progname);
73 static NamespaceInfo *findNamespace(const char *nsoid, const char *objoid);
74 static void dumpClasses(const TableInfo *tblinfo, const int numTables,
75 Archive *fout, const bool oids);
76 static void dumpComment(Archive *fout, const char *target,
77 const char *namespace, const char *owner,
78 const char *oid, const char *classname, int subid,
79 const char *((*deps)[]));
80 static void dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
81 FuncInfo *g_finfo, int numFuncs,
82 TypeInfo *g_tinfo, int numTypes);
83 static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
84 static void dumpOneCompositeType(Archive *fout, TypeInfo *tinfo);
85 static void dumpOneTable(Archive *fout, TableInfo *tbinfo,
86 TableInfo *g_tblinfo);
87 static void dumpOneSequence(Archive *fout, TableInfo *tbinfo,
88 const bool schemaOnly, const bool dataOnly);
90 static void dumpTableACL(Archive *fout, TableInfo *tbinfo);
91 static void dumpFuncACL(Archive *fout, FuncInfo *finfo);
92 static void dumpAggACL(Archive *fout, AggInfo *finfo);
93 static void dumpACL(Archive *fout, const char *type, const char *name,
94 const char *tag, const char *nspname,
95 const char *owner, const char *acl, const char *objoid);
97 static void dumpConstraints(Archive *fout, TableInfo *tblinfo, int numTables);
98 static void dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables);
99 static void dumpRules(Archive *fout, TableInfo *tblinfo, int numTables);
100 static char *format_function_signature(FuncInfo *finfo, bool honor_quotes);
101 static void dumpOneFunc(Archive *fout, FuncInfo *finfo);
102 static void dumpOneOpr(Archive *fout, OprInfo *oprinfo,
103 OprInfo *g_oprinfo, int numOperators);
104 static const char *convertRegProcReference(const char *proc);
105 static const char *convertOperatorReference(const char *opr,
106 OprInfo *g_oprinfo, int numOperators);
107 static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo);
108 static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
109 static Oid findLastBuiltinOid_V71(const char *);
110 static Oid findLastBuiltinOid_V70(void);
111 static void setMaxOid(Archive *fout);
112 static void selectSourceSchema(const char *schemaName);
113 static char *getFormattedTypeName(const char *oid, OidOptions opts);
114 static char *myFormatType(const char *typname, int32 typmod);
115 static const char *fmtQualifiedId(const char *schema, const char *id);
116 static int dumpBlobs(Archive *AH, char *, void *);
117 static int dumpDatabase(Archive *AH);
118 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
119 static const char *fmtCopyColumnList(const TableInfo *ti);
126 bool g_verbose; /* User wants verbose narration of our
128 Archive *g_fout; /* the script file */
129 PGconn *g_conn; /* the database connection */
131 /* various user-settable parameters */
132 bool dumpData; /* dump data using proper insert strings */
133 bool attrNames; /* put attr names into insert strings */
138 /* obsolete as of 7.3: */
139 static Oid g_last_builtin_oid; /* value of the last builtin oid */
141 static char *selectTableName = NULL; /* name of a single table to dump */
142 static char *selectSchemaName = NULL; /* name of a single schema to dump */
144 char g_opaque_type[10]; /* name for the opaque type */
146 /* placeholders for the delimiters for comments */
147 char g_comment_start[10];
148 char g_comment_end[10];
150 /* these are to avoid passing around info for findNamespace() */
151 static NamespaceInfo *g_namespaces;
152 static int g_numNamespaces;
156 main(int argc, char **argv)
159 const char *filename = NULL;
160 const char *format = "p";
161 const char *dbname = NULL;
162 const char *pghost = NULL;
163 const char *pgport = NULL;
164 const char *username = NULL;
169 bool force_password = false;
170 int compressLevel = -1;
171 bool ignore_version = false;
174 int outputCreate = 0;
176 int outputNoOwner = 0;
177 static int use_setsessauth = 0;
178 static int disable_triggers = 0;
179 char *outputSuperuser = NULL;
181 RestoreOptions *ropt;
183 static struct option long_options[] = {
184 {"data-only", no_argument, NULL, 'a'},
185 {"blobs", no_argument, NULL, 'b'},
186 {"clean", no_argument, NULL, 'c'},
187 {"create", no_argument, NULL, 'C'},
188 {"file", required_argument, NULL, 'f'},
189 {"format", required_argument, NULL, 'F'},
190 {"inserts", no_argument, NULL, 'd'},
191 {"attribute-inserts", no_argument, NULL, 'D'},
192 {"column-inserts", no_argument, NULL, 'D'},
193 {"host", required_argument, NULL, 'h'},
194 {"ignore-version", no_argument, NULL, 'i'},
195 {"no-reconnect", no_argument, NULL, 'R'},
196 {"oids", no_argument, NULL, 'o'},
197 {"no-owner", no_argument, NULL, 'O'},
198 {"port", required_argument, NULL, 'p'},
199 {"schema", required_argument, NULL, 'n'},
200 {"schema-only", no_argument, NULL, 's'},
201 {"superuser", required_argument, NULL, 'S'},
202 {"table", required_argument, NULL, 't'},
203 {"password", no_argument, NULL, 'W'},
204 {"username", required_argument, NULL, 'U'},
205 {"verbose", no_argument, NULL, 'v'},
206 {"no-privileges", no_argument, NULL, 'x'},
207 {"no-acl", no_argument, NULL, 'x'},
208 {"compress", required_argument, NULL, 'Z'},
209 {"help", no_argument, NULL, '?'},
210 {"version", no_argument, NULL, 'V'},
213 * the following options don't have an equivalent short option
214 * letter, but are available as '-X long-name'
216 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
217 {"disable-triggers", no_argument, &disable_triggers, 1},
224 setlocale(LC_ALL, "");
225 bindtextdomain("pg_dump", LOCALEDIR);
226 textdomain("pg_dump");
231 strcpy(g_comment_start, "-- ");
232 g_comment_end[0] = '\0';
233 strcpy(g_opaque_type, "opaque");
235 dataOnly = schemaOnly = dumpData = attrNames = false;
237 progname = get_progname(argv[0]);
239 /* Set default options based on progname */
240 if (strcmp(progname, "pg_backup") == 0)
248 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
253 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
255 puts("pg_dump (PostgreSQL) " PG_VERSION);
260 while ((c = getopt_long(argc, argv, "abcCdDf:F:h:in:oOp:RsS:t:uU:vWxX:Z:",
261 long_options, &optindex)) != -1)
265 case 'a': /* Dump data only */
269 case 'b': /* Dump blobs */
273 case 'c': /* clean (i.e., drop) schema prior to
278 case 'C': /* Create DB */
282 case 'd': /* dump data as proper insert strings */
286 case 'D': /* dump data as proper insert strings with
300 case 'h': /* server host */
304 case 'i': /* ignore database version mismatch */
305 ignore_version = true;
308 case 'n': /* Dump data for this schema only */
309 selectSchemaName = strdup(optarg);
312 case 'o': /* Dump oids */
316 case 'O': /* Don't reconnect to match owner */
320 case 'p': /* server port */
325 /* no-op, still accepted for backwards compatibility */
328 case 's': /* dump schema only */
332 case 'S': /* Username for superuser in plain text
334 outputSuperuser = strdup(optarg);
337 case 't': /* Dump data for this table only */
338 selectTableName = strdup(optarg);
342 force_password = true;
343 username = simple_prompt("User name: ", 100, true);
350 case 'v': /* verbose */
355 force_password = true;
358 case 'x': /* skip ACL dump */
363 * Option letters were getting scarce, so I invented this
364 * new scheme: '-X feature' turns on some feature. Compare
365 * to the -f option in GCC. You should also add an
366 * equivalent GNU-style option --feature. Features that
367 * require arguments should use '-X feature=foo'.
370 if (strcmp(optarg, "use-set-session-authorization") == 0)
371 /* no-op, still allowed for compatibility */ ;
372 else if (strcmp(optarg, "disable-triggers") == 0)
373 disable_triggers = 1;
377 _("%s: invalid -X option -- %s\n"),
379 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
384 case 'Z': /* Compression Level */
385 compressLevel = atoi(optarg);
387 /* This covers the long options equivalent to -X xxx. */
393 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
398 if (optind < (argc - 1))
400 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
401 progname, argv[optind + 1]);
402 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
407 /* Get database name from command line */
409 dbname = argv[optind];
411 if (dataOnly && schemaOnly)
413 write_msg(NULL, "options \"schema only\" (-s) and \"data only\" (-a) cannot be used together\n");
417 if (dataOnly && outputClean)
419 write_msg(NULL, "options \"clean\" (-c) and \"data only\" (-a) cannot be used together\n");
423 if (outputBlobs && selectTableName != NULL)
425 write_msg(NULL, "large-object output not supported for a single table\n");
426 write_msg(NULL, "use a full dump instead\n");
430 if (outputBlobs && selectSchemaName != NULL)
432 write_msg(NULL, "large-object output not supported for a single schema\n");
433 write_msg(NULL, "use a full dump instead\n");
437 if (dumpData == true && oids == true)
439 write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together\n");
440 write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
444 if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
446 write_msg(NULL, "large-object output is not supported for plain-text dump files\n");
447 write_msg(NULL, "(Use a different output format.)\n");
451 /* open the output file */
456 g_fout = CreateArchive(filename, archCustom, compressLevel);
461 g_fout = CreateArchive(filename, archFiles, compressLevel);
467 g_fout = CreateArchive(filename, archNull, 0);
472 g_fout = CreateArchive(filename, archTar, compressLevel);
476 write_msg(NULL, "invalid output format \"%s\" specified\n", format);
482 write_msg(NULL, "could not open output file \"%s\" for writing\n", filename);
486 /* Let the archiver know how noisy to be */
487 g_fout->verbose = g_verbose;
489 g_fout->minRemoteVersion = 70000; /* we can handle back to 7.0 */
490 g_fout->maxRemoteVersion = parse_version(PG_VERSION);
491 if (g_fout->maxRemoteVersion < 0)
493 write_msg(NULL, "could not parse version string \"%s\"\n", PG_VERSION);
498 * Open the database using the Archiver, so it knows about it. Errors
501 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport,
502 username, force_password, ignore_version);
505 * Start serializable transaction to dump consistent data.
507 res = PQexec(g_conn, "BEGIN");
508 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
509 exit_horribly(g_fout, NULL, "BEGIN command failed: %s",
510 PQerrorMessage(g_conn));
513 res = PQexec(g_conn, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE");
514 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
515 exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
516 PQerrorMessage(g_conn));
519 /* Set the datestyle to ISO to ensure the dump's portability */
520 res = PQexec(g_conn, "SET DATESTYLE = ISO");
521 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
522 exit_horribly(g_fout, NULL, "could not set datestyle to ISO: %s",
523 PQerrorMessage(g_conn));
527 * If supported, set extra_float_digits so that we can dump float data
528 * exactly (given correctly implemented float I/O code, anyway)
530 if (g_fout->remoteVersion >= 70400)
532 res = PQexec(g_conn, "SET extra_float_digits TO 2");
533 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
534 exit_horribly(g_fout, NULL, "could not set extra_float_digits: %s",
535 PQerrorMessage(g_conn));
539 /* Find the last built-in OID, if needed */
540 if (g_fout->remoteVersion < 70300)
542 if (g_fout->remoteVersion >= 70100)
543 g_last_builtin_oid = findLastBuiltinOid_V71(PQdb(g_conn));
545 g_last_builtin_oid = findLastBuiltinOid_V70();
547 write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
550 /* Dump the database definition */
552 dumpDatabase(g_fout);
557 tblinfo = dumpSchema(g_fout, &numTables, aclsSkip, schemaOnly, dataOnly);
560 dumpClasses(tblinfo, numTables, g_fout, oids);
563 ArchiveEntry(g_fout, "0", "BLOBS", NULL, "",
564 "BLOBS", NULL, "", "", NULL, dumpBlobs, NULL);
566 if (!dataOnly) /* dump indexes and triggers at the end
569 dumpConstraints(g_fout, tblinfo, numTables);
570 dumpTriggers(g_fout, tblinfo, numTables);
571 dumpRules(g_fout, tblinfo, numTables);
574 /* Now sort the output nicely: by OID within object types */
575 SortTocByOID(g_fout);
576 SortTocByObjectType(g_fout);
580 ropt = NewRestoreOptions();
581 ropt->filename = (char *) filename;
582 ropt->dropSchema = outputClean;
583 ropt->aclsSkip = aclsSkip;
584 ropt->superuser = outputSuperuser;
585 ropt->create = outputCreate;
586 ropt->noOwner = outputNoOwner;
587 ropt->disable_triggers = disable_triggers;
589 if (compressLevel == -1)
590 ropt->compression = 0;
592 ropt->compression = compressLevel;
594 ropt->suppressDumpWarnings = true; /* We've already shown
597 RestoreArchive(g_fout, ropt);
600 CloseArchive(g_fout);
608 help(const char *progname)
610 printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
611 printf(_("Usage:\n"));
612 printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
614 printf(_("\nGeneral options:\n"));
615 printf(_(" -f, --file=FILENAME output file name\n"));
616 printf(_(" -F, --format=c|t|p output file format (custom, tar, plain text)\n"));
617 printf(_(" -i, --ignore-version proceed even when server version mismatches\n"
618 " pg_dump version\n"));
619 printf(_(" -v, --verbose verbose mode\n"));
620 printf(_(" -Z, --compress=0-9 compression level for compressed formats\n"));
621 printf(_(" --help show this help, then exit\n"));
622 printf(_(" --version output version information, then exit\n"));
624 printf(_("\nOptions controlling the output content:\n"));
625 printf(_(" -a, --data-only dump only the data, not the schema\n"));
626 printf(_(" -b, --blobs include large objects in dump\n"));
627 printf(_(" -c, --clean clean (drop) schema prior to create\n"));
628 printf(_(" -C, --create include commands to create database in dump\n"));
629 printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
630 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
631 printf(_(" -n, --schema=SCHEMA dump the named schema only\n"));
632 printf(_(" -o, --oids include OIDs in dump\n"));
633 printf(_(" -O, --no-owner do not output commands to set object ownership\n"
634 " in plain text format\n"));
635 printf(_(" -s, --schema-only dump only the schema, no data\n"));
636 printf(_(" -S, --superuser=NAME specify the superuser user name to use in\n"
637 " plain text format\n"));
638 printf(_(" -t, --table=TABLE dump the named table only\n"));
639 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
640 printf(_(" -X disable-triggers, --disable-triggers\n"
641 " disable triggers during data-only restore\n"));
643 printf(_("\nConnection options:\n"));
644 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
645 printf(_(" -p, --port=PORT database server port number\n"));
646 printf(_(" -U, --username=NAME connect as specified database user\n"));
647 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
649 printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
650 "variable value is used.\n\n"));
651 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
659 write_msg(NULL, "*** aborted because of error\n");
664 * selectDumpableNamespace: policy-setting subroutine
665 * Mark a namespace as to be dumped or not
668 selectDumpableNamespace(NamespaceInfo *nsinfo)
671 * If a specific table is being dumped, do not dump any complete
672 * namespaces. If a specific namespace is being dumped, dump just
673 * that namespace. Otherwise, dump all non-system namespaces.
675 if (selectTableName != NULL)
676 nsinfo->dump = false;
677 else if (selectSchemaName != NULL)
679 if (strcmp(nsinfo->nspname, selectSchemaName) == 0)
682 nsinfo->dump = false;
684 else if (strncmp(nsinfo->nspname, "pg_", 3) == 0 ||
685 strcmp(nsinfo->nspname, "information_schema") == 0)
686 nsinfo->dump = false;
692 * selectDumpableTable: policy-setting subroutine
693 * Mark a table as to be dumped or not
696 selectDumpableTable(TableInfo *tbinfo)
699 * Always dump if dumping parent namespace; else, if a particular
700 * tablename has been specified, dump matching table name; else, do
703 tbinfo->dump = false;
704 if (tbinfo->relnamespace->dump)
706 else if (selectTableName != NULL &&
707 strcmp(tbinfo->relname, selectTableName) == 0)
709 /* If both -s and -t specified, must match both to dump */
710 if (selectSchemaName == NULL)
712 else if (strcmp(tbinfo->relnamespace->nspname, selectSchemaName) == 0)
718 * Dump a table's contents for loading using the COPY command
719 * - this routine is called by the Archiver when it wants the table
723 #define COPYBUFSIZ 8192
726 dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
728 const DumpContext *dctx = (DumpContext *) dctxv;
729 TableInfo *tbinfo = &dctx->tblinfo[dctx->tblidx];
730 const char *classname = tbinfo->relname;
731 const bool hasoids = tbinfo->hasoids;
732 const bool oids = dctx->oids;
733 PQExpBuffer q = createPQExpBuffer();
737 char copybuf[COPYBUFSIZ];
738 const char *column_list;
741 write_msg(NULL, "dumping contents of table %s\n", classname);
744 * Make sure we are in proper schema. We will qualify the table name
745 * below anyway (in case its name conflicts with a pg_catalog table);
746 * but this ensures reproducible results in case the table contains
747 * regproc, regclass, etc columns.
749 selectSourceSchema(tbinfo->relnamespace->nspname);
752 * If possible, specify the column list explicitly so that we have no
753 * possibility of retrieving data in the wrong column order. (The
754 * default column ordering of COPY will not be what we want in certain
755 * corner cases involving ADD COLUMN and inheritance.)
757 if (g_fout->remoteVersion >= 70300)
758 column_list = fmtCopyColumnList(tbinfo);
760 column_list = ""; /* can't select columns in COPY */
764 appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
765 fmtQualifiedId(tbinfo->relnamespace->nspname,
771 appendPQExpBuffer(q, "COPY %s %s TO stdout;",
772 fmtQualifiedId(tbinfo->relnamespace->nspname,
776 res = PQexec(g_conn, q->data);
778 PQresultStatus(res) == PGRES_FATAL_ERROR)
780 write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
782 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
783 write_msg(NULL, "The command was: %s\n", q->data);
786 if (PQresultStatus(res) != PGRES_COPY_OUT)
788 write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
790 write_msg(NULL, "The server returned status %d when %d was expected.\n",
791 PQresultStatus(res), PGRES_COPY_OUT);
792 write_msg(NULL, "The command was: %s\n", q->data);
800 ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
802 if (copybuf[0] == '\\' &&
806 copydone = true; /* don't print this... */
810 archputs(copybuf, fout);
817 archputc('\n', fout);
827 * There was considerable discussion in late July, 2000 regarding
828 * slowing down pg_dump when backing up large tables. Users with
829 * both slow & fast (muti-processor) machines experienced
830 * performance degradation when doing a backup.
832 * Initial attempts based on sleeping for a number of ms for each ms
833 * of work were deemed too complex, then a simple 'sleep in each
834 * loop' implementation was suggested. The latter failed because
835 * the loop was too tight. Finally, the following was implemented:
837 * If throttle is non-zero, then See how long since the last sleep.
838 * Work out how long to sleep (based on ratio). If sleep is more
839 * than 100ms, then sleep reset timer EndIf EndIf
841 * where the throttle value was the number of ms to sleep per ms of
842 * work. The calculation was done in each loop.
844 * Most of the hard work is done in the backend, and this solution
845 * still did not work particularly well: on slow machines, the
846 * ratio was 50:1, and on medium paced machines, 1:1, and on fast
847 * multi-processor machines, it had little or no effect, for
848 * reasons that were unclear.
850 * Further discussion ensued, and the proposal was dropped.
852 * For those people who want this feature, it can be implemented
853 * using gettimeofday in each loop, calculating the time since
854 * last sleep, multiplying that by the sleep ratio, then if the
855 * result is more than a preset 'minimum sleep time' (say 100ms),
856 * call the 'select' function to sleep for a subsecond period ie.
858 * select(0, NULL, NULL, NULL, &tvi);
860 * This will return after the interval specified in the structure
861 * tvi. Finally, call gettimeofday again to save the 'last sleep
865 archprintf(fout, "\\.\n\n\n");
867 ret = PQendcopy(g_conn);
870 write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
871 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
872 write_msg(NULL, "The command was: %s\n", q->data);
877 destroyPQExpBuffer(q);
882 dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
884 const DumpContext *dctx = (DumpContext *) dctxv;
885 TableInfo *tbinfo = &dctx->tblinfo[dctx->tblidx];
886 const char *classname = tbinfo->relname;
887 PQExpBuffer q = createPQExpBuffer();
894 * Make sure we are in proper schema. We will qualify the table name
895 * below anyway (in case its name conflicts with a pg_catalog table);
896 * but this ensures reproducible results in case the table contains
897 * regproc, regclass, etc columns.
899 selectSourceSchema(tbinfo->relnamespace->nspname);
901 if (fout->remoteVersion >= 70100)
903 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
904 "SELECT * FROM ONLY %s",
905 fmtQualifiedId(tbinfo->relnamespace->nspname,
910 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
912 fmtQualifiedId(tbinfo->relnamespace->nspname,
916 res = PQexec(g_conn, q->data);
918 PQresultStatus(res) != PGRES_COMMAND_OK)
920 write_msg(NULL, "dumpClasses(): SQL command failed\n");
921 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
922 write_msg(NULL, "The command was: %s\n", q->data);
930 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
932 PQresultStatus(res) != PGRES_TUPLES_OK)
934 write_msg(NULL, "dumpClasses(): SQL command failed\n");
935 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
936 write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
940 nfields = PQnfields(res);
941 for (tuple = 0; tuple < PQntuples(res); tuple++)
943 archprintf(fout, "INSERT INTO %s ", fmtId(classname));
946 /* corner case for zero-column table */
947 archprintf(fout, "DEFAULT VALUES;\n");
950 if (attrNames == true)
953 appendPQExpBuffer(q, "(");
954 for (field = 0; field < nfields; field++)
957 appendPQExpBuffer(q, ", ");
958 appendPQExpBuffer(q, fmtId(PQfname(res, field)));
960 appendPQExpBuffer(q, ") ");
961 archprintf(fout, "%s", q->data);
963 archprintf(fout, "VALUES (");
964 for (field = 0; field < nfields; field++)
967 archprintf(fout, ", ");
968 if (PQgetisnull(res, tuple, field))
970 archprintf(fout, "NULL");
974 /* XXX This code is partially duplicated in ruleutils.c */
975 switch (PQftype(res, field))
986 * These types are printed without quotes
987 * unless they contain values that aren't
988 * accepted by the scanner unquoted (e.g.,
989 * 'NaN'). Note that strtod() and friends
990 * might accept NaN, so we can't use that to
993 * In reality we only need to defend against
994 * infinity and NaN, so we need not get too
995 * crazy about pattern matching here.
997 const char *s = PQgetvalue(res, tuple, field);
999 if (strspn(s, "0123456789 +-eE.") == strlen(s))
1000 archprintf(fout, "%s", s);
1002 archprintf(fout, "'%s'", s);
1008 archprintf(fout, "B'%s'",
1009 PQgetvalue(res, tuple, field));
1013 if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
1014 archprintf(fout, "true");
1016 archprintf(fout, "false");
1020 /* All other types are printed as string literals. */
1021 resetPQExpBuffer(q);
1022 appendStringLiteral(q, PQgetvalue(res, tuple, field), false);
1023 archprintf(fout, "%s", q->data);
1027 archprintf(fout, ");\n");
1029 } while (PQntuples(res) > 0);
1031 archprintf(fout, "\n\n");
1034 res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
1036 PQresultStatus(res) != PGRES_COMMAND_OK)
1038 write_msg(NULL, "dumpClasses(): SQL command failed\n");
1039 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1040 write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
1045 destroyPQExpBuffer(q);
1052 * dump the contents of all the classes.
1055 dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
1058 PQExpBuffer copyBuf = createPQExpBuffer();
1059 DataDumperPtr dumpFn;
1060 DumpContext *dumpCtx;
1064 for (i = 0; i < numTables; i++)
1066 const char *classname = tblinfo[i].relname;
1068 /* Skip VIEW relations */
1069 if (tblinfo[i].relkind == RELKIND_VIEW)
1072 if (tblinfo[i].relkind == RELKIND_SEQUENCE) /* already dumped */
1075 if (tblinfo[i].dump)
1078 write_msg(NULL, "preparing to dump the contents of table %s\n",
1081 dumpCtx = (DumpContext *) calloc(1, sizeof(DumpContext));
1082 dumpCtx->tblinfo = (TableInfo *) tblinfo;
1083 dumpCtx->tblidx = i;
1084 dumpCtx->oids = oids;
1088 /* Dump/restore using COPY */
1089 dumpFn = dumpClasses_nodumpData;
1090 resetPQExpBuffer(copyBuf);
1091 /* must use 2 steps here 'cause fmtId is nonreentrant */
1092 appendPQExpBuffer(copyBuf, "COPY %s ",
1093 fmtId(tblinfo[i].relname));
1094 appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
1095 fmtCopyColumnList(&(tblinfo[i])),
1096 (oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
1097 copyStmt = copyBuf->data;
1101 /* Restore using INSERT */
1102 dumpFn = dumpClasses_dumpData;
1106 ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
1107 tblinfo[i].relnamespace->nspname,
1109 "TABLE DATA", NULL, "", "", copyStmt,
1114 destroyPQExpBuffer(copyBuf);
1120 * dump the database definition
1123 dumpDatabase(Archive *AH)
1125 PQExpBuffer dbQry = createPQExpBuffer();
1126 PQExpBuffer delQry = createPQExpBuffer();
1127 PQExpBuffer creaQry = createPQExpBuffer();
1133 const char *datname,
1138 datname = PQdb(g_conn);
1141 write_msg(NULL, "saving database definition\n");
1143 /* Make sure we are in proper schema */
1144 selectSourceSchema("pg_catalog");
1146 /* Get the database owner and parameters from pg_database */
1147 appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba,"
1148 " pg_encoding_to_char(encoding) as encoding,"
1149 " datpath from pg_database"
1150 " where datname = ");
1151 appendStringLiteral(dbQry, datname, true);
1153 res = PQexec(g_conn, dbQry->data);
1155 PQresultStatus(res) != PGRES_TUPLES_OK)
1157 write_msg(NULL, "SQL command failed\n");
1158 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1159 write_msg(NULL, "The command was: %s\n", dbQry->data);
1163 ntups = PQntuples(res);
1167 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1174 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1179 i_dba = PQfnumber(res, "dba");
1180 i_encoding = PQfnumber(res, "encoding");
1181 i_datpath = PQfnumber(res, "datpath");
1182 dba = PQgetvalue(res, 0, i_dba);
1183 encoding = PQgetvalue(res, 0, i_encoding);
1184 datpath = PQgetvalue(res, 0, i_datpath);
1186 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1188 if (strlen(datpath) > 0)
1190 appendPQExpBuffer(creaQry, " LOCATION = ");
1191 appendStringLiteral(creaQry, datpath, true);
1193 if (strlen(encoding) > 0)
1195 appendPQExpBuffer(creaQry, " ENCODING = ");
1196 appendStringLiteral(creaQry, encoding, true);
1198 appendPQExpBuffer(creaQry, ";\n");
1200 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1203 ArchiveEntry(AH, "0", /* OID */
1205 NULL, /* Namespace */
1207 "DATABASE", /* Desc */
1209 creaQry->data, /* Create */
1210 delQry->data, /* Del */
1213 NULL); /* Dumper Arg */
1217 destroyPQExpBuffer(dbQry);
1218 destroyPQExpBuffer(delQry);
1219 destroyPQExpBuffer(creaQry);
1231 #define loBufSize 16384
1232 #define loFetchSize 1000
1235 dumpBlobs(Archive *AH, char *junkOid, void *junkVal)
1237 PQExpBuffer oidQry = createPQExpBuffer();
1238 PQExpBuffer oidFetchQry = createPQExpBuffer();
1242 char buf[loBufSize];
1247 write_msg(NULL, "saving large objects\n");
1249 /* Make sure we are in proper schema */
1250 selectSourceSchema("pg_catalog");
1252 /* Cursor to get all BLOB tables */
1253 if (AH->remoteVersion >= 70100)
1254 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1256 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
1258 res = PQexec(g_conn, oidQry->data);
1259 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1261 write_msg(NULL, "dumpBlobs(): cursor declaration failed: %s", PQerrorMessage(g_conn));
1265 /* Fetch for cursor */
1266 appendPQExpBuffer(oidFetchQry, "Fetch %d in blobOid", loFetchSize);
1272 res = PQexec(g_conn, oidFetchQry->data);
1274 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
1276 write_msg(NULL, "dumpBlobs(): fetch from cursor failed: %s",
1277 PQerrorMessage(g_conn));
1281 /* Process the tuples, if any */
1282 for (i = 0; i < PQntuples(res); i++)
1284 blobOid = atooid(PQgetvalue(res, i, 0));
1286 loFd = lo_open(g_conn, blobOid, INV_READ);
1289 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1290 PQerrorMessage(g_conn));
1294 StartBlob(AH, blobOid);
1296 /* Now read it in chunks, sending data to archive */
1299 cnt = lo_read(g_conn, loFd, buf, loBufSize);
1302 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1303 PQerrorMessage(g_conn));
1307 WriteData(AH, buf, cnt);
1311 lo_close(g_conn, loFd);
1313 EndBlob(AH, blobOid);
1316 } while (PQntuples(res) > 0);
1318 destroyPQExpBuffer(oidQry);
1319 destroyPQExpBuffer(oidFetchQry);
1326 * read all namespaces in the system catalogs and return them in the
1327 * NamespaceInfo* structure
1329 * numNamespaces is set to the number of namespaces read in
1332 getNamespaces(int *numNamespaces)
1338 NamespaceInfo *nsinfo;
1345 * Before 7.3, there are no real namespaces; create two dummy entries,
1346 * one for user stuff and one for system stuff.
1348 if (g_fout->remoteVersion < 70300)
1350 nsinfo = (NamespaceInfo *) malloc(2 * sizeof(NamespaceInfo));
1352 nsinfo[0].oid = strdup("0");
1353 nsinfo[0].nspname = strdup("");
1354 nsinfo[0].usename = strdup("");
1355 nsinfo[0].nspacl = strdup("");
1357 selectDumpableNamespace(&nsinfo[0]);
1359 nsinfo[1].oid = strdup("1");
1360 nsinfo[1].nspname = strdup("pg_catalog");
1361 nsinfo[1].usename = strdup("");
1362 nsinfo[1].nspacl = strdup("");
1364 selectDumpableNamespace(&nsinfo[1]);
1366 g_namespaces = nsinfo;
1367 g_numNamespaces = *numNamespaces = 2;
1372 query = createPQExpBuffer();
1374 /* Make sure we are in proper schema */
1375 selectSourceSchema("pg_catalog");
1378 * we fetch all namespaces including system ones, so that every object
1379 * we read in can be linked to a containing namespace.
1381 appendPQExpBuffer(query, "SELECT oid, nspname, "
1382 "(select usename from pg_user where nspowner = usesysid) as usename, "
1384 "FROM pg_namespace");
1386 res = PQexec(g_conn, query->data);
1388 PQresultStatus(res) != PGRES_TUPLES_OK)
1390 write_msg(NULL, "query to obtain list of schemas failed: %s", PQerrorMessage(g_conn));
1394 ntups = PQntuples(res);
1396 nsinfo = (NamespaceInfo *) malloc(ntups * sizeof(NamespaceInfo));
1398 i_oid = PQfnumber(res, "oid");
1399 i_nspname = PQfnumber(res, "nspname");
1400 i_usename = PQfnumber(res, "usename");
1401 i_nspacl = PQfnumber(res, "nspacl");
1403 for (i = 0; i < ntups; i++)
1405 nsinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1406 nsinfo[i].nspname = strdup(PQgetvalue(res, i, i_nspname));
1407 nsinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1408 nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
1410 /* Decide whether to dump this namespace */
1411 selectDumpableNamespace(&nsinfo[i]);
1413 if (strlen(nsinfo[i].usename) == 0)
1414 write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
1419 * If the user attempted to dump a specific namespace, check to ensure
1420 * that the specified namespace actually exists.
1422 if (selectSchemaName)
1424 for (i = 0; i < ntups; i++)
1425 if (strcmp(nsinfo[i].nspname, selectSchemaName) == 0)
1428 /* Didn't find a match */
1431 write_msg(NULL, "specified schema \"%s\" does not exist\n",
1438 destroyPQExpBuffer(query);
1440 g_namespaces = nsinfo;
1441 g_numNamespaces = *numNamespaces = ntups;
1448 * given a namespace OID and an object OID, look up the info read by
1451 * NB: for pre-7.3 source database, we use object OID to guess whether it's
1452 * a system object or not. In 7.3 and later there is no guessing.
1454 static NamespaceInfo *
1455 findNamespace(const char *nsoid, const char *objoid)
1459 if (g_fout->remoteVersion >= 70300)
1461 for (i = 0; i < g_numNamespaces; i++)
1463 NamespaceInfo *nsinfo = &g_namespaces[i];
1465 if (strcmp(nsoid, nsinfo->oid) == 0)
1468 write_msg(NULL, "schema with OID %s does not exist\n", nsoid);
1473 /* This code depends on the layout set up by getNamespaces. */
1474 if (atooid(objoid) > g_last_builtin_oid)
1475 i = 0; /* user object */
1477 i = 1; /* system object */
1478 return &g_namespaces[i];
1481 return NULL; /* keep compiler quiet */
1486 * read all types in the system catalogs and return them in the
1487 * TypeInfo* structure
1489 * numTypes is set to the number of types read in
1492 getTypes(int *numTypes)
1497 PQExpBuffer query = createPQExpBuffer();
1510 * we include even the built-in types because those may be used as
1511 * array elements by user-defined types
1513 * we filter out the built-in types when we dump out the types
1515 * same approach for undefined (shell) types
1518 /* Make sure we are in proper schema */
1519 selectSourceSchema("pg_catalog");
1521 if (g_fout->remoteVersion >= 70300)
1523 appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
1525 "(select usename from pg_user where typowner = usesysid) as usename, "
1526 "typelem, typrelid, "
1527 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
1528 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
1529 "typtype, typisdefined "
1534 appendPQExpBuffer(query, "SELECT pg_type.oid, typname, "
1535 "0::oid as typnamespace, "
1536 "(select usename from pg_user where typowner = usesysid) as usename, "
1537 "typelem, typrelid, "
1538 "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
1539 "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END as typrelkind, "
1540 "typtype, typisdefined "
1544 res = PQexec(g_conn, query->data);
1546 PQresultStatus(res) != PGRES_TUPLES_OK)
1548 write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
1552 ntups = PQntuples(res);
1554 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
1556 i_oid = PQfnumber(res, "oid");
1557 i_typname = PQfnumber(res, "typname");
1558 i_typnamespace = PQfnumber(res, "typnamespace");
1559 i_usename = PQfnumber(res, "usename");
1560 i_typelem = PQfnumber(res, "typelem");
1561 i_typrelid = PQfnumber(res, "typrelid");
1562 i_typrelkind = PQfnumber(res, "typrelkind");
1563 i_typtype = PQfnumber(res, "typtype");
1564 i_typisdefined = PQfnumber(res, "typisdefined");
1566 for (i = 0; i < ntups; i++)
1568 tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1569 tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
1570 tinfo[i].typnamespace = findNamespace(PQgetvalue(res, i, i_typnamespace),
1572 tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1573 tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
1574 tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
1575 tinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
1576 tinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
1579 * check for user-defined array types, omit system generated ones
1581 if ((strcmp(tinfo[i].typelem, "0") != 0) &&
1582 tinfo[i].typname[0] != '_')
1583 tinfo[i].isArray = true;
1585 tinfo[i].isArray = false;
1587 if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
1588 tinfo[i].isDefined = true;
1590 tinfo[i].isDefined = false;
1592 if (strlen(tinfo[i].usename) == 0 && tinfo[i].isDefined)
1593 write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
1601 destroyPQExpBuffer(query);
1608 * read all operators in the system catalogs and return them in the
1609 * OprInfo* structure
1611 * numOprs is set to the number of operators read in
1614 getOperators(int *numOprs)
1619 PQExpBuffer query = createPQExpBuffer();
1628 * find all operators, including builtin operators; we filter out
1629 * system-defined operators at dump-out time.
1632 /* Make sure we are in proper schema */
1633 selectSourceSchema("pg_catalog");
1635 if (g_fout->remoteVersion >= 70300)
1637 appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, "
1639 "(select usename from pg_user where oprowner = usesysid) as usename, "
1640 "oprcode::oid as oprcode "
1641 "from pg_operator");
1645 appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, "
1646 "0::oid as oprnamespace, "
1647 "(select usename from pg_user where oprowner = usesysid) as usename, "
1648 "oprcode::oid as oprcode "
1649 "from pg_operator");
1652 res = PQexec(g_conn, query->data);
1654 PQresultStatus(res) != PGRES_TUPLES_OK)
1656 write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
1660 ntups = PQntuples(res);
1663 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
1665 i_oid = PQfnumber(res, "oid");
1666 i_oprname = PQfnumber(res, "oprname");
1667 i_oprnamespace = PQfnumber(res, "oprnamespace");
1668 i_usename = PQfnumber(res, "usename");
1669 i_oprcode = PQfnumber(res, "oprcode");
1671 for (i = 0; i < ntups; i++)
1673 oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1674 oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
1675 oprinfo[i].oprnamespace = findNamespace(PQgetvalue(res, i, i_oprnamespace),
1677 oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1678 oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
1680 if (strlen(oprinfo[i].usename) == 0)
1681 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
1682 oprinfo[i].oprname);
1687 destroyPQExpBuffer(query);
1694 * read all opclasses in the system catalogs and return them in the
1695 * OpclassInfo* structure
1697 * numOpclasses is set to the number of opclasses read in
1700 getOpclasses(int *numOpclasses)
1705 PQExpBuffer query = createPQExpBuffer();
1706 OpclassInfo *opcinfo;
1713 * find all opclasses, including builtin opclasses; we filter out
1714 * system-defined opclasses at dump-out time.
1717 /* Make sure we are in proper schema */
1718 selectSourceSchema("pg_catalog");
1720 if (g_fout->remoteVersion >= 70300)
1722 appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
1724 "(select usename from pg_user where opcowner = usesysid) as usename "
1729 appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
1730 "0::oid as opcnamespace, "
1731 "''::name as usename "
1735 res = PQexec(g_conn, query->data);
1737 PQresultStatus(res) != PGRES_TUPLES_OK)
1739 write_msg(NULL, "query to obtain list of operator classes failed: %s", PQerrorMessage(g_conn));
1743 ntups = PQntuples(res);
1744 *numOpclasses = ntups;
1746 opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
1748 i_oid = PQfnumber(res, "oid");
1749 i_opcname = PQfnumber(res, "opcname");
1750 i_opcnamespace = PQfnumber(res, "opcnamespace");
1751 i_usename = PQfnumber(res, "usename");
1753 for (i = 0; i < ntups; i++)
1755 opcinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1756 opcinfo[i].opcname = strdup(PQgetvalue(res, i, i_opcname));
1757 opcinfo[i].opcnamespace = findNamespace(PQgetvalue(res, i, i_opcnamespace),
1759 opcinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1761 if (g_fout->remoteVersion >= 70300)
1763 if (strlen(opcinfo[i].usename) == 0)
1764 write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
1765 opcinfo[i].opcname);
1771 destroyPQExpBuffer(query);
1778 * read all the user-defined aggregates in the system catalogs and
1779 * return them in the AggInfo* structure
1781 * numAggs is set to the number of aggregates read in
1784 getAggregates(int *numAggs)
1789 PQExpBuffer query = createPQExpBuffer();
1799 /* Make sure we are in proper schema */
1800 selectSourceSchema("pg_catalog");
1802 /* find all user-defined aggregates */
1804 if (g_fout->remoteVersion >= 70300)
1806 appendPQExpBuffer(query, "SELECT pg_proc.oid, proname as aggname, "
1807 "pronamespace as aggnamespace, "
1808 "proargtypes[0] as aggbasetype, "
1809 "(select usename from pg_user where proowner = usesysid) as usename, "
1813 "AND pronamespace != "
1814 "(select oid from pg_namespace where nspname = 'pg_catalog')");
1818 appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, "
1819 "0::oid as aggnamespace, "
1821 "(select usename from pg_user where aggowner = usesysid) as usename, "
1823 "from pg_aggregate "
1824 "where oid > '%u'::oid",
1825 g_last_builtin_oid);
1828 res = PQexec(g_conn, query->data);
1830 PQresultStatus(res) != PGRES_TUPLES_OK)
1832 write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
1833 PQerrorMessage(g_conn));
1837 ntups = PQntuples(res);
1840 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
1842 i_oid = PQfnumber(res, "oid");
1843 i_aggname = PQfnumber(res, "aggname");
1844 i_aggnamespace = PQfnumber(res, "aggnamespace");
1845 i_aggbasetype = PQfnumber(res, "aggbasetype");
1846 i_usename = PQfnumber(res, "usename");
1847 i_aggacl = PQfnumber(res, "aggacl");
1849 for (i = 0; i < ntups; i++)
1851 agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1852 agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1853 agginfo[i].aggnamespace = findNamespace(PQgetvalue(res, i, i_aggnamespace),
1855 agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1856 agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1857 if (strlen(agginfo[i].usename) == 0)
1858 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
1859 agginfo[i].aggname);
1860 agginfo[i].aggacl = strdup(PQgetvalue(res, i, i_aggacl));
1861 agginfo[i].anybasetype = false; /* computed when it's dumped */
1862 agginfo[i].fmtbasetype = NULL; /* computed when it's dumped */
1867 destroyPQExpBuffer(query);
1874 * read all the user-defined functions in the system catalogs and
1875 * return them in the FuncInfo* structure
1877 * numFuncs is set to the number of functions read in
1880 getFuncs(int *numFuncs)
1885 PQExpBuffer query = createPQExpBuffer();
1898 /* Make sure we are in proper schema */
1899 selectSourceSchema("pg_catalog");
1901 /* find all user-defined funcs */
1903 if (g_fout->remoteVersion >= 70300)
1905 appendPQExpBuffer(query,
1906 "SELECT pg_proc.oid, proname, prolang, "
1907 "pronargs, proargtypes, prorettype, proacl, "
1909 "(select usename from pg_user where proowner = usesysid) as usename "
1911 "WHERE NOT proisagg "
1912 "AND pronamespace != "
1913 "(select oid from pg_namespace where nspname = 'pg_catalog')");
1917 appendPQExpBuffer(query,
1918 "SELECT pg_proc.oid, proname, prolang, "
1919 "pronargs, proargtypes, prorettype, "
1920 "'{=X}' as proacl, "
1921 "0::oid as pronamespace, "
1922 "(select usename from pg_user where proowner = usesysid) as usename "
1924 "where pg_proc.oid > '%u'::oid",
1925 g_last_builtin_oid);
1928 res = PQexec(g_conn, query->data);
1930 PQresultStatus(res) != PGRES_TUPLES_OK)
1932 write_msg(NULL, "query to obtain list of functions failed: %s",
1933 PQerrorMessage(g_conn));
1937 ntups = PQntuples(res);
1941 finfo = (FuncInfo *) calloc(ntups, sizeof(FuncInfo));
1943 i_oid = PQfnumber(res, "oid");
1944 i_proname = PQfnumber(res, "proname");
1945 i_pronamespace = PQfnumber(res, "pronamespace");
1946 i_usename = PQfnumber(res, "usename");
1947 i_prolang = PQfnumber(res, "prolang");
1948 i_pronargs = PQfnumber(res, "pronargs");
1949 i_proargtypes = PQfnumber(res, "proargtypes");
1950 i_prorettype = PQfnumber(res, "prorettype");
1951 i_proacl = PQfnumber(res, "proacl");
1953 for (i = 0; i < ntups; i++)
1955 finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1956 finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
1957 finfo[i].pronamespace = findNamespace(PQgetvalue(res, i, i_pronamespace),
1959 finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1960 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
1961 finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
1962 finfo[i].proacl = strdup(PQgetvalue(res, i, i_proacl));
1963 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
1964 if (finfo[i].nargs == 0)
1965 finfo[i].argtypes = NULL;
1968 finfo[i].argtypes = malloc(finfo[i].nargs * sizeof(finfo[i].argtypes[0]));
1969 parseNumericArray(PQgetvalue(res, i, i_proargtypes),
1974 finfo[i].dumped = false;
1976 if (strlen(finfo[i].usename) == 0)
1977 write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
1983 destroyPQExpBuffer(query);
1990 * read all the user-defined tables (no indexes, no catalogs)
1991 * in the system catalogs return them in the TableInfo* structure
1993 * numTables is set to the number of tables read in
1996 getTables(int *numTables)
2001 PQExpBuffer query = createPQExpBuffer();
2002 PQExpBuffer delqry = createPQExpBuffer();
2003 PQExpBuffer lockquery = createPQExpBuffer();
2020 /* Make sure we are in proper schema */
2021 selectSourceSchema("pg_catalog");
2024 * Find all the tables (including views and sequences).
2026 * We include system catalogs, so that we can work if a user table is
2027 * defined to inherit from a system catalog (pretty weird, but...)
2029 * We ignore tables that are not type 'r' (ordinary relation) or 'S'
2030 * (sequence) or 'v' (view).
2032 * Note: in this phase we should collect only a minimal amount of
2033 * information about each table, basically just enough to decide if it
2034 * is interesting. We must fetch all tables in this phase because
2035 * otherwise we cannot correctly identify inherited columns, serial
2039 if (g_fout->remoteVersion >= 70300)
2042 * Left join to pick up dependency info linking sequences to their
2043 * serial column, if any
2045 appendPQExpBuffer(query,
2046 "SELECT c.oid, relname, relacl, relkind, "
2048 "(select usename from pg_user where relowner = usesysid) as usename, "
2049 "relchecks, reltriggers, "
2050 "relhasindex, relhasrules, relhasoids, "
2051 "d.refobjid as owning_tab, "
2052 "d.refobjsubid as owning_col "
2054 "left join pg_depend d on "
2055 "(c.relkind = '%c' and "
2056 "d.classid = c.tableoid and d.objid = c.oid and "
2057 "d.objsubid = 0 and "
2058 "d.refclassid = c.tableoid and d.deptype = 'i') "
2059 "where relkind in ('%c', '%c', '%c') "
2062 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2064 else if (g_fout->remoteVersion >= 70200)
2066 appendPQExpBuffer(query,
2067 "SELECT pg_class.oid, relname, relacl, relkind, "
2068 "0::oid as relnamespace, "
2069 "(select usename from pg_user where relowner = usesysid) as usename, "
2070 "relchecks, reltriggers, "
2071 "relhasindex, relhasrules, relhasoids, "
2072 "NULL::oid as owning_tab, "
2073 "NULL::int4 as owning_col "
2075 "where relkind in ('%c', '%c', '%c') "
2077 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2079 else if (g_fout->remoteVersion >= 70100)
2081 /* all tables have oids in 7.1 */
2082 appendPQExpBuffer(query,
2083 "SELECT pg_class.oid, relname, relacl, relkind, "
2084 "0::oid as relnamespace, "
2085 "(select usename from pg_user where relowner = usesysid) as usename, "
2086 "relchecks, reltriggers, "
2087 "relhasindex, relhasrules, "
2088 "'t'::bool as relhasoids, "
2089 "NULL::oid as owning_tab, "
2090 "NULL::int4 as owning_col "
2092 "where relkind in ('%c', '%c', '%c') "
2094 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2099 * Before 7.1, view relkind was not set to 'v', so we must check
2100 * if we have a view by looking for a rule in pg_rewrite.
2102 appendPQExpBuffer(query,
2103 "SELECT c.oid, relname, relacl, "
2104 "CASE WHEN relhasrules and relkind = 'r' "
2105 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
2106 " r.ev_class = c.oid AND r.ev_type = '1') "
2107 "THEN '%c'::\"char\" "
2108 "ELSE relkind END AS relkind,"
2109 "0::oid as relnamespace, "
2110 "(select usename from pg_user where relowner = usesysid) as usename, "
2111 "relchecks, reltriggers, "
2112 "relhasindex, relhasrules, "
2113 "'t'::bool as relhasoids, "
2114 "NULL::oid as owning_tab, "
2115 "NULL::int4 as owning_col "
2117 "where relkind in ('%c', '%c') "
2120 RELKIND_RELATION, RELKIND_SEQUENCE);
2123 res = PQexec(g_conn, query->data);
2125 PQresultStatus(res) != PGRES_TUPLES_OK)
2127 write_msg(NULL, "query to obtain list of tables failed: %s",
2128 PQerrorMessage(g_conn));
2132 ntups = PQntuples(res);
2137 * Extract data from result and lock dumpable tables. We do the
2138 * locking before anything else, to minimize the window wherein a
2139 * table could disappear under us.
2141 * Note that we have to save info about all tables here, even when
2142 * dumping only one, because we don't yet know which tables might be
2143 * inheritance ancestors of the target table.
2145 tblinfo = (TableInfo *) calloc(ntups, sizeof(TableInfo));
2147 i_reloid = PQfnumber(res, "oid");
2148 i_relname = PQfnumber(res, "relname");
2149 i_relnamespace = PQfnumber(res, "relnamespace");
2150 i_relacl = PQfnumber(res, "relacl");
2151 i_relkind = PQfnumber(res, "relkind");
2152 i_usename = PQfnumber(res, "usename");
2153 i_relchecks = PQfnumber(res, "relchecks");
2154 i_reltriggers = PQfnumber(res, "reltriggers");
2155 i_relhasindex = PQfnumber(res, "relhasindex");
2156 i_relhasrules = PQfnumber(res, "relhasrules");
2157 i_relhasoids = PQfnumber(res, "relhasoids");
2158 i_owning_tab = PQfnumber(res, "owning_tab");
2159 i_owning_col = PQfnumber(res, "owning_col");
2161 for (i = 0; i < ntups; i++)
2163 tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
2164 tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
2165 tblinfo[i].relnamespace = findNamespace(PQgetvalue(res, i, i_relnamespace),
2167 tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2168 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
2169 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
2170 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
2171 tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
2172 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
2173 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
2174 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2175 if (PQgetisnull(res, i, i_owning_tab))
2177 tblinfo[i].owning_tab = NULL;
2178 tblinfo[i].owning_col = 0;
2182 tblinfo[i].owning_tab = strdup(PQgetvalue(res, i, i_owning_tab));
2183 tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
2186 /* other fields were zeroed above */
2189 * Decide whether we want to dump this table. Sequences owned by
2190 * serial columns are never dumpable on their own; we will
2191 * transpose their owning table's dump flag to them below.
2193 if (tblinfo[i].owning_tab == NULL)
2194 selectDumpableTable(&tblinfo[i]);
2196 tblinfo[i].dump = false;
2197 tblinfo[i].interesting = tblinfo[i].dump;
2200 * Read-lock target tables to make sure they aren't DROPPED or
2201 * altered in schema before we get around to dumping them.
2203 * Note that we don't explicitly lock parents of the target tables;
2204 * we assume our lock on the child is enough to prevent schema
2205 * alterations to parent tables.
2207 * NOTE: it'd be kinda nice to lock views and sequences too, not only
2208 * plain tables, but the backend doesn't presently allow that.
2210 if (tblinfo[i].dump && tblinfo[i].relkind == RELKIND_RELATION)
2214 resetPQExpBuffer(lockquery);
2215 appendPQExpBuffer(lockquery,
2216 "LOCK TABLE %s IN ACCESS SHARE MODE",
2217 fmtQualifiedId(tblinfo[i].relnamespace->nspname,
2218 tblinfo[i].relname));
2219 lres = PQexec(g_conn, lockquery->data);
2220 if (!lres || PQresultStatus(lres) != PGRES_COMMAND_OK)
2222 write_msg(NULL, "attempt to lock table \"%s\" failed: %s",
2223 tblinfo[i].relname, PQerrorMessage(g_conn));
2229 /* Emit notice if join for owner failed */
2230 if (strlen(tblinfo[i].usename) == 0)
2231 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
2232 tblinfo[i].relname);
2236 * If the user is attempting to dump a specific table, check to ensure
2237 * that the specified table actually exists. (This is a bit simplistic
2238 * since we don't fully check the combination of -n and -t switches.)
2240 if (selectTableName)
2242 for (i = 0; i < ntups; i++)
2243 if (strcmp(tblinfo[i].relname, selectTableName) == 0)
2246 /* Didn't find a match */
2249 write_msg(NULL, "specified table \"%s\" does not exist\n",
2256 destroyPQExpBuffer(query);
2257 destroyPQExpBuffer(delqry);
2258 destroyPQExpBuffer(lockquery);
2265 * read all the inheritance information
2266 * from the system catalogs return them in the InhInfo* structure
2268 * numInherits is set to the number of pairs read in
2271 getInherits(int *numInherits)
2276 PQExpBuffer query = createPQExpBuffer();
2282 /* Make sure we are in proper schema */
2283 selectSourceSchema("pg_catalog");
2285 /* find all the inheritance information */
2287 appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
2289 res = PQexec(g_conn, query->data);
2291 PQresultStatus(res) != PGRES_TUPLES_OK)
2293 write_msg(NULL, "query to obtain inheritance relationships failed: %s",
2294 PQerrorMessage(g_conn));
2298 ntups = PQntuples(res);
2300 *numInherits = ntups;
2302 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
2304 i_inhrelid = PQfnumber(res, "inhrelid");
2305 i_inhparent = PQfnumber(res, "inhparent");
2307 for (i = 0; i < ntups; i++)
2309 inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2310 inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
2315 destroyPQExpBuffer(query);
2322 * for each interesting table, read its attributes types and names
2324 * this is implemented in a very inefficient way right now, looping
2325 * through the tblinfo and doing a join per table to find the attrs and their
2331 getTableAttrs(TableInfo *tblinfo, int numTables)
2336 PQExpBuffer q = createPQExpBuffer();
2341 int i_attstattarget;
2352 for (i = 0; i < numTables; i++)
2354 TableInfo *tbinfo = &tblinfo[i];
2356 /* Don't bother to collect info for sequences */
2357 if (tbinfo->relkind == RELKIND_SEQUENCE)
2360 /* Don't bother with uninteresting tables, either */
2361 if (!tbinfo->interesting)
2365 * Make sure we are in proper schema for this table; this allows
2366 * correct retrieval of formatted type names and default exprs
2368 selectSourceSchema(tbinfo->relnamespace->nspname);
2370 /* find all the user attributes and their types */
2373 * we must read the attribute names in attribute number order!
2374 * because we will use the attnum to index into the attnames array
2375 * later. We actually ask to order by "attrelid, attnum" because
2376 * (at least up to 7.3) the planner is not smart enough to realize
2377 * it needn't re-sort the output of an indexscan on
2378 * pg_attribute_relid_attnum_index.
2381 write_msg(NULL, "finding the columns and types of table \"%s\"\n",
2384 resetPQExpBuffer(q);
2386 if (g_fout->remoteVersion >= 70300)
2388 /* need left join here to not fail on dropped columns ... */
2389 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, "
2390 "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, "
2391 "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname "
2392 "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t "
2393 "on a.atttypid = t.oid "
2394 "where a.attrelid = '%s'::pg_catalog.oid "
2395 "and a.attnum > 0::pg_catalog.int2 "
2396 "order by a.attrelid, a.attnum",
2399 else if (g_fout->remoteVersion >= 70100)
2402 * attstattarget doesn't exist in 7.1. It does exist in 7.2,
2403 * but we don't dump it because we can't tell whether it's
2404 * been explicitly set or was just a default.
2406 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, "
2407 "a.attnotnull, a.atthasdef, false as attisdropped, null as attislocal, "
2408 "format_type(t.oid,a.atttypmod) as atttypname "
2409 "from pg_attribute a left join pg_type t "
2410 "on a.atttypid = t.oid "
2411 "where a.attrelid = '%s'::oid "
2412 "and a.attnum > 0::int2 "
2413 "order by a.attrelid, a.attnum",
2418 /* format_type not available before 7.1 */
2419 appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, "
2420 "attnotnull, atthasdef, false as attisdropped, null as attislocal, "
2421 "(select typname from pg_type where oid = atttypid) as atttypname "
2422 "from pg_attribute a "
2423 "where attrelid = '%s'::oid "
2424 "and attnum > 0::int2 "
2425 "order by attrelid, attnum",
2429 res = PQexec(g_conn, q->data);
2431 PQresultStatus(res) != PGRES_TUPLES_OK)
2433 write_msg(NULL, "query to get table columns failed: %s", PQerrorMessage(g_conn));
2437 ntups = PQntuples(res);
2439 i_attnum = PQfnumber(res, "attnum");
2440 i_attname = PQfnumber(res, "attname");
2441 i_atttypname = PQfnumber(res, "atttypname");
2442 i_atttypmod = PQfnumber(res, "atttypmod");
2443 i_attstattarget = PQfnumber(res, "attstattarget");
2444 i_attstorage = PQfnumber(res, "attstorage");
2445 i_typstorage = PQfnumber(res, "typstorage");
2446 i_attnotnull = PQfnumber(res, "attnotnull");
2447 i_atthasdef = PQfnumber(res, "atthasdef");
2448 i_attisdropped = PQfnumber(res, "attisdropped");
2449 i_attislocal = PQfnumber(res, "attislocal");
2451 tbinfo->numatts = ntups;
2452 tbinfo->attnames = (char **) malloc(ntups * sizeof(char *));
2453 tbinfo->atttypnames = (char **) malloc(ntups * sizeof(char *));
2454 tbinfo->atttypmod = (int *) malloc(ntups * sizeof(int));
2455 tbinfo->attstattarget = (int *) malloc(ntups * sizeof(int));
2456 tbinfo->attstorage = (char *) malloc(ntups * sizeof(char));
2457 tbinfo->typstorage = (char *) malloc(ntups * sizeof(char));
2458 tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool));
2459 tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool));
2460 tbinfo->attisserial = (bool *) malloc(ntups * sizeof(bool));
2461 tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool));
2462 tbinfo->adef_expr = (char **) malloc(ntups * sizeof(char *));
2463 tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool));
2464 tbinfo->inhAttrDef = (bool *) malloc(ntups * sizeof(bool));
2465 tbinfo->inhNotNull = (bool *) malloc(ntups * sizeof(bool));
2466 hasdefaults = false;
2468 for (j = 0; j < ntups; j++)
2470 if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
2472 write_msg(NULL, "invalid column numbering in table \"%s\"\n",
2476 tbinfo->attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2477 tbinfo->atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname));
2478 tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2479 tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
2480 tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
2481 tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
2482 tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
2483 tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
2484 tbinfo->attisserial[j] = false; /* fix below */
2485 tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
2486 tbinfo->adef_expr[j] = NULL; /* fix below */
2487 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
2489 /* these flags will be set in flagInhAttrs() */
2490 tbinfo->inhAttrs[j] = false;
2491 tbinfo->inhAttrDef[j] = false;
2492 tbinfo->inhNotNull[j] = false;
2502 write_msg(NULL, "finding default expressions of table \"%s\"\n",
2505 resetPQExpBuffer(q);
2506 if (g_fout->remoteVersion >= 70300)
2508 appendPQExpBuffer(q, "SELECT adnum, "
2509 "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
2510 "FROM pg_catalog.pg_attrdef "
2511 "WHERE adrelid = '%s'::pg_catalog.oid",
2514 else if (g_fout->remoteVersion >= 70200)
2516 appendPQExpBuffer(q, "SELECT adnum, "
2517 "pg_get_expr(adbin, adrelid) AS adsrc "
2519 "WHERE adrelid = '%s'::oid",
2524 /* no pg_get_expr, so must rely on adsrc */
2525 appendPQExpBuffer(q, "SELECT adnum, adsrc FROM pg_attrdef "
2526 "WHERE adrelid = '%s'::oid",
2529 res = PQexec(g_conn, q->data);
2531 PQresultStatus(res) != PGRES_TUPLES_OK)
2533 write_msg(NULL, "query to get column default values failed: %s",
2534 PQerrorMessage(g_conn));
2538 numDefaults = PQntuples(res);
2539 for (j = 0; j < numDefaults; j++)
2541 int adnum = atoi(PQgetvalue(res, j, 0));
2543 if (adnum <= 0 || adnum > ntups)
2545 write_msg(NULL, "invalid adnum value %d for table \"%s\"\n",
2546 adnum, tbinfo->relname);
2549 tbinfo->adef_expr[adnum - 1] = strdup(PQgetvalue(res, j, 1));
2555 * Check to see if any columns are serial columns. Our first
2556 * quick filter is that it must be integer or bigint with a
2557 * default. If so, we scan to see if we found a sequence linked
2558 * to this column. If we did, mark the column and sequence
2561 for (j = 0; j < ntups; j++)
2564 * Note assumption that format_type will show these types as
2565 * exactly "integer" and "bigint" regardless of schema path.
2566 * This is correct in 7.3 but needs to be watched.
2568 if (strcmp(tbinfo->atttypnames[j], "integer") != 0 &&
2569 strcmp(tbinfo->atttypnames[j], "bigint") != 0)
2571 if (tbinfo->adef_expr[j] == NULL)
2573 for (k = 0; k < numTables; k++)
2575 TableInfo *seqinfo = &tblinfo[k];
2577 if (seqinfo->owning_tab != NULL &&
2578 strcmp(seqinfo->owning_tab, tbinfo->oid) == 0 &&
2579 seqinfo->owning_col == j + 1)
2582 * Found a match. Copy the table's interesting and
2583 * dumpable flags to the sequence.
2585 tbinfo->attisserial[j] = true;
2586 seqinfo->interesting = tbinfo->interesting;
2587 seqinfo->dump = tbinfo->dump;
2594 destroyPQExpBuffer(q);
2601 * This routine is used to dump any comments associated with the
2602 * oid handed to this routine. The routine takes a constant character
2603 * string for the target part of the comment-creation command, plus
2604 * the namespace and owner of the object (for labeling the ArchiveEntry),
2605 * plus OID, class name, and subid which are the lookup key for pg_description.
2606 * If a matching pg_description entry is found, it is dumped.
2607 * Additional dependencies can be passed for the comment, too --- this is
2608 * needed for VIEWs, whose comments are filed under the table OID but
2609 * which are dumped in order by their rule OID.
2613 dumpComment(Archive *fout, const char *target,
2614 const char *namespace, const char *owner,
2615 const char *oid, const char *classname, int subid,
2616 const char *((*deps)[]))
2622 /* Comments are SCHEMA not data */
2627 * Note we do NOT change source schema here; preserve the caller's
2631 /* Build query to find comment */
2633 query = createPQExpBuffer();
2635 if (fout->remoteVersion >= 70300)
2637 appendPQExpBuffer(query, "SELECT description FROM pg_catalog.pg_description "
2638 "WHERE objoid = '%s'::pg_catalog.oid and classoid = "
2639 "'pg_catalog.%s'::pg_catalog.regclass "
2640 "and objsubid = %d",
2641 oid, classname, subid);
2643 else if (fout->remoteVersion >= 70200)
2645 appendPQExpBuffer(query, "SELECT description FROM pg_description "
2646 "WHERE objoid = '%s'::oid and classoid = "
2647 "(SELECT oid FROM pg_class where relname = '%s') "
2648 "and objsubid = %d",
2649 oid, classname, subid);
2653 /* Note: this will fail to find attribute comments in pre-7.2... */
2654 appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = '%s'::oid", oid);
2659 res = PQexec(g_conn, query->data);
2660 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2662 write_msg(NULL, "query to get comment on OID %s failed: %s",
2663 oid, PQerrorMessage(g_conn));
2667 /* If a comment exists, build COMMENT ON statement */
2669 if (PQntuples(res) == 1)
2671 i_description = PQfnumber(res, "description");
2672 resetPQExpBuffer(query);
2673 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
2674 appendStringLiteral(query, PQgetvalue(res, 0, i_description), false);
2675 appendPQExpBuffer(query, ";\n");
2677 ArchiveEntry(fout, oid, target, namespace, owner,
2679 query->data, "", NULL, NULL, NULL);
2683 destroyPQExpBuffer(query);
2687 * dumpTableComment --
2689 * As above, but dump comments for both the specified table (or view)
2690 * and its columns. For speed, we want to do this with only one query.
2693 dumpTableComment(Archive *fout, TableInfo *tbinfo,
2694 const char *reltypename,
2695 const char *((*deps)[]))
2705 /* Comments are SCHEMA not data */
2710 * Note we do NOT change source schema here; preserve the caller's
2714 /* Build query to find comments */
2716 query = createPQExpBuffer();
2717 target = createPQExpBuffer();
2719 if (fout->remoteVersion >= 70300)
2721 appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_catalog.pg_description "
2722 "WHERE objoid = '%s'::pg_catalog.oid and classoid = "
2723 "'pg_catalog.pg_class'::pg_catalog.regclass "
2724 "ORDER BY objoid, classoid, objsubid",
2727 else if (fout->remoteVersion >= 70200)
2729 appendPQExpBuffer(query, "SELECT description, objsubid FROM pg_description "
2730 "WHERE objoid = '%s'::oid and classoid = "
2731 "(SELECT oid FROM pg_class where relname = 'pg_class') "
2732 "ORDER BY objoid, classoid, objsubid",
2737 /* Note: this will fail to find attribute comments in pre-7.2... */
2738 appendPQExpBuffer(query, "SELECT description, 0 as objsubid FROM pg_description WHERE objoid = '%s'::oid", tbinfo->oid);
2743 res = PQexec(g_conn, query->data);
2744 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2746 write_msg(NULL, "query to get comments on table %s failed: %s",
2747 tbinfo->relname, PQerrorMessage(g_conn));
2750 i_description = PQfnumber(res, "description");
2751 i_objsubid = PQfnumber(res, "objsubid");
2753 /* If comments exist, build COMMENT ON statements */
2755 ntups = PQntuples(res);
2756 for (i = 0; i < ntups; i++)
2758 const char *descr = PQgetvalue(res, i, i_description);
2759 int objsubid = atoi(PQgetvalue(res, i, i_objsubid));
2763 resetPQExpBuffer(target);
2764 appendPQExpBuffer(target, "%s %s", reltypename,
2765 fmtId(tbinfo->relname));
2767 resetPQExpBuffer(query);
2768 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
2769 appendStringLiteral(query, descr, false);
2770 appendPQExpBuffer(query, ";\n");
2772 ArchiveEntry(fout, tbinfo->oid, target->data,
2773 tbinfo->relnamespace->nspname, tbinfo->usename,
2775 query->data, "", NULL, NULL, NULL);
2777 else if (objsubid > 0 && objsubid <= tbinfo->numatts)
2779 resetPQExpBuffer(target);
2780 appendPQExpBuffer(target, "COLUMN %s.",
2781 fmtId(tbinfo->relname));
2782 appendPQExpBuffer(target, "%s",
2783 fmtId(tbinfo->attnames[objsubid - 1]));
2785 resetPQExpBuffer(query);
2786 appendPQExpBuffer(query, "COMMENT ON %s IS ", target->data);
2787 appendStringLiteral(query, descr, false);
2788 appendPQExpBuffer(query, ";\n");
2790 ArchiveEntry(fout, tbinfo->oid, target->data,
2791 tbinfo->relnamespace->nspname, tbinfo->usename,
2793 query->data, "", NULL, NULL, NULL);
2798 destroyPQExpBuffer(query);
2799 destroyPQExpBuffer(target);
2805 * This routine is used to dump any comments associated with the
2806 * database to which we are currently connected.
2809 dumpDBComment(Archive *fout)
2815 /* Make sure we are in proper schema */
2816 selectSourceSchema("pg_catalog");
2818 /* Build query to find comment */
2820 query = createPQExpBuffer();
2821 appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
2822 appendStringLiteral(query, PQdb(g_conn), true);
2826 res = PQexec(g_conn, query->data);
2827 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2829 write_msg(NULL, "query to get database OID failed: %s",
2830 PQerrorMessage(g_conn));
2834 /* If a comment exists, build COMMENT ON statement */
2836 if (PQntuples(res) != 0)
2838 i_oid = PQfnumber(res, "oid");
2839 resetPQExpBuffer(query);
2840 appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn)));
2841 dumpComment(fout, query->data, NULL, "",
2842 PQgetvalue(res, 0, i_oid), "pg_database", 0, NULL);
2846 destroyPQExpBuffer(query);
2851 * writes out to fout the queries to recreate user-defined namespaces
2854 dumpNamespaces(Archive *fout, NamespaceInfo *nsinfo, int numNamespaces)
2856 PQExpBuffer q = createPQExpBuffer();
2857 PQExpBuffer delq = createPQExpBuffer();
2861 for (i = 0; i < numNamespaces; i++)
2863 NamespaceInfo *nspinfo = &nsinfo[i];
2865 /* skip if not to be dumped */
2869 /* don't dump dummy namespace from pre-7.3 source */
2870 if (strlen(nspinfo->nspname) == 0)
2873 qnspname = strdup(fmtId(nspinfo->nspname));
2876 * If it's the PUBLIC namespace, don't emit a CREATE SCHEMA record
2877 * for it, since we expect PUBLIC to exist already in the
2878 * destination database. But do emit ACL in case it's not standard,
2881 * Note that ownership is shown in the AUTHORIZATION clause,
2882 * while the archive entry is listed with empty owner (causing
2883 * it to be emitted with SET SESSION AUTHORIZATION DEFAULT).
2884 * This seems the best way of dealing with schemas owned by
2885 * users without CREATE SCHEMA privilege. Further hacking has
2886 * to be applied for --no-owner mode, though!
2888 if (strcmp(nspinfo->nspname, "public") != 0)
2890 resetPQExpBuffer(q);
2891 resetPQExpBuffer(delq);
2893 appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
2895 appendPQExpBuffer(q, "CREATE SCHEMA %s AUTHORIZATION %s;\n",
2896 qnspname, fmtId(nspinfo->usename));
2898 ArchiveEntry(fout, nspinfo->oid, nspinfo->nspname,
2899 NULL, "", "SCHEMA", NULL,
2900 q->data, delq->data, NULL, NULL, NULL);
2903 /* Dump Schema Comments */
2904 resetPQExpBuffer(q);
2905 appendPQExpBuffer(q, "SCHEMA %s", qnspname);
2906 dumpComment(fout, q->data,
2907 NULL, nspinfo->usename,
2908 nspinfo->oid, "pg_namespace", 0, NULL);
2910 dumpACL(fout, "SCHEMA", qnspname, nspinfo->nspname, NULL,
2911 nspinfo->usename, nspinfo->nspacl,
2917 destroyPQExpBuffer(q);
2918 destroyPQExpBuffer(delq);
2923 * writes out to fout the queries to recreate a user-defined base type
2924 * as requested by dumpTypes
2927 dumpOneBaseType(Archive *fout, TypeInfo *tinfo,
2928 FuncInfo *g_finfo, int numFuncs,
2929 TypeInfo *g_tinfo, int numTypes)
2931 PQExpBuffer q = createPQExpBuffer();
2932 PQExpBuffer delq = createPQExpBuffer();
2933 PQExpBuffer query = createPQExpBuffer();
2944 char *typreceiveoid;
2951 const char *((*deps)[]);
2954 deps = malloc(sizeof(char *) * 10);
2956 /* Set proper schema search path so regproc references list correctly */
2957 selectSourceSchema(tinfo->typnamespace->nspname);
2959 /* Fetch type-specific details */
2960 if (fout->remoteVersion >= 70400)
2962 appendPQExpBuffer(query, "SELECT typlen, "
2963 "typinput, typoutput, typreceive, typsend, "
2964 "typinput::pg_catalog.oid as typinputoid, "
2965 "typoutput::pg_catalog.oid as typoutputoid, "
2966 "typreceive::pg_catalog.oid as typreceiveoid, "
2967 "typsend::pg_catalog.oid as typsendoid, "
2968 "typdelim, typdefault, typbyval, typalign, "
2970 "FROM pg_catalog.pg_type "
2971 "WHERE oid = '%s'::pg_catalog.oid",
2974 else if (fout->remoteVersion >= 70300)
2976 appendPQExpBuffer(query, "SELECT typlen, "
2977 "typinput, typoutput, "
2978 "'-' as typreceive, '-' as typsend, "
2979 "typinput::pg_catalog.oid as typinputoid, "
2980 "typoutput::pg_catalog.oid as typoutputoid, "
2981 "0 as typreceiveoid, 0 as typsendoid, "
2982 "typdelim, typdefault, typbyval, typalign, "
2984 "FROM pg_catalog.pg_type "
2985 "WHERE oid = '%s'::pg_catalog.oid",
2988 else if (fout->remoteVersion >= 70100)
2991 * Note: although pre-7.3 catalogs contain typreceive and typsend,
2992 * ignore them because they are not right.
2994 appendPQExpBuffer(query, "SELECT typlen, "
2995 "typinput, typoutput, "
2996 "'-' as typreceive, '-' as typsend, "
2997 "typinput::oid as typinputoid, "
2998 "typoutput::oid as typoutputoid, "
2999 "0 as typreceiveoid, 0 as typsendoid, "
3000 "typdelim, typdefault, typbyval, typalign, "
3003 "WHERE oid = '%s'::oid",
3008 appendPQExpBuffer(query, "SELECT typlen, "
3009 "typinput, typoutput, "
3010 "'-' as typreceive, '-' as typsend, "
3011 "typinput::oid as typinputoid, "
3012 "typoutput::oid as typoutputoid, "
3013 "0 as typreceiveoid, 0 as typsendoid, "
3014 "typdelim, typdefault, typbyval, typalign, "
3015 "'p'::char as typstorage "
3017 "WHERE oid = '%s'::oid",
3021 res = PQexec(g_conn, query->data);
3023 PQresultStatus(res) != PGRES_TUPLES_OK)
3025 write_msg(NULL, "query to obtain information on data type \"%s\" failed: %s",
3026 tinfo->typname, PQerrorMessage(g_conn));
3030 /* Expecting a single result only */
3031 ntups = PQntuples(res);
3034 write_msg(NULL, "Got %d rows instead of one from: %s",
3035 ntups, query->data);
3039 typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
3040 typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
3041 typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
3042 typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
3043 typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
3044 typinputoid = PQgetvalue(res, 0, PQfnumber(res, "typinputoid"));
3045 typoutputoid = PQgetvalue(res, 0, PQfnumber(res, "typoutputoid"));
3046 typreceiveoid = PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid"));
3047 typsendoid = PQgetvalue(res, 0, PQfnumber(res, "typsendoid"));
3048 typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
3049 if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
3052 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
3053 typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
3054 typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
3055 typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
3058 * Before we create a type, we need to create the input and output
3059 * functions for it, if they haven't been created already. So make
3060 * sure there are dependency entries for this. But don't include
3061 * dependencies if the functions aren't going to be dumped.
3063 funcInd = findFuncByOid(g_finfo, numFuncs, typinputoid);
3064 if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
3065 (*deps)[depIdx++] = strdup(typinputoid);
3067 funcInd = findFuncByOid(g_finfo, numFuncs, typoutputoid);
3068 if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
3069 (*deps)[depIdx++] = strdup(typoutputoid);
3071 if (strcmp(typreceiveoid, "0") != 0)
3073 funcInd = findFuncByOid(g_finfo, numFuncs, typreceiveoid);
3074 if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
3075 (*deps)[depIdx++] = strdup(typreceiveoid);
3078 if (strcmp(typsendoid, "0") != 0)
3080 funcInd = findFuncByOid(g_finfo, numFuncs, typsendoid);
3081 if (funcInd >= 0 && g_finfo[funcInd].pronamespace->dump)
3082 (*deps)[depIdx++] = strdup(typsendoid);
3086 * DROP must be fully qualified in case same name appears in
3089 appendPQExpBuffer(delq, "DROP TYPE %s.",
3090 fmtId(tinfo->typnamespace->nspname));
3091 appendPQExpBuffer(delq, "%s CASCADE;\n",
3092 fmtId(tinfo->typname));
3094 appendPQExpBuffer(q,
3095 "CREATE TYPE %s (\n"
3096 " INTERNALLENGTH = %s",
3097 fmtId(tinfo->typname),
3098 (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
3100 if (fout->remoteVersion >= 70300)
3102 /* regproc result is correctly quoted in 7.3 */
3103 appendPQExpBuffer(q, ",\n INPUT = %s", typinput);
3104 appendPQExpBuffer(q, ",\n OUTPUT = %s", typoutput);
3105 if (strcmp(typreceiveoid, "0") != 0)
3106 appendPQExpBuffer(q, ",\n RECEIVE = %s", typreceive);
3107 if (strcmp(typsendoid, "0") != 0)
3108 appendPQExpBuffer(q, ",\n SEND = %s", typsend);
3112 /* regproc delivers an unquoted name before 7.3 */
3113 /* cannot combine these because fmtId uses static result area */
3114 appendPQExpBuffer(q, ",\n INPUT = %s", fmtId(typinput));
3115 appendPQExpBuffer(q, ",\n OUTPUT = %s", fmtId(typoutput));
3116 /* no chance that receive/send need be printed */
3119 if (typdefault != NULL)
3121 appendPQExpBuffer(q, ",\n DEFAULT = ");
3122 appendStringLiteral(q, typdefault, true);
3129 /* reselect schema in case changed by function dump */
3130 selectSourceSchema(tinfo->typnamespace->nspname);
3131 elemType = getFormattedTypeName(tinfo->typelem, zeroAsOpaque);
3132 appendPQExpBuffer(q, ",\n ELEMENT = %s", elemType);
3135 (*deps)[depIdx++] = strdup(tinfo->typelem);
3138 if (typdelim && strcmp(typdelim, ",") != 0)
3140 appendPQExpBuffer(q, ",\n DELIMITER = ");
3141 appendStringLiteral(q, typdelim, true);
3144 if (strcmp(typalign, "c") == 0)
3145 appendPQExpBuffer(q, ",\n ALIGNMENT = char");
3146 else if (strcmp(typalign, "s") == 0)
3147 appendPQExpBuffer(q, ",\n ALIGNMENT = int2");
3148 else if (strcmp(typalign, "i") == 0)
3149 appendPQExpBuffer(q, ",\n ALIGNMENT = int4");
3150 else if (strcmp(typalign, "d") == 0)
3151 appendPQExpBuffer(q, ",\n ALIGNMENT = double");
3153 if (strcmp(typstorage, "p") == 0)
3154 appendPQExpBuffer(q, ",\n STORAGE = plain");
3155 else if (strcmp(typstorage, "e") == 0)
3156 appendPQExpBuffer(q, ",\n STORAGE = external");
3157 else if (strcmp(typstorage, "x") == 0)
3158 appendPQExpBuffer(q, ",\n STORAGE = extended");
3159 else if (strcmp(typstorage, "m") == 0)
3160 appendPQExpBuffer(q, ",\n STORAGE = main");
3162 if (strcmp(typbyval, "t") == 0)
3163 appendPQExpBuffer(q, ",\n PASSEDBYVALUE");
3165 appendPQExpBuffer(q, "\n);\n");
3167 (*deps)[depIdx++] = NULL; /* End of List */
3169 ArchiveEntry(fout, tinfo->oid, tinfo->typname,
3170 tinfo->typnamespace->nspname,
3171 tinfo->usename, "TYPE", deps,
3172 q->data, delq->data, NULL, NULL, NULL);
3174 /* Dump Type Comments */
3175 resetPQExpBuffer(q);
3177 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname));
3178 dumpComment(fout, q->data,
3179 tinfo->typnamespace->nspname, tinfo->usename,
3180 tinfo->oid, "pg_type", 0, NULL);
3183 destroyPQExpBuffer(q);
3184 destroyPQExpBuffer(delq);
3185 destroyPQExpBuffer(query);
3190 * writes out to fout the queries to recreate a user-defined domain
3191 * as requested by dumpTypes
3194 dumpOneDomain(Archive *fout, TypeInfo *tinfo)
3196 PQExpBuffer q = createPQExpBuffer();
3197 PQExpBuffer delq = createPQExpBuffer();
3198 PQExpBuffer query = createPQExpBuffer();
3199 PQExpBuffer chkquery = createPQExpBuffer();
3207 const char *((*deps)[]);
3210 deps = malloc(sizeof(char *) * 10);
3212 /* Set proper schema search path so type references list correctly */
3213 selectSourceSchema(tinfo->typnamespace->nspname);
3215 /* Fetch domain specific details */
3216 /* We assume here that remoteVersion must be at least 70300 */
3217 appendPQExpBuffer(query, "SELECT typnotnull, "
3218 "pg_catalog.format_type(typbasetype, typtypmod) as typdefn, "
3219 "typdefault, typbasetype "
3220 "FROM pg_catalog.pg_type "
3221 "WHERE oid = '%s'::pg_catalog.oid",
3224 res = PQexec(g_conn, query->data);
3226 PQresultStatus(res) != PGRES_TUPLES_OK)
3228 write_msg(NULL, "query to obtain domain information failed: %s", PQerrorMessage(g_conn));
3232 /* Expecting a single result only */
3233 ntups = PQntuples(res);
3236 write_msg(NULL, "Got %d rows instead of one from: %s",
3237 ntups, query->data);
3241 typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
3242 typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
3243 if (PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
3246 typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
3247 typbasetype = PQgetvalue(res, 0, PQfnumber(res, "typbasetype"));
3250 * DROP must be fully qualified in case same name appears in
3253 appendPQExpBuffer(delq, "DROP DOMAIN %s.",
3254 fmtId(tinfo->typnamespace->nspname));
3255 appendPQExpBuffer(delq, "%s;\n",
3256 fmtId(tinfo->typname));
3258 appendPQExpBuffer(q,
3259 "CREATE DOMAIN %s AS %s",
3260 fmtId(tinfo->typname),
3263 /* Depends on the base type */
3264 (*deps)[depIdx++] = strdup(typbasetype);
3266 if (typnotnull[0] == 't')
3267 appendPQExpBuffer(q, " NOT NULL");
3270 appendPQExpBuffer(q, " DEFAULT %s", typdefault);
3275 * Fetch and process CHECK constraints for the domain
3277 if (g_fout->remoteVersion >= 70400)
3278 appendPQExpBuffer(chkquery, "SELECT conname, "
3279 "pg_catalog.pg_get_constraintdef(oid) AS consrc "
3280 "FROM pg_catalog.pg_constraint "
3281 "WHERE contypid = '%s'::pg_catalog.oid",
3284 appendPQExpBuffer(chkquery, "SELECT conname, 'CHECK (' || consrc || ')' AS consrc "
3285 "FROM pg_catalog.pg_constraint "
3286 "WHERE contypid = '%s'::pg_catalog.oid",
3289 res = PQexec(g_conn, chkquery->data);
3291 PQresultStatus(res) != PGRES_TUPLES_OK)
3293 write_msg(NULL, "query to obtain domain constraint information failed: %s",
3294 PQerrorMessage(g_conn));
3298 ntups = PQntuples(res);
3299 for (i = 0; i < ntups; i++)
3304 conname = PQgetvalue(res, i, PQfnumber(res, "conname"));
3305 consrc = PQgetvalue(res, i, PQfnumber(res, "consrc"));
3307 appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
3308 fmtId(conname), consrc);
3311 appendPQExpBuffer(q, ";\n");
3313 (*deps)[depIdx++] = NULL; /* End of List */
3315 ArchiveEntry(fout, tinfo->oid, tinfo->typname,
3316 tinfo->typnamespace->nspname,
3317 tinfo->usename, "DOMAIN", deps,
3318 q->data, delq->data, NULL, NULL, NULL);
3320 /* Dump Domain Comments */
3321 resetPQExpBuffer(q);
3323 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->typname));
3324 dumpComment(fout, q->data,
3325 tinfo->typnamespace->nspname, tinfo->usename,
3326 tinfo->oid, "pg_type", 0, NULL);
3329 destroyPQExpBuffer(q);
3330 destroyPQExpBuffer(delq);
3331 destroyPQExpBuffer(query);
3332 destroyPQExpBuffer(chkquery);
3336 * dumpOneCompositeType
3337 * writes out to fout the queries to recreate a user-defined stand-alone
3338 * composite type as requested by dumpTypes
3341 dumpOneCompositeType(Archive *fout, TypeInfo *tinfo)
3343 PQExpBuffer q = createPQExpBuffer();
3344 PQExpBuffer delq = createPQExpBuffer();
3345 PQExpBuffer query = createPQExpBuffer();
3352 /* Set proper schema search path so type references list correctly */
3353 selectSourceSchema(tinfo->typnamespace->nspname);
3355 /* Fetch type specific details */
3356 /* We assume here that remoteVersion must be at least 70300 */
3358 appendPQExpBuffer(query, "SELECT a.attname, "
3359 "pg_catalog.format_type(a.atttypid, a.atttypmod) as atttypdefn "
3360 "FROM pg_catalog.pg_type t, pg_catalog.pg_attribute a "
3361 "WHERE t.oid = '%s'::pg_catalog.oid "
3362 "AND a.attrelid = t.typrelid "
3363 "AND NOT a.attisdropped "
3364 "ORDER BY a.attnum ",
3367 res = PQexec(g_conn, query->data);
3369 PQresultStatus(res) != PGRES_TUPLES_OK)
3371 write_msg(NULL, "query to obtain data type information failed: %s", PQerrorMessage(g_conn));
3375 /* Expecting at least a single result */
3376 ntups = PQntuples(res);
3379 write_msg(NULL, "query yielded no rows: %s\n", query->data);
3383 i_attname = PQfnumber(res, "attname");
3384 i_atttypdefn = PQfnumber(res, "atttypdefn");
3386 appendPQExpBuffer(q, "CREATE TYPE %s AS (",
3387 fmtId(tinfo->typname));
3389 for (i = 0; i < ntups; i++)
3394 attname = PQgetvalue(res, i, i_attname);
3395 atttypdefn = PQgetvalue(res, i, i_atttypdefn);
3397 appendPQExpBuffer(q, "\n\t%s %s", fmtId(attname), atttypdefn);
3399 appendPQExpBuffer(q, ",");
3401 appendPQExpBuffer(q, "\n);\n");
3404 * DROP must be fully qualified in case same name appears in
3407 appendPQExpBuffer(delq, "DROP TYPE %s.",
3408 fmtId(tinfo->typnamespace->nspname));
3409 appendPQExpBuffer(delq, "%s;\n",
3410 fmtId(tinfo->typname));
3412 ArchiveEntry(fout, tinfo->oid, tinfo->typname,
3413 tinfo->typnamespace->nspname,
3414 tinfo->usename, "TYPE", NULL,
3415 q->data, delq->data, NULL, NULL, NULL);
3417 /* Dump Type Comments */
3418 resetPQExpBuffer(q);
3420 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo->typname));
3421 dumpComment(fout, q->data,
3422 tinfo->typnamespace->nspname, tinfo->usename,
3423 tinfo->oid, "pg_type", 0, NULL);
3426 destroyPQExpBuffer(q);
3427 destroyPQExpBuffer(delq);
3428 destroyPQExpBuffer(query);
3433 * writes out to fout the queries to recreate all the user-defined types
3436 dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
3437 TypeInfo *tinfo, int numTypes)
3441 for (i = 0; i < numTypes; i++)
3443 /* Dump only types in dumpable namespaces */
3444 if (!tinfo[i].typnamespace->dump)
3447 /* skip complex types, except for standalone composite types */
3448 if (atooid(tinfo[i].typrelid) != 0 && tinfo[i].typrelkind != 'c')
3451 /* skip undefined placeholder types */
3452 if (!tinfo[i].isDefined)
3455 /* skip all array types that start w/ underscore */
3456 if ((tinfo[i].typname[0] == '_') &&
3457 atooid(tinfo[i].typelem) != 0)
3460 /* Dump out in proper style */
3461 if (tinfo[i].typtype == 'b')
3462 dumpOneBaseType(fout, &tinfo[i],
3463 finfo, numFuncs, tinfo, numTypes);
3464 else if (tinfo[i].typtype == 'd')
3465 dumpOneDomain(fout, &tinfo[i]);
3466 else if (tinfo[i].typtype == 'c')
3467 dumpOneCompositeType(fout, &tinfo[i]);
3473 * writes out to fout the queries to recreate user-defined procedural languages
3476 dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
3479 PQExpBuffer query = createPQExpBuffer();
3480 PQExpBuffer defqry = createPQExpBuffer();
3481 PQExpBuffer delqry = createPQExpBuffer();
3486 int i_lanplcallfoid;
3487 int i_lanvalidator = -1;
3492 const char *lanplcallfoid;
3493 const char *lanvalidator;
3494 const char *((*deps)[]);
3500 /* Make sure we are in proper schema */
3501 selectSourceSchema("pg_catalog");
3503 appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
3506 res = PQexec(g_conn, query->data);
3508 PQresultStatus(res) != PGRES_TUPLES_OK)
3510 write_msg(NULL, "query to obtain list of procedural languages failed: %s",
3511 PQerrorMessage(g_conn));
3514 ntups = PQntuples(res);
3516 i_lanname = PQfnumber(res, "lanname");
3517 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
3518 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
3519 i_oid = PQfnumber(res, "oid");
3520 if (fout->remoteVersion >= 70300)
3522 i_lanvalidator = PQfnumber(res, "lanvalidator");
3523 i_lanacl = PQfnumber(res, "lanacl");
3526 for (i = 0; i < ntups; i++)
3528 lanoid = PQgetvalue(res, i, i_oid);
3529 lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3530 lanname = PQgetvalue(res, i, i_lanname);
3531 if (fout->remoteVersion >= 70300)
3533 lanvalidator = PQgetvalue(res, i, i_lanvalidator);
3534 lanacl = PQgetvalue(res, i, i_lanacl);
3543 * Current theory is to dump PLs iff their underlying functions
3544 * will be dumped (are in a dumpable namespace, or have a
3545 * non-system OID in pre-7.3 databases). Actually, we treat the
3546 * PL itself as being in the underlying function's namespace,
3547 * though it isn't really. This avoids searchpath problems for
3548 * the HANDLER clause.
3550 * If the underlying function is in the pg_catalog namespace,
3551 * we won't have loaded it into finfo[] at all; therefore,
3552 * treat failure to find it in finfo[] as indicating we shouldn't
3553 * dump it, not as an error condition. Ditto for the validator.
3556 fidx = findFuncByOid(finfo, numFuncs, lanplcallfoid);
3560 if (!finfo[fidx].pronamespace->dump)
3563 if (strcmp(lanvalidator, "0") != 0)
3565 vidx = findFuncByOid(finfo, numFuncs, lanvalidator);
3570 resetPQExpBuffer(defqry);
3571 resetPQExpBuffer(delqry);
3573 /* Make a dependency to ensure function is dumped first */
3574 deps = malloc(sizeof(char *) * 10);
3577 (*deps)[depIdx++] = strdup(lanplcallfoid);
3579 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
3582 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
3583 (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
3586 appendPQExpBuffer(defqry, " HANDLER %s",
3587 fmtId(finfo[fidx].proname));
3588 if (strcmp(lanvalidator, "0") != 0)
3590 appendPQExpBuffer(defqry, " VALIDATOR ");
3591 /* Cope with possibility that validator is in different schema */
3592 if (finfo[vidx].pronamespace != finfo[fidx].pronamespace)
3593 appendPQExpBuffer(defqry, "%s.",
3594 fmtId(finfo[vidx].pronamespace->nspname));
3595 appendPQExpBuffer(defqry, "%s",
3596 fmtId(finfo[vidx].proname));
3597 (*deps)[depIdx++] = strdup(lanvalidator);
3599 appendPQExpBuffer(defqry, ";\n");
3601 (*deps)[depIdx++] = NULL; /* End of List */
3603 ArchiveEntry(fout, lanoid, lanname,
3604 finfo[fidx].pronamespace->nspname, "",
3605 "PROCEDURAL LANGUAGE", deps,
3606 defqry->data, delqry->data, NULL, NULL, NULL);
3610 char *tmp = strdup(fmtId(lanname));
3612 dumpACL(fout, "ACL LANGUAGE", tmp, lanname,
3613 finfo[fidx].pronamespace->nspname,
3614 NULL, lanacl, lanoid);
3621 destroyPQExpBuffer(query);
3622 destroyPQExpBuffer(defqry);
3623 destroyPQExpBuffer(delqry);
3628 * writes out to fout the queries to recreate all the user-defined functions
3631 dumpFuncs(Archive *fout, FuncInfo finfo[], int numFuncs)
3635 for (i = 0; i < numFuncs; i++)
3637 /* Dump only funcs in dumpable namespaces */
3638 if (!finfo[i].pronamespace->dump)
3641 dumpOneFunc(fout, &finfo[i]);
3643 dumpFuncACL(fout, &finfo[i]);
3648 * format_function_signature: generate function name and argument list
3650 * The argument type names are qualified if needed. The function name
3651 * is never qualified.
3654 format_function_signature(FuncInfo *finfo, bool honor_quotes)
3659 initPQExpBuffer(&fn);
3661 appendPQExpBuffer(&fn, "%s(", fmtId(finfo->proname));
3663 appendPQExpBuffer(&fn, "%s(", finfo->proname);
3664 for (j = 0; j < finfo->nargs; j++)
3668 typname = getFormattedTypeName(finfo->argtypes[j], zeroAsOpaque);
3669 appendPQExpBuffer(&fn, "%s%s",
3670 (j > 0) ? ", " : "",
3674 appendPQExpBuffer(&fn, ")");
3680 dumpFuncACL(Archive *fout, FuncInfo *finfo)
3685 funcsig = format_function_signature(finfo, true);
3686 funcsig_tag = format_function_signature(finfo, false);
3687 dumpACL(fout, "FUNCTION", funcsig, funcsig_tag,
3688 finfo->pronamespace->nspname,
3689 finfo->usename, finfo->proacl, finfo->oid);
3697 * dump out only one function
3700 dumpOneFunc(Archive *fout, FuncInfo *finfo)
3702 PQExpBuffer query = createPQExpBuffer();
3703 PQExpBuffer q = createPQExpBuffer();
3704 PQExpBuffer delqry = createPQExpBuffer();
3705 PQExpBuffer asPart = createPQExpBuffer();
3706 PGresult *res = NULL;
3707 char *funcsig = NULL;
3708 char *funcsig_tag = NULL;
3718 char *funcproclang; /* Boolean : is this function a PLang
3724 finfo->dumped = true;
3726 /* Set proper schema search path so type references list correctly */
3727 selectSourceSchema(finfo->pronamespace->nspname);
3729 /* Fetch function-specific details */
3730 if (g_fout->remoteVersion >= 70300)
3732 appendPQExpBuffer(query,
3733 "SELECT proretset, prosrc, probin, "
3734 "provolatile, proisstrict, prosecdef, "
3735 "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname, "
3736 "exists (SELECT 'x' FROM pg_catalog.pg_language WHERE lanplcallfoid = pg_catalog.pg_proc.oid) as funcproclang "
3737 "FROM pg_catalog.pg_proc "
3738 "WHERE oid = '%s'::pg_catalog.oid",
3741 else if (g_fout->remoteVersion >= 70100)
3743 appendPQExpBuffer(query,
3744 "SELECT proretset, prosrc, probin, "
3745 "case when proiscachable then 'i' else 'v' end as provolatile, "
3747 "'f'::boolean as prosecdef, "
3748 "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname, "
3749 "exists (SELECT 'x' FROM pg_language WHERE lanplcallfoid = pg_proc.oid) as funcproclang "
3751 "WHERE oid = '%s'::oid",
3756 appendPQExpBuffer(query,
3757 "SELECT proretset, prosrc, probin, "
3758 "case when proiscachable then 'i' else 'v' end as provolatile, "
3759 "'f'::boolean as proisstrict, "
3760 "'f'::boolean as prosecdef, "
3761 "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname, "
3762 "exists (SELECT 'x' FROM pg_language WHERE lanplcallfoid = pg_proc.oid) as funcproclang "
3764 "WHERE oid = '%s'::oid",
3768 res = PQexec(g_conn, query->data);
3770 PQresultStatus(res) != PGRES_TUPLES_OK)
3772 write_msg(NULL, "query to obtain information on function \"%s\" failed: %s",
3773 finfo->proname, PQerrorMessage(g_conn));
3777 /* Expecting a single result only */
3778 ntups = PQntuples(res);
3781 write_msg(NULL, "Got %d rows instead of one from: %s",
3782 ntups, query->data);
3786 proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
3787 prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
3788 probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
3789 provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
3790 proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
3791 prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
3792 lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
3793 funcproclang = PQgetvalue(res, 0, PQfnumber(res, "funcproclang"));
3796 * See backend/commands/define.c for details of how the 'AS' clause is
3799 if (strcmp(probin, "-") != 0)
3801 appendPQExpBuffer(asPart, "AS ");
3802 appendStringLiteral(asPart, probin, true);
3803 if (strcmp(prosrc, "-") != 0)
3805 appendPQExpBuffer(asPart, ", ");
3806 appendStringLiteral(asPart, prosrc, false);
3811 if (strcmp(prosrc, "-") != 0)
3813 appendPQExpBuffer(asPart, "AS ");
3814 appendStringLiteral(asPart, prosrc, false);
3818 funcsig = format_function_signature(finfo, true);
3819 funcsig_tag = format_function_signature(finfo, false);
3822 * DROP must be fully qualified in case same name appears in
3825 appendPQExpBuffer(delqry, "DROP FUNCTION %s.%s;\n",
3826 fmtId(finfo->pronamespace->nspname),
3829 rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
3831 appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
3832 appendPQExpBuffer(q, "RETURNS %s%s\n %s\n LANGUAGE %s",
3833 (proretset[0] == 't') ? "SETOF " : "",
3840 if (provolatile[0] != PROVOLATILE_VOLATILE)
3842 if (provolatile[0] == PROVOLATILE_IMMUTABLE)
3843 appendPQExpBuffer(q, " IMMUTABLE");
3844 else if (provolatile[0] == PROVOLATILE_STABLE)
3845 appendPQExpBuffer(q, " STABLE");
3846 else if (provolatile[0] != PROVOLATILE_VOLATILE)
3848 write_msg(NULL, "unrecognized provolatile value for function \"%s\"\n",
3854 if (proisstrict[0] == 't')
3855 appendPQExpBuffer(q, " STRICT");
3857 if (prosecdef[0] == 't')
3858 appendPQExpBuffer(q, " SECURITY DEFINER");
3860 appendPQExpBuffer(q, ";\n");
3862 ArchiveEntry(fout, finfo->oid, funcsig_tag,
3863 finfo->pronamespace->nspname,
3864 finfo->usename, strcmp(funcproclang, "t") ? "FUNCTION" : "FUNC PROCEDURAL LANGUAGE", NULL,
3865 q->data, delqry->data,
3868 /* Dump Function Comments */
3870 resetPQExpBuffer(q);
3871 appendPQExpBuffer(q, "FUNCTION %s", funcsig);
3872 dumpComment(fout, q->data,
3873 finfo->pronamespace->nspname, finfo->usename,
3874 finfo->oid, "pg_proc", 0, NULL);
3879 destroyPQExpBuffer(query);
3880 destroyPQExpBuffer(q);
3881 destroyPQExpBuffer(delqry);
3882 destroyPQExpBuffer(asPart);
3892 dumpCasts(Archive *fout,
3893 FuncInfo *finfo, int numFuncs,
3894 TypeInfo *tinfo, int numTypes)
3897 PQExpBuffer query = createPQExpBuffer();
3898 PQExpBuffer defqry = createPQExpBuffer();
3899 PQExpBuffer delqry = createPQExpBuffer();
3900 PQExpBuffer castsig = createPQExpBuffer();
3904 /* Make sure we are in proper schema */
3905 selectSourceSchema("pg_catalog");
3907 if (fout->remoteVersion >= 70300)
3908 appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castcontext FROM pg_cast ORDER BY 1,2,3;");
3910 appendPQExpBuffer(query, "SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3;");
3912 res = PQexec(g_conn, query->data);
3913 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
3915 write_msg(NULL, "query to obtain list of casts failed: %s",
3916 PQerrorMessage(g_conn));
3919 ntups = PQntuples(res);
3921 for (i = 0; i < ntups; i++)
3923 char *castoid = PQgetvalue(res, i, 0);
3924 char *castsource = PQgetvalue(res, i, 1);
3925 char *casttarget = PQgetvalue(res, i, 2);
3926 char *castfunc = PQgetvalue(res, i, 3);
3927 char *castcontext = PQgetvalue(res, i, 4);
3929 const char *((*deps)[]);
3933 if (strcmp(castfunc, "0") != 0)
3934 fidx = findFuncByOid(finfo, numFuncs, castfunc);
3937 * As per discussion we dump casts if one or more of the underlying
3938 * objects (the conversion function and the two data types) are not
3939 * builtin AND if all of the non-builtin objects namespaces are
3940 * included in the dump. Builtin meaning, the namespace name does
3941 * not start with "pg_".
3943 source_idx = findTypeByOid(tinfo, numTypes, castsource);
3944 target_idx = findTypeByOid(tinfo, numTypes, casttarget);
3947 * Skip this cast if all objects are from pg_
3949 if ((fidx < 0 || strncmp(finfo[fidx].pronamespace->nspname, "pg_", 3) == 0) &&
3950 strncmp(tinfo[source_idx].typnamespace->nspname, "pg_", 3) == 0 &&
3951 strncmp(tinfo[target_idx].typnamespace->nspname, "pg_", 3) == 0)
3955 * Skip cast if function isn't from pg_ and that namespace is
3959 strncmp(finfo[fidx].pronamespace->nspname, "pg_", 3) != 0 &&
3960 !finfo[fidx].pronamespace->dump)
3964 * Same for the Source type
3966 if (strncmp(tinfo[source_idx].typnamespace->nspname, "pg_", 3) != 0 &&
3967 !tinfo[source_idx].typnamespace->dump)
3971 * and the target type.
3973 if (strncmp(tinfo[target_idx].typnamespace->nspname, "pg_", 3) != 0 &&
3974 !tinfo[target_idx].typnamespace->dump)
3977 /* Make a dependency to ensure function is dumped first */
3980 deps = malloc(sizeof(char *) * 2);
3982 (*deps)[0] = strdup(castfunc);
3983 (*deps)[1] = NULL; /* End of List */
3988 resetPQExpBuffer(defqry);
3989 resetPQExpBuffer(delqry);
3990 resetPQExpBuffer(castsig);
3992 appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
3993 getFormattedTypeName(castsource, zeroAsNone),
3994 getFormattedTypeName(casttarget, zeroAsNone));
3996 appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
3997 getFormattedTypeName(castsource, zeroAsNone),
3998 getFormattedTypeName(casttarget, zeroAsNone));
4000 if (strcmp(castfunc, "0") == 0)
4001 appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
4003 appendPQExpBuffer(defqry, "WITH FUNCTION %s",
4004 format_function_signature(&finfo[fidx], true));
4006 if (strcmp(castcontext, "a") == 0)
4007 appendPQExpBuffer(defqry, " AS ASSIGNMENT");
4008 else if (strcmp(castcontext, "i") == 0)
4009 appendPQExpBuffer(defqry, " AS IMPLICIT");
4010 appendPQExpBuffer(defqry, ";\n");
4012 appendPQExpBuffer(castsig, "CAST (%s AS %s)",
4013 getFormattedTypeName(castsource, zeroAsNone),
4014 getFormattedTypeName(casttarget, zeroAsNone));
4016 ArchiveEntry(fout, castoid,
4018 tinfo[source_idx].typnamespace->nspname, "",
4020 defqry->data, delqry->data,
4026 destroyPQExpBuffer(query);
4027 destroyPQExpBuffer(defqry);
4028 destroyPQExpBuffer(delqry);
4029 destroyPQExpBuffer(castsig);
4035 * writes out to fout the queries to recreate all the user-defined operators
4038 dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators)
4042 for (i = 0; i < numOperators; i++)
4044 /* Dump only operators in dumpable namespaces */
4045 if (!oprinfo[i].oprnamespace->dump)
4049 * some operators are invalid because they were the result of user
4050 * defining operators before commutators exist
4052 if (strcmp(oprinfo[i].oprcode, "0") == 0)
4056 dumpOneOpr(fout, &oprinfo[i],
4057 oprinfo, numOperators);
4063 * write out a single operator definition
4066 dumpOneOpr(Archive *fout, OprInfo *oprinfo,
4067 OprInfo *g_oprinfo, int numOperators)
4069 PQExpBuffer query = createPQExpBuffer();
4070 PQExpBuffer q = createPQExpBuffer();
4071 PQExpBuffer delq = createPQExpBuffer();
4072 PQExpBuffer oprid = createPQExpBuffer();
4073 PQExpBuffer details = createPQExpBuffer();
4104 /* Make sure we are in proper schema so regoperator works correctly */
4105 selectSourceSchema(oprinfo->oprnamespace->nspname);
4107 if (g_fout->remoteVersion >= 70300)
4109 appendPQExpBuffer(query, "SELECT oprkind, "
4110 "oprcode::pg_catalog.regprocedure, "
4111 "oprleft::pg_catalog.regtype, "
4112 "oprright::pg_catalog.regtype, "
4113 "oprcom::pg_catalog.regoperator, "
4114 "oprnegate::pg_catalog.regoperator, "
4115 "oprrest::pg_catalog.regprocedure, "
4116 "oprjoin::pg_catalog.regprocedure, "
4118 "oprlsortop::pg_catalog.regoperator, "
4119 "oprrsortop::pg_catalog.regoperator, "
4120 "oprltcmpop::pg_catalog.regoperator, "
4121 "oprgtcmpop::pg_catalog.regoperator "
4122 "from pg_catalog.pg_operator "
4123 "where oid = '%s'::pg_catalog.oid",
4126 else if (g_fout->remoteVersion >= 70100)
4128 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
4129 "CASE WHEN oprleft = 0 THEN '-' "
4130 "ELSE format_type(oprleft, NULL) END as oprleft, "
4131 "CASE WHEN oprright = 0 THEN '-' "
4132 "ELSE format_type(oprright, NULL) END as oprright, "
4133 "oprcom, oprnegate, oprrest, oprjoin, "
4134 "oprcanhash, oprlsortop, oprrsortop, "
4135 "0 as oprltcmpop, 0 as oprgtcmpop "
4137 "where oid = '%s'::oid",
4142 appendPQExpBuffer(query, "SELECT oprkind, oprcode, "
4143 "CASE WHEN oprleft = 0 THEN '-'::name "
4144 "ELSE (select typname from pg_type where oid = oprleft) END as oprleft, "
4145 "CASE WHEN oprright = 0 THEN '-'::name "
4146 "ELSE (select typname from pg_type where oid = oprright) END as oprright, "
4147 "oprcom, oprnegate, oprrest, oprjoin, "
4148 "oprcanhash, oprlsortop, oprrsortop, "
4149 "0 as oprltcmpop, 0 as oprgtcmpop "
4151 "where oid = '%s'::oid",
4155 res = PQexec(g_conn, query->data);
4157 PQresultStatus(res) != PGRES_TUPLES_OK)
4159 write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
4163 /* Expecting a single result only */
4164 ntups = PQntuples(res);
4167 write_msg(NULL, "Got %d rows instead of one from: %s",
4168 ntups, query->data);
4172 i_oprkind = PQfnumber(res, "oprkind");
4173 i_oprcode = PQfnumber(res, "oprcode");
4174 i_oprleft = PQfnumber(res, "oprleft");
4175 i_oprright = PQfnumber(res, "oprright");
4176 i_oprcom = PQfnumber(res, "oprcom");
4177 i_oprnegate = PQfnumber(res, "oprnegate");
4178 i_oprrest = PQfnumber(res, "oprrest");
4179 i_oprjoin = PQfnumber(res, "oprjoin");
4180 i_oprcanhash = PQfnumber(res, "oprcanhash");
4181 i_oprlsortop = PQfnumber(res, "oprlsortop");
4182 i_oprrsortop = PQfnumber(res, "oprrsortop");
4183 i_oprltcmpop = PQfnumber(res, "oprltcmpop");
4184 i_oprgtcmpop = PQfnumber(res, "oprgtcmpop");
4186 oprkind = PQgetvalue(res, 0, i_oprkind);
4187 oprcode = PQgetvalue(res, 0, i_oprcode);
4188 oprleft = PQgetvalue(res, 0, i_oprleft);
4189 oprright = PQgetvalue(res, 0, i_oprright);
4190 oprcom = PQgetvalue(res, 0, i_oprcom);
4191 oprnegate = PQgetvalue(res, 0, i_oprnegate);
4192 oprrest = PQgetvalue(res, 0, i_oprrest);
4193 oprjoin = PQgetvalue(res, 0, i_oprjoin);
4194 oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
4195 oprlsortop = PQgetvalue(res, 0, i_oprlsortop);
4196 oprrsortop = PQgetvalue(res, 0, i_oprrsortop);
4197 oprltcmpop = PQgetvalue(res, 0, i_oprltcmpop);
4198 oprgtcmpop = PQgetvalue(res, 0, i_oprgtcmpop);
4200 appendPQExpBuffer(details, " PROCEDURE = %s",
4201 convertRegProcReference(oprcode));
4203 appendPQExpBuffer(oprid, "%s (",
4207 * right unary means there's a left arg and left unary means there's a
4210 if (strcmp(oprkind, "r") == 0 ||
4211 strcmp(oprkind, "b") == 0)
4213 if (g_fout->remoteVersion >= 70100)
4216 name = fmtId(oprleft);
4217 appendPQExpBuffer(details, ",\n LEFTARG = %s", name);
4218 appendPQExpBuffer(oprid, "%s", name);
4221 appendPQExpBuffer(oprid, "NONE");
4223 if (strcmp(oprkind, "l") == 0 ||
4224 strcmp(oprkind, "b") == 0)
4226 if (g_fout->remoteVersion >= 70100)
4229 name = fmtId(oprright);
4230 appendPQExpBuffer(details, ",\n RIGHTARG = %s", name);
4231 appendPQExpBuffer(oprid, ", %s)", name);
4234 appendPQExpBuffer(oprid, ", NONE)");
4236 name = convertOperatorReference(oprcom, g_oprinfo, numOperators);
4238 appendPQExpBuffer(details, ",\n COMMUTATOR = %s", name);
4240 name = convertOperatorReference(oprnegate, g_oprinfo, numOperators);
4242 appendPQExpBuffer(details, ",\n NEGATOR = %s", name);
4244 if (strcmp(oprcanhash, "t") == 0)
4245 appendPQExpBuffer(details, ",\n HASHES");
4247 name = convertRegProcReference(oprrest);
4249 appendPQExpBuffer(details, ",\n RESTRICT = %s", name);
4251 name = convertRegProcReference(oprjoin);
4253 appendPQExpBuffer(details, ",\n JOIN = %s", name);
4255 name = convertOperatorReference(oprlsortop, g_oprinfo, numOperators);
4257 appendPQExpBuffer(details, ",\n SORT1 = %s", name);
4259 name = convertOperatorReference(oprrsortop, g_oprinfo, numOperators);
4261 appendPQExpBuffer(details, ",\n SORT2 = %s", name);
4263 name = convertOperatorReference(oprltcmpop, g_oprinfo, numOperators);
4265 appendPQExpBuffer(details, ",\n LTCMP = %s", name);
4267 name = convertOperatorReference(oprgtcmpop, g_oprinfo, numOperators);
4269 appendPQExpBuffer(details, ",\n GTCMP = %s", name);
4272 * DROP must be fully qualified in case same name appears in
4275 appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
4276 fmtId(oprinfo->oprnamespace->nspname),
4279 appendPQExpBuffer(q, "CREATE OPERATOR %s (\n%s\n);\n",
4280 oprinfo->oprname, details->data);
4282 ArchiveEntry(fout, oprinfo->oid, oprinfo->oprname,
4283 oprinfo->oprnamespace->nspname, oprinfo->usename,
4285 q->data, delq->data,
4288 /* Dump Operator Comments */
4290 resetPQExpBuffer(q);
4291 appendPQExpBuffer(q, "OPERATOR %s", oprid->data);
4292 dumpComment(fout, q->data,
4293 oprinfo->oprnamespace->nspname, oprinfo->usename,
4294 oprinfo->oid, "pg_operator", 0, NULL);
4298 destroyPQExpBuffer(query);
4299 destroyPQExpBuffer(q);
4300 destroyPQExpBuffer(delq);
4301 destroyPQExpBuffer(oprid);
4302 destroyPQExpBuffer(details);
4306 * Convert a function reference obtained from pg_operator
4308 * Returns what to print, or NULL if function references is InvalidOid
4310 * In 7.3 the input is a REGPROCEDURE display; we have to strip the
4311 * argument-types part. In prior versions, the input is a REGPROC display.
4314 convertRegProcReference(const char *proc)
4316 /* In all cases "-" means a null reference */
4317 if (strcmp(proc, "-") == 0)
4320 if (g_fout->remoteVersion >= 70300)
4326 name = strdup(proc);
4327 /* find non-double-quoted left paren */
4329 for (paren = name; *paren; paren++)
4331 if (*paren == '(' && !inquote)
4342 /* REGPROC before 7.3 does not quote its result */
4347 * Convert an operator cross-reference obtained from pg_operator
4349 * Returns what to print, or NULL to print nothing
4351 * In 7.3 the input is a REGOPERATOR display; we have to strip the
4352 * argument-types part. In prior versions, the input is just a
4353 * numeric OID, which we search our operator list for.
4356 convertOperatorReference(const char *opr,
4357 OprInfo *g_oprinfo, int numOperators)
4361 /* In all cases "0" means a null reference */
4362 if (strcmp(opr, "0") == 0)
4365 if (g_fout->remoteVersion >= 70300)
4371 /* find non-double-quoted left paren */
4373 for (paren = name; *paren; paren++)
4375 if (*paren == '(' && !inquote)
4386 name = findOprByOid(g_oprinfo, numOperators, opr);
4388 write_msg(NULL, "WARNING: could not find operator with OID %s\n",
4396 * writes out to fout the queries to recreate all the user-defined
4400 dumpOpclasses(Archive *fout, OpclassInfo *opcinfo, int numOpclasses)
4404 for (i = 0; i < numOpclasses; i++)
4406 /* Dump only opclasses in dumpable namespaces */
4407 if (!opcinfo[i].opcnamespace->dump)
4411 dumpOneOpclass(fout, &opcinfo[i]);
4417 * write out a single operator class definition
4420 dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
4422 PQExpBuffer query = createPQExpBuffer();
4423 PQExpBuffer q = createPQExpBuffer();
4424 PQExpBuffer delq = createPQExpBuffer();
4449 * XXX currently we do not implement dumping of operator classes from
4450 * pre-7.3 databases. This could be done but it seems not worth the
4453 if (g_fout->remoteVersion < 70300)
4456 /* Make sure we are in proper schema so regoperator works correctly */
4457 selectSourceSchema(opcinfo->opcnamespace->nspname);
4459 /* Get additional fields from the pg_opclass row */
4460 appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
4461 "opckeytype::pg_catalog.regtype, "
4463 "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
4464 "FROM pg_catalog.pg_opclass "
4465 "WHERE oid = '%s'::pg_catalog.oid",
4468 res = PQexec(g_conn, query->data);
4470 PQresultStatus(res) != PGRES_TUPLES_OK)
4472 write_msg(NULL, "query to obtain operator class details failed: %s", PQerrorMessage(g_conn));
4476 /* Expecting a single result only */
4477 ntups = PQntuples(res);
4480 write_msg(NULL, "Got %d rows instead of one from: %s",
4481 ntups, query->data);
4485 i_opcintype = PQfnumber(res, "opcintype");
4486 i_opckeytype = PQfnumber(res, "opckeytype");
4487 i_opcdefault = PQfnumber(res, "opcdefault");
4488 i_amname = PQfnumber(res, "amname");
4490 opcintype = PQgetvalue(res, 0, i_opcintype);
4491 opckeytype = PQgetvalue(res, 0, i_opckeytype);
4492 opcdefault = PQgetvalue(res, 0, i_opcdefault);
4493 amname = PQgetvalue(res, 0, i_amname);
4496 * DROP must be fully qualified in case same name appears in
4499 appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
4500 fmtId(opcinfo->opcnamespace->nspname));
4501 appendPQExpBuffer(delq, ".%s",
4502 fmtId(opcinfo->opcname));
4503 appendPQExpBuffer(delq, " USING %s;\n",
4506 /* Build the fixed portion of the CREATE command */
4507 appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n ",
4508 fmtId(opcinfo->opcname));
4509 if (strcmp(opcdefault, "t") == 0)
4510 appendPQExpBuffer(q, "DEFAULT ");
4511 appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n ",
4517 if (strcmp(opckeytype, "-") != 0)
4519 appendPQExpBuffer(q, "STORAGE %s",
4527 * Now fetch and print the OPERATOR entries (pg_amop rows).
4529 resetPQExpBuffer(query);
4531 appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
4532 "amopopr::pg_catalog.regoperator "
4533 "FROM pg_catalog.pg_amop "
4534 "WHERE amopclaid = '%s'::pg_catalog.oid "
4535 "ORDER BY amopstrategy",
4538 res = PQexec(g_conn, query->data);
4540 PQresultStatus(res) != PGRES_TUPLES_OK)
4542 write_msg(NULL, "query to obtain operator class operators failed: %s", PQerrorMessage(g_conn));
4546 ntups = PQntuples(res);
4548 i_amopstrategy = PQfnumber(res, "amopstrategy");
4549 i_amopreqcheck = PQfnumber(res, "amopreqcheck");
4550 i_amopopr = PQfnumber(res, "amopopr");
4552 for (i = 0; i < ntups; i++)
4554 amopstrategy = PQgetvalue(res, i, i_amopstrategy);
4555 amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
4556 amopopr = PQgetvalue(res, i, i_amopopr);
4559 appendPQExpBuffer(q, " ,\n ");
4561 appendPQExpBuffer(q, "OPERATOR %s %s",
4562 amopstrategy, amopopr);
4563 if (strcmp(amopreqcheck, "t") == 0)
4564 appendPQExpBuffer(q, " RECHECK");
4572 * Now fetch and print the FUNCTION entries (pg_amproc rows).
4574 resetPQExpBuffer(query);
4576 appendPQExpBuffer(query, "SELECT amprocnum, "
4577 "amproc::pg_catalog.regprocedure "
4578 "FROM pg_catalog.pg_amproc "
4579 "WHERE amopclaid = '%s'::pg_catalog.oid "
4580 "ORDER BY amprocnum",
4583 res = PQexec(g_conn, query->data);
4585 PQresultStatus(res) != PGRES_TUPLES_OK)
4587 write_msg(NULL, "query to obtain operator class functions failed: %s", PQerrorMessage(g_conn));
4591 ntups = PQntuples(res);
4593 i_amprocnum = PQfnumber(res, "amprocnum");
4594 i_amproc = PQfnumber(res, "amproc");
4596 for (i = 0; i < ntups; i++)
4598 amprocnum = PQgetvalue(res, i, i_amprocnum);
4599 amproc = PQgetvalue(res, i, i_amproc);
4602 appendPQExpBuffer(q, " ,\n ");
4604 appendPQExpBuffer(q, "FUNCTION %s %s",
4612 appendPQExpBuffer(q, ";\n");
4614 ArchiveEntry(fout, opcinfo->oid, opcinfo->opcname,
4615 opcinfo->opcnamespace->nspname, opcinfo->usename,
4616 "OPERATOR CLASS", NULL,
4617 q->data, delq->data,
4620 destroyPQExpBuffer(query);
4621 destroyPQExpBuffer(q);
4622 destroyPQExpBuffer(delq);
4628 * writes out to fout the queries to create all the user-defined aggregates
4631 dumpAggs(Archive *fout, AggInfo agginfo[], int numAggs)
4635 for (i = 0; i < numAggs; i++)
4637 /* Dump only aggs in dumpable namespaces */
4638 if (!agginfo[i].aggnamespace->dump)
4641 dumpOneAgg(fout, &agginfo[i]);
4643 dumpAggACL(fout, &agginfo[i]);
4649 * format_aggregate_signature: generate aggregate name and argument list
4651 * The argument type names are qualified if needed. The aggregate name
4652 * is never qualified.
4655 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
4657 PQExpBufferData buf;
4659 initPQExpBuffer(&buf);
4661 appendPQExpBuffer(&buf, "%s",
4662 fmtId(agginfo->aggname));
4664 appendPQExpBuffer(&buf, "%s", agginfo->aggname);
4666 /* If using regtype or format_type, fmtbasetype is already quoted */
4667 if (fout->remoteVersion >= 70100)
4669 if (agginfo->anybasetype)
4670 appendPQExpBuffer(&buf, "(*)");
4672 appendPQExpBuffer(&buf, "(%s)", agginfo->fmtbasetype);
4676 if (agginfo->anybasetype)
4677 appendPQExpBuffer(&buf, "(*)");
4679 appendPQExpBuffer(&buf, "(%s)",
4680 fmtId(agginfo->fmtbasetype));
4688 dumpAggACL(Archive *fout, AggInfo *finfo)
4693 aggsig = format_aggregate_signature(finfo, fout, true);
4694 aggsig_tag = format_aggregate_signature(finfo, fout, false);
4695 dumpACL(fout, "FUNCTION", aggsig, aggsig_tag,
4696 finfo->aggnamespace->nspname,
4697 finfo->usename, finfo->aggacl, finfo->oid);
4705 * write out a single aggregate definition
4708 dumpOneAgg(Archive *fout, AggInfo *agginfo)
4710 PQExpBuffer query = createPQExpBuffer();
4711 PQExpBuffer q = createPQExpBuffer();
4712 PQExpBuffer delq = createPQExpBuffer();
4713 PQExpBuffer details = createPQExpBuffer();
4725 const char *aggtransfn;
4726 const char *aggfinalfn;
4727 const char *aggtranstype;
4728 const char *agginitval;
4731 /* Make sure we are in proper schema */
4732 selectSourceSchema(agginfo->aggnamespace->nspname);
4734 /* Get aggregate-specific details */
4735 if (g_fout->remoteVersion >= 70300)
4737 appendPQExpBuffer(query, "SELECT aggtransfn, "
4738 "aggfinalfn, aggtranstype::pg_catalog.regtype, "
4740 "proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype as anybasetype, "
4741 "proargtypes[0]::pg_catalog.regtype as fmtbasetype, "
4742 "'t'::boolean as convertok "
4743 "from pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
4744 "where a.aggfnoid = p.oid "
4745 "and p.oid = '%s'::pg_catalog.oid",
4748 else if (g_fout->remoteVersion >= 70100)
4750 appendPQExpBuffer(query, "SELECT aggtransfn, aggfinalfn, "
4751 "format_type(aggtranstype, NULL) as aggtranstype, "
4753 "aggbasetype = 0 as anybasetype, "
4754 "CASE WHEN aggbasetype = 0 THEN '-' "
4755 "ELSE format_type(aggbasetype, NULL) END as fmtbasetype, "
4756 "'t'::boolean as convertok "
4757 "from pg_aggregate "
4758 "where oid = '%s'::oid",
4763 appendPQExpBuffer(query, "SELECT aggtransfn1 as aggtransfn, "
4765 "(select typname from pg_type where oid = aggtranstype1) as aggtranstype, "
4766 "agginitval1 as agginitval, "
4767 "aggbasetype = 0 as anybasetype, "
4768 "(select typname from pg_type where oid = aggbasetype) as fmtbasetype, "
4769 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok "
4770 "from pg_aggregate "
4771 "where oid = '%s'::oid",
4775 res = PQexec(g_conn, query->data);
4777 PQresultStatus(res) != PGRES_TUPLES_OK)
4779 write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
4780 PQerrorMessage(g_conn));
4784 /* Expecting a single result only */
4785 ntups = PQntuples(res);
4788 write_msg(NULL, "Got %d rows instead of one from: %s",
4789 ntups, query->data);
4793 i_aggtransfn = PQfnumber(res, "aggtransfn");
4794 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
4795 i_aggtranstype = PQfnumber(res, "aggtranstype");
4796 i_agginitval = PQfnumber(res, "agginitval");
4797 i_anybasetype = PQfnumber(res, "anybasetype");
4798 i_fmtbasetype = PQfnumber(res, "fmtbasetype");
4799 i_convertok = PQfnumber(res, "convertok");
4801 aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
4802 aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
4803 aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
4804 agginitval = PQgetvalue(res, 0, i_agginitval);
4805 /* we save anybasetype so that dumpAggACL can use it later */
4806 agginfo->anybasetype = (PQgetvalue(res, 0, i_anybasetype)[0] == 't');
4807 /* we save fmtbasetype so that dumpAggACL can use it later */
4808 agginfo->fmtbasetype = strdup(PQgetvalue(res, 0, i_fmtbasetype));
4809 convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
4811 aggsig = format_aggregate_signature(agginfo, g_fout, true);
4812 aggsig_tag = format_aggregate_signature(agginfo, g_fout, false);
4816 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
4819 appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
4821 ArchiveEntry(fout, agginfo->oid, aggsig_tag,
4822 agginfo->aggnamespace->nspname, agginfo->usename,
4824 q->data, "" /* Del */ ,
4829 if (g_fout->remoteVersion >= 70300)
4831 /* If using 7.3's regproc or regtype, data is already quoted */
4832 appendPQExpBuffer(details, " BASETYPE = %s,\n SFUNC = %s,\n STYPE = %s",
4833 agginfo->anybasetype ? "'any'" :
4834 agginfo->fmtbasetype,
4838 else if (g_fout->remoteVersion >= 70100)
4840 /* format_type quotes, regproc does not */
4841 appendPQExpBuffer(details, " BASETYPE = %s,\n SFUNC = %s,\n STYPE = %s",
4842 agginfo->anybasetype ? "'any'" :
4843 agginfo->fmtbasetype,
4849 /* need quotes all around */
4850 appendPQExpBuffer(details, " BASETYPE = %s,\n",
4851 agginfo->anybasetype ? "'any'" :
4852 fmtId(agginfo->fmtbasetype));
4853 appendPQExpBuffer(details, " SFUNC = %s,\n",
4855 appendPQExpBuffer(details, " STYPE = %s",
4856 fmtId(aggtranstype));
4859 if (!PQgetisnull(res, 0, i_agginitval))
4861 appendPQExpBuffer(details, ",\n INITCOND = ");
4862 appendStringLiteral(details, agginitval, true);
4865 if (strcmp(aggfinalfn, "-") != 0)
4867 appendPQExpBuffer(details, ",\n FINALFUNC = %s",
4872 * DROP must be fully qualified in case same name appears in
4875 appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
4876 fmtId(agginfo->aggnamespace->nspname),
4879 appendPQExpBuffer(q, "CREATE AGGREGATE %s (\n%s\n);\n",
4880 fmtId(agginfo->aggname),
4883 ArchiveEntry(fout, agginfo->oid, aggsig_tag,
4884 agginfo->aggnamespace->nspname, agginfo->usename,
4886 q->data, delq->data,
4889 /* Dump Aggregate Comments */
4891 resetPQExpBuffer(q);
4892 appendPQExpBuffer(q, "AGGREGATE %s", aggsig);
4893 if (g_fout->remoteVersion >= 70300)
4894 dumpComment(fout, q->data,
4895 agginfo->aggnamespace->nspname, agginfo->usename,
4896 agginfo->oid, "pg_proc", 0, NULL);
4898 dumpComment(fout, q->data,
4899 agginfo->aggnamespace->nspname, agginfo->usename,
4900 agginfo->oid, "pg_aggregate", 0, NULL);
4904 destroyPQExpBuffer(query);
4905 destroyPQExpBuffer(q);
4906 destroyPQExpBuffer(delq);
4907 destroyPQExpBuffer(details);
4914 * Write out grant/revoke information
4916 * 'type' must be TABLE, FUNCTION, LANGUAGE, or SCHEMA.
4917 * 'name' is the formatted name of the object. Must be quoted etc. already.
4918 * 'tag' is the tag for the archive entry (typ. unquoted name of object).
4919 * 'nspname' is the namespace the object is in (NULL if none).
4920 * 'owner' is the owner, NULL if there is no owner (for languages).
4921 * 'acls' is the string read out of the fooacl system catalog field;
4922 * it will be parsed here.
4923 * 'objoid' is the OID of the object for purposes of ordering.
4927 dumpACL(Archive *fout, const char *type, const char *name,
4928 const char *tag, const char *nspname, const char *owner,
4929 const char *acls, const char *objoid)
4934 * acl_lang is a flag only true if we are dumping language's ACL, so
4935 * we can set 'type' to a value that is suitable to build SQL requests
4936 * as for other types.
4938 bool acl_lang = false;
4940 if (!strcmp(type, "ACL LANGUAGE"))
4946 sql = createPQExpBuffer();
4948 if (!buildACLCommands(name, type, acls, owner, fout->remoteVersion, sql))
4950 write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
4956 ArchiveEntry(fout, objoid, tag, nspname,
4958 acl_lang ? "ACL LANGUAGE" : "ACL",
4959 NULL, sql->data, "", NULL, NULL, NULL);
4961 destroyPQExpBuffer(sql);
4966 dumpTableACL(Archive *fout, TableInfo *tbinfo)
4968 char *namecopy = strdup(fmtId(tbinfo->relname));
4972 * Choose OID to use for sorting ACL into position. For a view, sort
4973 * by the view OID; for a serial sequence, sort by the owning table's
4974 * OID; otherwise use the table's own OID.
4976 if (tbinfo->viewoid != NULL)
4977 dumpoid = tbinfo->viewoid;
4978 else if (tbinfo->owning_tab != NULL)
4979 dumpoid = tbinfo->owning_tab;
4981 dumpoid = tbinfo->oid;
4983 dumpACL(fout, "TABLE", namecopy, tbinfo->relname,
4984 tbinfo->relnamespace->nspname, tbinfo->usename, tbinfo->relacl,
4993 * write out to fout the declarations (not data) of all user-defined tables
4996 dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
4997 const bool aclsSkip, const bool schemaOnly, const bool dataOnly)
5002 * Dump non-serial sequences first, in case they are referenced in
5005 for (i = 0; i < numTables; i++)
5007 TableInfo *tbinfo = &tblinfo[i];
5009 if (tbinfo->relkind != RELKIND_SEQUENCE)
5012 if (tbinfo->dump && tbinfo->owning_tab == NULL)
5014 dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
5015 if (!dataOnly && !aclsSkip)
5016 dumpTableACL(fout, tbinfo);
5022 for (i = 0; i < numTables; i++)
5024 TableInfo *tbinfo = &tblinfo[i];
5026 if (tbinfo->relkind == RELKIND_SEQUENCE) /* already dumped */
5031 dumpOneTable(fout, tbinfo, tblinfo);
5033 dumpTableACL(fout, tbinfo);
5039 * Dump serial sequences last (we will not emit any CREATE commands,
5040 * but we do have to think about ACLs and setval operations).
5042 for (i = 0; i < numTables; i++)
5044 TableInfo *tbinfo = &tblinfo[i];
5046 if (tbinfo->relkind != RELKIND_SEQUENCE)
5049 if (tbinfo->dump && tbinfo->owning_tab != NULL)
5051 dumpOneSequence(fout, tbinfo, schemaOnly, dataOnly);
5052 if (!dataOnly && !aclsSkip)
5053 dumpTableACL(fout, tbinfo);
5060 * write the declaration (not data) of one user-defined table or view
5063 dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo)
5065 PQExpBuffer query = createPQExpBuffer();
5066 PQExpBuffer q = createPQExpBuffer();
5067 PQExpBuffer delq = createPQExpBuffer();
5071 int actual_atts; /* number of attrs in this CREATE statment */
5075 const char *((*commentDeps)[]);
5079 /* Make sure we are in proper schema */
5080 selectSourceSchema(tbinfo->relnamespace->nspname);
5082 /* Is it a table or a view? */
5083 if (tbinfo->relkind == RELKIND_VIEW)
5087 reltypename = "VIEW";
5089 /* Fetch the view definition */
5090 if (g_fout->remoteVersion >= 70300)
5092 /* Beginning in 7.3, viewname is not unique; use OID */
5093 appendPQExpBuffer(query, "SELECT pg_catalog.pg_get_viewdef(ev_class) as viewdef, "
5095 " from pg_catalog.pg_rewrite where"
5096 " ev_class = '%s'::pg_catalog.oid and"
5097 " rulename = '_RETURN';",
5102 appendPQExpBuffer(query, "SELECT definition as viewdef, "
5103 "(select oid from pg_rewrite where "
5104 " rulename=('_RET' || viewname)::name) as view_oid"
5105 " from pg_views where viewname = ");
5106 appendStringLiteral(query, tbinfo->relname, true);
5107 appendPQExpBuffer(query, ";");
5110 res = PQexec(g_conn, query->data);
5111 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
5113 write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
5114 tbinfo->relname, PQerrorMessage(g_conn));
5118 if (PQntuples(res) != 1)
5120 if (PQntuples(res) < 1)
5121 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
5124 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
5129 if (PQgetisnull(res, 0, 1))
5131 write_msg(NULL, "query to obtain definition of view \"%s\" returned null OID\n",
5136 viewdef = PQgetvalue(res, 0, 0);
5138 if (strlen(viewdef) == 0)
5140 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
5145 /* We use the OID of the view rule as the object OID */
5146 objoid = strdup(PQgetvalue(res, 0, 1));
5147 /* Save it for use by dumpACL, too */
5148 tbinfo->viewoid = objoid;
5151 * DROP must be fully qualified in case same name appears in
5154 appendPQExpBuffer(delq, "DROP VIEW %s.",
5155 fmtId(tbinfo->relnamespace->nspname));
5156 appendPQExpBuffer(delq, "%s;\n",
5157 fmtId(tbinfo->relname));
5159 appendPQExpBuffer(q, "CREATE VIEW %s AS\n %s\n",
5160 fmtId(tbinfo->relname), viewdef);
5165 * Views can have default values -- however, they must be
5166 * specified in an ALTER TABLE command after the view has been
5167 * created, not in the view definition itself.
5169 for (j = 0; j < tbinfo->numatts; j++)
5171 if (tbinfo->adef_expr[j] != NULL && !tbinfo->inhAttrDef[j])
5173 appendPQExpBuffer(q, "ALTER TABLE %s ",
5174 fmtId(tbinfo->relname));
5175 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
5176 fmtId(tbinfo->attnames[j]),
5177 tbinfo->adef_expr[j]);
5181 commentDeps = malloc(sizeof(char *) * 2);
5182 (*commentDeps)[0] = strdup(objoid);
5183 (*commentDeps)[1] = NULL; /* end of list */
5187 reltypename = "TABLE";
5188 objoid = tbinfo->oid;
5190 numParents = tbinfo->numParents;
5191 parentIndexes = tbinfo->parentIndexes;
5194 * DROP must be fully qualified in case same name appears in
5197 appendPQExpBuffer(delq, "DROP TABLE %s.",
5198 fmtId(tbinfo->relnamespace->nspname));
5199 appendPQExpBuffer(delq, "%s;\n",
5200 fmtId(tbinfo->relname));
5202 appendPQExpBuffer(q, "CREATE TABLE %s (",
5203 fmtId(tbinfo->relname));
5205 for (j = 0; j < tbinfo->numatts; j++)
5207 /* Is this one of the table's own attrs, and not dropped ? */
5208 if (!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j])
5210 /* Format properly if not first attr */
5211 if (actual_atts > 0)
5212 appendPQExpBuffer(q, ",");
5213 appendPQExpBuffer(q, "\n ");
5215 /* Attribute name */
5216 appendPQExpBuffer(q, "%s ",
5217 fmtId(tbinfo->attnames[j]));
5219 /* Attribute type */
5220 if (g_fout->remoteVersion >= 70100)
5222 char *typname = tbinfo->atttypnames[j];
5224 if (tbinfo->attisserial[j])
5226 if (strcmp(typname, "integer") == 0)
5228 else if (strcmp(typname, "bigint") == 0)
5229 typname = "bigserial";
5231 appendPQExpBuffer(q, "%s", typname);
5235 /* If no format_type, fake it */
5236 appendPQExpBuffer(q, "%s",
5237 myFormatType(tbinfo->atttypnames[j],
5238 tbinfo->atttypmod[j]));
5241 /* Default value --- suppress if inherited or serial */
5242 if (tbinfo->adef_expr[j] != NULL &&
5243 !tbinfo->inhAttrDef[j] &&
5244 !tbinfo->attisserial[j])
5245 appendPQExpBuffer(q, " DEFAULT %s",
5246 tbinfo->adef_expr[j]);
5249 * Not Null constraint --- suppress if inherited
5251 * Note: we could suppress this for serial columns since
5252 * SERIAL implies NOT NULL. We choose not to for forward
5253 * compatibility, since there has been some talk of making
5254 * SERIAL not imply NOT NULL, in which case the explicit
5255 * specification would be needed.
5257 if (tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
5258 appendPQExpBuffer(q, " NOT NULL");
5265 * Add non-inherited CHECK constraints, if any. If a constraint
5266 * matches by name and condition with a constraint belonging to a
5267 * parent class (OR conditions match and both names start with
5268 * '$'), we assume it was inherited.
5270 if (tbinfo->ncheck > 0)
5278 write_msg(NULL, "finding check constraints for table \"%s\"\n",
5281 resetPQExpBuffer(query);
5282 if (g_fout->remoteVersion >= 70400)
5283 appendPQExpBuffer(query, "SELECT conname, "
5284 " pg_catalog.pg_get_constraintdef(c1.oid) AS consrc "
5285 " from pg_catalog.pg_constraint c1 "
5286 " where conrelid = '%s'::pg_catalog.oid "
5287 " and contype = 'c' "
5290 " pg_catalog.pg_constraint c2, "
5291 " pg_catalog.pg_inherits i "
5292 " where i.inhrelid = c1.conrelid "
5293 " and (c2.conname = c1.conname "
5294 " or (c2.conname[0] = '$' "
5295 " and c1.conname[0] = '$')"
5297 " and pg_catalog.pg_get_constraintdef(c2.oid) "
5298 " = pg_catalog.pg_get_constraintdef(c1.oid) "
5299 " and c2.conrelid = i.inhparent) "
5300 " order by conname ",
5302 else if (g_fout->remoteVersion >= 70300)
5303 appendPQExpBuffer(query, "SELECT conname, "
5304 " 'CHECK (' || consrc || ')' AS consrc"
5305 " from pg_catalog.pg_constraint c1"
5306 " where conrelid = '%s'::pg_catalog.oid "
5307 " and contype = 'c' "
5310 " pg_catalog.pg_constraint c2, "
5311 " pg_catalog.pg_inherits i "
5312 " where i.inhrelid = c1.conrelid "
5313 " and (c2.conname = c1.conname "
5314 " or (c2.conname[0] = '$' "
5315 " and c1.conname[0] = '$')"
5317 " and c2.consrc = c1.consrc "
5318 " and c2.conrelid = i.inhparent) "
5319 " order by conname ",
5322 appendPQExpBuffer(query, "SELECT rcname as conname,"
5323 " 'CHECK (' || rcsrc || ')' as consrc"
5324 " from pg_relcheck c1"
5325 " where rcrelid = '%s'::oid "
5327 " (select 1 from pg_relcheck c2, "
5329 " where i.inhrelid = c1.rcrelid "
5330 " and (c2.rcname = c1.rcname "
5331 " or (c2.rcname[0] = '$' "
5332 " and c1.rcname[0] = '$')"
5334 " and c2.rcsrc = c1.rcsrc "
5335 " and c2.rcrelid = i.inhparent) "
5336 " order by rcname ",
5338 res2 = PQexec(g_conn, query->data);
5340 PQresultStatus(res2) != PGRES_TUPLES_OK)
5342 write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
5345 ntups2 = PQntuples(res2);
5346 if (ntups2 > tbinfo->ncheck)
5348 write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
5349 tbinfo->ncheck, tbinfo->relname, ntups2);
5350 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
5354 i_conname = PQfnumber(res2, "conname");
5355 i_consrc = PQfnumber(res2, "consrc");
5357 for (j = 0; j < ntups2; j++)
5359 const char *name = PQgetvalue(res2, j, i_conname);
5360 const char *expr = PQgetvalue(res2, j, i_consrc);
5362 if (actual_atts + j > 0)
5363 appendPQExpBuffer(q, ",\n ");
5365 appendPQExpBuffer(q, "CONSTRAINT %s ",
5367 appendPQExpBuffer(q, "%s", expr);
5373 * Primary Key: In versions of PostgreSQL prior to 7.2, we needed
5374 * to include the primary key in the table definition. However,
5375 * this is not ideal because it creates an index on the table,
5376 * which makes COPY slower. As of release 7.2, we can add primary
5377 * keys to a table after it has been created, using ALTER TABLE;
5378 * see dumpIndexes() for more information. Therefore, we ignore
5379 * primary keys in this function.
5382 appendPQExpBuffer(q, "\n)");
5386 appendPQExpBuffer(q, "\nINHERITS (");
5387 for (k = 0; k < numParents; k++)
5389 TableInfo *parentRel = &g_tblinfo[parentIndexes[k]];
5392 appendPQExpBuffer(q, ", ");
5393 if (parentRel->relnamespace != tbinfo->relnamespace)
5394 appendPQExpBuffer(q, "%s.",
5395 fmtId(parentRel->relnamespace->nspname));
5396 appendPQExpBuffer(q, "%s",
5397 fmtId(parentRel->relname));
5399 appendPQExpBuffer(q, ")");
5402 if (!tbinfo->hasoids)
5403 appendPQExpBuffer(q, " WITHOUT OIDS");
5405 appendPQExpBuffer(q, ";\n");
5407 /* Loop dumping statistics and storage statements */
5408 for (j = 0; j < tbinfo->numatts; j++)
5411 * Dump per-column statistics information. We only issue an
5412 * ALTER TABLE statement if the attstattarget entry for this
5413 * column is non-negative (i.e. it's not the default value)
5415 if (tbinfo->attstattarget[j] >= 0 &&
5416 !tbinfo->attisdropped[j])
5418 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
5419 fmtId(tbinfo->relname));
5420 appendPQExpBuffer(q, "ALTER COLUMN %s ",
5421 fmtId(tbinfo->attnames[j]));
5422 appendPQExpBuffer(q, "SET STATISTICS %d;\n",
5423 tbinfo->attstattarget[j]);
5427 * Dump per-column storage information. The statement is only
5428 * dumped if the storage has been changed from the type's
5431 if (!tbinfo->attisdropped[j] && tbinfo->attstorage[j] != tbinfo->typstorage[j])
5433 switch (tbinfo->attstorage[j])
5439 storage = "EXTERNAL";
5445 storage = "EXTENDED";
5452 * Only dump the statement if it's a storage type we
5455 if (storage != NULL)
5457 appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
5458 fmtId(tbinfo->relname));
5459 appendPQExpBuffer(q, "ALTER COLUMN %s ",
5460 fmtId(tbinfo->attnames[j]));
5461 appendPQExpBuffer(q, "SET STORAGE %s;\n",
5468 ArchiveEntry(fout, objoid, tbinfo->relname,
5469 tbinfo->relnamespace->nspname, tbinfo->usename,
5470 reltypename, NULL, q->data, delq->data,
5473 /* Dump Table Comments */
5474 dumpTableComment(fout, tbinfo, reltypename, commentDeps);
5476 /* commentDeps now belongs to the archive entry ... don't free it! */
5478 destroyPQExpBuffer(query);
5479 destroyPQExpBuffer(q);
5480 destroyPQExpBuffer(delq);
5484 * getAttrName: extract the correct name for an attribute
5486 * The array tblInfo->attnames[] only provides names of user attributes;
5487 * if a system attribute number is supplied, we have to fake it.
5488 * We also do a little bit of bounds checking for safety's sake.
5491 getAttrName(int attrnum, TableInfo *tblInfo)
5493 if (attrnum > 0 && attrnum <= tblInfo->numatts)
5494 return tblInfo->attnames[attrnum - 1];
5497 case SelfItemPointerAttributeNumber:
5499 case ObjectIdAttributeNumber:
5501 case MinTransactionIdAttributeNumber:
5503 case MinCommandIdAttributeNumber:
5505 case MaxTransactionIdAttributeNumber:
5507 case MaxCommandIdAttributeNumber:
5509 case TableOidAttributeNumber:
5512 write_msg(NULL, "invalid column number %d for table \"%s\"\n",
5513 attrnum, tblInfo->relname);
5515 return NULL; /* keep compiler quiet */
5520 * write out to fout all the user-defined indexes for dumpable tables
5523 dumpIndexes(Archive *fout, TableInfo *tblinfo, int numTables)
5527 PQExpBuffer query = createPQExpBuffer();
5528 PQExpBuffer q = createPQExpBuffer();
5529 PQExpBuffer delq = createPQExpBuffer();
5538 int i_indisclustered;
5541 for (i = 0; i < numTables; i++)
5543 TableInfo *tbinfo = &tblinfo[i];
5545 /* Only plain tables have indexes */
5546 if (tbinfo->relkind != RELKIND_RELATION || !tbinfo->hasindex)
5552 /* Make sure we are in proper schema so indexdef is right */
5553 selectSourceSchema(tbinfo->relnamespace->nspname);
5556 * The point of the messy-looking outer join is to find a
5557 * constraint that is related by an internal dependency link to
5558 * the index. If we find one, we emit an ADD CONSTRAINT command
5559 * instead of a CREATE INDEX command. We assume an index won't
5560 * have more than one internal dependency.
5562 resetPQExpBuffer(query);
5563 if (g_fout->remoteVersion >= 70300)
5564 appendPQExpBuffer(query,
5565 "SELECT i.indexrelid as indexreloid, "
5566 "coalesce(c.conname, t.relname) as indexrelname, "
5567 "pg_catalog.pg_get_indexdef(i.indexrelid) as indexdef, "
5568 "i.indkey, i.indisclustered, "
5569 "t.relnatts as indnkeys, "
5570 "coalesce(c.contype, '0') as contype, "
5571 "coalesce(c.oid, '0') as conoid "
5572 "FROM pg_catalog.pg_index i "
5573 "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
5574 "LEFT JOIN pg_catalog.pg_depend d "
5575 "ON (d.classid = t.tableoid "
5576 "AND d.objid = t.oid "
5577 "AND d.deptype = 'i') "
5578 "LEFT JOIN pg_catalog.pg_constraint c "
5579 "ON (d.refclassid = c.tableoid "
5580 "AND d.refobjid = c.oid) "
5581 "WHERE i.indrelid = '%s'::pg_catalog.oid "
5582 "ORDER BY indexrelname",
5585 appendPQExpBuffer(query,
5586 "SELECT i.indexrelid as indexreloid, "
5587 "t.relname as indexrelname, "
5588 "pg_get_indexdef(i.indexrelid) as indexdef, "
5589 "i.indkey, false as indisclustered, "
5590 "t.relnatts as indnkeys, "
5591 "CASE WHEN i.indisprimary THEN 'p'::char "
5592 "ELSE '0'::char END as contype, "
5594 "FROM pg_index i, pg_class t "
5595 "WHERE t.oid = i.indexrelid "
5596 "AND i.indrelid = '%s'::oid "
5597 "ORDER BY indexrelname",
5600 res = PQexec(g_conn, query->data);
5602 PQresultStatus(res) != PGRES_TUPLES_OK)
5604 write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
5608 ntups = PQntuples(res);
5610 i_indexreloid = PQfnumber(res, "indexreloid");
5611 i_indexrelname = PQfnumber(res, "indexrelname");
5612 i_indexdef = PQfnumber(res, "indexdef");
5613 i_contype = PQfnumber(res, "contype");
5614 i_conoid = PQfnumber(res, "conoid");
5615 i_indkey = PQfnumber(res, "indkey");
5616 i_indisclustered = PQfnumber(res, "indisclustered");
5617 i_indnkeys = PQfnumber(res, "indnkeys");
5619 for (j = 0; j < ntups; j++)
5621 const char *indexreloid = PQgetvalue(res, j, i_indexreloid);
5622 const char *indexrelname = PQgetvalue(res, j, i_indexrelname);
5623 const char *indexdef = PQgetvalue(res, j, i_indexdef);
5624 char contype = *(PQgetvalue(res, j, i_contype));
5625 const char *conoid = PQgetvalue(res, j, i_conoid);
5626 bool indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
5628 resetPQExpBuffer(q);
5629 resetPQExpBuffer(delq);
5631 if (contype == 'p' || contype == 'u')
5634 * If we found a constraint matching the index, emit ADD
5635 * CONSTRAINT not CREATE INDEX.
5637 * In a pre-7.3 database, we take this path iff the index was
5638 * marked indisprimary.
5640 int indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
5641 char **indkeys = (char **) malloc(indnkeys * sizeof(char *));
5644 parseNumericArray(PQgetvalue(res, j, i_indkey),
5647 appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
5648 fmtId(tbinfo->relname));
5649 appendPQExpBuffer(q, " ADD CONSTRAINT %s %s (",
5650 fmtId(indexrelname),
5651 contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
5653 for (k = 0; k < indnkeys; k++)
5655 int indkey = atoi(indkeys[k]);
5656 const char *attname;
5658 if (indkey == InvalidAttrNumber)
5660 attname = getAttrName(indkey, tbinfo);
5662 appendPQExpBuffer(q, "%s%s",
5663 (k == 0) ? "" : ", ",
5667 appendPQExpBuffer(q, ");\n");
5669 /* If the index is clustered, we need to record that. */
5672 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
5673 fmtId(tbinfo->relname));
5674 appendPQExpBuffer(q, " ON %s;\n",
5675 fmtId(indexrelname));
5679 * DROP must be fully qualified in case same name appears
5682 appendPQExpBuffer(delq, "ALTER TABLE ONLY %s.",
5683 fmtId(tbinfo->relnamespace->nspname));
5684 appendPQExpBuffer(delq, "%s ",
5685 fmtId(tbinfo->relname));
5686 appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
5687 fmtId(indexrelname));
5689 ArchiveEntry(fout, indexreloid,
5691 tbinfo->relnamespace->nspname,
5694 q->data, delq->data,
5697 for (k = 0; k < indnkeys; k++)
5701 /* Dump Constraint Comments */
5702 resetPQExpBuffer(q);
5703 appendPQExpBuffer(q, "CONSTRAINT %s ",
5704 fmtId(indexrelname));
5705 appendPQExpBuffer(q, "ON %s",
5706 fmtId(tbinfo->relname));
5707 dumpComment(fout, q->data,
5708 tbinfo->relnamespace->nspname,
5710 conoid, "pg_constraint", 0, NULL);
5714 /* Plain secondary index */
5715 appendPQExpBuffer(q, "%s;\n", indexdef);
5717 /* If the index is clustered, we need to record that. */
5720 appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
5721 fmtId(tbinfo->relname));
5722 appendPQExpBuffer(q, " ON %s;\n",
5723 fmtId(indexrelname));
5727 * DROP must be fully qualified in case same name appears
5730 appendPQExpBuffer(delq, "DROP INDEX %s.",
5731 fmtId(tbinfo->relnamespace->nspname));
5732 appendPQExpBuffer(delq, "%s;\n",
5733 fmtId(indexrelname));
5735 ArchiveEntry(fout, indexreloid,
5737 tbinfo->relnamespace->nspname,
5740 q->data, delq->data,
5744 /* Dump Index Comments */
5745 resetPQExpBuffer(q);
5746 appendPQExpBuffer(q, "INDEX %s",
5747 fmtId(indexrelname));
5748 dumpComment(fout, q->data,
5749 tbinfo->relnamespace->nspname,
5751 indexreloid, "pg_class", 0, NULL);
5757 destroyPQExpBuffer(query);
5758 destroyPQExpBuffer(q);
5759 destroyPQExpBuffer(delq);
5764 * find the maximum oid and generate a COPY statement to set it
5768 setMaxOid(Archive *fout)
5774 res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy integer)");
5776 PQresultStatus(res) != PGRES_COMMAND_OK)
5778 write_msg(NULL, "could not create pgdump_oid table: %s", PQerrorMessage(g_conn));
5782 res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
5784 PQresultStatus(res) != PGRES_COMMAND_OK)
5786 write_msg(NULL, "could not insert into pgdump_oid table: %s", PQerrorMessage(g_conn));
5789 max_oid = PQoidValue(res);
5792 write_msg(NULL, "inserted invalid OID\n");
5796 res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
5798 PQresultStatus(res) != PGRES_COMMAND_OK)
5800 write_msg(NULL, "could not drop pgdump_oid table: %s", PQerrorMessage(g_conn));
5805 write_msg(NULL, "maximum system OID is %u\n", max_oid);
5806 snprintf(sql, sizeof(sql),
5807 "CREATE TEMPORARY TABLE pgdump_oid (dummy integer);\n"
5808 "COPY pgdump_oid WITH OIDS FROM stdin;\n"
5811 "DROP TABLE pgdump_oid;\n",
5814 ArchiveEntry(fout, "0", "Max OID", NULL, "",
5821 * findLastBuiltInOid -
5822 * find the last built in oid
5824 * For 7.1 and 7.2, we do this by retrieving datlastsysoid from the
5825 * pg_database entry for the current database
5828 findLastBuiltinOid_V71(const char *dbname)
5833 PQExpBuffer query = createPQExpBuffer();
5835 resetPQExpBuffer(query);
5836 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
5837 appendStringLiteral(query, dbname, true);
5839 res = PQexec(g_conn, query->data);
5841 PQresultStatus(res) != PGRES_TUPLES_OK)
5843 write_msg(NULL, "error in finding the last system OID: %s", PQerrorMessage(g_conn));
5846 ntups = PQntuples(res);
5849 write_msg(NULL, "missing pg_database entry for this database\n");
5854 write_msg(NULL, "found more than one pg_database entry for this database\n");
5857 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
5859 destroyPQExpBuffer(query);
5864 * findLastBuiltInOid -
5865 * find the last built in oid
5867 * For 7.0, we do this by assuming that the last thing that initdb does is to
5868 * create the pg_indexes view. This sucks in general, but seeing that 7.0.x
5869 * initdb won't be changing anymore, it'll do.
5872 findLastBuiltinOid_V70(void)
5878 res = PQexec(g_conn,
5879 "SELECT oid FROM pg_class WHERE relname = 'pg_indexes'");
5881 PQresultStatus(res) != PGRES_TUPLES_OK)
5883 write_msg(NULL, "error in finding the template1 database: %s", PQerrorMessage(g_conn));
5886 ntups = PQntuples(res);
5889 write_msg(NULL, "could not find entry for database template1 in table pg_database\n");
5894 write_msg(NULL, "found more than one entry for database template1 in table pg_database\n");
5897 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
5903 dumpOneSequence(Archive *fout, TableInfo *tbinfo,
5904 const bool schemaOnly, const bool dataOnly)
5916 PQExpBuffer query = createPQExpBuffer();
5917 PQExpBuffer delqry = createPQExpBuffer();
5919 /* Make sure we are in proper schema */
5920 selectSourceSchema(tbinfo->relnamespace->nspname);
5922 snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
5923 snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
5925 appendPQExpBuffer(query,
5926 "SELECT sequence_name, last_value, increment_by, "
5927 "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
5928 " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
5930 "END AS max_value, "
5931 "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
5932 " WHEN increment_by < 0 AND min_value = %s THEN NULL "
5934 "END AS min_value, "
5935 "cache_value, is_cycled, is_called from %s",
5937 fmtId(tbinfo->relname));
5939 res = PQexec(g_conn, query->data);
5940 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
5942 write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo->relname, PQerrorMessage(g_conn));
5946 if (PQntuples(res) != 1)
5948 write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
5949 tbinfo->relname, PQntuples(res));
5953 /* Disable this check: it fails if sequence has been renamed */
5955 if (strcmp(PQgetvalue(res, 0, 0), tbinfo->relname) != 0)
5957 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
5958 tbinfo->relname, PQgetvalue(res, 0, 0));
5963 last = PQgetvalue(res, 0, 1);
5964 incby = PQgetvalue(res, 0, 2);
5965 if (!PQgetisnull(res, 0, 3))
5966 maxv = PQgetvalue(res, 0, 3);
5967 if (!PQgetisnull(res, 0, 4))
5968 minv = PQgetvalue(res, 0, 4);
5969 cache = PQgetvalue(res, 0, 5);
5970 cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
5971 called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
5974 * The logic we use for restoring sequences is as follows:
5976 * Add a basic CREATE SEQUENCE statement (use last_val for start if
5977 * called is false, else use min_val for start_val). Skip this if the
5978 * sequence came from a SERIAL column.
5980 * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
5981 * data. We do this for serial sequences too.
5984 if (!dataOnly && tbinfo->owning_tab == NULL)
5986 resetPQExpBuffer(delqry);
5989 * DROP must be fully qualified in case same name appears in
5992 appendPQExpBuffer(delqry, "DROP SEQUENCE %s.",
5993 fmtId(tbinfo->relnamespace->nspname));
5994 appendPQExpBuffer(delqry, "%s;\n",
5995 fmtId(tbinfo->relname));
5997 resetPQExpBuffer(query);
5998 appendPQExpBuffer(query,
5999 "CREATE SEQUENCE %s\n",
6000 fmtId(tbinfo->relname));
6003 appendPQExpBuffer(query, " START WITH %s\n", last);
6005 appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
6008 appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
6010 appendPQExpBuffer(query, " NO MAXVALUE\n");
6013 appendPQExpBuffer(query, " MINVALUE %s\n", minv);
6015 appendPQExpBuffer(query, " NO MINVALUE\n");
6017 appendPQExpBuffer(query,
6019 cache, (cycled ? "\n CYCLE" : ""));
6021 ArchiveEntry(fout, tbinfo->oid, tbinfo->relname,
6022 tbinfo->relnamespace->nspname, tbinfo->usename,
6024 query->data, delqry->data,
6030 resetPQExpBuffer(query);
6031 appendPQExpBuffer(query, "SELECT pg_catalog.setval(");
6032 appendStringLiteral(query, fmtId(tbinfo->relname), true);
6033 appendPQExpBuffer(query, ", %s, %s);\n",
6034 last, (called ? "true" : "false"));
6036 ArchiveEntry(fout, tbinfo->oid, tbinfo->relname,
6037 tbinfo->relnamespace->nspname, tbinfo->usename,
6038 "SEQUENCE SET", NULL,
6039 query->data, "" /* Del */ ,
6045 /* Dump Sequence Comments */
6047 resetPQExpBuffer(query);
6048 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->relname));
6049 dumpComment(fout, query->data,
6050 tbinfo->relnamespace->nspname, tbinfo->usename,
6051 tbinfo->oid, "pg_class", 0, NULL);
6056 destroyPQExpBuffer(query);
6057 destroyPQExpBuffer(delqry);
6063 * Dump out constraints after all table creation statements in
6064 * an alter table format. Currently handles foreign keys only.
6065 * (Unique and primary key constraints are handled with indexes,
6066 * while check constraints are merged into the table definition.)
6068 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that
6069 * the current table data is not processed
6072 dumpConstraints(Archive *fout, TableInfo *tblinfo, int numTables)
6084 /* pg_constraint was created in 7.3, so nothing to do if older */
6085 if (g_fout->remoteVersion < 70300)
6088 query = createPQExpBuffer();
6089 delqry = createPQExpBuffer();
6091 for (i = 0; i < numTables; i++)
6093 TableInfo *tbinfo = &tblinfo[i];
6095 if (tbinfo->ntrig == 0 || !tbinfo->dump)
6099 write_msg(NULL, "dumping foreign key constraints for table \"%s\"\n",
6103 * select table schema to ensure regproc name is qualified if
6106 selectSourceSchema(tbinfo->relnamespace->nspname);
6108 resetPQExpBuffer(query);
6109 appendPQExpBuffer(query,
6110 "SELECT oid, conname, "
6111 "pg_catalog.pg_get_constraintdef(oid) as condef "
6112 "FROM pg_catalog.pg_constraint "
6113 "WHERE conrelid = '%s'::pg_catalog.oid "
6114 "AND contype = 'f'",
6116 res = PQexec(g_conn, query->data);
6118 PQresultStatus(res) != PGRES_TUPLES_OK)
6120 write_msg(NULL, "query to obtain list of foreign key definitions failed: %s", PQerrorMessage(g_conn));
6123 ntups = PQntuples(res);
6125 i_conoid = PQfnumber(res, "oid");
6126 i_conname = PQfnumber(res, "conname");
6127 i_condef = PQfnumber(res, "condef");
6129 for (j = 0; j < ntups; j++)
6131 const char *conOid = PQgetvalue(res, j, i_conoid);
6132 const char *conName = PQgetvalue(res, j, i_conname);
6133 const char *conDef = PQgetvalue(res, j, i_condef);
6135 resetPQExpBuffer(query);
6136 appendPQExpBuffer(query, "ALTER TABLE ONLY %s\n",
6137 fmtId(tbinfo->relname));
6138 appendPQExpBuffer(query, " ADD CONSTRAINT %s %s;\n",
6143 * DROP must be fully qualified in case same name appears in
6146 resetPQExpBuffer(delqry);
6147 appendPQExpBuffer(delqry, "ALTER TABLE ONLY %s.",
6148 fmtId(tbinfo->relnamespace->nspname));
6149 appendPQExpBuffer(delqry, "%s ",
6150 fmtId(tbinfo->relname));
6151 appendPQExpBuffer(delqry, "DROP CONSTRAINT %s;\n",
6154 ArchiveEntry(fout, conOid,
6156 tbinfo->relnamespace->nspname,
6158 "FK CONSTRAINT", NULL,
6159 query->data, delqry->data,
6162 resetPQExpBuffer(query);
6163 appendPQExpBuffer(query, "CONSTRAINT %s ",
6165 appendPQExpBuffer(query, "ON %s",
6166 fmtId(tbinfo->relname));
6168 dumpComment(fout, query->data,
6169 tbinfo->relnamespace->nspname, tbinfo->usename,
6170 conOid, "pg_constraint", 0, NULL);
6176 destroyPQExpBuffer(query);
6177 destroyPQExpBuffer(delqry);
6181 dumpTriggers(Archive *fout, TableInfo *tblinfo, int numTables)
6185 PQExpBuffer query = createPQExpBuffer();
6186 PQExpBuffer delqry = createPQExpBuffer();
6202 for (i = 0; i < numTables; i++)
6204 TableInfo *tbinfo = &tblinfo[i];
6206 if (tbinfo->ntrig == 0 || !tbinfo->dump)
6210 write_msg(NULL, "dumping triggers for table \"%s\"\n",
6214 * select table schema to ensure regproc name is qualified if
6217 selectSourceSchema(tbinfo->relnamespace->nspname);
6219 resetPQExpBuffer(query);
6220 if (g_fout->remoteVersion >= 70300)
6223 * We ignore triggers that are tied to a foreign-key
6226 appendPQExpBuffer(query,
6228 "tgfoid::pg_catalog.regproc as tgfname, "
6229 "tgtype, tgnargs, tgargs, "
6230 "tgisconstraint, tgconstrname, tgdeferrable, "
6231 "tgconstrrelid, tginitdeferred, oid, "
6232 "tgconstrrelid::pg_catalog.regclass as tgconstrrelname "
6233 "from pg_catalog.pg_trigger t "
6234 "where tgrelid = '%s'::pg_catalog.oid "
6235 "and (not tgisconstraint "
6237 " (SELECT 1 FROM pg_catalog.pg_depend d "
6238 " JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
6239 " WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
6244 appendPQExpBuffer(query,
6245 "SELECT tgname, tgfoid::regproc as tgfname, "
6246 "tgtype, tgnargs, tgargs, "
6247 "tgisconstraint, tgconstrname, tgdeferrable, "
6248 "tgconstrrelid, tginitdeferred, oid, "
6249 "(select relname from pg_class where oid = tgconstrrelid) "
6250 " as tgconstrrelname "
6252 "where tgrelid = '%s'::oid",
6255 res = PQexec(g_conn, query->data);
6257 PQresultStatus(res) != PGRES_TUPLES_OK)
6259 write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
6262 ntups = PQntuples(res);
6265 * We may have less triggers than recorded due to constraint
6266 * triggers which are dumped by dumpConstraints
6268 if (ntups > tbinfo->ntrig)
6270 write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
6271 tbinfo->ntrig, tbinfo->relname, ntups);
6274 i_tgname = PQfnumber(res, "tgname");
6275 i_tgfname = PQfnumber(res, "tgfname");
6276 i_tgtype = PQfnumber(res, "tgtype");
6277 i_tgnargs = PQfnumber(res, "tgnargs");
6278 i_tgargs = PQfnumber(res, "tgargs");
6279 i_tgoid = PQfnumber(res, "oid");
6280 i_tgisconstraint = PQfnumber(res, "tgisconstraint");
6281 i_tgconstrname = PQfnumber(res, "tgconstrname");
6282 i_tgdeferrable = PQfnumber(res, "tgdeferrable");
6283 i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
6284 i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
6285 i_tginitdeferred = PQfnumber(res, "tginitdeferred");
6287 for (j = 0; j < ntups; j++)
6289 const char *tgoid = PQgetvalue(res, j, i_tgoid);
6290 char *tgname = PQgetvalue(res, j, i_tgname);
6291 const char *tgfname = PQgetvalue(res, j, i_tgfname);
6292 int2 tgtype = atoi(PQgetvalue(res, j, i_tgtype));
6293 int tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
6294 const char *tgargs = PQgetvalue(res, j, i_tgargs);
6298 char *tgconstrrelid;
6302 if (strcmp(PQgetvalue(res, j, i_tgisconstraint), "f") == 0)
6307 if (strcmp(PQgetvalue(res, j, i_tgdeferrable), "f") == 0)
6312 if (strcmp(PQgetvalue(res, j, i_tginitdeferred), "f") == 0)
6317 resetPQExpBuffer(delqry);
6320 * DROP must be fully qualified in case same name appears in
6323 appendPQExpBuffer(delqry, "DROP TRIGGER %s ",
6325 appendPQExpBuffer(delqry, "ON %s.",
6326 fmtId(tbinfo->relnamespace->nspname));
6327 appendPQExpBuffer(delqry, "%s;\n",
6328 fmtId(tbinfo->relname));
6330 resetPQExpBuffer(query);
6333 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
6334 appendPQExpBuffer(query, fmtId(PQgetvalue(res, j, i_tgconstrname)));
6338 appendPQExpBuffer(query, "CREATE TRIGGER ");
6339 appendPQExpBuffer(query, fmtId(tgname));
6341 appendPQExpBuffer(query, "\n ");
6344 if (TRIGGER_FOR_BEFORE(tgtype))
6345 appendPQExpBuffer(query, "BEFORE");
6347 appendPQExpBuffer(query, "AFTER");
6348 if (TRIGGER_FOR_INSERT(tgtype))
6350 appendPQExpBuffer(query, " INSERT");
6353 if (TRIGGER_FOR_DELETE(tgtype))
6356 appendPQExpBuffer(query, " OR DELETE");
6358 appendPQExpBuffer(query, " DELETE");
6361 if (TRIGGER_FOR_UPDATE(tgtype))
6364 appendPQExpBuffer(query, " OR UPDATE");
6366 appendPQExpBuffer(query, " UPDATE");
6368 appendPQExpBuffer(query, " ON %s\n",
6369 fmtId(tbinfo->relname));
6373 tgconstrrelid = PQgetvalue(res, j, i_tgconstrrelid);
6375 if (strcmp(tgconstrrelid, "0") != 0)
6378 if (PQgetisnull(res, j, i_tgconstrrelname))
6380 write_msg(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %s)\n",
6381 tgname, tbinfo->relname, tgconstrrelid);
6385 /* If we are using regclass, name is already quoted */
6386 if (g_fout->remoteVersion >= 70300)
6387 appendPQExpBuffer(query, " FROM %s\n ",
6388 PQgetvalue(res, j, i_tgconstrrelname));
6390 appendPQExpBuffer(query, " FROM %s\n ",
6391 fmtId(PQgetvalue(res, j, i_tgconstrrelname)));
6394 appendPQExpBuffer(query, "NOT ");
6395 appendPQExpBuffer(query, "DEFERRABLE INITIALLY ");
6397 appendPQExpBuffer(query, "DEFERRED\n");
6399 appendPQExpBuffer(query, "IMMEDIATE\n");
6403 if (TRIGGER_FOR_ROW(tgtype))
6404 appendPQExpBuffer(query, " FOR EACH ROW\n ");
6406 appendPQExpBuffer(query, " FOR EACH STATEMENT\n ");
6408 /* In 7.3, result of regproc is already quoted */
6409 if (g_fout->remoteVersion >= 70300)
6410 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
6413 appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
6415 for (findx = 0; findx < tgnargs; findx++)
6421 p = strchr(p, '\\');
6424 write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
6425 PQgetvalue(res, j, i_tgargs),
6436 if (p[0] == '0' && p[1] == '0' && p[2] == '0')
6440 appendPQExpBufferChar(query, '\'');
6441 for (s = tgargs; s < p;)
6444 appendPQExpBufferChar(query, '\\');
6445 appendPQExpBufferChar(query, *s++);
6447 appendPQExpBufferChar(query, '\'');
6448 appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
6451 appendPQExpBuffer(query, ");\n");
6453 ArchiveEntry(fout, tgoid,
6455 tbinfo->relnamespace->nspname,
6458 query->data, delqry->data,
6461 resetPQExpBuffer(query);
6462 appendPQExpBuffer(query, "TRIGGER %s ",
6464 appendPQExpBuffer(query, "ON %s",
6465 fmtId(tbinfo->relname));
6467 dumpComment(fout, query->data,
6468 tbinfo->relnamespace->nspname, tbinfo->usename,
6469 tgoid, "pg_trigger", 0, NULL);
6475 destroyPQExpBuffer(query);
6476 destroyPQExpBuffer(delqry);
6481 dumpRules(Archive *fout, TableInfo *tblinfo, int numTables)
6487 PQExpBuffer query = createPQExpBuffer();
6488 PQExpBuffer cmd = createPQExpBuffer();
6494 write_msg(NULL, "dumping out rules\n");
6497 * For each table we dump
6499 for (t = 0; t < numTables; t++)
6501 TableInfo *tbinfo = &tblinfo[t];
6503 if (!tbinfo->hasrules || !tbinfo->dump)
6506 /* Make sure we are in proper schema */
6507 selectSourceSchema(tbinfo->relnamespace->nspname);
6510 * Get all rules defined for this table, except view select rules
6512 resetPQExpBuffer(query);
6514 if (g_fout->remoteVersion >= 70300)
6516 appendPQExpBuffer(query,
6517 "SELECT pg_catalog.pg_get_ruledef(oid) AS definition,"
6519 "FROM pg_catalog.pg_rewrite "
6520 "WHERE ev_class = '%s'::pg_catalog.oid "
6521 "AND rulename != '_RETURN' "
6528 * We include pg_rules in the cross since it filters out all
6529 * view rules (pjw 15-Sep-2000).
6531 appendPQExpBuffer(query, "SELECT definition,"
6532 " pg_rewrite.oid, pg_rewrite.rulename "
6533 "FROM pg_rewrite, pg_class, pg_rules "
6534 "WHERE pg_class.relname = ");
6535 appendStringLiteral(query, tbinfo->relname, true);
6536 appendPQExpBuffer(query,
6537 " AND pg_rewrite.ev_class = pg_class.oid "
6538 " AND pg_rules.tablename = pg_class.relname "
6539 " AND pg_rules.rulename = pg_rewrite.rulename "
6540 "ORDER BY pg_rewrite.oid");
6543 res = PQexec(g_conn, query->data);
6545 PQresultStatus(res) != PGRES_TUPLES_OK)
6547 write_msg(NULL, "query to get rules associated with table \"%s\" failed: %s",
6548 tbinfo->relname, PQerrorMessage(g_conn));
6552 nrules = PQntuples(res);
6553 i_definition = PQfnumber(res, "definition");
6554 i_oid = PQfnumber(res, "oid");
6555 i_rulename = PQfnumber(res, "rulename");
6561 for (i = 0; i < nrules; i++)
6563 printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, i, i_definition));
6564 ArchiveEntry(fout, PQgetvalue(res, i, i_oid),
6565 PQgetvalue(res, i, i_rulename),
6566 tbinfo->relnamespace->nspname,
6573 /* Dump rule comments */
6575 resetPQExpBuffer(query);
6576 appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename)));
6577 appendPQExpBuffer(query, " ON %s", fmtId(tbinfo->relname));
6578 dumpComment(fout, query->data,
6579 tbinfo->relnamespace->nspname,
6581 PQgetvalue(res, i, i_oid), "pg_rewrite", 0, NULL);
6588 destroyPQExpBuffer(query);
6589 destroyPQExpBuffer(cmd);
6593 * selectSourceSchema - make the specified schema the active search path
6594 * in the source database.
6596 * NB: pg_catalog is explicitly searched after the specified schema;
6597 * so user names are only qualified if they are cross-schema references,
6598 * and system names are only qualified if they conflict with a user name
6599 * in the current schema.
6601 * Whenever the selected schema is not pg_catalog, be careful to qualify
6602 * references to system catalogs and types in our emitted commands!
6605 selectSourceSchema(const char *schemaName)
6607 static char *curSchemaName = NULL;
6611 /* Not relevant if fetching from pre-7.3 DB */
6612 if (g_fout->remoteVersion < 70300)
6614 /* Ignore null schema names */
6615 if (schemaName == NULL || *schemaName == '\0')
6617 /* Optimize away repeated selection of same schema */
6618 if (curSchemaName && strcmp(curSchemaName, schemaName) == 0)
6621 query = createPQExpBuffer();
6622 appendPQExpBuffer(query, "SET search_path = %s",
6624 if (strcmp(schemaName, "pg_catalog") != 0)
6625 appendPQExpBuffer(query, ", pg_catalog");
6626 res = PQexec(g_conn, query->data);
6628 PQresultStatus(res) != PGRES_COMMAND_OK)
6630 write_msg(NULL, "command to set search_path failed: %s",
6631 PQerrorMessage(g_conn));
6635 destroyPQExpBuffer(query);
6638 free(curSchemaName);
6639 curSchemaName = strdup(schemaName);
6643 * getFormattedTypeName - retrieve a nicely-formatted type name for the
6646 * NB: in 7.3 and up the result may depend on the currently-selected
6647 * schema; this is why we don't try to cache the names.
6650 getFormattedTypeName(const char *oid, OidOptions opts)
6657 if (atooid(oid) == 0)
6659 if ((opts & zeroAsOpaque) != 0)
6660 return strdup(g_opaque_type);
6661 else if ((opts & zeroAsAny) != 0)
6662 return strdup("'any'");
6663 else if ((opts & zeroAsStar) != 0)
6665 else if ((opts & zeroAsNone) != 0)
6666 return strdup("NONE");
6669 query = createPQExpBuffer();
6670 if (g_fout->remoteVersion >= 70300)
6672 appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%s'::pg_catalog.oid, NULL)",
6675 else if (g_fout->remoteVersion >= 70100)
6677 appendPQExpBuffer(query, "SELECT format_type('%s'::oid, NULL)",
6682 appendPQExpBuffer(query, "SELECT typname "
6684 "WHERE oid = '%s'::oid",
6688 res = PQexec(g_conn, query->data);
6690 PQresultStatus(res) != PGRES_TUPLES_OK)
6692 write_msg(NULL, "query to obtain name of data type %s failed: %s",
6693 oid, PQerrorMessage(g_conn));
6697 /* Expecting a single result only */
6698 ntups = PQntuples(res);
6701 write_msg(NULL, "query yielded %d rows instead of one: %s\n",
6702 ntups, query->data);
6706 if (g_fout->remoteVersion >= 70100)
6708 /* already quoted */
6709 result = strdup(PQgetvalue(res, 0, 0));
6713 /* may need to quote it */
6714 result = strdup(fmtId(PQgetvalue(res, 0, 0)));
6718 destroyPQExpBuffer(query);
6724 * myFormatType --- local implementation of format_type for use with 7.0.
6727 myFormatType(const char *typname, int32 typmod)
6730 PQExpBuffer buf = createPQExpBuffer();
6732 /* Show lengths on bpchar and varchar */
6733 if (!strcmp(typname, "bpchar"))
6735 int len = (typmod - VARHDRSZ);
6737 appendPQExpBuffer(buf, "character");
6739 appendPQExpBuffer(buf, "(%d)",
6742 else if (!strcmp(typname, "varchar"))
6744 appendPQExpBuffer(buf, "character varying");
6746 appendPQExpBuffer(buf, "(%d)",
6749 else if (!strcmp(typname, "numeric"))
6751 appendPQExpBuffer(buf, "numeric");
6758 tmp_typmod = typmod - VARHDRSZ;
6759 precision = (tmp_typmod >> 16) & 0xffff;
6760 scale = tmp_typmod & 0xffff;
6761 appendPQExpBuffer(buf, "(%d,%d)",
6767 * char is an internal single-byte data type; Let's make sure we force
6768 * it through with quotes. - thomas 1998-12-13
6770 else if (strcmp(typname, "char") == 0)
6771 appendPQExpBuffer(buf, "\"char\"");
6773 appendPQExpBuffer(buf, "%s", fmtId(typname));
6775 result = strdup(buf->data);
6776 destroyPQExpBuffer(buf);
6782 * fmtQualifiedId - convert a qualified name to the proper format for
6783 * the source database.
6785 * Like fmtId, use the result before calling again.
6788 fmtQualifiedId(const char *schema, const char *id)
6790 static PQExpBuffer id_return = NULL;
6792 if (id_return) /* first time through? */
6793 resetPQExpBuffer(id_return);
6795 id_return = createPQExpBuffer();
6797 /* Suppress schema name if fetching from pre-7.3 DB */
6798 if (g_fout->remoteVersion >= 70300 && schema && *schema)
6800 appendPQExpBuffer(id_return, "%s.",
6803 appendPQExpBuffer(id_return, "%s",
6806 return id_return->data;
6810 * Return a column list clause for the given relation.
6812 * Special case: if there are no undropped columns in the relation, return
6813 * "", not an invalid "()" column list.
6816 fmtCopyColumnList(const TableInfo *ti)
6818 static PQExpBuffer q = NULL;
6819 int numatts = ti->numatts;
6820 char **attnames = ti->attnames;
6821 bool *attisdropped = ti->attisdropped;
6825 if (q) /* first time through? */
6826 resetPQExpBuffer(q);
6828 q = createPQExpBuffer();
6830 appendPQExpBuffer(q, "(");
6832 for (i = 0; i < numatts; i++)
6834 if (attisdropped[i])
6837 appendPQExpBuffer(q, ", ");
6838 appendPQExpBuffer(q, "%s", fmtId(attnames[i]));
6843 return ""; /* no undropped columns */
6845 appendPQExpBuffer(q, ")");