1 /*-------------------------------------------------------------------------
4 * pg_dump is a utility for dumping out a postgres database
7 * Portions Copyright (c) 1996-2001, 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
11 * dump out a script that reproduces
12 * the schema of the database in terms of
14 * user-defined functions
21 * the output script is SQL that is understood by PostgreSQL
25 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.257 2002/04/29 17:30:18 tgl Exp $
27 *-------------------------------------------------------------------------
31 * Although this is not a backend module, we must include postgres.h anyway
32 * so that we can include a bunch of backend include files. pg_dump has
33 * never pretended to be very independent of the backend anyhow ...
37 #include <unistd.h> /* for getopt() */
53 #include "access/attnum.h"
54 #include "access/htup.h"
55 #include "catalog/pg_class.h"
56 #include "catalog/pg_proc.h"
57 #include "catalog/pg_trigger.h"
58 #include "catalog/pg_type.h"
61 #include "libpq/libpq-fs.h"
64 #include "pg_backup.h"
65 #include "pg_backup_archiver.h"
67 typedef enum _formatLiteralOptions
70 PASS_LFTAB = 3 /* NOTE: 1 and 2 are reserved in case we
71 * want to make a mask. */
72 /* We could make this a bit mask for control chars, but I don't */
73 /* see any value in making it more complex...the current code */
74 /* only checks for 'opts == CONV_ALL' anyway. */
75 } formatLiteralOptions;
77 static void dumpComment(Archive *fout, const char *target, const char *oid,
78 const char *classname, int subid,
79 const char *((*deps)[]));
80 static void dumpOneDomain(Archive *fout, TypeInfo *tinfo);
81 static void dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly);
82 static void dumpACL(Archive *fout, TableInfo tbinfo);
83 static void dumpTriggers(Archive *fout, const char *tablename,
84 TableInfo *tblinfo, int numTables);
85 static void dumpRules(Archive *fout, const char *tablename,
86 TableInfo *tblinfo, int numTables);
87 static void formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts);
88 static void clearTableInfo(TableInfo *, int);
89 static void dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
90 TypeInfo *tinfo, int numTypes);
91 static Oid findLastBuiltinOid_V71(const char *);
92 static Oid findLastBuiltinOid_V70(void);
93 static void setMaxOid(Archive *fout);
96 static void AddAcl(char *aclbuf, const char *keyword);
97 static char *GetPrivileges(Archive *AH, const char *s);
99 static int dumpBlobs(Archive *AH, char *, void *);
100 static int dumpDatabase(Archive *AH);
101 static PQExpBuffer getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo);
102 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
109 bool g_verbose; /* User wants verbose narration of our
111 Oid g_last_builtin_oid; /* value of the last builtin oid */
112 Archive *g_fout; /* the script file */
113 PGconn *g_conn; /* the database connection */
115 bool force_quotes; /* User wants to suppress double-quotes */
116 bool dumpData; /* dump data using proper insert strings */
117 bool attrNames; /* put attr names into insert strings */
122 char g_opaque_type[10]; /* name for the opaque type */
124 /* placeholders for the delimiters for comments */
125 char g_comment_start[10];
126 char g_comment_end[10];
129 typedef struct _dumpContext
137 help(const char *progname)
139 printf(gettext("%s dumps a database as a text file or to other formats.\n\n"), progname);
140 puts(gettext("Usage:"));
141 printf(gettext(" %s [options] dbname\n\n"), progname);
142 puts(gettext("Options:"));
144 #ifdef HAVE_GETOPT_LONG
146 " -a, --data-only dump only the data, not the schema\n"
147 " -b, --blobs include large objects in dump\n"
148 " -c, --clean clean (drop) schema prior to create\n"
149 " -C, --create include commands to create database in dump\n"
150 " -d, --inserts dump data as INSERT, rather than COPY, commands\n"
151 " -D, --column-inserts dump data as INSERT commands with column names\n"
152 " -f, --file=FILENAME output file name\n"
153 " -F, --format {c|t|p} output file format (custom, tar, plain text)\n"
154 " -h, --host=HOSTNAME database server host name\n"
155 " -i, --ignore-version proceed even when server version mismatches\n"
157 " -n, --no-quotes suppress most quotes around identifiers\n"
158 " -N, --quotes enable most quotes around identifiers\n"
159 " -o, --oids include oids in dump\n"
160 " -O, --no-owner do not output \\connect commands in plain\n"
162 " -p, --port=PORT database server port number\n"
163 " -R, --no-reconnect disable ALL reconnections to the database in\n"
164 " plain text format\n"
165 " -s, --schema-only dump only the schema, no data\n"
166 " -S, --superuser=NAME specify the superuser user name to use in\n"
167 " plain text format\n"
168 " -t, --table=TABLE dump this table only (* for all)\n"
169 " -U, --username=NAME connect as specified database user\n"
170 " -v, --verbose verbose mode\n"
171 " -W, --password force password prompt (should happen automatically)\n"
172 " -x, --no-privileges do not dump privileges (grant/revoke)\n"
173 " -X use-set-session-authorization, --use-set-session-authorization\n"
174 " output SET SESSION AUTHORIZATION commands rather\n"
175 " than \\connect commands\n"
176 " -Z, --compress {0-9} compression level for compressed formats\n"
180 " -a dump only the data, not the schema\n"
181 " -b include large objects in dump\n"
182 " -c clean (drop) schema prior to create\n"
183 " -C include commands to create database in dump\n"
184 " -d dump data as INSERT, rather than COPY, commands\n"
185 " -D dump data as INSERT commands with column names\n"
186 " -f FILENAME output file name\n"
187 " -F {c|t|p} output file format (custom, tar, plain text)\n"
188 " -h HOSTNAME database server host name\n"
189 " -i proceed even when server version mismatches\n"
191 " -n suppress most quotes around identifiers\n"
192 " -N enable most quotes around identifiers\n"
193 " -o include oids in dump\n"
194 " -O do not output \\connect commands in plain\n"
196 " -p PORT database server port number\n"
197 " -R disable ALL reconnections to the database in\n"
198 " plain text format\n"
199 " -s dump only the schema, no data\n"
200 " -S NAME specify the superuser user name to use in\n"
201 " plain text format\n"
202 " -t TABLE dump this table only (* for all)\n"
203 " -U NAME connect as specified database user\n"
205 " -W force password prompt (should happen automatically)\n"
206 " -x do not dump privileges (grant/revoke)\n"
207 " -X use-set-session-authorization\n"
208 " output SET SESSION AUTHORIZATION commands rather\n"
209 " than \\connect commands\n"
210 " -Z {0-9} compression level for compressed formats\n"
213 puts(gettext("If no database name is not supplied, then the PGDATABASE environment\n"
214 "variable value is used.\n\n"
215 "Report bugs to <pgsql-bugs@postgresql.org>."));
224 write_msg(NULL, "*** aborted because of error\n");
229 #define COPYBUFSIZ 8192
232 * Dump a table's contents for loading using the COPY command
233 * - this routine is called by the Archiver when it wants the table
238 dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv)
240 const DumpContext *dctx = (DumpContext *) dctxv;
241 const char *classname = dctx->tblinfo[dctx->tblidx].relname;
242 const bool hasoids = dctx->tblinfo[dctx->tblidx].hasoids;
243 const bool oids = dctx->oids;
249 char copybuf[COPYBUFSIZ];
252 write_msg(NULL, "dumping out the contents of table %s\n", classname);
257 * archprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
258 * fmtId(classname, force_quotes));
260 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
264 sprintf(query, "COPY %s WITH OIDS TO stdout;",
265 fmtId(classname, force_quotes));
270 * archprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname,
273 * - Not used as of V1.3 (needs to be in ArchiveEntry call)
277 sprintf(query, "COPY %s TO stdout;", fmtId(classname, force_quotes));
279 res = PQexec(g_conn, query);
281 PQresultStatus(res) == PGRES_FATAL_ERROR)
283 write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed\n",
285 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
286 write_msg(NULL, "The command was: %s\n", query);
291 if (PQresultStatus(res) != PGRES_COPY_OUT)
293 write_msg(NULL, "SQL command to dump the contents of table \"%s\" executed abnormally.\n",
295 write_msg(NULL, "The server returned status %d when %d was expected.\n",
296 PQresultStatus(res), PGRES_COPY_OUT);
297 write_msg(NULL, "The command was: %s\n", query);
306 ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
308 if (copybuf[0] == '\\' &&
312 copydone = true; /* don't print this... */
316 archputs(copybuf, fout);
323 archputc('\n', fout);
333 * There was considerable discussion in late July, 2000
334 * regarding slowing down pg_dump when backing up large
335 * tables. Users with both slow & fast (muti-processor)
336 * machines experienced performance degradation when doing
339 * Initial attempts based on sleeping for a number of ms for
340 * each ms of work were deemed too complex, then a simple
341 * 'sleep in each loop' implementation was suggested. The
342 * latter failed because the loop was too tight. Finally,
343 * the following was implemented:
345 * If throttle is non-zero, then See how long since the last
346 * sleep. Work out how long to sleep (based on ratio). If
347 * sleep is more than 100ms, then sleep reset timer EndIf
350 * where the throttle value was the number of ms to sleep per
351 * ms of work. The calculation was done in each loop.
353 * Most of the hard work is done in the backend, and this
354 * solution still did not work particularly well: on slow
355 * machines, the ratio was 50:1, and on medium paced
356 * machines, 1:1, and on fast multi-processor machines, it
357 * had little or no effect, for reasons that were unclear.
359 * Further discussion ensued, and the proposal was dropped.
361 * For those people who want this feature, it can be
362 * implemented using gettimeofday in each loop,
363 * calculating the time since last sleep, multiplying that
364 * by the sleep ratio, then if the result is more than a
365 * preset 'minimum sleep time' (say 100ms), call the
366 * 'select' function to sleep for a subsecond period ie.
368 * select(0, NULL, NULL, NULL, &tvi);
370 * This will return after the interval specified in the
371 * structure tvi. Fianally, call gettimeofday again to
372 * save the 'last sleep time'.
375 archprintf(fout, "\\.\n");
377 ret = PQendcopy(g_conn);
380 write_msg(NULL, "SQL command to dump the contents of table \"%s\" failed: PQendcopy() failed.\n", classname);
381 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
382 write_msg(NULL, "The command was: %s\n", query);
392 dumpClasses_dumpData(Archive *fout, char *oid, void *dctxv)
394 const DumpContext *dctx = (DumpContext *) dctxv;
395 const char *classname = dctx->tblinfo[dctx->tblidx].relname;
398 PQExpBuffer q = createPQExpBuffer();
402 if (fout->remoteVersion >= 70100)
403 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM ONLY %s", fmtId(classname, force_quotes));
405 appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR SELECT * FROM %s", fmtId(classname, force_quotes));
407 res = PQexec(g_conn, q->data);
409 PQresultStatus(res) != PGRES_COMMAND_OK)
411 write_msg(NULL, "dumpClasses(): SQL command failed\n");
412 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
413 write_msg(NULL, "The command was: %s\n", q->data);
421 res = PQexec(g_conn, "FETCH 100 FROM _pg_dump_cursor");
423 PQresultStatus(res) != PGRES_TUPLES_OK)
425 write_msg(NULL, "dumpClasses(): SQL command failed\n");
426 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
427 write_msg(NULL, "The command was: FETCH 100 FROM _pg_dump_cursor\n");
431 for (tuple = 0; tuple < PQntuples(res); tuple++)
433 archprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
434 if (attrNames == true)
437 appendPQExpBuffer(q, "(");
438 for (field = 0; field < PQnfields(res); field++)
441 appendPQExpBuffer(q, ",");
442 appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
444 appendPQExpBuffer(q, ") ");
445 archprintf(fout, "%s", q->data);
447 archprintf(fout, "VALUES (");
448 for (field = 0; field < PQnfields(res); field++)
451 archprintf(fout, ",");
452 if (PQgetisnull(res, tuple, field))
454 archprintf(fout, "NULL");
457 switch (PQftype(res, field))
461 case OIDOID: /* int types */
463 case FLOAT8OID: /* float types */
464 /* These types are printed without quotes */
465 archprintf(fout, "%s",
466 PQgetvalue(res, tuple, field));
470 archprintf(fout, "B'%s'",
471 PQgetvalue(res, tuple, field));
476 * All other types are printed as string literals,
477 * with appropriate escaping of special
481 formatStringLiteral(q, PQgetvalue(res, tuple, field), CONV_ALL);
482 archprintf(fout, "%s", q->data);
486 archprintf(fout, ");\n");
489 } while (PQntuples(res) > 0);
492 res = PQexec(g_conn, "CLOSE _pg_dump_cursor");
494 PQresultStatus(res) != PGRES_COMMAND_OK)
496 write_msg(NULL, "dumpClasses(): SQL command failed\n");
497 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
498 write_msg(NULL, "The command was: CLOSE _pg_dump_cursor\n");
503 destroyPQExpBuffer(q);
508 * Convert a string value to an SQL string literal,
509 * with appropriate escaping of special characters.
510 * Quote mark ' goes to '' per SQL standard, other
511 * stuff goes to \ sequences.
512 * The literal is appended to the given PQExpBuffer.
515 formatStringLiteral(PQExpBuffer buf, const char *str, const formatLiteralOptions opts)
517 appendPQExpBufferChar(buf, '\'');
522 if (ch == '\\' || ch == '\'')
524 appendPQExpBufferChar(buf, ch); /* double these */
525 appendPQExpBufferChar(buf, ch);
527 else if ((unsigned char) ch < (unsigned char) ' ' &&
529 || (ch != '\n' && ch != '\t')
533 * generate octal escape for control chars other than
536 appendPQExpBufferChar(buf, '\\');
537 appendPQExpBufferChar(buf, ((ch >> 6) & 3) + '0');
538 appendPQExpBufferChar(buf, ((ch >> 3) & 7) + '0');
539 appendPQExpBufferChar(buf, (ch & 7) + '0');
542 appendPQExpBufferChar(buf, ch);
544 appendPQExpBufferChar(buf, '\'');
549 * dump the contents of all the classes.
552 dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout,
553 const char *onlytable, const bool oids, const bool force_quotes)
556 DataDumperPtr dumpFn;
557 DumpContext *dumpCtx;
563 if (onlytable == NULL || (strlen(onlytable) == 0))
564 write_msg(NULL, "preparing to dump the contents of all %d tables/sequences\n", numTables);
566 write_msg(NULL, "preparing to dump the contents of only one table/sequence\n");
569 for (i = 0; i < numTables; i++)
571 const char *classname = tblinfo[i].relname;
573 /* Skip VIEW relations */
574 if (tblinfo[i].viewdef != NULL)
577 if (tblinfo[i].relkind == RELKIND_SEQUENCE) /* already dumped */
580 if (!onlytable || (strcmp(classname, onlytable) == 0) || (strlen(onlytable) == 0))
583 write_msg(NULL, "preparing to dump the contents of table %s\n", classname);
586 becomeUser(fout, tblinfo[i].usename);
589 dumpCtx = (DumpContext *) malloc(sizeof(DumpContext));
590 dumpCtx->tblinfo = (TableInfo *) tblinfo;
592 dumpCtx->oids = oids;
596 /* Dump/restore using COPY */
597 dumpFn = dumpClasses_nodumpData;
598 sprintf(copyBuf, "COPY %s %sFROM stdin;\n",
599 fmtId(tblinfo[i].relname, force_quotes),
600 (oids && tblinfo[i].hasoids) ? "WITH OIDS " : "");
605 /* Restore using INSERT */
606 dumpFn = dumpClasses_dumpData;
610 ArchiveEntry(fout, tblinfo[i].oid, tblinfo[i].relname,
611 "TABLE DATA", NULL, "", "",
612 copyStmt, tblinfo[i].usename,
621 parse_version(const char *versionString)
628 cnt = sscanf(versionString, "%d.%d.%d", &vmaj, &vmin, &vrev);
632 write_msg(NULL, "unable to parse version string \"%s\"\n", versionString);
639 return (100 * vmaj + vmin) * 100 + vrev;
645 main(int argc, char **argv)
648 const char *filename = NULL;
649 const char *format = "p";
650 const char *dbname = NULL;
651 const char *pghost = NULL;
652 const char *pgport = NULL;
653 const char *username = NULL;
654 char *tablename = NULL;
658 bool force_password = false;
659 int compressLevel = -1;
660 bool ignore_version = false;
663 int outputCreate = 0;
665 int outputNoOwner = 0;
666 int outputNoReconnect = 0;
667 static int use_setsessauth = 0;
668 char *outputSuperuser = NULL;
670 RestoreOptions *ropt;
672 #ifdef HAVE_GETOPT_LONG
673 static struct option long_options[] = {
674 {"data-only", no_argument, NULL, 'a'},
675 {"blobs", no_argument, NULL, 'b'},
676 {"clean", no_argument, NULL, 'c'},
677 {"create", no_argument, NULL, 'C'},
678 {"file", required_argument, NULL, 'f'},
679 {"format", required_argument, NULL, 'F'},
680 {"inserts", no_argument, NULL, 'd'},
681 {"attribute-inserts", no_argument, NULL, 'D'},
682 {"column-inserts", no_argument, NULL, 'D'},
683 {"host", required_argument, NULL, 'h'},
684 {"ignore-version", no_argument, NULL, 'i'},
685 {"no-reconnect", no_argument, NULL, 'R'},
686 {"no-quotes", no_argument, NULL, 'n'},
687 {"quotes", no_argument, NULL, 'N'},
688 {"oids", no_argument, NULL, 'o'},
689 {"no-owner", no_argument, NULL, 'O'},
690 {"port", required_argument, NULL, 'p'},
691 {"schema-only", no_argument, NULL, 's'},
692 {"superuser", required_argument, NULL, 'S'},
693 {"table", required_argument, NULL, 't'},
694 {"password", no_argument, NULL, 'W'},
695 {"username", required_argument, NULL, 'U'},
696 {"verbose", no_argument, NULL, 'v'},
697 {"no-privileges", no_argument, NULL, 'x'},
698 {"no-acl", no_argument, NULL, 'x'},
699 {"compress", required_argument, NULL, 'Z'},
700 {"help", no_argument, NULL, '?'},
701 {"version", no_argument, NULL, 'V'},
704 * the following options don't have an equivalent short option
705 * letter, but are available as '-X long-name'
707 {"use-set-session-authorization", no_argument, &use_setsessauth, 1}
713 setlocale(LC_ALL, "");
714 bindtextdomain("pg_dump", LOCALEDIR);
715 textdomain("pg_dump");
721 strcpy(g_comment_start, "-- ");
722 g_comment_end[0] = '\0';
723 strcpy(g_opaque_type, "opaque");
725 dataOnly = schemaOnly = dumpData = attrNames = false;
727 if (!strrchr(argv[0], '/'))
730 progname = strrchr(argv[0], '/') + 1;
732 /* Set default options based on progname */
733 if (strcmp(progname, "pg_backup") == 0)
741 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
746 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
748 puts("pg_dump (PostgreSQL) " PG_VERSION);
753 #ifdef HAVE_GETOPT_LONG
754 while ((c = getopt_long(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?", long_options, &optindex)) != -1)
756 while ((c = getopt(argc, argv, "abcCdDf:F:h:inNoOp:RsS:t:uU:vWxX:zZ:V?-")) != -1)
762 case 'a': /* Dump data only */
766 case 'b': /* Dump blobs */
770 case 'c': /* clean (i.e., drop) schema prior to
775 case 'C': /* Create DB */
780 case 'd': /* dump data as proper insert strings */
784 case 'D': /* dump data as proper insert strings with
798 case 'h': /* server host */
802 case 'i': /* ignore database version mismatch */
803 ignore_version = true;
806 case 'n': /* Do not force double-quotes on
808 force_quotes = false;
811 case 'N': /* Force double-quotes on identifiers */
815 case 'o': /* Dump oids */
820 case 'O': /* Don't reconnect to match owner */
824 case 'p': /* server port */
828 case 'R': /* No reconnect */
829 outputNoReconnect = 1;
832 case 's': /* dump schema only */
836 case 'S': /* Username for superuser in plain text
838 outputSuperuser = strdup(optarg);
841 case 't': /* Dump data for this table only */
845 tablename = strdup(optarg);
848 * quoted string? Then strip quotes and preserve
851 if (tablename[0] == '"')
853 strcpy(tablename, &tablename[1]);
854 if (*(tablename + strlen(tablename) - 1) == '"')
855 *(tablename + strlen(tablename) - 1) = '\0';
857 /* otherwise, convert table name to lowercase... */
860 for (i = 0; tablename[i]; i++)
861 if (isupper((unsigned char) tablename[i]))
862 tablename[i] = tolower((unsigned char) tablename[i]);
865 * '*' is a special case meaning ALL tables, but
868 if (strcmp(tablename, "*") == 0)
876 force_password = true;
877 username = simple_prompt("User name: ", 100, true);
884 case 'v': /* verbose */
889 force_password = true;
892 case 'x': /* skip ACL dump */
897 * Option letters were getting scarce, so I invented this
898 * new scheme: '-X feature' turns on some feature. Compare
899 * to the -f option in GCC. You should also add an
900 * equivalent GNU-style option --feature. Features that
901 * require arguments should use '-X feature=foo'.
904 if (strcmp(optarg, "use-set-session-authorization") == 0)
909 gettext("%s: invalid -X option -- %s\n"),
911 fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
915 case 'Z': /* Compression Level */
916 compressLevel = atoi(optarg);
919 #ifndef HAVE_GETOPT_LONG
922 gettext("%s was compiled without support for long options.\n"
923 "Use --help for help on invocation options.\n"),
928 /* This covers the long options equivalent to -X xxx. */
933 fprintf(stderr, gettext("Try '%s --help' for more information.\n"), progname);
938 if (optind < (argc - 1))
941 gettext("%s: too many command line options (first is '%s')\n"
942 "Try '%s --help' for more information.\n"),
943 progname, argv[optind + 1], progname);
947 /* Get the target database name */
949 dbname = argv[optind];
951 dbname = getenv("PGDATABASE");
954 write_msg(NULL, "no database name specified\n");
958 if (dataOnly && schemaOnly)
960 write_msg(NULL, "The options \"schema only\" (-s) and \"data only\" (-a) cannot be used together.\n");
964 if (outputBlobs && tablename != NULL && strlen(tablename) > 0)
966 write_msg(NULL, "Large object output is not supported for a single table.\n");
967 write_msg(NULL, "Use all tables or a full dump instead.\n");
971 if (dumpData == true && oids == true)
973 write_msg(NULL, "INSERT (-d, -D) and OID (-o) options cannot be used together.\n");
974 write_msg(NULL, "(The INSERT command cannot set oids.)\n");
978 if (outputBlobs == true && (format[0] == 'p' || format[0] == 'P'))
980 write_msg(NULL, "large object output is not supported for plain text dump files.\n");
981 write_msg(NULL, "(Use a different output format.)\n");
985 /* open the output file */
991 g_fout = CreateArchive(filename, archCustom, compressLevel);
996 g_fout = CreateArchive(filename, archFiles, compressLevel);
1002 g_fout = CreateArchive(filename, archNull, 0);
1007 g_fout = CreateArchive(filename, archTar, compressLevel);
1011 write_msg(NULL, "invalid output format '%s' specified\n", format);
1017 write_msg(NULL, "could not open output file %s for writing\n", filename);
1021 /* Let the archiver know how noisy to be */
1022 g_fout->verbose = g_verbose;
1025 * Open the database using the Archiver, so it knows about it. Errors
1028 g_fout->minRemoteVersion = 70000; /* we can handle back to 7.0 */
1029 g_fout->maxRemoteVersion = parse_version(PG_VERSION);
1030 g_conn = ConnectDatabase(g_fout, dbname, pghost, pgport, username, force_password, ignore_version);
1033 * Start serializable transaction to dump consistent data
1038 res = PQexec(g_conn, "begin");
1039 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1040 exit_horribly(g_fout, NULL, "BEGIN command failed: %s",
1041 PQerrorMessage(g_conn));
1044 res = PQexec(g_conn, "set transaction isolation level serializable");
1045 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1046 exit_horribly(g_fout, NULL, "could not set transaction isolation level to serializable: %s",
1047 PQerrorMessage(g_conn));
1052 if (g_fout->remoteVersion >= 70100)
1053 g_last_builtin_oid = findLastBuiltinOid_V71(dbname);
1055 g_last_builtin_oid = findLastBuiltinOid_V70();
1057 /* Dump the database definition */
1059 dumpDatabase(g_fout);
1065 write_msg(NULL, "last built-in oid is %u\n", g_last_builtin_oid);
1066 tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip, oids, schemaOnly, dataOnly);
1069 dumpClasses(tblinfo, numTables, g_fout, tablename, oids, force_quotes);
1072 ArchiveEntry(g_fout, "0", "BLOBS", "BLOBS", NULL, "", "", "", "", dumpBlobs, 0);
1074 if (!dataOnly) /* dump indexes and triggers at the end
1075 * for performance */
1077 dumpTriggers(g_fout, tablename, tblinfo, numTables);
1078 dumpRules(g_fout, tablename, tblinfo, numTables);
1081 /* Now sort the output nicely */
1082 SortTocByOID(g_fout);
1083 MoveToStart(g_fout, "DATABASE");
1084 MoveToEnd(g_fout, "TABLE DATA");
1085 MoveToEnd(g_fout, "BLOBS");
1086 MoveToEnd(g_fout, "INDEX");
1087 MoveToEnd(g_fout, "CONSTRAINT");
1088 MoveToEnd(g_fout, "TRIGGER");
1089 MoveToEnd(g_fout, "RULE");
1090 MoveToEnd(g_fout, "SEQUENCE SET");
1093 * Moving all comments to end is annoying, but must do it for comments
1094 * on stuff we just moved, and we don't seem to have quite enough
1095 * dependency structure to get it really right...
1097 MoveToEnd(g_fout, "COMMENT");
1101 ropt = NewRestoreOptions();
1102 ropt->filename = (char *) filename;
1103 ropt->dropSchema = outputClean;
1104 ropt->aclsSkip = aclsSkip;
1105 ropt->superuser = outputSuperuser;
1106 ropt->create = outputCreate;
1107 ropt->noOwner = outputNoOwner;
1108 ropt->noReconnect = outputNoReconnect;
1109 ropt->use_setsessauth = use_setsessauth;
1111 if (outputSuperuser)
1112 ropt->superuser = outputSuperuser;
1114 ropt->superuser = PQuser(g_conn);
1116 if (compressLevel == -1)
1117 ropt->compression = 0;
1119 ropt->compression = compressLevel;
1121 ropt->suppressDumpWarnings = true; /* We've already shown
1124 RestoreArchive(g_fout, ropt);
1127 CloseArchive(g_fout);
1129 clearTableInfo(tblinfo, numTables);
1136 * dump the database definition
1140 dumpDatabase(Archive *AH)
1142 PQExpBuffer dbQry = createPQExpBuffer();
1143 PQExpBuffer delQry = createPQExpBuffer();
1144 PQExpBuffer creaQry = createPQExpBuffer();
1150 const char *datname,
1155 datname = PQdb(g_conn);
1158 write_msg(NULL, "saving database definition\n");
1160 /* Get the database owner and parameters from pg_database */
1161 appendPQExpBuffer(dbQry, "select (select usename from pg_user where usesysid = datdba) as dba,"
1162 " encoding, datpath from pg_database"
1163 " where datname = ");
1164 formatStringLiteral(dbQry, datname, CONV_ALL);
1166 res = PQexec(g_conn, dbQry->data);
1168 PQresultStatus(res) != PGRES_TUPLES_OK)
1170 write_msg(NULL, "SQL command failed\n");
1171 write_msg(NULL, "Error message from server: %s", PQerrorMessage(g_conn));
1172 write_msg(NULL, "The command was: %s\n", dbQry->data);
1176 ntups = PQntuples(res);
1180 write_msg(NULL, "missing pg_database entry for database \"%s\"\n",
1187 write_msg(NULL, "query returned more than one (%d) pg_database entry for database \"%s\"\n",
1192 i_dba = PQfnumber(res, "dba");
1193 i_encoding = PQfnumber(res, "encoding");
1194 i_datpath = PQfnumber(res, "datpath");
1195 dba = PQgetvalue(res, 0, i_dba);
1196 encoding = PQgetvalue(res, 0, i_encoding);
1197 datpath = PQgetvalue(res, 0, i_datpath);
1199 appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
1200 fmtId(datname, force_quotes));
1201 if (strlen(encoding) > 0)
1202 appendPQExpBuffer(creaQry, " ENCODING = %s", encoding);
1203 if (strlen(datpath) > 0)
1204 appendPQExpBuffer(creaQry, " LOCATION = '%s'", datpath);
1205 appendPQExpBuffer(creaQry, ";\n");
1207 appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
1208 fmtId(datname, force_quotes));
1210 ArchiveEntry(AH, "0" /* OID */ , datname /* Name */ , "DATABASE", NULL,
1211 creaQry->data /* Create */ , delQry->data /* Del */ ,
1212 "" /* Copy */ , dba /* Owner */ ,
1213 NULL /* Dumper */ , 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 /* Cursor to get all BLOB tables */
1250 if (AH->remoteVersion >= 70100)
1251 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT DISTINCT loid FROM pg_largeobject");
1253 appendPQExpBuffer(oidQry, "Declare blobOid Cursor for SELECT oid from pg_class where relkind = 'l'");
1255 res = PQexec(g_conn, oidQry->data);
1256 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
1258 write_msg(NULL, "dumpBlobs(): cursor declaration failed: %s", PQerrorMessage(g_conn));
1262 /* Fetch for cursor */
1263 appendPQExpBuffer(oidFetchQry, "Fetch %d in blobOid", loFetchSize);
1269 res = PQexec(g_conn, oidFetchQry->data);
1271 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
1273 write_msg(NULL, "dumpBlobs(): fetch from cursor failed: %s",
1274 PQerrorMessage(g_conn));
1278 /* Process the tuples, if any */
1279 for (i = 0; i < PQntuples(res); i++)
1281 blobOid = atooid(PQgetvalue(res, i, 0));
1283 loFd = lo_open(g_conn, blobOid, INV_READ);
1286 write_msg(NULL, "dumpBlobs(): could not open large object: %s",
1287 PQerrorMessage(g_conn));
1291 StartBlob(AH, blobOid);
1293 /* Now read it in chunks, sending data to archive */
1296 cnt = lo_read(g_conn, loFd, buf, loBufSize);
1299 write_msg(NULL, "dumpBlobs(): error reading large object: %s",
1300 PQerrorMessage(g_conn));
1304 WriteData(AH, buf, cnt);
1308 lo_close(g_conn, loFd);
1310 EndBlob(AH, blobOid);
1313 } while (PQntuples(res) > 0);
1315 destroyPQExpBuffer(oidQry);
1316 destroyPQExpBuffer(oidFetchQry);
1323 * read all base types in the system catalogs and return them in the
1324 * TypeInfo* structure
1326 * numTypes is set to the number of types read in
1330 getTypes(int *numTypes)
1335 PQExpBuffer query = createPQExpBuffer();
1359 /* find all base types */
1362 * we include even the built-in types because those may be used as
1363 * array elements by user-defined types
1365 * we filter out the built-in types when we dump out the types
1368 if (g_fout->remoteVersion < 70100)
1370 appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1371 "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
1372 "typdefault, typrelid, typalign, 'p'::char as typstorage, typbyval, typisdefined, "
1373 "(select usename from pg_user where typowner = usesysid) as usename, "
1374 "typname as typedefn, typtype "
1379 appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
1380 "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
1381 "typdefault, typrelid, typalign, typstorage, typbyval, typisdefined, "
1382 "(select usename from pg_user where typowner = usesysid) as usename, "
1383 "format_type(pg_type.oid, NULL) as typedefn, typtype "
1387 res = PQexec(g_conn, query->data);
1389 PQresultStatus(res) != PGRES_TUPLES_OK)
1391 write_msg(NULL, "query to obtain list of data types failed: %s", PQerrorMessage(g_conn));
1395 ntups = PQntuples(res);
1397 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
1399 i_oid = PQfnumber(res, "oid");
1400 i_typowner = PQfnumber(res, "typowner");
1401 i_typname = PQfnumber(res, "typname");
1402 i_typlen = PQfnumber(res, "typlen");
1403 i_typprtlen = PQfnumber(res, "typprtlen");
1404 i_typinput = PQfnumber(res, "typinput");
1405 i_typoutput = PQfnumber(res, "typoutput");
1406 i_typreceive = PQfnumber(res, "typreceive");
1407 i_typsend = PQfnumber(res, "typsend");
1408 i_typelem = PQfnumber(res, "typelem");
1409 i_typdelim = PQfnumber(res, "typdelim");
1410 i_typdefault = PQfnumber(res, "typdefault");
1411 i_typrelid = PQfnumber(res, "typrelid");
1412 i_typalign = PQfnumber(res, "typalign");
1413 i_typstorage = PQfnumber(res, "typstorage");
1414 i_typbyval = PQfnumber(res, "typbyval");
1415 i_typisdefined = PQfnumber(res, "typisdefined");
1416 i_usename = PQfnumber(res, "usename");
1417 i_typedefn = PQfnumber(res, "typedefn");
1418 i_typtype = PQfnumber(res, "typtype");
1420 for (i = 0; i < ntups; i++)
1422 tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1423 tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
1424 tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
1425 tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
1426 tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
1427 tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
1428 tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
1429 tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
1430 tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
1431 tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
1432 tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
1433 if (PQgetisnull(res, i, i_typdefault))
1434 tinfo[i].typdefault = NULL;
1436 tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
1437 tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
1438 tinfo[i].typalign = strdup(PQgetvalue(res, i, i_typalign));
1439 tinfo[i].typstorage = strdup(PQgetvalue(res, i, i_typstorage));
1440 tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1441 tinfo[i].typedefn = strdup(PQgetvalue(res, i, i_typedefn));
1442 tinfo[i].typtype = strdup(PQgetvalue(res, i, i_typtype));
1444 if (strlen(tinfo[i].usename) == 0)
1445 write_msg(NULL, "WARNING: owner of data type %s appears to be invalid\n",
1448 if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
1449 tinfo[i].passedbyvalue = 0;
1451 tinfo[i].passedbyvalue = 1;
1454 * check for user-defined array types, omit system generated ones
1456 if ((strcmp(tinfo[i].typelem, "0") != 0) &&
1457 tinfo[i].typname[0] != '_')
1458 tinfo[i].isArray = 1;
1460 tinfo[i].isArray = 0;
1462 if (strcmp(PQgetvalue(res, i, i_typisdefined), "f") == 0)
1463 tinfo[i].isDefined = 0;
1465 tinfo[i].isDefined = 1;
1472 destroyPQExpBuffer(query);
1479 * read all operators in the system catalogs and return them in the
1480 * OprInfo* structure
1482 * numOprs is set to the number of operators read in
1485 getOperators(int *numOprs)
1490 PQExpBuffer query = createPQExpBuffer();
1510 * find all operators, including builtin operators, filter out
1511 * system-defined operators at dump-out time
1514 appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
1515 "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
1516 "oprcanhash, oprlsortop, oprrsortop, "
1517 "(select usename from pg_user where oprowner = usesysid) as usename "
1518 "from pg_operator");
1520 res = PQexec(g_conn, query->data);
1522 PQresultStatus(res) != PGRES_TUPLES_OK)
1524 write_msg(NULL, "query to obtain list of operators failed: %s", PQerrorMessage(g_conn));
1528 ntups = PQntuples(res);
1531 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
1533 i_oid = PQfnumber(res, "oid");
1534 i_oprname = PQfnumber(res, "oprname");
1535 i_oprkind = PQfnumber(res, "oprkind");
1536 i_oprcode = PQfnumber(res, "oprcode");
1537 i_oprleft = PQfnumber(res, "oprleft");
1538 i_oprright = PQfnumber(res, "oprright");
1539 i_oprcom = PQfnumber(res, "oprcom");
1540 i_oprnegate = PQfnumber(res, "oprnegate");
1541 i_oprrest = PQfnumber(res, "oprrest");
1542 i_oprjoin = PQfnumber(res, "oprjoin");
1543 i_oprcanhash = PQfnumber(res, "oprcanhash");
1544 i_oprlsortop = PQfnumber(res, "oprlsortop");
1545 i_oprrsortop = PQfnumber(res, "oprrsortop");
1546 i_usename = PQfnumber(res, "usename");
1548 for (i = 0; i < ntups; i++)
1550 oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1551 oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
1552 oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
1553 oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
1554 oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
1555 oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
1556 oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
1557 oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
1558 oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
1559 oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
1560 oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
1561 oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
1562 oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
1563 oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1565 if (strlen(oprinfo[i].usename) == 0)
1566 write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
1567 oprinfo[i].oprname);
1573 destroyPQExpBuffer(query);
1579 clearTypeInfo(TypeInfo *tp, int numTypes)
1583 for (i = 0; i < numTypes; ++i)
1588 free(tp[i].typowner);
1590 free(tp[i].typname);
1593 if (tp[i].typprtlen)
1594 free(tp[i].typprtlen);
1596 free(tp[i].typinput);
1597 if (tp[i].typoutput)
1598 free(tp[i].typoutput);
1599 if (tp[i].typreceive)
1600 free(tp[i].typreceive);
1602 free(tp[i].typsend);
1604 free(tp[i].typelem);
1606 free(tp[i].typdelim);
1607 if (tp[i].typdefault)
1608 free(tp[i].typdefault);
1610 free(tp[i].typrelid);
1612 free(tp[i].typalign);
1613 if (tp[i].typstorage)
1614 free(tp[i].typstorage);
1616 free(tp[i].usename);
1618 free(tp[i].typedefn);
1624 clearFuncInfo(FuncInfo *fun, int numFuncs)
1631 for (i = 0; i < numFuncs; ++i)
1636 free(fun[i].proname);
1638 free(fun[i].usename);
1639 if (fun[i].argtypes)
1641 for (a = 0; a < fun[i].nargs; ++a)
1642 if (fun[i].argtypes[a])
1643 free(fun[i].argtypes[a]);
1644 free(fun[i].argtypes);
1646 if (fun[i].prorettype)
1647 free(fun[i].prorettype);
1649 free(fun[i].prosrc);
1651 free(fun[i].probin);
1657 clearTableInfo(TableInfo *tblinfo, int numTables)
1662 for (i = 0; i < numTables; ++i)
1666 free(tblinfo[i].oid);
1667 if (tblinfo[i].relacl)
1668 free(tblinfo[i].relacl);
1669 if (tblinfo[i].usename)
1670 free(tblinfo[i].usename);
1672 if (tblinfo[i].relname)
1673 free(tblinfo[i].relname);
1675 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
1678 /* Process Attributes */
1679 for (j = 0; j < tblinfo[i].numatts; j++)
1681 if (tblinfo[i].attnames[j])
1682 free(tblinfo[i].attnames[j]);
1683 if (tblinfo[i].typnames[j])
1684 free(tblinfo[i].typnames[j]);
1687 if (tblinfo[i].triggers)
1689 for (j = 0; j < tblinfo[i].ntrig; j++)
1691 if (tblinfo[i].triggers[j].tgsrc)
1692 free(tblinfo[i].triggers[j].tgsrc);
1693 if (tblinfo[i].triggers[j].oid)
1694 free(tblinfo[i].triggers[j].oid);
1695 if (tblinfo[i].triggers[j].tgname)
1696 free(tblinfo[i].triggers[j].tgname);
1697 if (tblinfo[i].triggers[j].tgdel)
1698 free(tblinfo[i].triggers[j].tgdel);
1700 free(tblinfo[i].triggers);
1703 if (tblinfo[i].atttypmod)
1704 free((int *) tblinfo[i].atttypmod);
1705 if (tblinfo[i].inhAttrs)
1706 free((int *) tblinfo[i].inhAttrs);
1707 if (tblinfo[i].inhAttrDef)
1708 free((int *) tblinfo[i].inhAttrDef);
1709 if (tblinfo[i].inhNotNull)
1710 free((int *) tblinfo[i].inhNotNull);
1711 if (tblinfo[i].attnames)
1712 free(tblinfo[i].attnames);
1713 if (tblinfo[i].atttypedefns)
1714 free(tblinfo[i].atttypedefns);
1715 if (tblinfo[i].typnames)
1716 free(tblinfo[i].typnames);
1717 if (tblinfo[i].notnull)
1718 free(tblinfo[i].notnull);
1719 if (tblinfo[i].primary_key_name)
1720 free(tblinfo[i].primary_key_name);
1726 clearInhInfo(InhInfo *inh, int numInherits)
1732 for (i = 0; i < numInherits; ++i)
1734 if (inh[i].inhrelid)
1735 free(inh[i].inhrelid);
1736 if (inh[i].inhparent)
1737 free(inh[i].inhparent);
1743 clearOprInfo(OprInfo *opr, int numOprs)
1749 for (i = 0; i < numOprs; ++i)
1754 free(opr[i].oprname);
1756 free(opr[i].oprkind);
1758 free(opr[i].oprcode);
1760 free(opr[i].oprleft);
1761 if (opr[i].oprright)
1762 free(opr[i].oprright);
1764 free(opr[i].oprcom);
1765 if (opr[i].oprnegate)
1766 free(opr[i].oprnegate);
1768 free(opr[i].oprrest);
1770 free(opr[i].oprjoin);
1771 if (opr[i].oprcanhash)
1772 free(opr[i].oprcanhash);
1773 if (opr[i].oprlsortop)
1774 free(opr[i].oprlsortop);
1775 if (opr[i].oprrsortop)
1776 free(opr[i].oprrsortop);
1778 free(opr[i].usename);
1784 clearIndInfo(IndInfo *ind, int numIndexes)
1791 for (i = 0; i < numIndexes; ++i)
1793 if (ind[i].indexreloid)
1794 free(ind[i].indexreloid);
1795 if (ind[i].indreloid)
1796 free(ind[i].indreloid);
1797 if (ind[i].indexrelname)
1798 free(ind[i].indexrelname);
1799 if (ind[i].indrelname)
1800 free(ind[i].indrelname);
1801 if (ind[i].indexdef)
1802 free(ind[i].indexdef);
1803 if (ind[i].indisprimary)
1804 free(ind[i].indisprimary);
1807 for (a = 0; a < ind[i].indnkeys; ++a)
1808 if (ind[i].indkey[a])
1809 free(ind[i].indkey[a]);
1810 free(ind[i].indkey);
1817 clearAggInfo(AggInfo *agginfo, int numArgs)
1823 for (i = 0; i < numArgs; ++i)
1826 free(agginfo[i].oid);
1827 if (agginfo[i].aggname)
1828 free(agginfo[i].aggname);
1829 if (agginfo[i].aggtransfn)
1830 free(agginfo[i].aggtransfn);
1831 if (agginfo[i].aggfinalfn)
1832 free(agginfo[i].aggfinalfn);
1833 if (agginfo[i].aggtranstype)
1834 free(agginfo[i].aggtranstype);
1835 if (agginfo[i].aggbasetype)
1836 free(agginfo[i].aggbasetype);
1837 if (agginfo[i].agginitval)
1838 free(agginfo[i].agginitval);
1839 if (agginfo[i].usename)
1840 free(agginfo[i].usename);
1847 * read all the user-defined aggregates in the system catalogs and
1848 * return them in the AggInfo* structure
1850 * numAggs is set to the number of aggregates read in
1853 getAggregates(int *numAggs)
1858 PQExpBuffer query = createPQExpBuffer();
1871 /* find all user-defined aggregates */
1873 if (g_fout->remoteVersion < 70100)
1875 appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn1 as aggtransfn, "
1876 "aggfinalfn, aggtranstype1 as aggtranstype, aggbasetype, "
1877 "agginitval1 as agginitval, "
1878 "(aggtransfn2 = 0 and aggtranstype2 = 0 and agginitval2 is null) as convertok, "
1879 "(select usename from pg_user where aggowner = usesysid) as usename "
1880 "from pg_aggregate");
1882 else if (g_fout->remoteVersion < 70300)
1884 appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn, "
1885 "aggfinalfn, aggtranstype, aggbasetype, "
1887 "'t'::boolean as convertok, "
1888 "(select usename from pg_user where aggowner = usesysid) as usename "
1889 "from pg_aggregate");
1893 appendPQExpBuffer(query, "SELECT p.oid, proname as aggname, aggtransfn, "
1894 "aggfinalfn, aggtranstype, proargtypes[0] as aggbasetype, "
1896 "'t'::boolean as convertok, "
1897 "(select usename from pg_user where proowner = usesysid) as usename "
1898 "from pg_aggregate a, pg_proc p "
1899 "where a.aggfnoid = p.oid");
1902 res = PQexec(g_conn, query->data);
1904 PQresultStatus(res) != PGRES_TUPLES_OK)
1906 write_msg(NULL, "query to obtain list of aggregate functions failed: %s",
1907 PQerrorMessage(g_conn));
1911 ntups = PQntuples(res);
1914 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
1916 i_oid = PQfnumber(res, "oid");
1917 i_aggname = PQfnumber(res, "aggname");
1918 i_aggtransfn = PQfnumber(res, "aggtransfn");
1919 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1920 i_aggtranstype = PQfnumber(res, "aggtranstype");
1921 i_aggbasetype = PQfnumber(res, "aggbasetype");
1922 i_agginitval = PQfnumber(res, "agginitval");
1923 i_usename = PQfnumber(res, "usename");
1924 i_convertok = PQfnumber(res, "convertok");
1926 for (i = 0; i < ntups; i++)
1928 agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1929 agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1930 agginfo[i].aggtransfn = strdup(PQgetvalue(res, i, i_aggtransfn));
1931 agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1932 agginfo[i].aggtranstype = strdup(PQgetvalue(res, i, i_aggtranstype));
1933 agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1934 agginfo[i].agginitval = strdup(PQgetvalue(res, i, i_agginitval));
1935 agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1936 if (strlen(agginfo[i].usename) == 0)
1937 write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
1938 agginfo[i].aggname);
1940 agginfo[i].convertok = (PQgetvalue(res, i, i_convertok)[0] == 't');
1946 destroyPQExpBuffer(query);
1953 * read all the user-defined functions in the system catalogs and
1954 * return them in the FuncInfo* structure
1956 * numFuncs is set to the number of functions read in
1961 getFuncs(int *numFuncs)
1966 PQExpBuffer query = createPQExpBuffer();
1983 /* find all user-defined funcs */
1985 if (g_fout->remoteVersion < 70100)
1987 appendPQExpBuffer(query,
1988 "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1989 "proretset, proargtypes, prosrc, probin, "
1990 "(select usename from pg_user where proowner = usesysid) as usename, "
1991 "case when proiscachable then 'i' else 'v' end as provolatile, "
1992 "'f'::boolean as proimplicit, "
1993 "'f'::boolean as proisstrict "
1995 "where pg_proc.oid > '%u'::oid",
1996 g_last_builtin_oid);
1998 else if (g_fout->remoteVersion < 70300)
2000 appendPQExpBuffer(query,
2001 "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
2002 "proretset, proargtypes, prosrc, probin, "
2003 "(select usename from pg_user where proowner = usesysid) as usename, "
2004 "case when proiscachable then 'i' else 'v' end as provolatile, "
2005 "'f'::boolean as proimplicit, "
2008 "where pg_proc.oid > '%u'::oid",
2009 g_last_builtin_oid);
2013 appendPQExpBuffer(query,
2014 "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
2015 "proretset, proargtypes, prosrc, probin, "
2016 "(select usename from pg_user where proowner = usesysid) as usename, "
2017 "provolatile, proimplicit, proisstrict "
2019 "where pg_proc.oid > '%u'::oid and not proisagg",
2020 g_last_builtin_oid);
2023 res = PQexec(g_conn, query->data);
2025 PQresultStatus(res) != PGRES_TUPLES_OK)
2027 write_msg(NULL, "query to obtain list of functions failed: %s",
2028 PQerrorMessage(g_conn));
2032 ntups = PQntuples(res);
2036 finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
2038 memset((char *) finfo, 0, ntups * sizeof(FuncInfo));
2040 i_oid = PQfnumber(res, "oid");
2041 i_proname = PQfnumber(res, "proname");
2042 i_prolang = PQfnumber(res, "prolang");
2043 i_pronargs = PQfnumber(res, "pronargs");
2044 i_proargtypes = PQfnumber(res, "proargtypes");
2045 i_prorettype = PQfnumber(res, "prorettype");
2046 i_proretset = PQfnumber(res, "proretset");
2047 i_prosrc = PQfnumber(res, "prosrc");
2048 i_probin = PQfnumber(res, "probin");
2049 i_provolatile = PQfnumber(res, "provolatile");
2050 i_isimplicit = PQfnumber(res, "proimplicit");
2051 i_isstrict = PQfnumber(res, "proisstrict");
2052 i_usename = PQfnumber(res, "usename");
2054 for (i = 0; i < ntups; i++)
2056 finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
2057 finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
2059 finfo[i].prosrc = strdup(PQgetvalue(res, i, i_prosrc));
2060 finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
2062 finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
2063 finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
2064 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
2065 finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
2066 finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2067 finfo[i].provolatile = (PQgetvalue(res, i, i_provolatile))[0];
2068 finfo[i].isimplicit = (strcmp(PQgetvalue(res, i, i_isimplicit), "t") == 0);
2069 finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
2071 if (strlen(finfo[i].usename) == 0)
2072 write_msg(NULL, "WARNING: owner of function \"%s\" appears to be invalid\n",
2075 finfo[i].argtypes = malloc(finfo[i].nargs * sizeof(finfo[i].argtypes[0]));
2076 parseNumericArray(PQgetvalue(res, i, i_proargtypes),
2079 finfo[i].dumped = 0;
2084 destroyPQExpBuffer(query);
2091 * read all the user-defined tables (no indexes, no catalogs)
2092 * in the system catalogs return them in the TableInfo* structure
2094 * numTables is set to the number of tables read in
2097 getTables(int *numTables, FuncInfo *finfo, int numFuncs, const char *tablename)
2102 PQExpBuffer query = createPQExpBuffer();
2103 PQExpBuffer delqry = createPQExpBuffer();
2104 PQExpBuffer lockquery = createPQExpBuffer();
2118 * find all the user-defined tables (no indexes and no catalogs),
2119 * ordering by oid is important so that we always process the parent
2120 * tables before the child tables when traversing the tblinfo*
2122 * we ignore tables that are not type 'r' (ordinary relation) or 'S'
2123 * (sequence) or 'v' (view).
2126 if (g_fout->remoteVersion >= 70200)
2128 appendPQExpBuffer(query,
2129 "SELECT pg_class.oid, relname, relacl, relkind, "
2130 "(select usename from pg_user where relowner = usesysid) as usename, "
2131 "relchecks, reltriggers, relhasindex, relhasoids "
2133 "where relname !~ '^pg_' "
2134 "and relkind in ('%c', '%c', '%c') "
2136 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2138 else if (g_fout->remoteVersion >= 70100)
2140 /* all tables have oids in 7.1 */
2141 appendPQExpBuffer(query,
2142 "SELECT pg_class.oid, relname, relacl, relkind, "
2143 "(select usename from pg_user where relowner = usesysid) as usename, "
2144 "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
2146 "where relname !~ '^pg_' "
2147 "and relkind in ('%c', '%c', '%c') "
2149 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2154 * Before 7.1, view relkind was not set to 'v', so we must check
2155 * if we have a view by looking for a rule in pg_rewrite.
2157 appendPQExpBuffer(query,
2158 "SELECT c.oid, relname, relacl, "
2159 "CASE WHEN relhasrules and relkind = 'r' "
2160 " and EXISTS(SELECT rulename FROM pg_rewrite r WHERE "
2161 " r.ev_class = c.oid AND r.ev_type = '1') "
2162 "THEN '%c'::\"char\" "
2163 "ELSE relkind END AS relkind,"
2164 "(select usename from pg_user where relowner = usesysid) as usename, "
2165 "relchecks, reltriggers, relhasindex, 't'::bool as relhasoids "
2167 "where relname !~ '^pg_' "
2168 "and relkind in ('%c', '%c', '%c') "
2171 RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
2174 res = PQexec(g_conn, query->data);
2176 PQresultStatus(res) != PGRES_TUPLES_OK)
2178 write_msg(NULL, "query to obtain list of tables failed: %s",
2179 PQerrorMessage(g_conn));
2183 ntups = PQntuples(res);
2188 * First pass: extract data from result and lock tables. We do the
2189 * locking before anything else, to minimize the window wherein a
2190 * table could disappear under us.
2192 * Note that we have to collect info about all tables here, even when
2193 * dumping only one, because we don't know which tables might be
2194 * inheritance ancestors of the target table. Possible future
2195 * improvement: suppress later collection of schema info about tables
2196 * that are determined not to be either targets or ancestors of
2199 tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
2201 i_reloid = PQfnumber(res, "oid");
2202 i_relname = PQfnumber(res, "relname");
2203 i_relacl = PQfnumber(res, "relacl");
2204 i_relkind = PQfnumber(res, "relkind");
2205 i_usename = PQfnumber(res, "usename");
2206 i_relchecks = PQfnumber(res, "relchecks");
2207 i_reltriggers = PQfnumber(res, "reltriggers");
2208 i_relhasindex = PQfnumber(res, "relhasindex");
2209 i_relhasoids = PQfnumber(res, "relhasoids");
2211 for (i = 0; i < ntups; i++)
2213 tblinfo[i].oid = strdup(PQgetvalue(res, i, i_reloid));
2214 tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
2215 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
2216 tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
2217 tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
2218 tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
2219 tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
2220 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
2221 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
2224 * Read-lock target tables to make sure they aren't DROPPED or
2225 * altered in schema before we get around to dumping them.
2227 * If no target tablename was specified, lock all tables we see,
2228 * otherwise lock only the specified table. (This is incomplete
2229 * because we'll still try to collect schema info about all
2230 * tables, and could possibly lose during that phase. But for the
2231 * typical use where we're dumping all tables anyway, it matters
2234 * NOTE: it'd be kinda nice to lock views and sequences too, not only
2235 * plain tables, but the backend doesn't presently allow that.
2237 if ((tblinfo[i].relkind == RELKIND_RELATION) &&
2238 (tablename == NULL || strcmp(tblinfo[i].relname, tablename) == 0))
2242 resetPQExpBuffer(lockquery);
2243 appendPQExpBuffer(lockquery,
2244 "LOCK TABLE %s IN ACCESS SHARE MODE",
2245 fmtId(tblinfo[i].relname, force_quotes));
2246 lres = PQexec(g_conn, lockquery->data);
2247 if (!lres || PQresultStatus(lres) != PGRES_COMMAND_OK)
2249 write_msg(NULL, "Attempt to lock table \"%s\" failed. %s",
2250 tblinfo[i].relname, PQerrorMessage(g_conn));
2261 * Second pass: pick up additional information about each table, as
2264 for (i = 0; i < *numTables; i++)
2266 /* Emit notice if join for owner failed */
2267 if (strlen(tblinfo[i].usename) == 0)
2268 write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
2269 tblinfo[i].relname);
2271 /* Get definition if it's a view */
2272 if (tblinfo[i].relkind == RELKIND_VIEW)
2276 resetPQExpBuffer(query);
2278 if (g_fout->remoteVersion < 70300)
2280 appendPQExpBuffer(query, "SELECT definition as viewdef, "
2281 "(select oid from pg_rewrite where "
2282 " rulename=('_RET' || viewname)::name) as view_oid"
2283 " from pg_views where viewname = ");
2284 formatStringLiteral(query, tblinfo[i].relname, CONV_ALL);
2285 appendPQExpBuffer(query, ";");
2289 /* Beginning in 7.3, viewname is not unique; use OID */
2290 appendPQExpBuffer(query, "SELECT pg_get_viewdef(ev_class) as viewdef, "
2292 " from pg_rewrite where"
2293 " ev_class = '%s'::oid and"
2294 " rulename = '_RETURN';",
2298 res2 = PQexec(g_conn, query->data);
2299 if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
2301 write_msg(NULL, "query to obtain definition of view \"%s\" failed: %s",
2302 tblinfo[i].relname, PQerrorMessage(g_conn));
2306 if (PQntuples(res2) != 1)
2308 if (PQntuples(res2) < 1)
2309 write_msg(NULL, "query to obtain definition of view \"%s\" returned no data\n",
2310 tblinfo[i].relname);
2312 write_msg(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
2313 tblinfo[i].relname);
2317 if (PQgetisnull(res2, 0, 1))
2319 write_msg(NULL, "query to obtain definition of view \"%s\" returned NULL oid\n",
2320 tblinfo[i].relname);
2324 tblinfo[i].viewdef = strdup(PQgetvalue(res2, 0, 0));
2325 tblinfo[i].viewoid = strdup(PQgetvalue(res2, 0, 1));
2327 if (strlen(tblinfo[i].viewdef) == 0)
2329 write_msg(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
2330 tblinfo[i].relname);
2336 tblinfo[i].viewdef = NULL;
2339 * Get non-inherited CHECK constraints, if any.
2341 * Exclude inherited CHECKs from CHECK constraints total. If a
2342 * constraint matches by name and condition with a constraint
2343 * belonging to a parent class (OR conditions match and both names
2344 * start with '$', we assume it was inherited.
2346 if (tblinfo[i].ncheck > 0)
2355 write_msg(NULL, "finding CHECK constraints for table %s\n",
2356 tblinfo[i].relname);
2358 resetPQExpBuffer(query);
2359 appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
2360 " where rcrelid = '%s'::oid "
2362 " (select * from pg_relcheck as c, pg_inherits as i "
2363 " where i.inhrelid = pg_relcheck.rcrelid "
2364 " and (c.rcname = pg_relcheck.rcname "
2365 " or ( c.rcname[0] = '$' "
2366 " and pg_relcheck.rcname[0] = '$')"
2368 " and c.rcsrc = pg_relcheck.rcsrc "
2369 " and c.rcrelid = i.inhparent) "
2370 " order by rcname ",
2372 res2 = PQexec(g_conn, query->data);
2374 PQresultStatus(res2) != PGRES_TUPLES_OK)
2376 write_msg(NULL, "query to obtain check constraints failed: %s", PQerrorMessage(g_conn));
2379 ntups2 = PQntuples(res2);
2380 if (ntups2 > tblinfo[i].ncheck)
2382 write_msg(NULL, "expected %d check constraints on table \"%s\" but found %d\n",
2383 tblinfo[i].ncheck, tblinfo[i].relname, ntups2);
2384 write_msg(NULL, "(The system catalogs might be corrupted.)\n");
2389 * Set ncheck to the number of *non-inherited* CHECK
2392 tblinfo[i].ncheck = ntups2;
2394 i_rcname = PQfnumber(res2, "rcname");
2395 i_rcsrc = PQfnumber(res2, "rcsrc");
2396 tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
2397 for (i2 = 0; i2 < ntups2; i2++)
2399 const char *name = PQgetvalue(res2, i2, i_rcname);
2400 const char *expr = PQgetvalue(res2, i2, i_rcsrc);
2402 resetPQExpBuffer(query);
2405 appendPQExpBuffer(query, "CONSTRAINT %s ",
2406 fmtId(name, force_quotes));
2408 appendPQExpBuffer(query, "CHECK (%s)", expr);
2409 tblinfo[i].check_expr[i2] = strdup(query->data);
2414 tblinfo[i].check_expr = NULL;
2416 /* Get primary key */
2417 if (tblinfo[i].hasindex)
2421 resetPQExpBuffer(query);
2422 appendPQExpBuffer(query,
2423 "SELECT indexrelid FROM pg_index i WHERE i.indisprimary AND i.indrelid = '%s'::oid ",
2425 res2 = PQexec(g_conn, query->data);
2426 if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
2428 write_msg(NULL, "query to obtain primary key of table \"%s\" failed: %s",
2429 tblinfo[i].relname, PQerrorMessage(g_conn));
2433 if (PQntuples(res2) > 1)
2435 write_msg(NULL, "query to obtain primary key of table \"%s\" produced more than one result\n",
2436 tblinfo[i].relname);
2440 if (PQntuples(res2) == 1)
2441 tblinfo[i].pkIndexOid = strdup(PQgetvalue(res2, 0, 0));
2443 tblinfo[i].pkIndexOid = NULL;
2447 tblinfo[i].pkIndexOid = NULL;
2449 /* Get primary key name (if primary key exist) */
2450 if (tblinfo[i].pkIndexOid != NULL)
2455 resetPQExpBuffer(query);
2456 appendPQExpBuffer(query,
2457 "SELECT relname FROM pg_class "
2458 "WHERE oid = '%s'::oid",
2459 tblinfo[i].pkIndexOid);
2461 res2 = PQexec(g_conn, query->data);
2462 if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
2464 write_msg(NULL, "query to obtain name of primary key of table \"%s\" failed: %s",
2465 tblinfo[i].relname, PQerrorMessage(g_conn));
2469 n = PQntuples(res2);
2473 write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned no rows\n",
2474 tblinfo[i].relname);
2476 write_msg(NULL, "query to obtain name of primary key of table \"%s\" returned %d rows\n",
2477 tblinfo[i].relname, n);
2481 tblinfo[i].primary_key_name =
2482 strdup(fmtId(PQgetvalue(res2, 0, 0), force_quotes));
2483 if (tblinfo[i].primary_key_name == NULL)
2485 write_msg(NULL, "out of memory\n");
2490 tblinfo[i].primary_key_name = NULL;
2493 if (tblinfo[i].ntrig > 0)
2512 write_msg(NULL, "finding triggers for table %s\n", tblinfo[i].relname);
2514 resetPQExpBuffer(query);
2515 appendPQExpBuffer(query,
2516 "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, "
2517 "tgisconstraint, tgconstrname, tgdeferrable, "
2518 "tgconstrrelid, tginitdeferred, oid, "
2519 "(select relname from pg_class where oid = tgconstrrelid) "
2520 " as tgconstrrelname "
2522 "where tgrelid = '%s'::oid ",
2524 res2 = PQexec(g_conn, query->data);
2526 PQresultStatus(res2) != PGRES_TUPLES_OK)
2528 write_msg(NULL, "query to obtain list of triggers failed: %s", PQerrorMessage(g_conn));
2531 ntups2 = PQntuples(res2);
2532 if (ntups2 != tblinfo[i].ntrig)
2534 write_msg(NULL, "expected %d triggers on table \"%s\" but found %d\n",
2535 tblinfo[i].ntrig, tblinfo[i].relname, ntups2);
2538 i_tgname = PQfnumber(res2, "tgname");
2539 i_tgfoid = PQfnumber(res2, "tgfoid");
2540 i_tgtype = PQfnumber(res2, "tgtype");
2541 i_tgnargs = PQfnumber(res2, "tgnargs");
2542 i_tgargs = PQfnumber(res2, "tgargs");
2543 i_tgoid = PQfnumber(res2, "oid");
2544 i_tgisconstraint = PQfnumber(res2, "tgisconstraint");
2545 i_tgconstrname = PQfnumber(res2, "tgconstrname");
2546 i_tgdeferrable = PQfnumber(res2, "tgdeferrable");
2547 i_tgconstrrelid = PQfnumber(res2, "tgconstrrelid");
2548 i_tgconstrrelname = PQfnumber(res2, "tgconstrrelname");
2549 i_tginitdeferred = PQfnumber(res2, "tginitdeferred");
2551 tblinfo[i].triggers = (TrigInfo *) malloc(ntups2 * sizeof(TrigInfo));
2552 resetPQExpBuffer(query);
2553 for (i2 = 0; i2 < ntups2; i2++)
2555 const char *tgfuncoid = PQgetvalue(res2, i2, i_tgfoid);
2556 char *tgfunc = NULL;
2557 int2 tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
2558 int tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
2559 const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
2563 char *tgconstrrelid;
2568 tgname = PQgetvalue(res2, i2, i_tgname);
2570 if (strcmp(PQgetvalue(res2, i2, i_tgisconstraint), "f") == 0)
2575 if (strcmp(PQgetvalue(res2, i2, i_tgdeferrable), "f") == 0)
2580 if (strcmp(PQgetvalue(res2, i2, i_tginitdeferred), "f") == 0)
2585 for (findx = 0; findx < numFuncs; findx++)
2587 if (strcmp(finfo[findx].oid, tgfuncoid) == 0 &&
2588 finfo[findx].nargs == 0 &&
2589 strcmp(finfo[findx].prorettype, "0") == 0)
2593 if (findx == numFuncs)
2599 * the funcname is an oid which we use to find the
2600 * name of the pg_proc. We need to do this because
2601 * getFuncs() only reads in the user-defined funcs not
2602 * all the funcs. We might not find what we want by
2603 * looking in FuncInfo*
2605 resetPQExpBuffer(query);
2606 appendPQExpBuffer(query,
2607 "SELECT proname from pg_proc "
2608 "where pg_proc.oid = '%s'::oid",
2611 r = PQexec(g_conn, query->data);
2612 if (!r || PQresultStatus(r) != PGRES_TUPLES_OK)
2614 write_msg(NULL, "query to obtain procedure name for trigger \"%s\" failed: %s",
2615 tgname, PQerrorMessage(g_conn));
2619 /* Sanity: Check we got only one tuple */
2620 numFuncs = PQntuples(r);
2624 write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned no rows\n",
2627 write_msg(NULL, "query to obtain procedure name for trigger \"%s\" (procedure OID %s) returned %d rows\n",
2628 tgname, tgfuncoid, numFuncs);
2632 tgfunc = strdup(PQgetvalue(r, 0, PQfnumber(r, "proname")));
2636 tgfunc = strdup(finfo[findx].proname);
2638 appendPQExpBuffer(delqry, "DROP TRIGGER %s ", fmtId(tgname, force_quotes));
2639 appendPQExpBuffer(delqry, "ON %s;\n",
2640 fmtId(tblinfo[i].relname, force_quotes));
2642 resetPQExpBuffer(query);
2645 appendPQExpBuffer(query, "CREATE CONSTRAINT TRIGGER ");
2646 appendPQExpBuffer(query, fmtId(PQgetvalue(res2, i2, i_tgconstrname), force_quotes));
2650 appendPQExpBuffer(query, "CREATE TRIGGER ");
2651 appendPQExpBuffer(query, fmtId(tgname, force_quotes));
2653 appendPQExpBufferChar(query, ' ');
2656 if (TRIGGER_FOR_BEFORE(tgtype))
2657 appendPQExpBuffer(query, "BEFORE");
2659 appendPQExpBuffer(query, "AFTER");
2660 if (TRIGGER_FOR_INSERT(tgtype))
2662 appendPQExpBuffer(query, " INSERT");
2665 if (TRIGGER_FOR_DELETE(tgtype))
2668 appendPQExpBuffer(query, " OR DELETE");
2670 appendPQExpBuffer(query, " DELETE");
2673 if (TRIGGER_FOR_UPDATE(tgtype))
2676 appendPQExpBuffer(query, " OR UPDATE");
2678 appendPQExpBuffer(query, " UPDATE");
2680 appendPQExpBuffer(query, " ON %s ", fmtId(tblinfo[i].relname, force_quotes));
2684 tgconstrrelid = PQgetvalue(res2, i2, i_tgconstrrelid);
2686 if (strcmp(tgconstrrelid, "0") != 0)
2689 if (PQgetisnull(res2, i2, i_tgconstrrelname))
2691 write_msg(NULL, "query produced NULL referenced table name for foreign key trigger \"%s\" on table \"%s\" (oid of table: %s)\n",
2692 tgname, tblinfo[i].relname, tgconstrrelid);
2696 appendPQExpBuffer(query, " FROM %s",
2697 fmtId(PQgetvalue(res2, i2, i_tgconstrrelname), force_quotes));
2700 appendPQExpBuffer(query, " NOT");
2701 appendPQExpBuffer(query, " DEFERRABLE INITIALLY ");
2703 appendPQExpBuffer(query, "DEFERRED");
2705 appendPQExpBuffer(query, "IMMEDIATE");
2709 appendPQExpBuffer(query, " FOR EACH ROW");
2710 appendPQExpBuffer(query, " EXECUTE PROCEDURE %s (",
2711 fmtId(tgfunc, force_quotes));
2712 for (findx = 0; findx < tgnargs; findx++)
2718 p = strchr(p, '\\');
2721 write_msg(NULL, "bad argument string (%s) for trigger \"%s\" on table \"%s\"\n",
2722 PQgetvalue(res2, i2, i_tgargs),
2724 tblinfo[i].relname);
2733 if (p[0] == '0' && p[1] == '0' && p[2] == '0')
2737 appendPQExpBufferChar(query, '\'');
2738 for (s = tgargs; s < p;)
2741 appendPQExpBufferChar(query, '\\');
2742 appendPQExpBufferChar(query, *s++);
2744 appendPQExpBufferChar(query, '\'');
2745 appendPQExpBuffer(query, (findx < tgnargs - 1) ? ", " : "");
2748 appendPQExpBuffer(query, ");\n");
2750 tblinfo[i].triggers[i2].tgsrc = strdup(query->data);
2752 /*** Initialize trcomments and troids ***/
2754 resetPQExpBuffer(query);
2755 appendPQExpBuffer(query, "TRIGGER %s ",
2756 fmtId(tgname, force_quotes));
2757 appendPQExpBuffer(query, "ON %s",
2758 fmtId(tblinfo[i].relname, force_quotes));
2759 tblinfo[i].triggers[i2].tgcomment = strdup(query->data);
2760 tblinfo[i].triggers[i2].oid = strdup(PQgetvalue(res2, i2, i_tgoid));
2761 tblinfo[i].triggers[i2].tgname = strdup(fmtId(tgname, false));
2762 tblinfo[i].triggers[i2].tgdel = strdup(delqry->data);
2770 tblinfo[i].triggers = NULL;
2774 destroyPQExpBuffer(query);
2775 destroyPQExpBuffer(delqry);
2776 destroyPQExpBuffer(lockquery);
2783 * read all the inheritance information
2784 * from the system catalogs return them in the InhInfo* structure
2786 * numInherits is set to the number of tables read in
2789 getInherits(int *numInherits)
2794 PQExpBuffer query = createPQExpBuffer();
2800 /* find all the inheritance information */
2802 appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
2804 res = PQexec(g_conn, query->data);
2806 PQresultStatus(res) != PGRES_TUPLES_OK)
2808 write_msg(NULL, "query to obtain inheritance relationships failed: %s",
2809 PQerrorMessage(g_conn));
2813 ntups = PQntuples(res);
2815 *numInherits = ntups;
2817 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
2819 i_inhrelid = PQfnumber(res, "inhrelid");
2820 i_inhparent = PQfnumber(res, "inhparent");
2822 for (i = 0; i < ntups; i++)
2824 inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
2825 inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
2830 destroyPQExpBuffer(query);
2837 * for each table in tblinfo, read its attributes types and names
2839 * this is implemented in a very inefficient way right now, looping
2840 * through the tblinfo and doing a join per table to find the attrs and their
2846 getTableAttrs(TableInfo *tblinfo, int numTables)
2850 PQExpBuffer q = createPQExpBuffer();
2860 for (i = 0; i < numTables; i++)
2862 if (tblinfo[i].relkind == RELKIND_SEQUENCE)
2865 /* find all the user attributes and their types */
2866 /* we must read the attribute names in attribute number order! */
2869 * because we will use the attnum to index into the attnames array
2873 write_msg(NULL, "finding the columns and types for table %s\n",
2874 tblinfo[i].relname);
2876 resetPQExpBuffer(q);
2878 if (g_fout->remoteVersion < 70100)
2880 /* Fake the LOJ below */
2881 appendPQExpBuffer(q,
2882 " SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
2883 " a.attnotnull, a.atthasdef, NULL as atttypedefn "
2884 " from pg_attribute a, pg_type t "
2885 " where a.attrelid = '%s'::oid "
2886 " and a.attnum > 0 "
2887 " and a.atttypid = t.oid "
2888 " UNION ALL SELECT a.attnum, a.attname, NULL as typname, a.atttypmod, "
2889 " a.attnotnull, a.atthasdef, NULL as atttypedefn "
2890 " from pg_attribute a "
2891 " where a.attrelid = '%s'::oid "
2892 " and a.attnum > 0 "
2893 " and Not Exists(Select * From pg_type t where a.atttypid = t.oid)"
2895 tblinfo[i].oid, tblinfo[i].oid);
2900 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
2901 "a.attnotnull, a.atthasdef, format_type(a.atttypid, a.atttypmod) as atttypedefn "
2902 "from pg_attribute a LEFT OUTER JOIN pg_type t ON a.atttypid = t.oid "
2903 "where a.attrelid = '%s'::oid "
2904 "and a.attnum > 0 order by attnum",
2908 res = PQexec(g_conn, q->data);
2910 PQresultStatus(res) != PGRES_TUPLES_OK)
2912 write_msg(NULL, "query to get table columns failed: %s", PQerrorMessage(g_conn));
2916 ntups = PQntuples(res);
2918 i_attname = PQfnumber(res, "attname");
2919 i_typname = PQfnumber(res, "typname");
2920 i_atttypmod = PQfnumber(res, "atttypmod");
2921 i_attnotnull = PQfnumber(res, "attnotnull");
2922 i_atthasdef = PQfnumber(res, "atthasdef");
2923 i_atttypedefn = PQfnumber(res, "atttypedefn");
2925 tblinfo[i].numatts = ntups;
2926 tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
2927 tblinfo[i].atttypedefns = (char **) malloc(ntups * sizeof(char *));
2928 tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
2929 tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
2930 tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
2931 tblinfo[i].inhAttrDef = (int *) malloc(ntups * sizeof(int));
2932 tblinfo[i].inhNotNull = (int *) malloc(ntups * sizeof(int));
2933 tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
2934 tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
2935 tblinfo[i].parentRels = NULL;
2936 tblinfo[i].numParents = 0;
2937 for (j = 0; j < ntups; j++)
2939 /* Sanity check on LOJ */
2940 if (PQgetisnull(res, j, i_typname))
2942 write_msg(NULL, "query produced NULL name for data type of column %d of table %s\n",
2943 j + 1, tblinfo[i].relname);
2947 tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
2948 tblinfo[i].atttypedefns[j] = strdup(PQgetvalue(res, j, i_atttypedefn));
2949 tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
2950 tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
2951 tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
2953 tblinfo[i].inhAttrDef[j] = 0;
2954 tblinfo[i].inhNotNull[j] = 0;
2956 tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
2957 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
2963 write_msg(NULL, "finding DEFAULT expression for column %s\n",
2964 tblinfo[i].attnames[j]);
2966 resetPQExpBuffer(q);
2967 appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
2968 "where adrelid = '%s'::oid and adnum = %d ",
2969 tblinfo[i].oid, j + 1);
2970 res2 = PQexec(g_conn, q->data);
2972 PQresultStatus(res2) != PGRES_TUPLES_OK)
2974 write_msg(NULL, "query to get column default value failed: %s",
2975 PQerrorMessage(g_conn));
2979 /* Sanity: Check we got only one tuple */
2980 numAttr = PQntuples(res2);
2983 write_msg(NULL, "query to get default value for column \"%s\" returned %d rows; expected 1\n",
2984 tblinfo[i].attnames[j], numAttr);
2988 tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
2992 tblinfo[i].adef_expr[j] = NULL;
2997 destroyPQExpBuffer(q);
3003 * read all the user-defined indexes information
3004 * from the system catalogs return them in the InhInfo* structure
3006 * numIndexes is set to the number of indexes read in
3011 getIndexes(int *numIndexes)
3014 PQExpBuffer query = createPQExpBuffer();
3029 * find all the user-defined indexes.
3031 * Notice we skip indexes on system classes
3036 appendPQExpBuffer(query,
3037 "SELECT i.indexrelid as indexreloid, "
3038 "i.indrelid as indreloid, "
3039 "t1.relname as indexrelname, t2.relname as indrelname, "
3040 "pg_get_indexdef(i.indexrelid) as indexdef, "
3041 "i.indisprimary, i.indkey, "
3042 "CASE WHEN i.indproc <> 0 "
3043 " THEN (SELECT pronargs FROM pg_proc WHERE pg_proc.oid = i.indproc) "
3044 " ELSE t1.relnatts END as indnkeys "
3045 "FROM pg_index i, pg_class t1, pg_class t2 "
3046 "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
3047 "and i.indexrelid > '%u'::oid "
3048 "and t2.relname !~ '^pg_' ",
3049 g_last_builtin_oid);
3051 if (g_fout->remoteVersion < 70100)
3052 appendPQExpBuffer(query, " and t2.relkind != 'l'");
3054 res = PQexec(g_conn, query->data);
3056 PQresultStatus(res) != PGRES_TUPLES_OK)
3058 write_msg(NULL, "query to obtain list of indexes failed: %s", PQerrorMessage(g_conn));
3062 ntups = PQntuples(res);
3064 *numIndexes = ntups;
3066 indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));
3068 memset((char *) indinfo, 0, ntups * sizeof(IndInfo));
3070 i_indexreloid = PQfnumber(res, "indexreloid");
3071 i_indreloid = PQfnumber(res, "indreloid");
3072 i_indexrelname = PQfnumber(res, "indexrelname");
3073 i_indrelname = PQfnumber(res, "indrelname");
3074 i_indexdef = PQfnumber(res, "indexdef");
3075 i_indisprimary = PQfnumber(res, "indisprimary");
3076 i_indnkeys = PQfnumber(res, "indnkeys");
3077 i_indkey = PQfnumber(res, "indkey");
3079 for (i = 0; i < ntups; i++)
3081 indinfo[i].indexreloid = strdup(PQgetvalue(res, i, i_indexreloid));
3082 indinfo[i].indreloid = strdup(PQgetvalue(res, i, i_indreloid));
3083 indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
3084 indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
3085 indinfo[i].indexdef = strdup(PQgetvalue(res, i, i_indexdef));
3086 indinfo[i].indisprimary = strdup(PQgetvalue(res, i, i_indisprimary));
3087 indinfo[i].indnkeys = atoi(PQgetvalue(res, i, i_indnkeys));
3088 indinfo[i].indkey = malloc(indinfo[i].indnkeys * sizeof(indinfo[i].indkey[0]));
3089 parseNumericArray(PQgetvalue(res, i, i_indkey),
3091 indinfo[i].indnkeys);
3095 destroyPQExpBuffer(query);
3100 /*------------------------------------------------------------------
3103 * This routine is used to dump any comments associated with the
3104 * oid handed to this routine. The routine takes a constant character
3105 * string for the target part of the comment-creation command, plus
3106 * OID, class name, and subid which are the primary key for pg_description.
3107 * If a matching pg_description entry is found, it is dumped.
3108 * Additional dependencies can be passed for the comment, too --- this is
3109 * needed for VIEWs, whose comments are filed under the table OID but
3110 * which are dumped in order by their rule OID.
3111 *------------------------------------------------------------------
3115 dumpComment(Archive *fout, const char *target, const char *oid,
3116 const char *classname, int subid,
3117 const char *((*deps)[]))
3123 /* Comments are SCHEMA not data */
3127 /*** Build query to find comment ***/
3129 query = createPQExpBuffer();
3131 if (fout->remoteVersion >= 70200)
3133 appendPQExpBuffer(query, "SELECT description FROM pg_description "
3134 "WHERE objoid = '%s'::oid and classoid = "
3135 "(SELECT oid FROM pg_class where relname = '%s') "
3136 "and objsubid = %d",
3137 oid, classname, subid);
3141 /* Note: this will fail to find attribute comments in pre-7.2... */
3142 appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = '%s'::oid", oid);
3145 /*** Execute query ***/
3147 res = PQexec(g_conn, query->data);
3148 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
3150 write_msg(NULL, "query to get comment on oid %s failed: %s",
3151 oid, PQerrorMessage(g_conn));
3155 /*** If a comment exists, build COMMENT ON statement ***/
3157 if (PQntuples(res) == 1)
3159 i_description = PQfnumber(res, "description");
3160 resetPQExpBuffer(query);
3161 appendPQExpBuffer(query, "COMMENT ON %s IS ", target);
3162 formatStringLiteral(query, PQgetvalue(res, 0, i_description),
3164 appendPQExpBuffer(query, ";\n");
3166 ArchiveEntry(fout, oid, target, "COMMENT", deps,
3167 query->data, "" /* Del */ ,
3168 "" /* Copy */ , "" /* Owner */ , NULL, NULL);
3171 /*** Clear the statement buffer and return ***/
3174 destroyPQExpBuffer(query);
3177 /*------------------------------------------------------------------
3180 * This routine is used to dump any comments associated with the
3181 * database to which we are currently connected. If the user chose
3182 * to dump the schema of the database, then this is the first
3184 *------------------------------------------------------------------
3188 dumpDBComment(Archive *fout)
3194 /*** Build query to find comment ***/
3196 query = createPQExpBuffer();
3197 appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = ");
3198 formatStringLiteral(query, PQdb(g_conn), CONV_ALL);
3200 /*** Execute query ***/
3202 res = PQexec(g_conn, query->data);
3203 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
3205 write_msg(NULL, "query to get database oid failed: %s",
3206 PQerrorMessage(g_conn));
3210 /*** If a comment exists, build COMMENT ON statement ***/
3212 if (PQntuples(res) != 0)
3214 i_oid = PQfnumber(res, "oid");
3215 resetPQExpBuffer(query);
3216 appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
3217 dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid),
3218 "pg_database", 0, NULL);
3221 /*** Clear the statement buffer and return ***/
3224 destroyPQExpBuffer(query);
3229 * wites out to fout the queries to recrease a user-defined domains
3230 * as requested by dumpTypes
3233 dumpOneDomain(Archive *fout, TypeInfo *tinfo)
3235 PQExpBuffer q = createPQExpBuffer();
3236 PQExpBuffer delq = createPQExpBuffer();
3239 PQExpBuffer query = createPQExpBuffer();
3241 const char *((*deps)[]);
3245 deps = malloc(sizeof(char *) * 10);
3247 /* Fetch domain specific details */
3248 resetPQExpBuffer(query);
3249 appendPQExpBuffer(query, "SELECT typnotnull, "
3250 "format_type(typbasetype, typtypmod) as typdefn, "
3253 "WHERE typname = '%s'",
3256 res = PQexec(g_conn, query->data);
3258 PQresultStatus(res) != PGRES_TUPLES_OK)
3260 write_msg(NULL, "query to obtain domain information failed: %s", PQerrorMessage(g_conn));
3264 /* Expecting a single result only */
3265 ntups = PQntuples(res);
3267 write_msg(NULL, "Domain %s non-existant.", fmtId(tinfo->typname, force_quotes));
3270 /* Drop the old copy */
3271 resetPQExpBuffer(delq);
3272 appendPQExpBuffer(delq, "DROP DOMAIN %s RESTRICT;\n", fmtId(tinfo->typname, force_quotes));
3274 resetPQExpBuffer(q);
3275 appendPQExpBuffer(q,
3276 "CREATE DOMAIN %s AS %s",
3277 fmtId(tinfo->typname, force_quotes),
3278 PQgetvalue(res, 0, PQfnumber(res, "typdefn"))
3281 /* Depends on the base type */
3282 (*deps)[depIdx++] = strdup(PQgetvalue(res, 0, PQfnumber(res, "typbasetype")));
3284 if (PQgetvalue(res, 0, PQfnumber(res, "typnotnull"))[0] == 't')
3285 appendPQExpBuffer(q, " NOT NULL");
3287 if (tinfo->typdefault)
3289 appendPQExpBuffer(q,
3294 appendPQExpBuffer(q, ";\n");
3297 (*deps)[depIdx++] = NULL; /* End of List */
3299 ArchiveEntry(fout, tinfo->oid, tinfo->typname, "DOMAIN", deps,
3300 q->data, delq->data, "", tinfo->usename, NULL, NULL);
3302 /*** Dump Domain Comments ***/
3303 resetPQExpBuffer(q);
3305 appendPQExpBuffer(q, "DOMAIN %s", fmtId(tinfo->typname, force_quotes));
3306 dumpComment(fout, q->data, tinfo->oid, "pg_type", 0, NULL);
3311 * writes out to fout the queries to recreate all the user-defined types
3315 dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
3316 TypeInfo *tinfo, int numTypes)
3319 PQExpBuffer q = createPQExpBuffer();
3320 PQExpBuffer delq = createPQExpBuffer();
3322 const char *((*deps)[]);
3325 for (i = 0; i < numTypes; i++)
3327 /* skip all the builtin types */
3328 if (atooid(tinfo[i].oid) <= g_last_builtin_oid)
3331 /* skip relation types */
3332 if (atooid(tinfo[i].typrelid) != 0)
3335 /* skip undefined placeholder types */
3336 if (!tinfo[i].isDefined)
3339 /* skip all array types that start w/ underscore */
3340 if ((tinfo[i].typname[0] == '_') &&
3341 (strcmp(tinfo[i].typinput, "array_in") == 0))
3344 /* Dump out domains as we run across them */
3345 if (strcmp(tinfo[i].typtype, "d") == 0) {
3346 dumpOneDomain(fout, &tinfo[i]);
3351 deps = malloc(sizeof(char *) * 10);
3355 * before we create a type, we need to create the input and output
3356 * functions for it, if they haven't been created already
3358 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
3361 (*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3362 dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3365 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
3368 (*deps)[depIdx++] = strdup(finfo[funcInd].oid);
3369 dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
3372 resetPQExpBuffer(delq);
3373 appendPQExpBuffer(delq, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
3375 resetPQExpBuffer(q);
3376 appendPQExpBuffer(q,
3378 "( internallength = %s, externallength = %s,",
3379 fmtId(tinfo[i].typname, force_quotes),
3380 (strcmp(tinfo[i].typlen, "-1") == 0) ?
3381 "variable" : tinfo[i].typlen,
3382 (strcmp(tinfo[i].typprtlen, "-1") == 0) ?
3383 "variable" : tinfo[i].typprtlen);
3384 /* cannot combine these because fmtId uses static result area */
3385 appendPQExpBuffer(q, " input = %s,",
3386 fmtId(tinfo[i].typinput, force_quotes));
3387 appendPQExpBuffer(q, " output = %s,",
3388 fmtId(tinfo[i].typoutput, force_quotes));
3389 appendPQExpBuffer(q, " send = %s,",
3390 fmtId(tinfo[i].typsend, force_quotes));
3391 appendPQExpBuffer(q, " receive = %s",
3392 fmtId(tinfo[i].typreceive, force_quotes));
3394 if (tinfo[i].typdefault != NULL)
3396 appendPQExpBuffer(q, ", default = ");
3397 formatStringLiteral(q, tinfo[i].typdefault, CONV_ALL);
3400 if (tinfo[i].isArray)
3404 elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem, zeroAsOpaque);
3405 if (elemType == NULL)
3407 write_msg(NULL, "notice: array type %s - type for elements (oid %s) is not dumped\n",
3408 tinfo[i].typname, tinfo[i].typelem);
3412 appendPQExpBuffer(q, ", element = %s, delimiter = ", elemType);
3413 formatStringLiteral(q, tinfo[i].typdelim, CONV_ALL);
3415 (*deps)[depIdx++] = strdup(tinfo[i].typelem);
3418 if (strcmp(tinfo[i].typalign, "c") == 0)
3419 appendPQExpBuffer(q, ", alignment = char");
3420 else if (strcmp(tinfo[i].typalign, "s") == 0)
3421 appendPQExpBuffer(q, ", alignment = int2");
3422 else if (strcmp(tinfo[i].typalign, "i") == 0)
3423 appendPQExpBuffer(q, ", alignment = int4");
3424 else if (strcmp(tinfo[i].typalign, "d") == 0)
3425 appendPQExpBuffer(q, ", alignment = double");
3427 if (strcmp(tinfo[i].typstorage, "p") == 0)
3428 appendPQExpBuffer(q, ", storage = plain");
3429 else if (strcmp(tinfo[i].typstorage, "e") == 0)
3430 appendPQExpBuffer(q, ", storage = external");
3431 else if (strcmp(tinfo[i].typstorage, "x") == 0)
3432 appendPQExpBuffer(q, ", storage = extended");
3433 else if (strcmp(tinfo[i].typstorage, "m") == 0)
3434 appendPQExpBuffer(q, ", storage = main");
3436 if (tinfo[i].passedbyvalue)
3437 appendPQExpBuffer(q, ", passedbyvalue);\n");
3439 appendPQExpBuffer(q, ");\n");
3441 (*deps)[depIdx++] = NULL; /* End of List */
3443 ArchiveEntry(fout, tinfo[i].oid, tinfo[i].typname, "TYPE", deps,
3444 q->data, delq->data, "", tinfo[i].usename, NULL, NULL);
3448 /*** Dump Type Comments ***/
3450 resetPQExpBuffer(q);
3452 appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
3453 dumpComment(fout, q->data, tinfo[i].oid, "pg_type", 0, NULL);
3456 destroyPQExpBuffer(q);
3457 destroyPQExpBuffer(delq);
3462 * writes out to fout the queries to recreate user-defined procedural languages
3466 dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs,
3467 TypeInfo *tinfo, int numTypes)
3470 PQExpBuffer query = createPQExpBuffer();
3471 PQExpBuffer defqry = createPQExpBuffer();
3472 PQExpBuffer delqry = createPQExpBuffer();
3477 int i_lanplcallfoid;
3482 const char *lanplcallfoid;
3486 appendPQExpBuffer(query, "SELECT oid, * FROM pg_language "
3489 res = PQexec(g_conn, query->data);
3491 PQresultStatus(res) != PGRES_TUPLES_OK)
3493 write_msg(NULL, "query to obtain list of procedural languages failed: %s",
3494 PQerrorMessage(g_conn));
3497 ntups = PQntuples(res);
3499 i_lanname = PQfnumber(res, "lanname");
3500 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
3501 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
3502 i_lancompiler = PQfnumber(res, "lancompiler");
3503 i_oid = PQfnumber(res, "oid");
3505 for (i = 0; i < ntups; i++)
3507 lanoid = atooid(PQgetvalue(res, i, i_oid));
3508 if (lanoid <= g_last_builtin_oid)
3511 lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
3514 for (fidx = 0; fidx < numFuncs; fidx++)
3516 if (!strcmp(finfo[fidx].oid, lanplcallfoid))
3519 if (fidx >= numFuncs)
3521 write_msg(NULL, "handler procedure for procedural language %s not found\n",
3522 PQgetvalue(res, i, i_lanname));
3526 dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
3528 lanname = PQgetvalue(res, i, i_lanname);
3529 lancompiler = PQgetvalue(res, i, i_lancompiler);
3531 appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
3532 formatStringLiteral(delqry, lanname, CONV_ALL);
3533 appendPQExpBuffer(delqry, ";\n");
3535 appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
3536 (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
3538 formatStringLiteral(defqry, lanname, CONV_ALL);
3539 appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
3540 fmtId(finfo[fidx].proname, force_quotes));
3541 formatStringLiteral(defqry, lancompiler, CONV_ALL);
3542 appendPQExpBuffer(defqry, ";\n");
3544 ArchiveEntry(fout, PQgetvalue(res, i, i_oid), lanname, "PROCEDURAL LANGUAGE",
3545 NULL, defqry->data, delqry->data, "", "", NULL, NULL);
3547 resetPQExpBuffer(defqry);
3548 resetPQExpBuffer(delqry);
3553 destroyPQExpBuffer(query);
3554 destroyPQExpBuffer(defqry);
3555 destroyPQExpBuffer(delqry);
3560 * writes out to fout the queries to recreate all the user-defined functions
3564 dumpFuncs(Archive *fout, FuncInfo *finfo, int numFuncs,
3565 TypeInfo *tinfo, int numTypes)
3569 for (i = 0; i < numFuncs; i++)
3570 dumpOneFunc(fout, finfo, i, tinfo, numTypes);
3575 * dump out only one function, the index of which is given in the third
3581 dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
3582 TypeInfo *tinfo, int numTypes)
3584 PQExpBuffer q = createPQExpBuffer();
3585 PQExpBuffer fn = createPQExpBuffer();
3586 PQExpBuffer delqry = createPQExpBuffer();
3587 PQExpBuffer fnlist = createPQExpBuffer();
3588 PQExpBuffer asPart = createPQExpBuffer();
3589 char *func_lang = NULL;
3597 char *listSepComma = ",";
3598 char *listSepNone = "";
3601 if (finfo[i].dumped)
3604 finfo[i].dumped = 1;
3606 /* becomeUser(fout, finfo[i].usename); */
3608 sprintf(query, "SELECT lanname FROM pg_language WHERE oid = '%u'::oid",
3610 res = PQexec(g_conn, query);
3612 PQresultStatus(res) != PGRES_TUPLES_OK)
3614 write_msg(NULL, "query to get name of procedural language failed: %s", PQerrorMessage(g_conn));
3617 nlangs = PQntuples(res);
3621 write_msg(NULL, "procedural language for function %s not found\n", finfo[i].proname);
3625 i_lanname = PQfnumber(res, "lanname");
3628 * See backend/commands/define.c for details of how the 'AS' clause is
3631 if (strcmp(finfo[i].probin, "-") != 0)
3633 appendPQExpBuffer(asPart, "AS ");
3634 formatStringLiteral(asPart, finfo[i].probin, CONV_ALL);
3635 if (strcmp(finfo[i].prosrc, "-") != 0)
3637 appendPQExpBuffer(asPart, ", ");
3638 formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3643 if (strcmp(finfo[i].prosrc, "-") != 0)
3645 appendPQExpBuffer(asPart, "AS ");
3646 formatStringLiteral(asPart, finfo[i].prosrc, PASS_LFTAB);
3650 func_lang = strdup(PQgetvalue(res, 0, i_lanname));
3654 resetPQExpBuffer(fn);
3655 appendPQExpBuffer(fn, "%s (", fmtId(finfo[i].proname, force_quotes));
3656 for (j = 0; j < finfo[i].nargs; j++)
3660 typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j], zeroAsOpaque);
3661 if (typname == NULL)
3663 write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
3666 write_msg(NULL, "reason: data type name of argument %d (oid %s) not found\n",
3667 j, finfo[i].argtypes[j]);
3671 appendPQExpBuffer(fn, "%s%s",
3674 appendPQExpBuffer(fnlist, "%s%s",
3678 appendPQExpBuffer(fn, ")");
3680 resetPQExpBuffer(delqry);
3681 appendPQExpBuffer(delqry, "DROP FUNCTION %s;\n", fn->data);
3683 rettypename = findTypeByOid(tinfo, numTypes, finfo[i].prorettype, zeroAsOpaque);
3685 if (rettypename == NULL)
3687 write_msg(NULL, "WARNING: function \"%s\" not dumped\n",
3690 write_msg(NULL, "reason: name of return data type (oid %s) not found\n",
3691 finfo[i].prorettype);
3695 resetPQExpBuffer(q);
3696 appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
3697 appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
3698 (finfo[i].retset) ? "SETOF " : "",
3701 formatStringLiteral(q, func_lang, CONV_ALL);
3703 if (finfo[i].provolatile != PROVOLATILE_VOLATILE ||
3704 finfo[i].isimplicit ||
3705 finfo[i].isstrict) /* OR in new attrs here */
3707 appendPQExpBuffer(q, " WITH (");
3708 listSep = listSepNone;
3710 if (finfo[i].provolatile == PROVOLATILE_IMMUTABLE)
3712 appendPQExpBuffer(q, "%s isImmutable", listSep);
3713 listSep = listSepComma;
3715 else if (finfo[i].provolatile == PROVOLATILE_STABLE)
3717 appendPQExpBuffer(q, "%s isStable", listSep);
3718 listSep = listSepComma;
3720 else if (finfo[i].provolatile != PROVOLATILE_VOLATILE)
3722 write_msg(NULL, "Unexpected provolatile value for function %s\n",
3727 if (finfo[i].isimplicit)
3729 appendPQExpBuffer(q, "%s implicitCoercion", listSep);
3730 listSep = listSepComma;
3733 if (finfo[i].isstrict)
3735 appendPQExpBuffer(q, "%s isStrict", listSep);
3736 listSep = listSepComma;
3739 appendPQExpBuffer(q, " )");
3742 appendPQExpBuffer(q, ";\n");
3744 ArchiveEntry(fout, finfo[i].oid, fn->data, "FUNCTION", NULL, q->data, delqry->data,
3745 "", finfo[i].usename, NULL, NULL);
3747 /*** Dump Function Comments ***/
3749 resetPQExpBuffer(q);
3750 appendPQExpBuffer(q, "FUNCTION %s ",
3751 fmtId(finfo[i].proname, force_quotes));
3752 appendPQExpBuffer(q, "( %s )", fnlist->data);
3753 dumpComment(fout, q->data, finfo[i].oid, "pg_proc", 0, NULL);
3756 destroyPQExpBuffer(q);
3757 destroyPQExpBuffer(fn);
3758 destroyPQExpBuffer(delqry);
3759 destroyPQExpBuffer(fnlist);
3760 destroyPQExpBuffer(asPart);
3766 * writes out to fout the queries to recreate all the user-defined operators
3770 dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators,
3771 TypeInfo *tinfo, int numTypes)
3774 PQExpBuffer q = createPQExpBuffer();
3775 PQExpBuffer delq = createPQExpBuffer();
3776 PQExpBuffer leftarg = createPQExpBuffer();
3777 PQExpBuffer rightarg = createPQExpBuffer();
3778 PQExpBuffer commutator = createPQExpBuffer();
3779 PQExpBuffer negator = createPQExpBuffer();
3780 PQExpBuffer restrictor = createPQExpBuffer();
3781 PQExpBuffer join = createPQExpBuffer();
3782 PQExpBuffer sort1 = createPQExpBuffer();
3783 PQExpBuffer sort2 = createPQExpBuffer();
3785 for (i = 0; i < numOperators; i++)
3789 resetPQExpBuffer(leftarg);
3790 resetPQExpBuffer(rightarg);
3791 resetPQExpBuffer(commutator);
3792 resetPQExpBuffer(negator);
3793 resetPQExpBuffer(restrictor);
3794 resetPQExpBuffer(join);
3795 resetPQExpBuffer(sort1);
3796 resetPQExpBuffer(sort2);
3798 /* skip all the builtin oids */
3799 if (atooid(oprinfo[i].oid) <= g_last_builtin_oid)
3803 * some operator are invalid because they were the result of user
3804 * defining operators before commutators exist
3806 if (strcmp(oprinfo[i].oprcode, "-") == 0)
3810 * right unary means there's a left arg and left unary means
3811 * there's a right arg
3813 if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
3814 strcmp(oprinfo[i].oprkind, "b") == 0)
3816 name = findTypeByOid(tinfo, numTypes,
3817 oprinfo[i].oprleft, zeroAsOpaque);
3820 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3821 oprinfo[i].oprname, oprinfo[i].oid);
3822 write_msg(NULL, "reason: oprleft (oid %s) not found\n",
3823 oprinfo[i].oprleft);
3826 appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ", name);
3829 if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
3830 strcmp(oprinfo[i].oprkind, "b") == 0)
3832 name = findTypeByOid(tinfo, numTypes,
3833 oprinfo[i].oprright, zeroAsOpaque);
3836 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3837 oprinfo[i].oprname, oprinfo[i].oid);
3838 write_msg(NULL, "reason: oprright (oid %s) not found\n",
3839 oprinfo[i].oprright);
3842 appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ", name);
3845 if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
3847 name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom);
3850 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3851 oprinfo[i].oprname, oprinfo[i].oid);
3852 write_msg(NULL, "reason: oprcom (oid %s) not found\n",
3856 appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ", name);
3859 if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
3861 name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate);
3864 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3865 oprinfo[i].oprname, oprinfo[i].oid);
3866 write_msg(NULL, "reason: oprnegate (oid %s) not found\n",
3867 oprinfo[i].oprnegate);
3870 appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ", name);
3873 if (!(strcmp(oprinfo[i].oprrest, "-") == 0))
3874 appendPQExpBuffer(restrictor, ",\n\tRESTRICT = %s ", oprinfo[i].oprrest);
3876 if (!(strcmp(oprinfo[i].oprjoin, "-") == 0))
3877 appendPQExpBuffer(join, ",\n\tJOIN = %s ", oprinfo[i].oprjoin);
3879 if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
3881 name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop);
3884 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3885 oprinfo[i].oprname, oprinfo[i].oid);
3886 write_msg(NULL, "reason: oprlsortop (oid %s) not found\n",
3887 oprinfo[i].oprlsortop);
3890 appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ", name);
3893 if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
3895 name = findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop);
3898 write_msg(NULL, "WARNING: operator \"%s\" (oid %s) not dumped\n",
3899 oprinfo[i].oprname, oprinfo[i].oid);
3900 write_msg(NULL, "reason: oprrsortop (oid %s) not found\n",
3901 oprinfo[i].oprrsortop);
3904 appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ", name);
3907 resetPQExpBuffer(delq);
3908 appendPQExpBuffer(delq, "DROP OPERATOR %s (%s",
3910 findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft,
3912 appendPQExpBuffer(delq, ", %s);\n",
3913 findTypeByOid(tinfo, numTypes, oprinfo[i].oprright,
3916 resetPQExpBuffer(q);
3917 appendPQExpBuffer(q,
3918 "CREATE OPERATOR %s "
3919 "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);\n",
3927 (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
3932 ArchiveEntry(fout, oprinfo[i].oid, oprinfo[i].oprname, "OPERATOR", NULL,
3933 q->data, delq->data, "", oprinfo[i].usename, NULL, NULL);
3936 destroyPQExpBuffer(q);
3937 destroyPQExpBuffer(delq);
3938 destroyPQExpBuffer(leftarg);
3939 destroyPQExpBuffer(rightarg);
3940 destroyPQExpBuffer(commutator);
3941 destroyPQExpBuffer(negator);
3942 destroyPQExpBuffer(restrictor);
3943 destroyPQExpBuffer(join);
3944 destroyPQExpBuffer(sort1);
3945 destroyPQExpBuffer(sort2);
3950 * writes out to fout the queries to create all the user-defined aggregates
3954 dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
3955 TypeInfo *tinfo, int numTypes)
3958 PQExpBuffer q = createPQExpBuffer();
3959 PQExpBuffer delq = createPQExpBuffer();
3960 PQExpBuffer aggSig = createPQExpBuffer();
3961 PQExpBuffer details = createPQExpBuffer();
3963 for (i = 0; i < numAggs; i++)
3967 resetPQExpBuffer(details);
3969 /* skip all the builtin oids */
3970 if (oidle(atooid(agginfo[i].oid), g_last_builtin_oid))
3973 resetPQExpBuffer(aggSig);
3974 appendPQExpBuffer(aggSig, "%s(%s)", agginfo[i].aggname,
3975 findTypeByOid(tinfo, numTypes,
3976 agginfo[i].aggbasetype,
3977 zeroAsStar + useBaseTypeName));
3979 if (!agginfo[i].convertok)
3981 write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
3984 resetPQExpBuffer(q);
3985 appendPQExpBuffer(q, "-- WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
3987 ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
3988 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
3992 name = findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype,
3993 zeroAsAny + useBaseTypeName);
3996 write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
3997 agginfo[i].aggname, agginfo[i].oid);
3998 write_msg(NULL, "reason: aggbasetype (oid %s) not found\n",
3999 agginfo[i].aggbasetype);
4001 resetPQExpBuffer(q);
4002 appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
4003 appendPQExpBuffer(q, "-- reason: aggbasetype (oid %s) not found\n", agginfo[i].aggbasetype);
4004 ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
4005 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
4008 appendPQExpBuffer(details, "BASETYPE = %s, ", name);
4010 name = findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype,
4011 zeroAsOpaque + useBaseTypeName);
4014 write_msg(NULL, "WARNING: aggregate function \"%s\" (oid %s) not dumped\n",
4015 agginfo[i].aggname, agginfo[i].oid);
4016 write_msg(NULL, "reason: aggtranstype (oid %s) not found\n",
4017 agginfo[i].aggtranstype);
4019 resetPQExpBuffer(q);
4020 appendPQExpBuffer(q, "-- WARNING: aggregate function \"%s\" (oid %s) not dumped\n", agginfo[i].aggname, agginfo[i].oid);
4021 appendPQExpBuffer(q, "-- reason: aggtranstype (oid %s) not found\n", agginfo[i].aggtranstype);
4022 ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "WARNING", NULL,
4023 q->data, "" /* Del */ , "", agginfo[i].usename, NULL, NULL);
4026 appendPQExpBuffer(details,
4027 "SFUNC = %s, STYPE = %s",
4028 agginfo[i].aggtransfn, name);
4030 if (agginfo[i].agginitval)
4032 appendPQExpBuffer(details, ", INITCOND = ");
4033 formatStringLiteral(details, agginfo[i].agginitval, CONV_ALL);
4036 if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
4037 appendPQExpBuffer(details, ", FINALFUNC = %s",
4038 agginfo[i].aggfinalfn);
4040 resetPQExpBuffer(delq);
4041 appendPQExpBuffer(delq, "DROP AGGREGATE %s;\n", aggSig->data);
4043 resetPQExpBuffer(q);
4044 appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s );\n",
4048 ArchiveEntry(fout, agginfo[i].oid, aggSig->data, "AGGREGATE", NULL,
4049 q->data, delq->data, "", agginfo[i].usename, NULL, NULL);
4051 /*** Dump Aggregate Comments ***/
4053 resetPQExpBuffer(q);
4054 appendPQExpBuffer(q, "AGGREGATE %s", aggSig->data);
4055 if (g_fout->remoteVersion < 70300)
4056 dumpComment(fout, q->data, agginfo[i].oid, "pg_aggregate",
4059 dumpComment(fout, q->data, agginfo[i].oid, "pg_proc",
4063 destroyPQExpBuffer(q);
4064 destroyPQExpBuffer(delq);
4065 destroyPQExpBuffer(aggSig);
4066 destroyPQExpBuffer(details);
4070 * These are some support functions to fix the acl problem of pg_dump
4072 * Matthew C. Aycock 12/02/97
4075 /* Append a keyword to a keyword list, inserting comma if needed.
4076 * Caller must make aclbuf big enough for all possible keywords.
4079 AddAcl(char *aclbuf, const char *keyword)
4082 strcat(aclbuf, ",");
4083 strcat(aclbuf, keyword);
4087 * This will take a string of privilege code letters and return a malloced,
4088 * comma delimited string of keywords for GRANT.
4090 * Note: for cross-version compatibility, it's important to use ALL when
4094 GetPrivileges(Archive *AH, const char *s)
4101 #define CONVERT_PRIV(code,keywd) \
4102 if (strchr(s, code)) \
4103 AddAcl(aclbuf, keywd); \
4107 CONVERT_PRIV('a', "INSERT");
4108 CONVERT_PRIV('r', "SELECT");
4109 CONVERT_PRIV('R', "RULE");
4111 if (AH->remoteVersion >= 70200)
4113 CONVERT_PRIV('w', "UPDATE");
4114 CONVERT_PRIV('d', "DELETE");
4115 CONVERT_PRIV('x', "REFERENCES");
4116 CONVERT_PRIV('t', "TRIGGER");
4120 /* 7.0 and 7.1 have a simpler worldview */
4121 CONVERT_PRIV('w', "UPDATE,DELETE");
4127 return strdup("ALL");
4129 return strdup(aclbuf);
4133 * The name says it all; a function to append a string if the dest
4134 * is big enough. If not, it does a realloc.
4137 strcatalloc(char **dest, int *dSize, char *src)
4139 int dLen = strlen(*dest);
4140 int sLen = strlen(src);
4142 if ((dLen + sLen) >= *dSize)
4144 *dSize = (dLen + sLen) * 2;
4145 *dest = realloc(*dest, *dSize);
4147 strcpy(*dest + dLen, src);
4153 * Write out grant/revoke information
4154 * Called for sequences and tables
4158 dumpACL(Archive *fout, TableInfo tbinfo)
4160 const char *acls = tbinfo.relacl;
4170 if (strlen(acls) == 0)
4171 return; /* table has default permissions */
4174 * Allocate a larginsh buffer for the output SQL.
4176 sql = (char *) malloc(sSize);
4179 * Revoke Default permissions for PUBLIC. Is this actually necessary,
4180 * or is it just a waste of time?
4182 sprintf(sql, "REVOKE ALL on %s from PUBLIC;\n",
4183 fmtId(tbinfo.relname, force_quotes));
4185 /* Make a working copy of acls so we can use strtok */
4186 aclbuf = strdup(acls);
4188 /* Scan comma-separated ACL items */
4189 for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
4192 * Token may start with '{' and/or '"'. Actually only the start
4193 * of the string should have '{', but we don't verify that.
4200 /* User name is string up to = in tok */
4201 eqpos = strchr(tok, '=');
4204 write_msg(NULL, "could not parse ACL list ('%s') for relation %s\n",
4205 acls, tbinfo.relname);
4210 * Parse the privileges (right-hand side). Skip if there are
4213 priv = GetPrivileges(fout, eqpos + 1);
4216 sprintf(tmp, "GRANT %s on %s to ",
4217 priv, fmtId(tbinfo.relname, force_quotes));
4218 strcatalloc(&sql, &sSize, tmp);
4221 * Note: fmtId() can only be called once per printf, so don't
4222 * try to merge printing of username into the above printf.
4226 /* Empty left-hand side means "PUBLIC" */
4227 strcatalloc(&sql, &sSize, "PUBLIC;\n");
4231 *eqpos = '\0'; /* it's ok to clobber aclbuf */
4232 if (strncmp(tok, "group ", strlen("group ")) == 0)
4233 sprintf(tmp, "GROUP %s;\n",
4234 fmtId(tok + strlen("group "), force_quotes));
4236 sprintf(tmp, "%s;\n", fmtId(tok, force_quotes));
4237 strcatalloc(&sql, &sSize, tmp);
4245 if (tbinfo.viewdef != NULL)
4246 objoid = tbinfo.viewoid;
4248 objoid = tbinfo.oid;
4250 ArchiveEntry(fout, objoid, tbinfo.relname, "ACL", NULL, sql, "", "", "", NULL, NULL);
4254 _dumpTableAttr70(TableInfo *tblinfo, int i, int j, PQExpBuffer q)
4260 /* Show lengths on bpchar and varchar */
4261 if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
4263 int len = (tblinfo[i].atttypmod[j] - VARHDRSZ);
4265 appendPQExpBuffer(q, "character");
4267 appendPQExpBuffer(q, "(%d)",
4268 tblinfo[i].atttypmod[j] - VARHDRSZ);
4270 else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
4272 appendPQExpBuffer(q, "character varying");
4273 if (tblinfo[i].atttypmod[j] != -1)
4275 appendPQExpBuffer(q, "(%d)",
4276 tblinfo[i].atttypmod[j] - VARHDRSZ);
4279 else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
4281 appendPQExpBuffer(q, "numeric");
4282 if (tblinfo[i].atttypmod[j] != -1)
4284 tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
4285 precision = (tmp_typmod >> 16) & 0xffff;
4286 scale = tmp_typmod & 0xffff;
4287 appendPQExpBuffer(q, "(%d,%d)",
4293 * char is an internal single-byte data type; Let's make sure we force
4294 * it through with quotes. - thomas 1998-12-13
4296 else if (!strcmp(tblinfo[i].typnames[j], "char"))
4298 appendPQExpBuffer(q, "%s",
4299 fmtId(tblinfo[i].typnames[j], true));
4303 appendPQExpBuffer(q, "%s",
4304 fmtId(tblinfo[i].typnames[j], false));
4310 * write out to fout all the user-define tables
4314 dumpTables(Archive *fout, TableInfo *tblinfo, int numTables,
4315 const char *tablename, const bool aclsSkip,
4316 const bool schemaOnly, const bool dataOnly)
4321 PQExpBuffer q = createPQExpBuffer();
4322 PQExpBuffer delq = createPQExpBuffer();
4323 char *serialSeq = NULL; /* implicit sequence name created
4324 * by SERIAL datatype */
4325 const char *serialSeqSuffix = "_id_seq"; /* suffix for implicit
4326 * SERIAL sequences */
4327 char **parentRels; /* list of names of parent relations */
4329 int actual_atts; /* number of attrs in this CREATE statment */
4332 const char *((*commentDeps)[]);
4334 /* First - dump SEQUENCEs */
4335 if (tablename && strlen(tablename) > 0)
4337 /* XXX this code only works for serial columns named "id" */
4338 /* We really need dependency analysis! */
4339 serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
4340 strcpy(serialSeq, tablename);
4341 strcat(serialSeq, serialSeqSuffix);
4343 for (i = 0; i < numTables; i++)
4345 if (tblinfo[i].relkind != RELKIND_SEQUENCE)
4347 if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
4348 || (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
4350 /* becomeUser(fout, tblinfo[i].usename); */
4351 dumpSequence(fout, tblinfo[i], schemaOnly, dataOnly);
4353 dumpACL(fout, tblinfo[i]);
4359 for (i = 0; i < numTables; i++)
4361 if (tblinfo[i].relkind == RELKIND_SEQUENCE) /* already dumped */
4364 if (!tablename || (!strcmp(tblinfo[i].relname, tablename)) || (strlen(tablename) == 0))
4367 resetPQExpBuffer(delq);
4368 resetPQExpBuffer(q);
4370 /* Use the view definition if there is one */
4371 if (tblinfo[i].viewdef != NULL)
4373 reltypename = "VIEW";
4374 objoid = tblinfo[i].viewoid;
4375 appendPQExpBuffer(delq, "DROP VIEW %s;\n", fmtId(tblinfo[i].relname, force_quotes));
4376 appendPQExpBuffer(q, "CREATE VIEW %s as %s\n", fmtId(tblinfo[i].relname, force_quotes), tblinfo[i].viewdef);
4379 * Views can have default values -- however, they must be
4380 * specified in an ALTER TABLE command after the view has
4381 * been created, not in the view definition itself.
4383 for (j = 0; j < tblinfo[i].numatts; j++)
4385 if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0) {
4386 appendPQExpBuffer(q, "ALTER TABLE %s ", fmtId(tblinfo[i].relname, force_quotes));
4387 appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
4388 fmtId(tblinfo[i].attnames[j], force_quotes),
4389 tblinfo[i].adef_expr[j]);
4393 commentDeps = malloc(sizeof(char *) * 2);
4394 (*commentDeps)[0] = strdup(objoid);
4395 (*commentDeps)[1] = NULL; /* end of list */
4399 reltypename = "TABLE";
4400 objoid = tblinfo[i].oid;
4402 parentRels = tblinfo[i].parentRels;
4403 numParents = tblinfo[i].numParents;
4405 appendPQExpBuffer(delq, "DROP TABLE %s;\n", fmtId(tblinfo[i].relname, force_quotes));
4407 appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
4409 for (j = 0; j < tblinfo[i].numatts; j++)
4411 /* Is this one of the table's own attrs ? */
4412 if (tblinfo[i].inhAttrs[j] == 0)
4414 /* Format properly if not first attr */
4415 if (actual_atts > 0)
4416 appendPQExpBuffer(q, ",\n\t");
4418 /* Attr name & type */
4419 appendPQExpBuffer(q, "%s ", fmtId(tblinfo[i].attnames[j], force_quotes));
4421 if (g_fout->remoteVersion >= 70100)
4422 appendPQExpBuffer(q, "%s", tblinfo[i].atttypedefns[j]);
4424 _dumpTableAttr70(tblinfo, i, j, q);
4427 if (tblinfo[i].adef_expr[j] != NULL && tblinfo[i].inhAttrDef[j] == 0)
4428 appendPQExpBuffer(q, " DEFAULT %s",
4429 tblinfo[i].adef_expr[j]);
4431 /* Not Null constraint */
4432 if (tblinfo[i].notnull[j] && tblinfo[i].inhNotNull[j] == 0)
4433 appendPQExpBuffer(q, " NOT NULL");
4441 /* Put the CONSTRAINTS inside the table def */
4442 for (k = 0; k < tblinfo[i].ncheck; k++)
4444 if (actual_atts + k > 0)
4445 appendPQExpBuffer(q, ",\n\t");
4447 appendPQExpBuffer(q, "%s",
4448 tblinfo[i].check_expr[k]);
4452 * Primary Key: In versions of PostgreSQL prior to 7.2, we
4453 * needed to include the primary key in the table definition.
4454 * However, this is not ideal because it creates an index
4455 * on the table, which makes COPY slower. As of release 7.2,
4456 * we can add primary keys to a table after is has been created,
4457 * using ALTER TABLE ; see dumpIndexes() for more information.
4458 * Therefore, we ignore primary keys in this function.
4461 appendPQExpBuffer(q, "\n)");
4465 appendPQExpBuffer(q, "\nINHERITS (");
4466 for (k = 0; k < numParents; k++)
4468 appendPQExpBuffer(q, "%s%s",
4469 (k > 0) ? ", " : "",
4470 fmtId(parentRels[k], force_quotes));
4472 appendPQExpBuffer(q, ")");
4475 if (!tblinfo[i].hasoids)
4476 appendPQExpBuffer(q, " WITHOUT OIDS");
4478 appendPQExpBuffer(q, ";\n");
4484 ArchiveEntry(fout, objoid, tblinfo[i].relname,
4485 reltypename, NULL, q->data, delq->data, "", tblinfo[i].usename,
4489 dumpACL(fout, tblinfo[i]);
4493 /* Dump Field Comments */
4495 for (j = 0; j < tblinfo[i].numatts; j++)
4497 resetPQExpBuffer(q);
4498 appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
4499 appendPQExpBuffer(q, ".");
4500 appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
4501 dumpComment(fout, q->data, tblinfo[i].oid,
4502 "pg_class", j + 1, commentDeps);
4505 /* Dump Table Comments */
4507 resetPQExpBuffer(q);
4508 appendPQExpBuffer(q, "%s %s", reltypename, fmtId(tblinfo[i].relname, force_quotes));
4509 dumpComment(fout, q->data, tblinfo[i].oid,
4510 "pg_class", 0, commentDeps);
4515 destroyPQExpBuffer(q);
4516 destroyPQExpBuffer(delq);
4520 getPKconstraint(TableInfo *tblInfo, IndInfo *indInfo)
4522 PQExpBuffer pkBuf = createPQExpBuffer();
4525 appendPQExpBuffer(pkBuf, "Constraint %s Primary Key (",
4526 tblInfo->primary_key_name);
4528 for (k = 0; k < indInfo->indnkeys; k++)
4531 const char *attname;
4533 indkey = atoi(indInfo->indkey[k]);
4534 if (indkey == InvalidAttrNumber)
4536 attname = getAttrName(indkey, tblInfo);
4538 appendPQExpBuffer(pkBuf, "%s%s",
4539 (k == 0) ? "" : ", ",
4540 fmtId(attname, force_quotes));
4543 appendPQExpBuffer(pkBuf, ")");
4549 * getAttrName: extract the correct name for an attribute
4551 * The array tblInfo->attnames[] only provides names of user attributes;
4552 * if a system attribute number is supplied, we have to fake it.
4553 * We also do a little bit of bounds checking for safety's sake.
4556 getAttrName(int attrnum, TableInfo *tblInfo)
4558 if (attrnum > 0 && attrnum <= tblInfo->numatts)
4559 return tblInfo->attnames[attrnum - 1];
4562 case SelfItemPointerAttributeNumber:
4564 case ObjectIdAttributeNumber:
4566 case MinTransactionIdAttributeNumber:
4568 case MinCommandIdAttributeNumber:
4570 case MaxTransactionIdAttributeNumber:
4572 case MaxCommandIdAttributeNumber:
4574 case TableOidAttributeNumber:
4577 write_msg(NULL, "getAttrName(): invalid column number %d for table %s\n",
4578 attrnum, tblInfo->relname);
4580 return NULL; /* keep compiler quiet */
4585 * write out to fout all the user-defined indexes
4588 dumpIndexes(Archive *fout, IndInfo *indinfo, int numIndexes,
4589 TableInfo *tblinfo, int numTables, const char *tablename)
4593 PQExpBuffer q = createPQExpBuffer();
4594 PQExpBuffer delq = createPQExpBuffer();
4595 PQExpBuffer id1 = createPQExpBuffer();
4597 for (i = 0; i < numIndexes; i++)
4599 if (tablename && tablename[0] &&
4600 (strcmp(indinfo[i].indrelname, tablename) != 0))
4603 tableInd = findTableByName(tblinfo, numTables,
4604 indinfo[i].indrelname);
4607 write_msg(NULL, "dumpIndexes(): failed sanity check, table %s was not found\n",
4608 indinfo[i].indrelname);
4612 /* Handle PK indexes */
4613 if (strcmp(indinfo[i].indisprimary, "t") == 0)
4615 PQExpBuffer consDef = getPKconstraint(&tblinfo[tableInd], &indinfo[i]);
4617 resetPQExpBuffer(q);
4619 appendPQExpBuffer(q, "Alter Table %s Add %s;",
4620 fmtId(tblinfo[tableInd].relname, force_quotes),
4623 ArchiveEntry(fout, indinfo[i].indexreloid, tblinfo[tableInd].primary_key_name,
4624 "CONSTRAINT", NULL, q->data, "",
4625 "", tblinfo[tableInd].usename, NULL, NULL);
4627 destroyPQExpBuffer(consDef);
4630 * Don't need to do anything else for this system-generated
4636 resetPQExpBuffer(id1);
4637 appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
4639 resetPQExpBuffer(q);
4640 appendPQExpBuffer(q, "%s;\n", indinfo[i].indexdef);
4642 resetPQExpBuffer(delq);
4643 appendPQExpBuffer(delq, "DROP INDEX %s;\n", id1->data);
4646 * We make the index belong to the owner of its table, which is
4647 * not necessarily right but should answer 99% of the time. Would
4648 * have to add owner name to IndInfo to do it right.
4650 ArchiveEntry(fout, indinfo[i].indexreloid, id1->data,
4651 "INDEX", NULL, q->data, delq->data,
4652 "", tblinfo[tableInd].usename, NULL, NULL);
4654 /* Dump Index Comments */
4655 resetPQExpBuffer(q);
4656 appendPQExpBuffer(q, "INDEX %s", id1->data);
4657 dumpComment(fout, q->data, indinfo[i].indexreloid,
4658 "pg_class", 0, NULL);
4661 destroyPQExpBuffer(q);
4662 destroyPQExpBuffer(delq);
4663 destroyPQExpBuffer(id1);
4668 * prints out the tuples in ASCII representation. The output is a valid
4669 * input to COPY FROM stdin.
4671 * We only need to do this for POSTGRES 4.2 databases since the
4672 * COPY TO statment doesn't escape newlines properly. It's been fixed
4675 * the attrmap passed in tells how to map the attributes copied in to the
4676 * attributes copied out
4680 dumpTuples(PGresult *res, FILE *fout, int *attrmap)
4686 char **outVals = NULL; /* values to copy out */
4694 * Print out the tuples but only print tuples with at least 1
4697 outVals = (char **) malloc(m * sizeof(char *));
4699 for (j = 0; j < n; j++)
4701 for (k = 0; k < m; k++)
4702 outVals[attrmap[k]] = PQgetvalue(res, j, k);
4703 for (k = 0; k < m; k++)
4705 char *pval = outVals[k];
4708 fputc('\t', fout); /* delimiter for attribute */
4712 while (*pval != '\0')
4714 /* escape tabs, newlines and backslashes */
4715 if (*pval == '\t' || *pval == '\n' || *pval == '\\')
4722 fputc('\n', fout); /* delimiter for a tuple */
4731 * find the maximum oid and generate a COPY statement to set it
4735 setMaxOid(Archive *fout)
4741 res = PQexec(g_conn, "CREATE TEMPORARY TABLE pgdump_oid (dummy int4)");
4743 PQresultStatus(res) != PGRES_COMMAND_OK)
4745 write_msg(NULL, "could not create pgdump_oid table: %s", PQerrorMessage(g_conn));
4749 res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
4751 PQresultStatus(res) != PGRES_COMMAND_OK)
4753 write_msg(NULL, "could not insert into pgdump_oid table: %s", PQerrorMessage(g_conn));
4756 max_oid = PQoidValue(res);
4759 write_msg(NULL, "inserted invalid oid\n");
4763 res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
4765 PQresultStatus(res) != PGRES_COMMAND_OK)
4767 write_msg(NULL, "could not drop pgdump_oid table: %s", PQerrorMessage(g_conn));
4772 write_msg(NULL, "maximum system oid is %u\n", max_oid);
4774 "CREATE TEMPORARY TABLE pgdump_oid (dummy int4);\n"
4775 "COPY pgdump_oid WITH OIDS FROM stdin;\n"
4778 "DROP TABLE pgdump_oid;\n",
4781 ArchiveEntry(fout, "0", "Max OID", "<Init>", NULL, sql, "", "", "", NULL, NULL);
4785 * findLastBuiltInOid -
4786 * find the last built in oid
4787 * we do this by retrieving datlastsysoid from the pg_database entry for this database,
4791 findLastBuiltinOid_V71(const char *dbname)
4796 PQExpBuffer query = createPQExpBuffer();
4798 resetPQExpBuffer(query);
4799 appendPQExpBuffer(query, "SELECT datlastsysoid from pg_database where datname = ");
4800 formatStringLiteral(query, dbname, CONV_ALL);
4802 res = PQexec(g_conn, query->data);
4804 PQresultStatus(res) != PGRES_TUPLES_OK)
4806 write_msg(NULL, "error in finding the last system oid: %s", PQerrorMessage(g_conn));
4809 ntups = PQntuples(res);
4812 write_msg(NULL, "missing pg_database entry for this database\n");
4817 write_msg(NULL, "found more than one pg_database entry for this database\n");
4820 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
4822 destroyPQExpBuffer(query);
4827 * findLastBuiltInOid -
4828 * find the last built in oid
4829 * we do this by looking up the oid of 'template1' in pg_database,
4830 * this is probably not foolproof but comes close
4834 findLastBuiltinOid_V70(void)
4840 res = PQexec(g_conn,
4841 "SELECT oid from pg_database where datname = 'template1'");
4843 PQresultStatus(res) != PGRES_TUPLES_OK)
4845 write_msg(NULL, "error in finding the template1 database: %s", PQerrorMessage(g_conn));
4848 ntups = PQntuples(res);
4851 write_msg(NULL, "could not find template1 database entry in the pg_database table\n");
4856 write_msg(NULL, "found more than one template1 database entry in the pg_database table\n");
4859 last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "oid")));
4865 dumpSequence(Archive *fout, TableInfo tbinfo, const bool schemaOnly, const bool dataOnly)
4875 PQExpBuffer query = createPQExpBuffer();
4876 PQExpBuffer delqry = createPQExpBuffer();
4878 appendPQExpBuffer(query,
4879 "SELECT sequence_name, last_value, increment_by, max_value, "
4880 "min_value, cache_value, is_cycled, is_called from %s",
4881 fmtId(tbinfo.relname, force_quotes));
4883 res = PQexec(g_conn, query->data);
4884 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
4886 write_msg(NULL, "query to get data of sequence \"%s\" failed: %s", tbinfo.relname, PQerrorMessage(g_conn));
4890 if (PQntuples(res) != 1)
4892 write_msg(NULL, "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
4893 tbinfo.relname, PQntuples(res));
4897 /* Disable this check: it fails if sequence has been renamed */
4899 if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
4901 write_msg(NULL, "query to get data of sequence \"%s\" returned name \"%s\"\n",
4902 tbinfo.relname, PQgetvalue(res, 0, 0));
4907 last = PQgetvalue(res, 0, 1);
4908 incby = PQgetvalue(res, 0, 2);
4909 maxv = PQgetvalue(res, 0, 3);
4910 minv = PQgetvalue(res, 0, 4);
4911 cache = PQgetvalue(res, 0, 5);
4912 cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
4913 called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
4916 * The logic we use for restoring sequences is as follows: - Add a
4917 * basic CREATE SEQUENCE statement (use last_val for start if called
4918 * is false, else use min_val for start_val).
4920 * Add a 'SETVAL(seq, last_val, iscalled)' at restore-time iff we load
4926 resetPQExpBuffer(delqry);
4927 appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
4928 fmtId(tbinfo.relname, force_quotes));
4930 resetPQExpBuffer(query);
4931 appendPQExpBuffer(query,
4932 "CREATE SEQUENCE %s start %s increment %s "
4933 "maxvalue %s minvalue %s cache %s%s;\n",
4934 fmtId(tbinfo.relname, force_quotes),
4935 (called ? minv : last),
4936 incby, maxv, minv, cache,
4937 (cycled ? " cycle" : ""));
4939 ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE", NULL,
4940 query->data, delqry->data, "", tbinfo.usename,
4946 resetPQExpBuffer(query);
4947 appendPQExpBuffer(query, "SELECT setval (");
4948 formatStringLiteral(query, fmtId(tbinfo.relname, force_quotes), CONV_ALL);
4949 appendPQExpBuffer(query, ", %s, %s);\n",
4950 last, (called ? "true" : "false"));
4952 ArchiveEntry(fout, tbinfo.oid, tbinfo.relname, "SEQUENCE SET", NULL,
4953 query->data, "" /* Del */ , "", tbinfo.usename,
4959 /* Dump Sequence Comments */
4961 resetPQExpBuffer(query);
4962 appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
4963 dumpComment(fout, query->data, tbinfo.oid,
4964 "pg_class", 0, NULL);
4969 destroyPQExpBuffer(query);
4970 destroyPQExpBuffer(delqry);
4975 dumpTriggers(Archive *fout, const char *tablename,
4976 TableInfo *tblinfo, int numTables)
4982 write_msg(NULL, "dumping out triggers\n");
4984 for (i = 0; i < numTables; i++)
4986 if (tablename && (strcmp(tblinfo[i].relname, tablename) != 0) && (strlen(tablename) > 0))
4989 for (j = 0; j < tblinfo[i].ntrig; j++)
4991 ArchiveEntry(fout, tblinfo[i].triggers[j].oid, tblinfo[i].triggers[j].tgname,
4992 "TRIGGER", NULL, tblinfo[i].triggers[j].tgsrc, "", "",
4993 tblinfo[i].usename, NULL, NULL);
4994 dumpComment(fout, tblinfo[i].triggers[j].tgcomment, tblinfo[i].triggers[j].oid,
4995 "pg_trigger", 0, NULL);
5002 dumpRules(Archive *fout, const char *tablename,
5003 TableInfo *tblinfo, int numTables)
5009 PQExpBuffer query = createPQExpBuffer();
5017 write_msg(NULL, "dumping out rules\n");
5020 * For each table we dump
5022 for (t = 0; t < numTables; t++)
5024 if (tablename && (strcmp(tblinfo[t].relname, tablename) != 0) && (strlen(tablename) > 0))
5028 * Get all rules defined for this table, except view select rules
5030 resetPQExpBuffer(query);
5032 if (g_fout->remoteVersion < 70300)
5035 * We include pg_rules in the cross since it filters out all view
5036 * rules (pjw 15-Sep-2000).
5038 appendPQExpBuffer(query, "SELECT definition,"
5039 " (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
5040 " pg_rewrite.oid, pg_rewrite.rulename "
5041 "FROM pg_rewrite, pg_class, pg_rules "
5042 "WHERE pg_class.relname = ");
5043 formatStringLiteral(query, tblinfo[t].relname, CONV_ALL);
5044 appendPQExpBuffer(query,
5045 " AND pg_rewrite.ev_class = pg_class.oid "
5046 " AND pg_rules.tablename = pg_class.relname "
5047 " AND pg_rules.rulename = pg_rewrite.rulename "
5048 "ORDER BY pg_rewrite.oid");
5052 appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.oid) AS definition,"
5053 " (select usename from pg_user where pg_class.relowner = usesysid) AS viewowner, "
5054 " pg_rewrite.oid, pg_rewrite.rulename "
5055 "FROM pg_rewrite, pg_class "
5056 "WHERE pg_class.oid = '%s'::oid "
5057 " AND pg_rewrite.ev_class = pg_class.oid "
5058 " AND pg_rewrite.rulename != '_RETURN' "
5059 "ORDER BY pg_rewrite.oid",
5063 res = PQexec(g_conn, query->data);
5065 PQresultStatus(res) != PGRES_TUPLES_OK)
5067 write_msg(NULL, "query to get rules associated with table \"%s\" failed: %s",
5068 tblinfo[t].relname, PQerrorMessage(g_conn));
5072 nrules = PQntuples(res);
5073 i_definition = PQfnumber(res, "definition");
5074 i_owner = PQfnumber(res, "viewowner");
5075 i_oid = PQfnumber(res, "oid");
5076 i_rulename = PQfnumber(res, "rulename");
5082 for (i = 0; i < nrules; i++)
5084 ArchiveEntry(fout, PQgetvalue(res, i, i_oid), PQgetvalue(res, i, i_rulename),
5085 "RULE", NULL, PQgetvalue(res, i, i_definition),
5086 "", "", PQgetvalue(res, i, i_owner), NULL, NULL);
5088 /* Dump rule comments */
5090 resetPQExpBuffer(query);
5091 appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename), force_quotes));
5092 appendPQExpBuffer(query, " ON %s", fmtId(tblinfo[t].relname, force_quotes));
5093 dumpComment(fout, query->data, PQgetvalue(res, i, i_oid),
5094 "pg_rewrite", 0, NULL);
5101 destroyPQExpBuffer(query);