1 /*-------------------------------------------------------------------------
4 * pg_dump is an utility for dumping out a postgres database
7 * pg_dump will read the system catalogs in a database and
8 * dump out a script that reproduces
9 * the schema of the database in terms of
11 * user-defined functions
18 * the output script is SQL that is understood by PostgreSQL
20 * Copyright (c) 1994, Regents of the University of California
24 * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.127 1999/12/27 15:42:43 momjian Exp $
26 * Modifications - 6/10/96 - dave@bensoft.com - version 1.13.dhb
28 * Applied 'insert string' patch from "Marc G. Fournier" <scrappy@ki.net>
29 * Added '-t table' option
33 * Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
35 * - Fixed dumpTable output to output lengths for char and varchar types!
36 * - Added single. quote to twin single quote expansion for 'insert' string
39 * Modifications - 7/26/96 - asussman@vidya.com
41 * - Fixed ouput lengths for char and varchar type where the length is variable (-1)
43 * Modifications - 6/1/97 - igor@sba.miami.edu
44 * - Added functions to free allocated memory used for retrieving
45 * indices,tables,inheritance,types,functions and aggregates.
46 * No more leaks reported by Purify.
49 * Modifications - 1/26/98 - pjlobo@euitt.upm.es
50 * - Added support for password authentication
51 *-------------------------------------------------------------------------
54 #include <unistd.h> /* for getopt() */
66 #include "access/attnum.h"
67 #include "access/htup.h"
68 #include "catalog/pg_index.h"
69 #include "catalog/pg_language.h"
70 #include "catalog/pg_trigger.h"
71 #include "catalog/pg_type.h"
80 static void dumpSequence(FILE *fout, TableInfo tbinfo);
81 static void dumpACL(FILE *fout, TableInfo tbinfo);
82 static void dumpTriggers(FILE *fout, const char *tablename,
83 TableInfo *tblinfo, int numTables);
84 static void dumpRules(FILE *fout, const char *tablename,
85 TableInfo *tblinfo, int numTables);
86 static char *checkForQuote(const char *s);
87 static void clearTableInfo(TableInfo *, int);
88 static void dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
89 TypeInfo *tinfo, int numTypes);
90 static int findLastBuiltinOid(void);
91 static bool isViewRule(char *relname);
92 static void setMaxOid(FILE *fout);
94 static void AddAcl(char *aclbuf, const char *keyword);
95 static char *GetPrivileges(const char *s);
96 static void becomeUser(FILE *fout, const char *username);
103 bool g_verbose; /* User wants verbose narration of our
105 int g_last_builtin_oid; /* value of the last builtin oid */
106 FILE *g_fout; /* the script file */
107 PGconn *g_conn; /* the database connection */
109 bool force_quotes; /* User wants to suppress double-quotes */
110 bool dumpData; /* dump data using proper insert strings */
111 bool attrNames; /* put attr names into insert strings */
117 char g_opaque_type[10]; /* name for the opaque type */
119 /* placeholders for the delimiters for comments */
120 char g_comment_start[10];
121 char g_comment_end[10];
125 usage(const char *progname)
128 "\nUsage: %s [options] dbname\n\n", progname);
130 #ifdef HAVE_GETOPT_LONG
133 " -a, --data-only dump out only the data, no schema\n"
134 " -c, --clean clean(drop) schema prior to create\n"
135 " -d, --insert-proper dump data as proper insert strings\n"
136 " -D, --insert-attr dump data as inserts with attribute names\n"
137 " -f, --out file script output filename\n"
138 " -h, --host hostname server host name\n"
139 " -n, --no-quotes suppress most quotes around identifiers\n"
140 " -N, --quotes enable most quotes around identifiers\n"
141 " -o, --oids dump object id's (oids)\n"
142 " -p, --port port server port number\n"
143 " -s, --schema-only dump out only the schema, no data\n"
144 " -t, --table table dump for this table only\n"
145 " -u, --password use password authentication\n"
146 " -v, --verbose verbose\n"
147 " -x, --no-acl do not dump ACL's (grant/revoke)\n"
148 " -?, --help show this help message\n"
154 " -a dump out only the data, no schema\n"
155 " -c clean(drop) schema prior to create\n"
156 " -d dump data as proper insert strings\n"
157 " -D dump data as inserts with attribute names\n"
158 " -f filename script output filename\n"
159 " -h hostname server host name\n"
160 " -n suppress most quotes around identifiers\n"
161 " -N enable most quotes around identifiers\n"
162 " -o dump object id's (oids)\n"
163 " -p port server port number\n"
164 " -s dump out only the schema, no data\n"
165 " -t table dump for this table only\n"
166 " -u use password authentication\n"
168 " -x do not dump ACL's (grant/revoke)\n"
169 " -? show this help message\n"
175 "\nIf dbname is not supplied, then the DATABASE environment variable value is used.\n\n");
181 exit_nicely(PGconn *conn)
190 * Determine if the relation is a VIEW
194 isViewRule(char *relname)
198 PQExpBuffer query = createPQExpBuffer();
200 appendPQExpBuffer(query, "select relname from pg_class, pg_rewrite ");
201 appendPQExpBuffer(query, "where pg_class.oid = ev_class ");
202 appendPQExpBuffer(query, "and pg_rewrite.ev_type = '1' ");
203 appendPQExpBuffer(query, "and rulename = '_RET%s'", relname);
205 res = PQexec(g_conn, query->data);
207 PQresultStatus(res) != PGRES_TUPLES_OK)
209 fprintf(stderr, "isViewRule(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
213 ntups = PQntuples(res);
216 return ntups > 0 ? TRUE : FALSE;
219 #define COPYBUFSIZ 8192
223 dumpClasses_nodumpData(FILE *fout, const char *classname, const bool oids)
230 char copybuf[COPYBUFSIZ];
234 fprintf(fout, "COPY %s WITH OIDS FROM stdin;\n",
235 fmtId(classname, force_quotes));
236 sprintf(query, "COPY %s WITH OIDS TO stdout;\n",
237 fmtId(classname, force_quotes));
241 fprintf(fout, "COPY %s FROM stdin;\n", fmtId(classname, force_quotes));
242 sprintf(query, "COPY %s TO stdout;\n", fmtId(classname, force_quotes));
244 res = PQexec(g_conn, query);
246 PQresultStatus(res) == PGRES_FATAL_ERROR)
248 fprintf(stderr, "SQL query to dump the contents of Table '%s' "
249 "did not execute. Explanation from backend: '%s'.\n"
250 "The query was: '%s'.\n",
251 classname, PQerrorMessage(g_conn), query);
256 if (PQresultStatus(res) != PGRES_COPY_OUT)
258 fprintf(stderr, "SQL query to dump the contents of Table '%s' "
259 "executed abnormally.\n"
260 "PQexec() returned status %d when %d was expected.\n"
261 "The query was: '%s'.\n",
262 classname, PQresultStatus(res), PGRES_COPY_OUT, query);
270 ret = PQgetline(g_conn, copybuf, COPYBUFSIZ);
272 if (copybuf[0] == '\\' &&
276 copydone = true; /* don't print this... */
280 fputs(copybuf, fout);
294 fprintf(fout, "\\.\n");
296 ret = PQendcopy(g_conn);
299 fprintf(stderr, "SQL query to dump the contents of Table '%s' "
300 "did not execute correctly. After we read all the "
301 "table contents from the backend, PQendcopy() failed. "
302 "Explanation from backend: '%s'.\n"
303 "The query was: '%s'.\n",
304 classname, PQerrorMessage(g_conn), query);
314 dumpClasses_dumpData(FILE *fout, const char *classname)
317 PQExpBuffer q = createPQExpBuffer();
322 appendPQExpBuffer(q, "SELECT * FROM %s", fmtId(classname, force_quotes));
323 res = PQexec(g_conn, q->data);
325 PQresultStatus(res) != PGRES_TUPLES_OK)
327 fprintf(stderr, "dumpClasses(): command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
330 for (tuple = 0; tuple < PQntuples(res); tuple++)
332 fprintf(fout, "INSERT INTO %s ", fmtId(classname, force_quotes));
333 if (attrNames == true)
336 appendPQExpBuffer(q, "(");
337 for (field = 0; field < PQnfields(res); field++)
340 appendPQExpBuffer(q, ",");
341 appendPQExpBuffer(q, fmtId(PQfname(res, field), force_quotes));
343 appendPQExpBuffer(q, ") ");
344 fprintf(fout, "%s", q->data);
346 fprintf(fout, "VALUES (");
347 for (field = 0; field < PQnfields(res); field++)
351 if (PQgetisnull(res, tuple, field))
353 fprintf(fout, "NULL");
356 switch (PQftype(res, field))
360 case OIDOID: /* int types */
362 case FLOAT8OID: /* float types */
363 /* These types are printed without quotes */
365 PQgetvalue(res, tuple, field));
369 * All other types are printed as string literals,
370 * with appropriate escaping of special
371 * characters. Quote mark ' goes to '' per SQL
372 * standard, other stuff goes to \ sequences.
375 expsrc = PQgetvalue(res, tuple, field);
380 if (ch == '\\' || ch == '\'')
382 putc(ch, fout); /* double these */
385 else if (ch < '\040')
387 /* generate octal escape for control chars */
389 putc(((ch >> 6) & 3) + '0', fout);
390 putc(((ch >> 3) & 7) + '0', fout);
391 putc((ch & 7) + '0', fout);
400 fprintf(fout, ");\n");
409 * dump the contents of all the classes.
412 dumpClasses(const TableInfo *tblinfo, const int numTables, FILE *fout,
413 const char *onlytable, const bool oids)
419 if (onlytable == NULL)
425 fprintf(stderr, "%s dumping out the contents of %s %d table%s/sequence%s %s\n",
426 g_comment_start, all_only,
427 (onlytable == NULL) ? numTables : 1,
428 (onlytable == NULL) ? "s" : "", (onlytable == NULL) ? "s" : "",
431 /* Dump SEQUENCEs first (if dataOnly) */
434 for (i = 0; i < numTables; i++)
436 if (!(tblinfo[i].sequence))
438 if (!onlytable || (!strcmp(tblinfo[i].relname, onlytable)))
441 fprintf(stderr, "%s dumping out schema of sequence '%s' %s\n",
442 g_comment_start, tblinfo[i].relname, g_comment_end);
443 becomeUser(fout, tblinfo[i].usename);
444 dumpSequence(fout, tblinfo[i]);
449 for (i = 0; i < numTables; i++)
451 const char *classname = tblinfo[i].relname;
453 /* Skip VIEW relations */
454 if (isViewRule(tblinfo[i].relname))
457 if (tblinfo[i].sequence)/* already dumped */
460 if (!onlytable || (!strcmp(classname, onlytable)))
463 fprintf(stderr, "%s dumping out the contents of Table '%s' %s\n",
464 g_comment_start, classname, g_comment_end);
466 becomeUser(fout, tblinfo[i].usename);
469 dumpClasses_nodumpData(fout, classname, oids);
471 dumpClasses_dumpData(fout, classname);
478 prompt_for_password(char *username, char *password)
483 #ifdef HAVE_TERMIOS_H
484 struct termios t_orig,
489 printf("Username: ");
490 fgets(username, 100, stdin);
491 length = strlen(username);
492 /* skip rest of the line */
493 if (length > 0 && username[length - 1] != '\n')
497 fgets(buf, 512, stdin);
498 } while (buf[strlen(buf) - 1] != '\n');
500 if (length > 0 && username[length - 1] == '\n')
501 username[length - 1] = '\0';
503 printf("Password: ");
504 #ifdef HAVE_TERMIOS_H
508 tcsetattr(0, TCSADRAIN, &t);
510 fgets(password, 100, stdin);
511 #ifdef HAVE_TERMIOS_H
512 tcsetattr(0, TCSADRAIN, &t_orig);
515 length = strlen(password);
516 /* skip rest of the line */
517 if (length > 0 && password[length - 1] != '\n')
521 fgets(buf, 512, stdin);
522 } while (buf[strlen(buf) - 1] != '\n');
524 if (length > 0 && password[length - 1] == '\n')
525 password[length - 1] = '\0';
532 main(int argc, char **argv)
535 const char *progname;
536 const char *filename = NULL;
537 const char *dbname = NULL;
538 const char *pghost = NULL;
539 const char *pgport = NULL;
540 char *tablename = NULL;
544 char connect_string[512] = "";
545 char tmp_string[128];
548 bool use_password = false;
550 #ifdef HAVE_GETOPT_LONG
551 static struct option long_options[] = {
552 {"data-only", no_argument, NULL, 'a'},
553 {"clean", no_argument, NULL, 'c'},
554 {"insert-proper",no_argument, NULL, 'd'},
555 {"insert-attr", no_argument, NULL, 'D'},
556 {"out", required_argument, NULL, 'f'},
557 {"to-file", required_argument, NULL, 'f'},
558 {"host", required_argument, NULL, 'h'},
559 {"no-quotes", no_argument, NULL, 'n'},
560 {"quotes", no_argument, NULL, 'N'},
561 {"oids", no_argument, NULL, 'o'},
562 {"port", required_argument, NULL, 'p'},
563 {"schema-only", no_argument, NULL, 's'},
564 {"table", required_argument, NULL, 't'},
565 {"password", no_argument, NULL, 'u'},
566 {"verbose", no_argument, NULL, 'v'},
567 {"no-acl", no_argument, NULL, 'x'},
568 {"help", no_argument, NULL, '?'},
577 strcpy(g_comment_start, "-- ");
578 g_comment_end[0] = '\0';
579 strcpy(g_opaque_type, "opaque");
581 dataOnly = schemaOnly = dumpData = attrNames = false;
585 #ifdef HAVE_GETOPT_LONG
586 while ((c = getopt_long(argc, argv, "acdDf:h:nNop:st:uvxz?", long_options, &optindex)) != -1)
588 while ((c = getopt(argc, argv, "acdDf:h:nNop:st:uvxz?")) != -1)
593 case 'a': /* Dump data only */
596 case 'c': /* clean (i.e., drop) schema prior to
600 case 'd': /* dump data as proper insert strings */
603 case 'D': /* dump data as proper insert strings with
608 case 'f': /* output file name */
611 case 'h': /* server host */
614 case 'n': /* Do not force double-quotes on
616 force_quotes = false;
618 case 'N': /* Force double-quotes on identifiers */
621 case 'o': /* Dump oids */
624 case 'p': /* server port */
627 case 's': /* dump schema only */
630 case 't': /* Dump data for this table only */
634 tablename = strdup(optarg);
637 * quoted string? Then strip quotes and preserve
640 if (tablename[0] == '"')
642 strcpy(tablename, &tablename[1]);
643 if (*(tablename + strlen(tablename) - 1) == '"')
644 *(tablename + strlen(tablename) - 1) = '\0';
646 /* otherwise, convert table name to lowercase... */
649 for (i = 0; tablename[i]; i++)
650 if (isascii((unsigned char) tablename[i]) &&
651 isupper(tablename[i]))
652 tablename[i] = tolower(tablename[i]);
659 case 'v': /* verbose */
662 case 'x': /* skip ACL dump */
665 case 'z': /* Old ACL option bjm 1999/05/27 */
667 "%s: The -z option(dump ACLs) is now the default, continuing.\n",
677 if (dumpData == true && oids == true)
680 "%s: INSERT's can not set oids, so INSERT and OID options can not be used together.\n",
685 /* open the output file */
686 if (filename == NULL)
691 g_fout = fopen(filename, "w");
693 g_fout = fopen(filename, "wb");
698 "%s: could not open output file named %s for writing\n",
705 if (!(dbname = argv[optind]) &&
706 !(dbname = getenv("DATABASE")))
708 fprintf(stderr, "%s: no database name specified\n", progname);
712 /* g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); */
715 sprintf(tmp_string, "host=%s ", pghost);
716 strcat(connect_string, tmp_string);
720 sprintf(tmp_string, "port=%s ", pgport);
721 strcat(connect_string, tmp_string);
725 sprintf(tmp_string, "dbname=%s ", dbname);
726 strcat(connect_string, tmp_string);
730 prompt_for_password(username, password);
731 strcat(connect_string, "authtype=password ");
732 sprintf(tmp_string, "user=%s ", username);
733 strcat(connect_string, tmp_string);
734 sprintf(tmp_string, "password=%s ", password);
735 strcat(connect_string, tmp_string);
736 MemSet(tmp_string, 0, sizeof(tmp_string));
737 MemSet(password, 0, sizeof(password));
739 g_conn = PQconnectdb(connect_string);
740 MemSet(connect_string, 0, sizeof(connect_string));
741 /* check to see that the backend connection was successfully made */
742 if (PQstatus(g_conn) == CONNECTION_BAD)
744 fprintf(stderr, "Connection to database '%s' failed.\n", dbname);
745 fprintf(stderr, "%s\n", PQerrorMessage(g_conn));
750 * Start serializable transaction to dump consistent data
755 res = PQexec(g_conn, "begin");
756 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
758 fprintf(stderr, "BEGIN command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
762 res = PQexec(g_conn, "set transaction isolation level serializable");
763 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
765 fprintf(stderr, "SET TRANSACTION command failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
771 g_last_builtin_oid = findLastBuiltinOid();
778 fprintf(stderr, "%s last builtin oid is %u %s\n",
779 g_comment_start, g_last_builtin_oid, g_comment_end);
780 tblinfo = dumpSchema(g_fout, &numTables, tablename, aclsSkip);
783 tblinfo = dumpSchema(NULL, &numTables, tablename, aclsSkip);
786 dumpClasses(tblinfo, numTables, g_fout, tablename, oids);
788 if (!dataOnly) /* dump indexes and triggers at the end
791 dumpSchemaIdx(g_fout, tablename, tblinfo, numTables);
792 dumpTriggers(g_fout, tablename, tblinfo, numTables);
793 dumpRules(g_fout, tablename, tblinfo, numTables);
797 if (g_fout != stdout)
800 clearTableInfo(tblinfo, numTables);
807 * read all base types in the system catalogs and return them in the
808 * TypeInfo* structure
810 * numTypes is set to the number of types read in
814 getTypes(int *numTypes)
819 PQExpBuffer query = createPQExpBuffer();
838 /* find all base types */
841 * we include even the built-in types because those may be used as
842 * array elements by user-defined types
846 * we filter out the built-in types when we dump out the types
849 appendPQExpBuffer(query, "SELECT pg_type.oid, typowner, typname, typlen, typprtlen, "
850 "typinput, typoutput, typreceive, typsend, typelem, typdelim, "
851 "typdefault, typrelid, typbyval, usename from pg_type, pg_user "
852 "where typowner = usesysid");
854 res = PQexec(g_conn, query->data);
856 PQresultStatus(res) != PGRES_TUPLES_OK)
858 fprintf(stderr, "getTypes(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
862 ntups = PQntuples(res);
864 tinfo = (TypeInfo *) malloc(ntups * sizeof(TypeInfo));
866 i_oid = PQfnumber(res, "oid");
867 i_typowner = PQfnumber(res, "typowner");
868 i_typname = PQfnumber(res, "typname");
869 i_typlen = PQfnumber(res, "typlen");
870 i_typprtlen = PQfnumber(res, "typprtlen");
871 i_typinput = PQfnumber(res, "typinput");
872 i_typoutput = PQfnumber(res, "typoutput");
873 i_typreceive = PQfnumber(res, "typreceive");
874 i_typsend = PQfnumber(res, "typsend");
875 i_typelem = PQfnumber(res, "typelem");
876 i_typdelim = PQfnumber(res, "typdelim");
877 i_typdefault = PQfnumber(res, "typdefault");
878 i_typrelid = PQfnumber(res, "typrelid");
879 i_typbyval = PQfnumber(res, "typbyval");
880 i_usename = PQfnumber(res, "usename");
882 for (i = 0; i < ntups; i++)
884 tinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
885 tinfo[i].typowner = strdup(PQgetvalue(res, i, i_typowner));
886 tinfo[i].typname = strdup(PQgetvalue(res, i, i_typname));
887 tinfo[i].typlen = strdup(PQgetvalue(res, i, i_typlen));
888 tinfo[i].typprtlen = strdup(PQgetvalue(res, i, i_typprtlen));
889 tinfo[i].typinput = strdup(PQgetvalue(res, i, i_typinput));
890 tinfo[i].typoutput = strdup(PQgetvalue(res, i, i_typoutput));
891 tinfo[i].typreceive = strdup(PQgetvalue(res, i, i_typreceive));
892 tinfo[i].typsend = strdup(PQgetvalue(res, i, i_typsend));
893 tinfo[i].typelem = strdup(PQgetvalue(res, i, i_typelem));
894 tinfo[i].typdelim = strdup(PQgetvalue(res, i, i_typdelim));
895 tinfo[i].typdefault = strdup(PQgetvalue(res, i, i_typdefault));
896 tinfo[i].typrelid = strdup(PQgetvalue(res, i, i_typrelid));
897 tinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
899 if (strcmp(PQgetvalue(res, i, i_typbyval), "f") == 0)
900 tinfo[i].passedbyvalue = 0;
902 tinfo[i].passedbyvalue = 1;
905 * check for user-defined array types, omit system generated ones
907 if ((strcmp(tinfo[i].typelem, "0") != 0) &&
908 tinfo[i].typname[0] != '_')
909 tinfo[i].isArray = 1;
911 tinfo[i].isArray = 0;
923 * read all operators in the system catalogs and return them in the
926 * numOprs is set to the number of operators read in
931 getOperators(int *numOprs)
936 PQExpBuffer query = createPQExpBuffer();
956 * find all operators, including builtin operators, filter out
957 * system-defined operators at dump-out time
960 appendPQExpBuffer(query, "SELECT pg_operator.oid, oprname, oprkind, oprcode, "
961 "oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, "
962 "oprcanhash, oprlsortop, oprrsortop, usename "
963 "from pg_operator, pg_user "
964 "where oprowner = usesysid");
966 res = PQexec(g_conn, query->data);
968 PQresultStatus(res) != PGRES_TUPLES_OK)
970 fprintf(stderr, "getOperators(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
974 ntups = PQntuples(res);
977 oprinfo = (OprInfo *) malloc(ntups * sizeof(OprInfo));
979 i_oid = PQfnumber(res, "oid");
980 i_oprname = PQfnumber(res, "oprname");
981 i_oprkind = PQfnumber(res, "oprkind");
982 i_oprcode = PQfnumber(res, "oprcode");
983 i_oprleft = PQfnumber(res, "oprleft");
984 i_oprright = PQfnumber(res, "oprright");
985 i_oprcom = PQfnumber(res, "oprcom");
986 i_oprnegate = PQfnumber(res, "oprnegate");
987 i_oprrest = PQfnumber(res, "oprrest");
988 i_oprjoin = PQfnumber(res, "oprjoin");
989 i_oprcanhash = PQfnumber(res, "oprcanhash");
990 i_oprlsortop = PQfnumber(res, "oprlsortop");
991 i_oprrsortop = PQfnumber(res, "oprrsortop");
992 i_usename = PQfnumber(res, "usename");
994 for (i = 0; i < ntups; i++)
996 oprinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
997 oprinfo[i].oprname = strdup(PQgetvalue(res, i, i_oprname));
998 oprinfo[i].oprkind = strdup(PQgetvalue(res, i, i_oprkind));
999 oprinfo[i].oprcode = strdup(PQgetvalue(res, i, i_oprcode));
1000 oprinfo[i].oprleft = strdup(PQgetvalue(res, i, i_oprleft));
1001 oprinfo[i].oprright = strdup(PQgetvalue(res, i, i_oprright));
1002 oprinfo[i].oprcom = strdup(PQgetvalue(res, i, i_oprcom));
1003 oprinfo[i].oprnegate = strdup(PQgetvalue(res, i, i_oprnegate));
1004 oprinfo[i].oprrest = strdup(PQgetvalue(res, i, i_oprrest));
1005 oprinfo[i].oprjoin = strdup(PQgetvalue(res, i, i_oprjoin));
1006 oprinfo[i].oprcanhash = strdup(PQgetvalue(res, i, i_oprcanhash));
1007 oprinfo[i].oprlsortop = strdup(PQgetvalue(res, i, i_oprlsortop));
1008 oprinfo[i].oprrsortop = strdup(PQgetvalue(res, i, i_oprrsortop));
1009 oprinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1018 clearTypeInfo(TypeInfo *tp, int numTypes)
1022 for (i = 0; i < numTypes; ++i)
1027 free(tp[i].typowner);
1029 free(tp[i].typname);
1032 if (tp[i].typprtlen)
1033 free(tp[i].typprtlen);
1035 free(tp[i].typinput);
1036 if (tp[i].typoutput)
1037 free(tp[i].typoutput);
1038 if (tp[i].typreceive)
1039 free(tp[i].typreceive);
1041 free(tp[i].typsend);
1043 free(tp[i].typelem);
1045 free(tp[i].typdelim);
1046 if (tp[i].typdefault)
1047 free(tp[i].typdefault);
1049 free(tp[i].typrelid);
1051 free(tp[i].usename);
1057 clearFuncInfo(FuncInfo *fun, int numFuncs)
1064 for (i = 0; i < numFuncs; ++i)
1069 free(fun[i].proname);
1071 free(fun[i].usename);
1072 for (a = 0; a < 8; ++a)
1073 if (fun[i].argtypes[a])
1074 free(fun[i].argtypes[a]);
1075 if (fun[i].prorettype)
1076 free(fun[i].prorettype);
1078 free(fun[i].prosrc);
1080 free(fun[i].probin);
1086 clearTableInfo(TableInfo *tblinfo, int numTables)
1091 for (i = 0; i < numTables; ++i)
1095 free(tblinfo[i].oid);
1096 if (tblinfo[i].relacl)
1097 free(tblinfo[i].relacl);
1098 if (tblinfo[i].usename)
1099 free(tblinfo[i].usename);
1101 if (tblinfo[i].relname)
1102 free(tblinfo[i].relname);
1104 if (tblinfo[i].sequence)
1107 /* Process Attributes */
1108 for (j = 0; j < tblinfo[i].numatts; j++)
1110 if (tblinfo[i].attnames[j])
1111 free(tblinfo[i].attnames[j]);
1112 if (tblinfo[i].typnames[j])
1113 free(tblinfo[i].typnames[j]);
1115 if (tblinfo[i].atttypmod)
1116 free((int *) tblinfo[i].atttypmod);
1117 if (tblinfo[i].inhAttrs)
1118 free((int *) tblinfo[i].inhAttrs);
1119 if (tblinfo[i].attnames)
1120 free(tblinfo[i].attnames);
1121 if (tblinfo[i].typnames)
1122 free(tblinfo[i].typnames);
1123 if (tblinfo[i].notnull)
1124 free(tblinfo[i].notnull);
1125 if (tblinfo[i].primary_key)
1126 free(tblinfo[i].primary_key);
1132 clearInhInfo(InhInfo *inh, int numInherits)
1138 for (i = 0; i < numInherits; ++i)
1140 if (inh[i].inhrelid)
1141 free(inh[i].inhrelid);
1142 if (inh[i].inhparent)
1143 free(inh[i].inhparent);
1149 clearOprInfo(OprInfo *opr, int numOprs)
1155 for (i = 0; i < numOprs; ++i)
1160 free(opr[i].oprname);
1162 free(opr[i].oprkind);
1164 free(opr[i].oprcode);
1166 free(opr[i].oprleft);
1167 if (opr[i].oprright)
1168 free(opr[i].oprright);
1170 free(opr[i].oprcom);
1171 if (opr[i].oprnegate)
1172 free(opr[i].oprnegate);
1174 free(opr[i].oprrest);
1176 free(opr[i].oprjoin);
1177 if (opr[i].oprcanhash)
1178 free(opr[i].oprcanhash);
1179 if (opr[i].oprlsortop)
1180 free(opr[i].oprlsortop);
1181 if (opr[i].oprrsortop)
1182 free(opr[i].oprrsortop);
1184 free(opr[i].usename);
1190 clearIndInfo(IndInfo *ind, int numIndices)
1197 for (i = 0; i < numIndices; ++i)
1199 if (ind[i].indexrelname)
1200 free(ind[i].indexrelname);
1201 if (ind[i].indrelname)
1202 free(ind[i].indrelname);
1203 if (ind[i].indamname)
1204 free(ind[i].indamname);
1206 free(ind[i].indproc);
1207 if (ind[i].indisunique)
1208 free(ind[i].indisunique);
1209 for (a = 0; a < INDEX_MAX_KEYS; ++a)
1211 if (ind[i].indkey[a])
1212 free(ind[i].indkey[a]);
1213 if (ind[i].indclass[a])
1214 free(ind[i].indclass[a]);
1221 clearAggInfo(AggInfo *agginfo, int numArgs)
1227 for (i = 0; i < numArgs; ++i)
1230 free(agginfo[i].oid);
1231 if (agginfo[i].aggname)
1232 free(agginfo[i].aggname);
1233 if (agginfo[i].aggtransfn1)
1234 free(agginfo[i].aggtransfn1);
1235 if (agginfo[i].aggtransfn2)
1236 free(agginfo[i].aggtransfn2);
1237 if (agginfo[i].aggfinalfn)
1238 free(agginfo[i].aggfinalfn);
1239 if (agginfo[i].aggtranstype1)
1240 free(agginfo[i].aggtranstype1);
1241 if (agginfo[i].aggbasetype)
1242 free(agginfo[i].aggbasetype);
1243 if (agginfo[i].aggtranstype2)
1244 free(agginfo[i].aggtranstype2);
1245 if (agginfo[i].agginitval1)
1246 free(agginfo[i].agginitval1);
1247 if (agginfo[i].agginitval2)
1248 free(agginfo[i].agginitval2);
1249 if (agginfo[i].usename)
1250 free(agginfo[i].usename);
1257 * read all the user-defined aggregates in the system catalogs and
1258 * return them in the AggInfo* structure
1260 * numAggs is set to the number of aggregates read in
1265 getAggregates(int *numAggs)
1270 PQExpBuffer query = createPQExpBuffer();
1278 int i_aggtranstype1;
1280 int i_aggtranstype2;
1285 /* find all user-defined aggregates */
1287 appendPQExpBuffer(query,
1288 "SELECT pg_aggregate.oid, aggname, aggtransfn1, aggtransfn2, "
1289 "aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, "
1290 "agginitval1, agginitval2, usename from pg_aggregate, pg_user "
1291 "where aggowner = usesysid");
1293 res = PQexec(g_conn, query->data);
1295 PQresultStatus(res) != PGRES_TUPLES_OK)
1297 fprintf(stderr, "getAggregates(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1298 exit_nicely(g_conn);
1301 ntups = PQntuples(res);
1304 agginfo = (AggInfo *) malloc(ntups * sizeof(AggInfo));
1306 i_oid = PQfnumber(res, "oid");
1307 i_aggname = PQfnumber(res, "aggname");
1308 i_aggtransfn1 = PQfnumber(res, "aggtransfn1");
1309 i_aggtransfn2 = PQfnumber(res, "aggtransfn2");
1310 i_aggfinalfn = PQfnumber(res, "aggfinalfn");
1311 i_aggtranstype1 = PQfnumber(res, "aggtranstype1");
1312 i_aggbasetype = PQfnumber(res, "aggbasetype");
1313 i_aggtranstype2 = PQfnumber(res, "aggtranstype2");
1314 i_agginitval1 = PQfnumber(res, "agginitval1");
1315 i_agginitval2 = PQfnumber(res, "agginitval2");
1316 i_usename = PQfnumber(res, "usename");
1318 for (i = 0; i < ntups; i++)
1320 agginfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1321 agginfo[i].aggname = strdup(PQgetvalue(res, i, i_aggname));
1322 agginfo[i].aggtransfn1 = strdup(PQgetvalue(res, i, i_aggtransfn1));
1323 agginfo[i].aggtransfn2 = strdup(PQgetvalue(res, i, i_aggtransfn2));
1324 agginfo[i].aggfinalfn = strdup(PQgetvalue(res, i, i_aggfinalfn));
1325 agginfo[i].aggtranstype1 = strdup(PQgetvalue(res, i, i_aggtranstype1));
1326 agginfo[i].aggbasetype = strdup(PQgetvalue(res, i, i_aggbasetype));
1327 agginfo[i].aggtranstype2 = strdup(PQgetvalue(res, i, i_aggtranstype2));
1328 agginfo[i].agginitval1 = strdup(PQgetvalue(res, i, i_agginitval1));
1329 agginfo[i].agginitval2 = strdup(PQgetvalue(res, i, i_agginitval2));
1330 agginfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1340 * read all the user-defined functions in the system catalogs and
1341 * return them in the FuncInfo* structure
1343 * numFuncs is set to the number of functions read in
1348 getFuncs(int *numFuncs)
1353 PQExpBuffer query = createPQExpBuffer();
1367 /* find all user-defined funcs */
1369 appendPQExpBuffer(query,
1370 "SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
1371 "proretset, proargtypes, prosrc, probin, usename "
1372 "from pg_proc, pg_user "
1373 "where pg_proc.oid > '%u'::oid and proowner = usesysid",
1374 g_last_builtin_oid);
1376 res = PQexec(g_conn, query->data);
1378 PQresultStatus(res) != PGRES_TUPLES_OK)
1380 fprintf(stderr, "getFuncs(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1381 exit_nicely(g_conn);
1384 ntups = PQntuples(res);
1388 finfo = (FuncInfo *) malloc(ntups * sizeof(FuncInfo));
1390 i_oid = PQfnumber(res, "oid");
1391 i_proname = PQfnumber(res, "proname");
1392 i_prolang = PQfnumber(res, "prolang");
1393 i_pronargs = PQfnumber(res, "pronargs");
1394 i_proargtypes = PQfnumber(res, "proargtypes");
1395 i_prorettype = PQfnumber(res, "prorettype");
1396 i_proretset = PQfnumber(res, "proretset");
1397 i_prosrc = PQfnumber(res, "prosrc");
1398 i_probin = PQfnumber(res, "probin");
1399 i_usename = PQfnumber(res, "usename");
1401 for (i = 0; i < ntups; i++)
1403 finfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1404 finfo[i].proname = strdup(PQgetvalue(res, i, i_proname));
1406 finfo[i].prosrc = checkForQuote(PQgetvalue(res, i, i_prosrc));
1407 finfo[i].probin = strdup(PQgetvalue(res, i, i_probin));
1409 finfo[i].prorettype = strdup(PQgetvalue(res, i, i_prorettype));
1410 finfo[i].retset = (strcmp(PQgetvalue(res, i, i_proretset), "t") == 0);
1411 finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
1412 finfo[i].lang = atoi(PQgetvalue(res, i, i_prolang));
1414 finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1416 parseArgTypes(finfo[i].argtypes, PQgetvalue(res, i, i_proargtypes));
1418 finfo[i].dumped = 0;
1429 * read all the user-defined tables (no indices, no catalogs)
1430 * in the system catalogs return them in the TableInfo* structure
1432 * numTables is set to the number of tables read in
1437 getTables(int *numTables, FuncInfo *finfo, int numFuncs)
1442 PQExpBuffer query = createPQExpBuffer();
1455 * find all the user-defined tables (no indices and no catalogs),
1456 * ordering by oid is important so that we always process the parent
1457 * tables before the child tables when traversing the tblinfo*
1459 * we ignore tables that are not type 'r' (ordinary relation)
1460 * or 'S' (sequence) --- in particular, Large Object relations
1461 * (type 'l') are ignored.
1464 appendPQExpBuffer(query,
1465 "SELECT pg_class.oid, relname, relkind, relacl, usename, "
1466 "relchecks, reltriggers, relhasindex "
1467 "from pg_class, pg_user "
1468 "where relowner = usesysid and "
1469 "(relkind = 'r' or relkind = 'S') and relname !~ '^pg_' "
1472 res = PQexec(g_conn, query->data);
1474 PQresultStatus(res) != PGRES_TUPLES_OK)
1476 fprintf(stderr, "getTables(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1477 exit_nicely(g_conn);
1480 ntups = PQntuples(res);
1484 tblinfo = (TableInfo *) malloc(ntups * sizeof(TableInfo));
1486 i_oid = PQfnumber(res, "oid");
1487 i_relname = PQfnumber(res, "relname");
1488 i_relkind = PQfnumber(res, "relkind");
1489 i_relacl = PQfnumber(res, "relacl");
1490 i_usename = PQfnumber(res, "usename");
1491 i_relchecks = PQfnumber(res, "relchecks");
1492 i_reltriggers = PQfnumber(res, "reltriggers");
1493 i_relhasindex = PQfnumber(res, "relhasindex");
1495 for (i = 0; i < ntups; i++)
1497 tblinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
1498 tblinfo[i].relname = strdup(PQgetvalue(res, i, i_relname));
1499 tblinfo[i].relacl = strdup(PQgetvalue(res, i, i_relacl));
1500 tblinfo[i].sequence = (strcmp(PQgetvalue(res, i, i_relkind), "S") == 0);
1501 tblinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
1502 tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
1503 tblinfo[i].ntrig = atoi(PQgetvalue(res, i, i_reltriggers));
1506 * Exclude inherited CHECKs from CHECK constraints total. If a
1507 * constraint matches by name and condition with a constraint
1508 * belonging to a parent class, we assume it was inherited.
1510 if (tblinfo[i].ncheck > 0)
1516 fprintf(stderr, "%s excluding inherited CHECK constraints "
1517 "for relation: '%s' %s\n",
1522 resetPQExpBuffer(query);
1523 appendPQExpBuffer(query, "SELECT rcname from pg_relcheck, pg_inherits as i "
1524 "where rcrelid = '%s'::oid "
1525 " and rcrelid = i.inhrelid"
1527 " (select * from pg_relcheck as c "
1528 " where c.rcname = pg_relcheck.rcname "
1529 " and c.rcsrc = pg_relcheck.rcsrc "
1530 " and c.rcrelid = i.inhparent) ",
1532 res2 = PQexec(g_conn, query->data);
1534 PQresultStatus(res2) != PGRES_TUPLES_OK)
1536 fprintf(stderr, "getTables(): SELECT (for inherited CHECK) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1537 exit_nicely(g_conn);
1539 ntups2 = PQntuples(res2);
1540 tblinfo[i].ncheck -= ntups2;
1541 if (tblinfo[i].ncheck < 0)
1543 fprintf(stderr, "getTables(): found more inherited CHECKs than total for "
1545 tblinfo[i].relname);
1546 exit_nicely(g_conn);
1551 /* Get non-inherited CHECK constraints, if any */
1552 if (tblinfo[i].ncheck > 0)
1561 fprintf(stderr, "%s finding CHECK constraints for relation: '%s' %s\n",
1566 resetPQExpBuffer(query);
1567 appendPQExpBuffer(query, "SELECT rcname, rcsrc from pg_relcheck "
1568 "where rcrelid = '%s'::oid "
1570 " (select * from pg_relcheck as c, pg_inherits as i "
1571 " where i.inhrelid = pg_relcheck.rcrelid "
1572 " and c.rcname = pg_relcheck.rcname "
1573 " and c.rcsrc = pg_relcheck.rcsrc "
1574 " and c.rcrelid = i.inhparent) ",
1576 res2 = PQexec(g_conn, query->data);
1578 PQresultStatus(res2) != PGRES_TUPLES_OK)
1580 fprintf(stderr, "getTables(): SELECT (for CHECK) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1581 exit_nicely(g_conn);
1583 ntups2 = PQntuples(res2);
1584 if (ntups2 != tblinfo[i].ncheck)
1586 fprintf(stderr, "getTables(): relation '%s': %d CHECKs were expected, but got %d\n",
1587 tblinfo[i].relname, tblinfo[i].ncheck, ntups2);
1588 exit_nicely(g_conn);
1590 i_rcname = PQfnumber(res2, "rcname");
1591 i_rcsrc = PQfnumber(res2, "rcsrc");
1592 tblinfo[i].check_expr = (char **) malloc(ntups2 * sizeof(char *));
1593 for (i2 = 0; i2 < ntups2; i2++)
1595 const char *name = PQgetvalue(res2, i2, i_rcname);
1596 const char *expr = PQgetvalue(res2, i2, i_rcsrc);
1598 resetPQExpBuffer(query);
1600 appendPQExpBuffer(query, "CONSTRAINT %s ", fmtId(name, force_quotes));
1601 appendPQExpBuffer(query, "CHECK (%s)", expr);
1602 tblinfo[i].check_expr[i2] = strdup(query->data);
1607 tblinfo[i].check_expr = NULL;
1609 /* Get primary key */
1610 if (strcmp(PQgetvalue(res, i, i_relhasindex), "t")==0)
1613 char str[INDEX_MAX_KEYS * NAMEDATALEN + 3] = "";
1616 resetPQExpBuffer(query);
1617 appendPQExpBuffer(query,
1619 "FROM pg_index i, pg_class c, pg_attribute a "
1620 "WHERE i.indisprimary AND i.indrelid = %s "
1621 " AND i.indexrelid = c.oid AND a.attnum > 0 AND a.attrelid = c.oid "
1622 "ORDER BY a.attnum ",
1624 res2 = PQexec(g_conn, query->data);
1625 if (!res2 || PQresultStatus(res2) != PGRES_TUPLES_OK)
1627 fprintf(stderr, "getTables(): SELECT (for PRIMARY KEY) failed. Explanation from backend: %s",
1628 PQerrorMessage(g_conn));
1629 exit_nicely(g_conn);
1632 for (j = 0; j < PQntuples(res2); j++)
1636 strcat(str, fmtId(PQgetvalue(res2, j, 0), force_quotes));
1639 if (strlen(str)>0) {
1640 tblinfo[i].primary_key = strdup(str);
1641 if (tblinfo[i].primary_key == NULL) {
1647 tblinfo[i].primary_key = NULL;
1650 tblinfo[i].primary_key = NULL;
1653 if (tblinfo[i].ntrig > 0)
1665 fprintf(stderr, "%s finding Triggers for relation: '%s' %s\n",
1670 resetPQExpBuffer(query);
1671 appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs "
1673 "where tgrelid = '%s'::oid ",
1675 res2 = PQexec(g_conn, query->data);
1677 PQresultStatus(res2) != PGRES_TUPLES_OK)
1679 fprintf(stderr, "getTables(): SELECT (for TRIGGER) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1680 exit_nicely(g_conn);
1682 ntups2 = PQntuples(res2);
1683 if (ntups2 != tblinfo[i].ntrig)
1685 fprintf(stderr, "getTables(): relation '%s': %d Triggers were expected, but got %d\n",
1686 tblinfo[i].relname, tblinfo[i].ntrig, ntups2);
1687 exit_nicely(g_conn);
1689 i_tgname = PQfnumber(res2, "tgname");
1690 i_tgfoid = PQfnumber(res2, "tgfoid");
1691 i_tgtype = PQfnumber(res2, "tgtype");
1692 i_tgnargs = PQfnumber(res2, "tgnargs");
1693 i_tgargs = PQfnumber(res2, "tgargs");
1694 tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *));
1695 resetPQExpBuffer(query);
1696 for (i2 = 0; i2 < ntups2; i2++)
1698 const char *tgfunc = PQgetvalue(res2, i2, i_tgfoid);
1699 int2 tgtype = atoi(PQgetvalue(res2, i2, i_tgtype));
1700 int tgnargs = atoi(PQgetvalue(res2, i2, i_tgnargs));
1701 const char *tgargs = PQgetvalue(res2, i2, i_tgargs);
1703 char farg[MAX_QUERY_SIZE];
1706 for (findx = 0; findx < numFuncs; findx++)
1708 if (strcmp(finfo[findx].oid, tgfunc) == 0 &&
1709 finfo[findx].nargs == 0 &&
1710 strcmp(finfo[findx].prorettype, "0") == 0)
1713 if (findx == numFuncs)
1715 fprintf(stderr, "getTables(): relation '%s': cannot find function with oid %s for trigger %s\n",
1716 tblinfo[i].relname, tgfunc, PQgetvalue(res2, i2, i_tgname));
1717 exit_nicely(g_conn);
1719 tgfunc = finfo[findx].proname;
1722 /* XXX - how to emit this DROP TRIGGER? */
1725 resetPQExpBuffer(query);
1726 appendPQExpBuffer(query, "DROP TRIGGER %s ON %s;\n",
1727 fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes),
1728 fmtId(tblinfo[i].relname, force_quotes));
1729 fputs(query->data, fout);
1733 resetPQExpBuffer(query);
1734 appendPQExpBuffer(query, "CREATE TRIGGER %s ", fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
1737 if (TRIGGER_FOR_BEFORE(tgtype))
1738 appendPQExpBuffer(query, "BEFORE");
1740 appendPQExpBuffer(query, "AFTER");
1741 if (TRIGGER_FOR_INSERT(tgtype))
1743 appendPQExpBuffer(query, " INSERT");
1746 if (TRIGGER_FOR_DELETE(tgtype))
1749 appendPQExpBuffer(query, " OR DELETE");
1751 appendPQExpBuffer(query, " DELETE");
1754 if (TRIGGER_FOR_UPDATE(tgtype))
1757 appendPQExpBuffer(query, " OR UPDATE");
1759 appendPQExpBuffer(query, " UPDATE");
1761 appendPQExpBuffer(query, " ON %s FOR EACH ROW EXECUTE PROCEDURE %s (",
1762 fmtId(tblinfo[i].relname, force_quotes), tgfunc);
1763 for (findx = 0; findx < tgnargs; findx++)
1770 p = strchr(p, '\\');
1773 fprintf(stderr, "getTables(): relation '%s': bad argument string (%s) for trigger '%s'\n",
1775 PQgetvalue(res2, i2, i_tgargs),
1776 PQgetvalue(res2, i2, i_tgname));
1777 exit_nicely(g_conn);
1785 if (p[0] == '0' && p[1] == '0' && p[2] == '0')
1789 for (s = tgargs, d = &(farg[0]); s < p;)
1796 appendPQExpBuffer(query, "'%s'%s", farg,
1797 (findx < tgnargs - 1) ? ", " : "");
1800 appendPQExpBuffer(query, ");\n");
1801 tblinfo[i].triggers[i2] = strdup(query->data);
1806 tblinfo[i].triggers = NULL;
1817 * read all the inheritance information
1818 * from the system catalogs return them in the InhInfo* structure
1820 * numInherits is set to the number of tables read in
1825 getInherits(int *numInherits)
1830 PQExpBuffer query = createPQExpBuffer();
1836 /* find all the inheritance information */
1838 appendPQExpBuffer(query, "SELECT inhrelid, inhparent from pg_inherits");
1840 res = PQexec(g_conn, query->data);
1842 PQresultStatus(res) != PGRES_TUPLES_OK)
1844 fprintf(stderr, "getInherits(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1845 exit_nicely(g_conn);
1848 ntups = PQntuples(res);
1850 *numInherits = ntups;
1852 inhinfo = (InhInfo *) malloc(ntups * sizeof(InhInfo));
1854 i_inhrelid = PQfnumber(res, "inhrelid");
1855 i_inhparent = PQfnumber(res, "inhparent");
1857 for (i = 0; i < ntups; i++)
1859 inhinfo[i].inhrelid = strdup(PQgetvalue(res, i, i_inhrelid));
1860 inhinfo[i].inhparent = strdup(PQgetvalue(res, i, i_inhparent));
1869 * for each table in tblinfo, read its attributes types and names
1871 * this is implemented in a very inefficient way right now, looping
1872 * through the tblinfo and doing a join per table to find the attrs and their
1878 getTableAttrs(TableInfo *tblinfo, int numTables)
1882 PQExpBuffer q = createPQExpBuffer();
1891 for (i = 0; i < numTables; i++)
1894 if (tblinfo[i].sequence)
1897 /* find all the user attributes and their types */
1898 /* we must read the attribute names in attribute number order! */
1901 * because we will use the attnum to index into the attnames array
1905 fprintf(stderr, "%s finding the attrs and types for table: '%s' %s\n",
1910 resetPQExpBuffer(q);
1911 appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
1912 "a.attnotnull, a.atthasdef "
1913 "from pg_attribute a, pg_type t "
1914 "where a.attrelid = '%s'::oid and a.atttypid = t.oid "
1915 "and a.attnum > 0 order by attnum",
1917 res = PQexec(g_conn, q->data);
1919 PQresultStatus(res) != PGRES_TUPLES_OK)
1921 fprintf(stderr, "getTableAttrs(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1922 exit_nicely(g_conn);
1925 ntups = PQntuples(res);
1927 i_attname = PQfnumber(res, "attname");
1928 i_typname = PQfnumber(res, "typname");
1929 i_atttypmod = PQfnumber(res, "atttypmod");
1930 i_attnotnull = PQfnumber(res, "attnotnull");
1931 i_atthasdef = PQfnumber(res, "atthasdef");
1933 tblinfo[i].numatts = ntups;
1934 tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
1935 tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
1936 tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
1937 tblinfo[i].inhAttrs = (int *) malloc(ntups * sizeof(int));
1938 tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool));
1939 tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *));
1940 tblinfo[i].parentRels = NULL;
1941 tblinfo[i].numParents = 0;
1942 for (j = 0; j < ntups; j++)
1944 tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
1945 tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
1946 tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
1947 tblinfo[i].inhAttrs[j] = 0; /* this flag is set in
1949 tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't') ? true : false;
1950 if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
1955 fprintf(stderr, "%s finding DEFAULT expression for attr: '%s' %s\n",
1957 tblinfo[i].attnames[j],
1960 resetPQExpBuffer(q);
1961 appendPQExpBuffer(q, "SELECT adsrc from pg_attrdef "
1962 "where adrelid = '%s'::oid and adnum = %d ",
1963 tblinfo[i].oid, j + 1);
1964 res2 = PQexec(g_conn, q->data);
1966 PQresultStatus(res2) != PGRES_TUPLES_OK)
1968 fprintf(stderr, "getTableAttrs(): SELECT (for DEFAULT) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
1969 exit_nicely(g_conn);
1971 tblinfo[i].adef_expr[j] = strdup(PQgetvalue(res2, 0, PQfnumber(res2, "adsrc")));
1975 tblinfo[i].adef_expr[j] = NULL;
1984 * read all the user-defined indices information
1985 * from the system catalogs return them in the InhInfo* structure
1987 * numIndices is set to the number of indices read in
1992 getIndices(int *numIndices)
1995 PQExpBuffer query = createPQExpBuffer();
2009 * find all the user-defined indices. We do not handle partial
2012 * Notice we skip indices on inversion objects (relkind 'l')
2014 * this is a 4-way join !!
2017 appendPQExpBuffer(query,
2018 "SELECT t1.relname as indexrelname, t2.relname as indrelname, "
2019 "i.indproc, i.indkey, i.indclass, "
2020 "a.amname as indamname, i.indisunique "
2021 "from pg_index i, pg_class t1, pg_class t2, pg_am a "
2022 "WHERE t1.oid = i.indexrelid and t2.oid = i.indrelid "
2023 "and t1.relam = a.oid and i.indexrelid > '%u'::oid "
2024 "and t2.relname !~ '^pg_' and t2.relkind != 'l' and not i.indisprimary",
2025 g_last_builtin_oid);
2027 res = PQexec(g_conn, query->data);
2029 PQresultStatus(res) != PGRES_TUPLES_OK)
2031 fprintf(stderr, "getIndices(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2032 exit_nicely(g_conn);
2035 ntups = PQntuples(res);
2037 *numIndices = ntups;
2039 indinfo = (IndInfo *) malloc(ntups * sizeof(IndInfo));
2041 i_indexrelname = PQfnumber(res, "indexrelname");
2042 i_indrelname = PQfnumber(res, "indrelname");
2043 i_indamname = PQfnumber(res, "indamname");
2044 i_indproc = PQfnumber(res, "indproc");
2045 i_indkey = PQfnumber(res, "indkey");
2046 i_indclass = PQfnumber(res, "indclass");
2047 i_indisunique = PQfnumber(res, "indisunique");
2049 for (i = 0; i < ntups; i++)
2051 indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
2052 indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
2053 indinfo[i].indamname = strdup(PQgetvalue(res, i, i_indamname));
2054 indinfo[i].indproc = strdup(PQgetvalue(res, i, i_indproc));
2055 parseArgTypes((char **) indinfo[i].indkey,
2056 (const char *) PQgetvalue(res, i, i_indkey));
2057 parseArgTypes((char **) indinfo[i].indclass,
2058 (const char *) PQgetvalue(res, i, i_indclass));
2059 indinfo[i].indisunique = strdup(PQgetvalue(res, i, i_indisunique));
2067 * writes out to fout the queries to recreate all the user-defined types
2071 dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
2072 TypeInfo *tinfo, int numTypes)
2075 PQExpBuffer q = createPQExpBuffer();
2078 for (i = 0; i < numTypes; i++)
2081 /* skip all the builtin types */
2082 if (atoi(tinfo[i].oid) < g_last_builtin_oid)
2085 /* skip relation types */
2086 if (atoi(tinfo[i].typrelid) != 0)
2089 /* skip all array types that start w/ underscore */
2090 if ((tinfo[i].typname[0] == '_') &&
2091 (strcmp(tinfo[i].typinput, "array_in") == 0))
2095 * before we create a type, we need to create the input and output
2096 * functions for it, if they haven't been created already
2098 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
2100 dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2102 funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
2104 dumpOneFunc(fout, finfo, funcInd, tinfo, numTypes);
2106 becomeUser(fout, tinfo[i].usename);
2110 resetPQExpBuffer(q);
2111 appendPQExpBuffer(q, "DROP TYPE %s;\n", fmtId(tinfo[i].typname, force_quotes));
2112 fputs(q->data, fout);
2115 resetPQExpBuffer(q);
2116 appendPQExpBuffer(q,
2118 "( internallength = %s, externallength = %s, input = %s, "
2119 "output = %s, send = %s, receive = %s, default = '%s'",
2120 fmtId(tinfo[i].typname, force_quotes),
2126 tinfo[i].typreceive,
2127 tinfo[i].typdefault);
2129 if (tinfo[i].isArray)
2133 elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem);
2135 appendPQExpBuffer(q, ", element = %s, delimiter = '%s'",
2136 elemType, tinfo[i].typdelim);
2138 if (tinfo[i].passedbyvalue)
2139 appendPQExpBuffer(q, ",passedbyvalue);\n");
2141 appendPQExpBuffer(q, ");\n");
2143 fputs(q->data, fout);
2149 * writes out to fout the queries to recreate user-defined procedural languages
2153 dumpProcLangs(FILE *fout, FuncInfo *finfo, int numFuncs,
2154 TypeInfo *tinfo, int numTypes)
2157 PQExpBuffer query = createPQExpBuffer();
2161 int i_lanplcallfoid;
2165 const char *lanplcallfoid;
2169 appendPQExpBuffer(query, "SELECT * FROM pg_language "
2172 res = PQexec(g_conn, query->data);
2174 PQresultStatus(res) != PGRES_TUPLES_OK)
2176 fprintf(stderr, "dumpProcLangs(): SELECT failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2177 exit_nicely(g_conn);
2179 ntups = PQntuples(res);
2181 i_lanname = PQfnumber(res, "lanname");
2182 i_lanpltrusted = PQfnumber(res, "lanpltrusted");
2183 i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
2184 i_lancompiler = PQfnumber(res, "lancompiler");
2186 for (i = 0; i < ntups; i++)
2188 lanplcallfoid = PQgetvalue(res, i, i_lanplcallfoid);
2189 for (fidx = 0; fidx < numFuncs; fidx++)
2191 if (!strcmp(finfo[fidx].oid, lanplcallfoid))
2194 if (fidx >= numFuncs)
2196 fprintf(stderr, "dumpProcLangs(): handler procedure for language %s not found\n", PQgetvalue(res, i, i_lanname));
2197 exit_nicely(g_conn);
2200 dumpOneFunc(fout, finfo, fidx, tinfo, numTypes);
2202 lanname = checkForQuote(PQgetvalue(res, i, i_lanname));
2203 lancompiler = checkForQuote(PQgetvalue(res, i, i_lancompiler));
2206 fprintf(fout, "DROP PROCEDURAL LANGUAGE '%s';\n", lanname);
2208 fprintf(fout, "CREATE %sPROCEDURAL LANGUAGE '%s' "
2209 "HANDLER %s LANCOMPILER '%s';\n",
2210 (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? "TRUSTED " : "",
2212 fmtId(finfo[fidx].proname, force_quotes),
2225 * writes out to fout the queries to recreate all the user-defined functions
2229 dumpFuncs(FILE *fout, FuncInfo *finfo, int numFuncs,
2230 TypeInfo *tinfo, int numTypes)
2234 for (i = 0; i < numFuncs; i++)
2235 dumpOneFunc(fout, finfo, i, tinfo, numTypes);
2240 * dump out only one function, the index of which is given in the third
2246 dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
2247 TypeInfo *tinfo, int numTypes)
2249 PQExpBuffer q = createPQExpBuffer();
2252 char func_lang[NAMEDATALEN + 1];
2254 if (finfo[i].dumped)
2257 finfo[i].dumped = 1;
2259 becomeUser(fout, finfo[i].usename);
2261 if (finfo[i].lang == INTERNALlanguageId)
2263 func_def = finfo[i].prosrc;
2264 strcpy(func_lang, "INTERNAL");
2266 else if (finfo[i].lang == ClanguageId)
2268 func_def = finfo[i].probin;
2269 strcpy(func_lang, "C");
2271 else if (finfo[i].lang == SQLlanguageId)
2273 func_def = finfo[i].prosrc;
2274 strcpy(func_lang, "SQL");
2283 sprintf(query, "SELECT lanname FROM pg_language "
2286 res = PQexec(g_conn, query);
2288 PQresultStatus(res) != PGRES_TUPLES_OK)
2290 fprintf(stderr, "dumpOneFunc(): SELECT for procedural language failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2291 exit_nicely(g_conn);
2293 nlangs = PQntuples(res);
2297 fprintf(stderr, "dumpOneFunc(): procedural language for function %s not found\n", finfo[i].proname);
2298 exit_nicely(g_conn);
2301 i_lanname = PQfnumber(res, "lanname");
2303 func_def = finfo[i].prosrc;
2304 strcpy(func_lang, PQgetvalue(res, 0, i_lanname));
2312 resetPQExpBuffer(q);
2313 appendPQExpBuffer(q, "DROP FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
2314 for (j = 0; j < finfo[i].nargs; j++)
2318 typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
2319 appendPQExpBuffer(q, "%s%s",
2321 fmtId(typname, false));
2323 appendPQExpBuffer(q, ");\n");
2324 fputs(q->data, fout);
2327 resetPQExpBuffer(q);
2328 appendPQExpBuffer(q, "CREATE FUNCTION %s (", fmtId(finfo[i].proname, force_quotes));
2329 for (j = 0; j < finfo[i].nargs; j++)
2333 typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
2334 appendPQExpBuffer(q, "%s%s",
2336 fmtId(typname, false));
2338 appendPQExpBuffer(q, " ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n",
2339 (finfo[i].retset) ? " SETOF " : "",
2340 fmtId(findTypeByOid(tinfo, numTypes, finfo[i].prorettype), false),
2341 func_def, func_lang);
2343 fputs(q->data, fout);
2349 * writes out to fout the queries to recreate all the user-defined operators
2353 dumpOprs(FILE *fout, OprInfo *oprinfo, int numOperators,
2354 TypeInfo *tinfo, int numTypes)
2357 PQExpBuffer q = createPQExpBuffer();
2358 PQExpBuffer leftarg = createPQExpBuffer();
2359 PQExpBuffer rightarg = createPQExpBuffer();
2360 PQExpBuffer commutator = createPQExpBuffer();
2361 PQExpBuffer negator = createPQExpBuffer();
2362 PQExpBuffer restrictor = createPQExpBuffer();
2363 PQExpBuffer join = createPQExpBuffer();
2364 PQExpBuffer sort1 = createPQExpBuffer();
2365 PQExpBuffer sort2 = createPQExpBuffer();
2367 for (i = 0; i < numOperators; i++)
2370 resetPQExpBuffer(leftarg);
2371 resetPQExpBuffer(rightarg);
2372 resetPQExpBuffer(commutator);
2373 resetPQExpBuffer(negator);
2374 resetPQExpBuffer(restrictor);
2375 resetPQExpBuffer(join);
2376 resetPQExpBuffer(sort1);
2377 resetPQExpBuffer(sort2);
2379 /* skip all the builtin oids */
2380 if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
2384 * some operator are invalid because they were the result of user
2385 * defining operators before commutators exist
2387 if (strcmp(oprinfo[i].oprcode, "-") == 0)
2391 * right unary means there's a left arg and left unary means
2392 * there's a right arg
2394 if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
2395 strcmp(oprinfo[i].oprkind, "b") == 0)
2397 appendPQExpBuffer(leftarg, ",\n\tLEFTARG = %s ",
2398 fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false));
2400 if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
2401 strcmp(oprinfo[i].oprkind, "b") == 0)
2403 appendPQExpBuffer(rightarg, ",\n\tRIGHTARG = %s ",
2404 fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
2406 if (!(strcmp(oprinfo[i].oprcom, "0") == 0))
2407 appendPQExpBuffer(commutator, ",\n\tCOMMUTATOR = %s ",
2408 findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));
2410 if (!(strcmp(oprinfo[i].oprnegate, "0") == 0))
2411 appendPQExpBuffer(negator, ",\n\tNEGATOR = %s ",
2412 findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));
2414 if (!(strcmp(oprinfo[i].oprrest, "-") == 0))
2415 appendPQExpBuffer(restrictor, ",\n\tRESTRICT = %s ", oprinfo[i].oprrest);
2417 if (!(strcmp(oprinfo[i].oprjoin, "-") == 0))
2418 appendPQExpBuffer(join, ",\n\tJOIN = %s ", oprinfo[i].oprjoin);
2420 if (!(strcmp(oprinfo[i].oprlsortop, "0") == 0))
2421 appendPQExpBuffer(sort1, ",\n\tSORT1 = %s ",
2422 findOprByOid(oprinfo, numOperators, oprinfo[i].oprlsortop));
2424 if (!(strcmp(oprinfo[i].oprrsortop, "0") == 0))
2425 appendPQExpBuffer(sort2, ",\n\tSORT2 = %s ",
2426 findOprByOid(oprinfo, numOperators, oprinfo[i].oprrsortop));
2428 becomeUser(fout, oprinfo[i].usename);
2432 resetPQExpBuffer(q);
2433 appendPQExpBuffer(q, "DROP OPERATOR %s (%s, %s);\n", oprinfo[i].oprname,
2434 fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft), false),
2435 fmtId(findTypeByOid(tinfo, numTypes, oprinfo[i].oprright), false));
2436 fputs(q->data, fout);
2439 resetPQExpBuffer(q);
2440 appendPQExpBuffer(q,
2441 "CREATE OPERATOR %s "
2442 "(PROCEDURE = %s %s%s%s%s%s%s%s%s%s);\n",
2450 (strcmp(oprinfo[i].oprcanhash, "t") == 0) ? ",\n\tHASHES" : "",
2455 fputs(q->data, fout);
2461 * writes out to fout the queries to create all the user-defined aggregates
2465 dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
2466 TypeInfo *tinfo, int numTypes)
2469 PQExpBuffer q = createPQExpBuffer();
2470 PQExpBuffer sfunc1 = createPQExpBuffer();
2471 PQExpBuffer sfunc2 = createPQExpBuffer();
2472 PQExpBuffer basetype = createPQExpBuffer();
2473 PQExpBuffer finalfunc = createPQExpBuffer();
2477 for (i = 0; i < numAggs; i++)
2480 resetPQExpBuffer(sfunc1);
2481 resetPQExpBuffer(sfunc2);
2482 resetPQExpBuffer(basetype);
2483 resetPQExpBuffer(finalfunc);
2485 /* skip all the builtin oids */
2486 if (atoi(agginfo[i].oid) < g_last_builtin_oid)
2489 appendPQExpBuffer(basetype,
2491 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2493 if (!(strcmp(agginfo[i].aggtransfn1, "-") == 0))
2495 appendPQExpBuffer(sfunc1,
2496 "SFUNC1 = %s, STYPE1 = %s",
2497 agginfo[i].aggtransfn1,
2498 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype1), false));
2499 if (agginfo[i].agginitval1)
2500 appendPQExpBuffer(sfunc1, ", INITCOND1 = '%s'",
2501 agginfo[i].agginitval1);
2505 if (!(strcmp(agginfo[i].aggtransfn2, "-") == 0))
2507 appendPQExpBuffer(sfunc2,
2508 "SFUNC2 = %s, STYPE2 = %s",
2509 agginfo[i].aggtransfn2,
2510 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggtranstype2), false));
2511 if (agginfo[i].agginitval2)
2512 appendPQExpBuffer(sfunc2, ", INITCOND2 = '%s'",
2513 agginfo[i].agginitval2);
2516 if (!(strcmp(agginfo[i].aggfinalfn, "-") == 0))
2517 appendPQExpBuffer(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
2518 if (sfunc1->data[0] != '\0' && sfunc2->data[0] != '\0')
2526 if (finalfunc->data[0] != '\0' && (sfunc1->data[0] != '\0' || sfunc2->data[0] != '\0'))
2534 becomeUser(fout, agginfo[i].usename);
2538 resetPQExpBuffer(q);
2539 appendPQExpBuffer(q, "DROP AGGREGATE %s %s;\n", agginfo[i].aggname,
2540 fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
2541 fputs(q->data, fout);
2544 resetPQExpBuffer(q);
2545 appendPQExpBuffer(q, "CREATE AGGREGATE %s ( %s %s%s %s%s %s );\n",
2554 fputs(q->data, fout);
2559 * These are some support functions to fix the acl problem of pg_dump
2561 * Matthew C. Aycock 12/02/97
2564 /* Append a keyword to a keyword list, inserting comma if needed.
2565 * Caller must make aclbuf big enough for all possible keywords.
2568 AddAcl(char *aclbuf, const char *keyword)
2571 strcat(aclbuf, ",");
2572 strcat(aclbuf, keyword);
2576 * This will take a string of 'arwR' and return a malloced,
2577 * comma delimited string of SELECT,INSERT,UPDATE,DELETE,RULE
2580 GetPrivileges(const char *s)
2587 AddAcl(aclbuf, "INSERT");
2590 AddAcl(aclbuf, "UPDATE,DELETE");
2593 AddAcl(aclbuf, "SELECT");
2596 AddAcl(aclbuf, "RULE");
2598 /* Special-case when they're all there */
2599 if (strcmp(aclbuf, "INSERT,UPDATE,DELETE,SELECT,RULE") == 0)
2600 return strdup("ALL");
2602 return strdup(aclbuf);
2607 * Write out grant/revoke information
2608 * Called for sequences and tables
2612 dumpACL(FILE *fout, TableInfo tbinfo)
2614 const char *acls = tbinfo.relacl;
2620 if (strlen(acls) == 0)
2621 return; /* table has default permissions */
2624 * Revoke Default permissions for PUBLIC. Is this actually necessary,
2625 * or is it just a waste of time?
2628 "REVOKE ALL on %s from PUBLIC;\n",
2629 fmtId(tbinfo.relname, force_quotes));
2631 /* Make a working copy of acls so we can use strtok */
2632 aclbuf = strdup(acls);
2634 /* Scan comma-separated ACL items */
2635 for (tok = strtok(aclbuf, ","); tok != NULL; tok = strtok(NULL, ","))
2638 * Token may start with '{' and/or '"'. Actually only the start
2639 * of the string should have '{', but we don't verify that.
2646 /* User name is string up to = in tok */
2647 eqpos = strchr(tok, '=');
2650 fprintf(stderr, "Could not parse ACL list for '%s'...Exiting!\n",
2652 exit_nicely(g_conn);
2656 * Parse the privileges (right-hand side). Skip if there are
2659 priv = GetPrivileges(eqpos + 1);
2663 "GRANT %s on %s to ",
2664 priv, fmtId(tbinfo.relname, force_quotes));
2667 * Note: fmtId() can only be called once per printf, so don't
2668 * try to merge printing of username into the above printf.
2672 /* Empty left-hand side means "PUBLIC" */
2673 fprintf(fout, "PUBLIC;\n");
2677 *eqpos = '\0'; /* it's ok to clobber aclbuf */
2678 if (strncmp(tok, "group ", strlen("group ")) == 0)
2679 fprintf(fout, "GROUP %s;\n",
2680 fmtId(tok + strlen("group "), force_quotes));
2682 fprintf(fout, "%s;\n", fmtId(tok, force_quotes));
2694 * write out to fout all the user-define tables
2698 dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
2699 InhInfo *inhinfo, int numInherits,
2700 TypeInfo *tinfo, int numTypes, const char *tablename,
2701 const bool aclsSkip)
2706 PQExpBuffer q = createPQExpBuffer();
2707 char *serialSeq = NULL; /* implicit sequence name created
2708 * by SERIAL datatype */
2709 const char *serialSeqSuffix = "_id_seq"; /* suffix for implicit
2710 * SERIAL sequences */
2711 char **parentRels; /* list of names of parent relations */
2713 int actual_atts; /* number of attrs in this CREATE statment */
2719 /* First - dump SEQUENCEs */
2722 serialSeq = malloc(strlen(tablename) + strlen(serialSeqSuffix) + 1);
2723 strcpy(serialSeq, tablename);
2724 strcat(serialSeq, serialSeqSuffix);
2726 for (i = 0; i < numTables; i++)
2728 if (!(tblinfo[i].sequence))
2730 if (!tablename || (!strcmp(tblinfo[i].relname, tablename))
2731 || (serialSeq && !strcmp(tblinfo[i].relname, serialSeq)))
2733 becomeUser(fout, tblinfo[i].usename);
2734 dumpSequence(fout, tblinfo[i]);
2736 dumpACL(fout, tblinfo[i]);
2742 for (i = 0; i < numTables; i++)
2744 if (tblinfo[i].sequence)/* already dumped */
2747 if (!tablename || (!strcmp(tblinfo[i].relname, tablename)))
2750 /* Skip VIEW relations */
2753 * if (isViewRule(tblinfo[i].relname)) continue;
2756 parentRels = tblinfo[i].parentRels;
2757 numParents = tblinfo[i].numParents;
2759 becomeUser(fout, tblinfo[i].usename);
2763 resetPQExpBuffer(q);
2764 appendPQExpBuffer(q, "DROP TABLE %s;\n", fmtId(tblinfo[i].relname, force_quotes));
2765 fputs(q->data, fout);
2768 resetPQExpBuffer(q);
2769 appendPQExpBuffer(q, "CREATE TABLE %s (\n\t", fmtId(tblinfo[i].relname, force_quotes));
2771 for (j = 0; j < tblinfo[i].numatts; j++)
2773 if (tblinfo[i].inhAttrs[j] == 0)
2775 if (actual_atts > 0)
2776 appendPQExpBuffer(q, ",\n\t");
2777 appendPQExpBuffer(q, "%s ",
2778 fmtId(tblinfo[i].attnames[j], force_quotes));
2780 /* Show lengths on bpchar and varchar */
2781 if (!strcmp(tblinfo[i].typnames[j], "bpchar"))
2783 int len = (tblinfo[i].atttypmod[j] - VARHDRSZ);
2785 appendPQExpBuffer(q, "character");
2787 appendPQExpBuffer(q, "(%d)",
2788 tblinfo[i].atttypmod[j] - VARHDRSZ);
2790 else if (!strcmp(tblinfo[i].typnames[j], "varchar"))
2792 appendPQExpBuffer(q, "character varying");
2793 if (tblinfo[i].atttypmod[j] != -1)
2795 appendPQExpBuffer(q, "(%d)",
2796 tblinfo[i].atttypmod[j] - VARHDRSZ);
2799 else if (!strcmp(tblinfo[i].typnames[j], "numeric"))
2801 appendPQExpBuffer(q, "numeric");
2802 if (tblinfo[i].atttypmod[j] != -1)
2804 tmp_typmod = tblinfo[i].atttypmod[j] - VARHDRSZ;
2805 precision = (tmp_typmod >> 16) & 0xffff;
2806 scale = tmp_typmod & 0xffff;
2807 appendPQExpBuffer(q, "(%d,%d)",
2813 * char is an internal single-byte data type; Let's
2814 * make sure we force it through with quotes. - thomas
2817 else if (!strcmp(tblinfo[i].typnames[j], "char"))
2819 appendPQExpBuffer(q, "%s",
2820 fmtId(tblinfo[i].typnames[j], true));
2824 appendPQExpBuffer(q, "%s",
2825 fmtId(tblinfo[i].typnames[j], false));
2827 if (tblinfo[i].adef_expr[j] != NULL)
2828 appendPQExpBuffer(q, " DEFAULT %s",
2829 tblinfo[i].adef_expr[j]);
2830 if (tblinfo[i].notnull[j])
2831 appendPQExpBuffer(q, " NOT NULL");
2836 /* put the CONSTRAINTS inside the table def */
2837 for (k = 0; k < tblinfo[i].ncheck; k++)
2839 if (actual_atts + k > 0)
2840 appendPQExpBuffer(q, ",\n\t");
2841 appendPQExpBuffer(q, "%s",
2842 tblinfo[i].check_expr[k]);
2846 if (tblinfo[i].primary_key) {
2847 if (actual_atts + tblinfo[i].ncheck > 0)
2848 appendPQExpBuffer(q, ",\n\t");
2849 appendPQExpBuffer(q, "PRIMARY KEY (%s)", tblinfo[i].primary_key);
2852 appendPQExpBuffer(q, "\n)");
2856 appendPQExpBuffer(q, "\ninherits (");
2857 for (k = 0; k < numParents; k++)
2859 appendPQExpBuffer(q, "%s%s",
2860 (k > 0) ? ", " : "",
2861 fmtId(parentRels[k], force_quotes));
2863 appendPQExpBuffer(q, ")");
2866 appendPQExpBuffer(q, ";\n");
2867 fputs(q->data, fout);
2869 dumpACL(fout, tblinfo[i]);
2877 * write out to fout all the user-define indices
2880 dumpIndices(FILE *fout, IndInfo *indinfo, int numIndices,
2881 TableInfo *tblinfo, int numTables, const char *tablename)
2886 PQExpBuffer attlist = createPQExpBuffer();
2887 char *classname[INDEX_MAX_KEYS];
2888 char *funcname; /* the name of the function to comput the
2894 PQExpBuffer q = createPQExpBuffer(),
2895 id1 = createPQExpBuffer(),
2896 id2 = createPQExpBuffer();
2899 for (i = 0; i < numIndices; i++)
2901 tableInd = findTableByName(tblinfo, numTables,
2902 indinfo[i].indrelname);
2905 fprintf(stderr, "failed sanity check, table %s was not found\n",
2906 indinfo[i].indrelname);
2910 if (strcmp(indinfo[i].indproc, "0") == 0)
2916 * the funcname is an oid which we use to find the name of the
2917 * pg_proc. We need to do this because getFuncs() only reads
2918 * in the user-defined funcs not all the funcs. We might not
2919 * find what we want by looking in FuncInfo*
2921 resetPQExpBuffer(q);
2922 appendPQExpBuffer(q,
2923 "SELECT proname from pg_proc "
2924 "where pg_proc.oid = '%s'::oid",
2925 indinfo[i].indproc);
2926 res = PQexec(g_conn, q->data);
2927 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2929 fprintf(stderr, "dumpIndices(): SELECT (funcname) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2930 exit_nicely(g_conn);
2932 funcname = strdup(PQgetvalue(res, 0,
2933 PQfnumber(res, "proname")));
2937 /* convert opclass oid(s) into names */
2938 for (nclass = 0; nclass < INDEX_MAX_KEYS; nclass++)
2940 indclass = atoi(indinfo[i].indclass[nclass]);
2943 resetPQExpBuffer(q);
2944 appendPQExpBuffer(q,
2945 "SELECT opcname from pg_opclass "
2946 "where pg_opclass.oid = '%u'::oid",
2948 res = PQexec(g_conn, q->data);
2949 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
2951 fprintf(stderr, "dumpIndices(): SELECT (classname) failed. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
2952 exit_nicely(g_conn);
2954 classname[nclass] = strdup(PQgetvalue(res, 0,
2955 PQfnumber(res, "opcname")));
2959 if (funcname && nclass != 1)
2961 fprintf(stderr, "dumpIndices(): Must be exactly one OpClass "
2962 "for functional index %s\n", indinfo[i].indexrelname);
2963 exit_nicely(g_conn);
2966 /* convert attribute numbers into attribute list */
2967 resetPQExpBuffer(attlist);
2968 for (k = 0; k < INDEX_MAX_KEYS; k++)
2972 indkey = atoi(indinfo[i].indkey[k]);
2973 if (indkey == InvalidAttrNumber)
2976 if (indkey == ObjectIdAttributeNumber - 1)
2979 attname = tblinfo[tableInd].attnames[indkey];
2981 appendPQExpBuffer(attlist, "%s%s",
2982 (k == 0) ? "" : ", ", fmtId(attname, force_quotes));
2987 fprintf(stderr, "dumpIndices(): OpClass not found for "
2988 "attribute '%s' of index '%s'\n",
2989 attname, indinfo[i].indexrelname);
2990 exit_nicely(g_conn);
2992 resetPQExpBuffer(id1);
2993 resetPQExpBuffer(id2);
2994 appendPQExpBuffer(id1, fmtId(attname, force_quotes));
2995 appendPQExpBuffer(id2, fmtId(classname[k], force_quotes));
2996 appendPQExpBuffer(attlist, "%s%s %s",
2997 (k == 0) ? "" : ", ", id1->data, id2->data);
3002 if (!tablename || (!strcmp(indinfo[i].indrelname, tablename)))
3006 * We make the index belong to the owner of its table, which
3007 * is not necessarily right but should answer 99% of the time.
3008 * Would have to add owner name to IndInfo to do it right.
3010 becomeUser(fout, tblinfo[tableInd].usename);
3012 resetPQExpBuffer(id1);
3013 resetPQExpBuffer(id2);
3014 appendPQExpBuffer(id1, fmtId(indinfo[i].indexrelname, force_quotes));
3015 appendPQExpBuffer(id2, fmtId(indinfo[i].indrelname, force_quotes));
3019 resetPQExpBuffer(q);
3020 appendPQExpBuffer(q, "DROP INDEX %s;\n", id1->data);
3021 fputs(q->data, fout);
3024 fprintf(fout, "CREATE %s INDEX %s on %s using %s (",
3025 (strcmp(indinfo[i].indisunique, "t") == 0) ? "UNIQUE" : "",
3028 indinfo[i].indamname);
3031 /* need 2 printf's here cuz fmtId has static return area */
3032 fprintf(fout, " %s", fmtId(funcname, false));
3033 fprintf(fout, " (%s) %s );\n", attlist->data, fmtId(classname[0], force_quotes));
3038 fprintf(fout, " %s );\n", attlist->data);
3046 * prints out the tuples in ASCII representation. The output is a valid
3047 * input to COPY FROM stdin.
3049 * We only need to do this for POSTGRES 4.2 databases since the
3050 * COPY TO statment doesn't escape newlines properly. It's been fixed
3053 * the attrmap passed in tells how to map the attributes copied in to the
3054 * attributes copied out
3058 dumpTuples(PGresult *res, FILE *fout, int *attrmap)
3064 char **outVals = NULL; /* values to copy out */
3073 * Print out the tuples but only print tuples with at least 1
3076 outVals = (char **) malloc(m * sizeof(char *));
3078 for (j = 0; j < n; j++)
3080 for (k = 0; k < m; k++)
3081 outVals[attrmap[k]] = PQgetvalue(res, j, k);
3082 for (k = 0; k < m; k++)
3084 char *pval = outVals[k];
3087 fputc('\t', fout); /* delimiter for attribute */
3091 while (*pval != '\0')
3093 /* escape tabs, newlines and backslashes */
3094 if (*pval == '\t' || *pval == '\n' || *pval == '\\')
3101 fputc('\n', fout); /* delimiter for a tuple */
3111 * find the maximum oid and generate a COPY statement to set it
3115 setMaxOid(FILE *fout)
3120 res = PQexec(g_conn, "CREATE TABLE pgdump_oid (dummy int4)");
3122 PQresultStatus(res) != PGRES_COMMAND_OK)
3124 fprintf(stderr, "Can not create pgdump_oid table. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3125 exit_nicely(g_conn);
3128 res = PQexec(g_conn, "INSERT INTO pgdump_oid VALUES (0)");
3130 PQresultStatus(res) != PGRES_COMMAND_OK)
3132 fprintf(stderr, "Can not insert into pgdump_oid table. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3133 exit_nicely(g_conn);
3135 max_oid = atol(PQoidStatus(res));
3138 fprintf(stderr, "Invalid max id in setMaxOid\n");
3139 exit_nicely(g_conn);
3142 res = PQexec(g_conn, "DROP TABLE pgdump_oid;");
3144 PQresultStatus(res) != PGRES_COMMAND_OK)
3146 fprintf(stderr, "Can not drop pgdump_oid table. Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3147 exit_nicely(g_conn);
3151 fprintf(stderr, "%s maximum system oid is %u %s\n",
3152 g_comment_start, max_oid, g_comment_end);
3153 fprintf(fout, "CREATE TABLE pgdump_oid (dummy int4);\n");
3154 fprintf(fout, "COPY pgdump_oid WITH OIDS FROM stdin;\n");
3155 fprintf(fout, "%-d\t0\n", max_oid);
3156 fprintf(fout, "\\.\n");
3157 fprintf(fout, "DROP TABLE pgdump_oid;\n");
3161 * findLastBuiltInOid -
3162 * find the last built in oid
3163 * we do this by looking up the oid of 'template1' in pg_database,
3164 * this is probably not foolproof but comes close
3168 findLastBuiltinOid(void)
3174 res = PQexec(g_conn,
3175 "SELECT oid from pg_database where datname = 'template1'");
3177 PQresultStatus(res) != PGRES_TUPLES_OK)
3179 fprintf(stderr,"pg_dump error in finding the template1 database.");
3180 fprintf(stderr,"Explanation from backend: '%s'.\n", PQerrorMessage(g_conn));
3181 exit_nicely(g_conn);
3183 ntups = PQntuples(res);
3186 fprintf(stderr,"pg_dump: couldn't find the template1 database.\n");
3187 fprintf(stderr,"There is no 'template1' entry in the 'pg_database' table.\n");
3188 exit_nicely(g_conn);
3192 fprintf(stderr,"pg_dump: found more than one template1 database.\n");
3193 fprintf(stderr,"There is more than one 'template1' entry in the 'pg_database' table\n");
3194 exit_nicely(g_conn);
3196 last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
3204 * checks a string for quote characters and quotes them
3207 checkForQuote(const char *s)
3215 r = malloc(strlen(s) * 3 + 1); /* definitely long enough */
3217 while ((c = *s) != '\0')
3222 r[j++] = '\''; /* quote the single quotes */
3238 dumpSequence(FILE *fout, TableInfo tbinfo)
3249 PQExpBuffer query = createPQExpBuffer();
3251 appendPQExpBuffer(query,
3252 "SELECT sequence_name, last_value, increment_by, max_value, "
3253 "min_value, cache_value, is_cycled, is_called from %s",
3254 fmtId(tbinfo.relname, force_quotes));
3256 res = PQexec(g_conn, query->data);
3257 if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
3259 fprintf(stderr, "dumpSequence(%s): SELECT failed. Explanation from backend: '%s'.\n", tbinfo.relname, PQerrorMessage(g_conn));
3260 exit_nicely(g_conn);
3263 if (PQntuples(res) != 1)
3265 fprintf(stderr, "dumpSequence(%s): %d (!= 1) tuples returned by SELECT\n",
3266 tbinfo.relname, PQntuples(res));
3267 exit_nicely(g_conn);
3270 if (strcmp(PQgetvalue(res, 0, 0), tbinfo.relname) != 0)
3272 fprintf(stderr, "dumpSequence(%s): different sequence name "
3273 "returned by SELECT: %s\n",
3274 tbinfo.relname, PQgetvalue(res, 0, 0));
3275 exit_nicely(g_conn);
3279 last = atoi(PQgetvalue(res, 0, 1));
3280 incby = atoi(PQgetvalue(res, 0, 2));
3281 maxv = atoi(PQgetvalue(res, 0, 3));
3282 minv = atoi(PQgetvalue(res, 0, 4));
3283 cache = atoi(PQgetvalue(res, 0, 5));
3284 t = PQgetvalue(res, 0, 6);
3286 t = PQgetvalue(res, 0, 7);
3293 resetPQExpBuffer(query);
3294 appendPQExpBuffer(query, "DROP SEQUENCE %s;\n", fmtId(tbinfo.relname, force_quotes));
3295 fputs(query->data, fout);
3298 resetPQExpBuffer(query);
3299 appendPQExpBuffer(query,
3300 "CREATE SEQUENCE %s start %d increment %d maxvalue %d "
3301 "minvalue %d cache %d %s;\n",
3302 fmtId(tbinfo.relname, force_quotes), last, incby, maxv, minv, cache,
3303 (cycled == 't') ? "cycle" : "");
3305 fputs(query->data, fout);
3308 return; /* nothing to do more */
3310 resetPQExpBuffer(query);
3311 appendPQExpBuffer(query, "SELECT nextval ('%s');\n", fmtId(tbinfo.relname, force_quotes));
3312 fputs(query->data, fout);
3318 dumpTriggers(FILE *fout, const char *tablename,
3319 TableInfo *tblinfo, int numTables)
3325 fprintf(stderr, "%s dumping out triggers %s\n",
3326 g_comment_start, g_comment_end);
3328 for (i = 0; i < numTables; i++)
3330 if (tablename && strcmp(tblinfo[i].relname, tablename))
3332 for (j = 0; j < tblinfo[i].ntrig; j++)
3334 becomeUser(fout, tblinfo[i].usename);
3335 fputs(tblinfo[i].triggers[j], fout);
3342 dumpRules(FILE *fout, const char *tablename,
3343 TableInfo *tblinfo, int numTables)
3349 PQExpBuffer query = createPQExpBuffer();
3354 fprintf(stderr, "%s dumping out rules %s\n",
3355 g_comment_start, g_comment_end);
3358 * For each table we dump
3360 for (t = 0; t < numTables; t++)
3362 if (tablename && strcmp(tblinfo[t].relname, tablename))
3366 * Get all rules defined for this table
3368 resetPQExpBuffer(query);
3369 appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.rulename) "
3370 "AS definition FROM pg_rewrite, pg_class "
3371 "WHERE pg_class.relname = '%s' "
3372 "AND pg_rewrite.ev_class = pg_class.oid "
3373 "ORDER BY pg_rewrite.oid",
3374 tblinfo[t].relname);
3375 res = PQexec(g_conn, query->data);
3377 PQresultStatus(res) != PGRES_TUPLES_OK)
3379 fprintf(stderr, "dumpRules(): SELECT failed for table %s. Explanation from backend: '%s'.\n",
3380 tblinfo[t].relname, PQerrorMessage(g_conn));
3381 exit_nicely(g_conn);
3384 nrules = PQntuples(res);
3385 i_definition = PQfnumber(res, "definition");
3390 for (i = 0; i < nrules; i++)
3391 fprintf(fout, "%s\n", PQgetvalue(res, i, i_definition));
3398 /* Issue a psql \connect command to become the specified user.
3399 * We want to do this only if we are dumping ACLs,
3400 * and only if the new username is different from the last one
3401 * (to avoid the overhead of useless backend launches).
3405 becomeUser(FILE *fout, const char *username)
3407 static const char *lastusername = "";
3412 if (strcmp(lastusername, username) == 0)
3415 fprintf(fout, "\\connect - %s\n", username);
3417 lastusername = username;