diff options
| author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
|---|---|---|
| committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
| commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
| tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/bin/pg_dump | |
| download | postgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz | |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/bin/pg_dump')
| -rw-r--r-- | src/bin/pg_dump/Makefile | 23 | ||||
| -rw-r--r-- | src/bin/pg_dump/README | 73 | ||||
| -rw-r--r-- | src/bin/pg_dump/common.c | 397 | ||||
| -rw-r--r-- | src/bin/pg_dump/pg_dump.c | 1443 | ||||
| -rw-r--r-- | src/bin/pg_dump/pg_dump.h | 195 |
5 files changed, 2131 insertions, 0 deletions
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile new file mode 100644 index 0000000000..5512f249fa --- /dev/null +++ b/src/bin/pg_dump/Makefile @@ -0,0 +1,23 @@ +#------------------------------------------------------------------------- +# +# Makefile.inc-- +# Makefile for bin/pg_dump +# +# Copyright (c) 1994, Regents of the University of California +# +# +# IDENTIFICATION +# $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $ +# +#------------------------------------------------------------------------- + +PROG= pg_dump + +MKDIR= ../../mk +include $(MKDIR)/postgres.mk +include ../Makefile.global + +SRCS= pg_dump.c common.c + +include $(MKDIR)/postgres.prog.mk + diff --git a/src/bin/pg_dump/README b/src/bin/pg_dump/README new file mode 100644 index 0000000000..17c433c898 --- /dev/null +++ b/src/bin/pg_dump/README @@ -0,0 +1,73 @@ +pg_dump is a utility for dumping out a postgres database into a script +file containing query commands. The script files are in a ASCII +format and can be used to reconstruct the database, even on other +machines and other architectures. pg_dump will produce the queries +necessary to re-generate all user-defined types, functions, tables, +indices, aggregates, and operators. In addition, all the data is +copied out in ASCII format so that it can be readily copied in again. + + +To build: + + % gmake clean install + +This version of the program will read in your postgres95 database and +output the schema and the data tuples in SQL. The dumps are useful +for moving from one postgres95 installation to another. + + +How to use pg_dump: +------------------- + +The command line options are fairly self explanatory. Use -help to +see the command line options. recommend using -v to get +more verbose descriptions of what pg_dump is doing. + +After running pg_dump, one should examine the output script file for any +warnings, especially in light of the limitations listed below. + +A typical use of pg_dump: + + % pg_dump -v -f oldDB.dump oldDB + % createdb newDB + % psql newDB < oldDB.dump + + +Caveats and limitations: +------------------------ + +pg_dump has a few limitations. The limitations mostly stem from +difficulty in extracting certain meta-information from the system +catalogs. + + rules and views: + pg_dump does not understand user-defined rules and views and + will fail to dump them properly. (This is due to the fact that + rules are stored as plans in the catalogs and not textually) + + partial indices: + pg_dump does not understand partial indices. (The reason is + the same as above. Partial index predicates are stored as plans) + + large objects: + pg_dump does not handle large objects. Large + objects are ignored and must be dealt with manually. + + oid preservation: + pg_dump does not preserve oid's while dumping. If you have + stored oid's explicitly in tables in user-defined attributes, + and are using them as keys, then the output scripts will not + regenerate your database correctly. + +pg_dump requires postgres95 beta0.03 or later. + +Bug-reporting +-------------- + +If you should find a problem with pg_dump, it is very important that +you provide a (small) sample database which illustrates the problem. +Please send bugs, questions, and feedback to the + postgres95@postgres95.vnet.net + + + diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c new file mode 100644 index 0000000000..96ea7f7295 --- /dev/null +++ b/src/bin/pg_dump/common.c @@ -0,0 +1,397 @@ +/*------------------------------------------------------------------------- + * + * common.c-- + * common routines between pg_dump and pg4_dump + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <sys/param.h> /* for MAXHOSTNAMELEN on most */ +#ifdef PORTNAME_sparc_solaris +#include <netdb.h> /* for MAXHOSTNAMELEN on some */ +#endif + +#include "postgres.h" +#include "libpq-fe.h" + +#include "pg_dump.h" + +/* dupstr : copies a string, while allocating space for it. + the CALLER is responsible for freeing the space + returns NULL if the argument is NULL*/ +char* +dupstr(char *s) +{ + char* result; + + if (s == NULL) + return NULL; + + result = (char*)malloc(strlen(s)+1); + strcpy(result, s); + return result; +} + + +/* + * findTypeByOid + * given an oid of a type, return its typename + * + * if oid is "0", return "opaque" -- this is a special case + * + * NOTE: should hash this, but just do linear search for now + */ + +char* +findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid) +{ + int i; + + if (strcmp(oid, "0") == 0) return g_opaque_type; + + for (i=0;i<numTypes;i++) { + if (strcmp(tinfo[i].oid, oid) == 0) + return tinfo[i].typname; + } + + /* should never get here */ + fprintf(stderr,"failed sanity check, type with oid %s was not found\n", + oid); + exit(2); +} + +/* + * findOprByOid + * given the oid of an operator, return the name of the operator + * + * + * NOTE: should hash this, but just do linear search for now + * + */ +char* +findOprByOid(OprInfo *oprinfo, int numOprs, char *oid) +{ + int i; + for (i=0;i<numOprs;i++) { + if (strcmp(oprinfo[i].oid, oid) == 0) + return oprinfo[i].oprname; + } + + /* should never get here */ + fprintf(stderr,"failed sanity check, opr with oid %s was not found\n", + oid); + exit(2); +} + + +/* + * findParentsByOid -- + * given the oid of a class, return the names of its parent classes + * and assign the number of parents to the last argument. + * + * + * returns NULL if none + */ + +char** +findParentsByOid(TableInfo* tblinfo, int numTables, + InhInfo* inhinfo, int numInherits, char *oid, + int *numParentsPtr) +{ + int i,j; + int parentInd; + char** result; + int numParents; + + numParents = 0; + for (i=0;i<numInherits;i++) { + if ( strcmp(inhinfo[i].inhrel, oid) == 0) { + numParents++; + } + } + + *numParentsPtr = numParents; + + if (numParents > 0) { + result = (char**)malloc(sizeof(char*) * numParents); + j = 0; + for (i=0;i<numInherits;i++) { + if ( strcmp(inhinfo[i].inhrel, oid) == 0) { + parentInd = findTableByOid(tblinfo, numTables, + inhinfo[i].inhparent); + result[j++] = tblinfo[parentInd].relname; + } + } + return result; + } + else + return NULL; +} + +/* + * parseArgTypes + * parse a string of eight numbers delimited by spaces + * into a character array + */ + +void +parseArgTypes(char **argtypes, char* str) +{ + int j, argNum; + char temp[100]; + char s; + + argNum = 0; + j = 0; + while ( (s = *str) != '\0') { + if (s == ' ') { + temp[j] = '\0'; + argtypes[argNum] = dupstr(temp); + argNum++; + j = 0; + } else { + temp[j] = s; + j++; + } + str++; + } + if (j != 0) { + temp[j] = '\0'; + argtypes[argNum] = dupstr(temp); + } + +} + + +/* + * strInArray: + * takes in a string and a string array and the number of elements in the + * string array. + * returns the index if the string is somewhere in the array, -1 otherwise + * + */ + +int +strInArray(char* pattern, char** arr, int arr_size) +{ + int i; + for (i=0;i<arr_size;i++) { + if (strcmp(pattern, arr[i]) == 0) + return i; + } + return -1; +} + +/* + * dumpSchema: + * we have a valid connection, we are now going to dump the schema + * into the file + * + */ + +TableInfo * +dumpSchema(FILE *fout, int *numTablesPtr) +{ + int numTypes; + int numFuncs; + int numTables; + int numInherits; + int numIndices; + int numAggregates; + int numOperators; + TypeInfo *tinfo; + FuncInfo *finfo; + AggInfo *agginfo; + TableInfo *tblinfo; + InhInfo *inhinfo; + IndInfo *indinfo; + OprInfo *oprinfo; + +if (g_verbose) fprintf(stderr,"%s reading user-defined types %s\n", + g_comment_start, g_comment_end); + tinfo = getTypes(&numTypes); + +if (g_verbose) fprintf(stderr,"%s reading user-defined functions %s\n", + g_comment_start, g_comment_end); + finfo = getFuncs(&numFuncs); + +if (g_verbose) fprintf(stderr,"%s reading user-defined aggregates %s\n", + g_comment_start, g_comment_end); + agginfo = getAggregates(&numAggregates); + +if (g_verbose) fprintf(stderr,"%s reading user-defined operators %s\n", + g_comment_start, g_comment_end); + oprinfo = getOperators(&numOperators); + +if (g_verbose) fprintf(stderr,"%s reading user-defined tables %s\n", + g_comment_start, g_comment_end); + tblinfo = getTables(&numTables); + +if (g_verbose) fprintf(stderr,"%s reading table inheritance information %s\n", + g_comment_start, g_comment_end); + inhinfo = getInherits(&numInherits); + +if (g_verbose) fprintf(stderr, "%s finding the attribute names and types for each table %s\n", + g_comment_start, g_comment_end); + getTableAttrs(tblinfo, numTables); + +if (g_verbose) fprintf(stderr, "%s flagging inherited attributes in subtables %s\n", + g_comment_start, g_comment_end); + flagInhAttrs(tblinfo, numTables, inhinfo, numInherits); + +if (g_verbose) fprintf(stderr,"%s reading indices information %s\n", + g_comment_start, g_comment_end); + indinfo = getIndices(&numIndices); + +if (g_verbose) fprintf(stderr,"%s dumping out user-defined types %s\n", + g_comment_start, g_comment_end); + dumpTypes(fout, finfo, numFuncs, tinfo, numTypes); + +if (g_verbose) fprintf(stderr,"%s dumping out tables %s\n", + g_comment_start, g_comment_end); + dumpTables(fout, tblinfo, numTables, inhinfo, numInherits, + tinfo, numTypes); + +if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n", + g_comment_start, g_comment_end); + dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes); + +if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n", + g_comment_start, g_comment_end); + dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes); + +if (g_verbose) fprintf(stderr,"%s dumping out user-defined operators %s\n", + g_comment_start, g_comment_end); + dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes); + +if (g_verbose) fprintf(stderr,"%s dumping out indices %s\n", + g_comment_start, g_comment_end); + dumpIndices(fout, indinfo, numIndices, tblinfo, numTables); + + *numTablesPtr = numTables; + return tblinfo; +} + + +/* flagInhAttrs - + * for each table in tblinfo, flag its inherited attributes + * so when we dump the table out, we don't dump out the inherited attributes + * + * initializes the parentRels field of each table + * + * modifies tblinfo + * + */ +void +flagInhAttrs(TableInfo* tblinfo, int numTables, + InhInfo* inhinfo, int numInherits) +{ + int i,j,k; + int parentInd; + + /* we go backwards because the tables in tblinfo are in OID + order, meaning the subtables are after the parent tables + we flag inherited attributes from child tables first */ + for (i = numTables-1; i >= 0; i--) { + tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables, + inhinfo, numInherits, + tblinfo[i].oid, + &tblinfo[i].numParents); + for (k=0;k<tblinfo[i].numParents;k++) { + parentInd = findTableByName(tblinfo, numTables, + tblinfo[i].parentRels[k]); + for (j=0;j<tblinfo[i].numatts;j++) { + if (strInArray(tblinfo[i].attnames[j], + tblinfo[parentInd].attnames, + tblinfo[parentInd].numatts) != -1) { + tblinfo[i].inhAttrs[j] = 1; + } + } + } + } +} + + +/* + * findTableByName + * finds the index (in tblinfo) of the table with the given relname + * returns -1 if not found + * + * NOTE: should hash this, but just do linear search for now + */ + +int +findTableByName(TableInfo* tblinfo, int numTables, char* relname) +{ + int i; + for (i=0;i<numTables;i++) { + if (strcmp(tblinfo[i].relname, relname) == 0) + return i; + } + return -1; +} + +/* + * findTableByOid + * finds the index (in tblinfo) of the table with the given oid + * returns -1 if not found + * + * NOTE: should hash this, but just do linear search for now + */ + +int +findTableByOid(TableInfo* tblinfo, int numTables, char* oid) +{ + int i; + for (i=0;i<numTables;i++) { + if (strcmp(tblinfo[i].oid, oid) == 0) + return i; + } + return -1; +} + + +/* + * findFuncByName + * finds the index (in finfo) of the function with the given name + * returns -1 if not found + * + * NOTE: should hash this, but just do linear search for now + */ + +int +findFuncByName(FuncInfo* finfo, int numFuncs, char* name) +{ + int i; + for (i=0;i<numFuncs;i++) { + if (strcmp(finfo[i].proname, name) == 0) + return i; + } + return -1; +} + +/* + * isArchiveName + * + * returns true if the relation name is an archive name, false otherwise + */ +int +isArchiveName(char* relname) +{ + return (strlen(relname) > 1 && relname[1] == ','); +} + + + + + + diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c new file mode 100644 index 0000000000..9ef8f8f35e --- /dev/null +++ b/src/bin/pg_dump/pg_dump.c @@ -0,0 +1,1443 @@ +/*------------------------------------------------------------------------- + * + * pg_dump.c-- + * pg_dump is an utility for dumping out a postgres database + * into a script file. + * + * pg_dump will read the system catalogs in a database and + * dump out a script that reproduces + * the schema of the database in terms of + * user-defined types + * user-defined functions + * tables + * indices + * aggregates + * operators + * + * the output script is SQL that is understood by Postgres95 + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/param.h> /* for MAXHOSTNAMELEN on most */ +#ifdef PORTNAME_sparc_solaris +#include <netdb.h> /* for MAXHOSTNAMELEN on some */ +#endif + +#include "postgres.h" +#include "libpq-fe.h" + +#include "pg_dump.h" + +extern char *optarg; +extern int optind, opterr; + +/* global decls */ +int g_verbose; /* verbose flag */ +int g_last_builtin_oid; /* value of the last builtin oid */ +FILE *g_fout; /* the script file */ +PGconn *g_conn; /* the database connection */ + +char g_opaque_type[10]; /* name for the opaque type */ + +/* placeholders for the delimiters for comments */ +char g_comment_start[10]; +char g_comment_end[10]; + + +static void +usage(char* progname) +{ + fprintf(stderr, "usage: %s [options] [dbname]\n",progname); + fprintf(stderr, "\t -f filename \t\t script output filename\n"); + fprintf(stderr, "\t -H hostname \t\t server host name\n"); + fprintf(stderr, "\t -p port \t\t server port number\n"); + fprintf(stderr, "\t -v \t\t verbose\n"); + fprintf(stderr, "\t -S \t\t dump out only the schema, no data\n"); + fprintf(stderr, "\n if dbname is not supplied, then the DATABASE environment name is used\n"); + fprintf(stderr, "\n"); + + fprintf(stderr, "\tpg_dump dumps out postgres databases and produces a script file\n"); + fprintf(stderr, "\tof SQL commands to regenerate the schema\n"); + fprintf(stderr, "\tThe SQL output is designed for import into Postgres95\n"); + exit(1); +} + +void +exit_nicely(PGconn* conn) +{ + PQfinish(conn); + exit(1); +} + + +void +main(int argc, char** argv) +{ + int c; + char* progname; + char* filename; + char* dbname; + int schemaOnly; + char *pghost = NULL; + char *pgport = NULL; + + TableInfo *tblinfo; + int numTables; + + dbname = NULL; + filename = NULL; + g_verbose = 0; + + strcpy(g_comment_start,"-- "); + g_comment_end[0] = '\0'; + strcpy(g_opaque_type, "opaque"); + + schemaOnly = 0; + + progname = *argv; + + while ((c = getopt(argc, argv,"f:H:p:vSD")) != EOF) { + switch(c) { + case 'f': /* output file name */ + filename = optarg; + break; + case 'H' : /* server host */ + pghost = optarg; + break; + case 'p' : /* server port */ + pgport = optarg; + break; + case 'v': /* verbose */ + g_verbose = 1; + break; + case 'S': /* dump schema only */ + schemaOnly = 1; + break; + default: + usage(progname); + break; + } + } + + /* open the output file */ + if (filename == NULL) { + g_fout = stdout; + } else { + g_fout = fopen(filename, "w"); + if (g_fout == NULL) { + fprintf(stderr,"%s: could not open output file named %s for writing\n", + progname, filename); + exit(2); + } + } + + /* find database */ + if (!(dbname = argv[optind]) && + !(dbname = getenv("DATABASE")) ) { + fprintf(stderr, "%s: no database name specified\n",progname); + exit (2); + } + + g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname); + /* check to see that the backend connection was successfully made */ + if (PQstatus(g_conn) == CONNECTION_BAD) { + fprintf(stderr,"Connection to database '%s' failed.\n", dbname); + fprintf(stderr,"%s",PQerrorMessage(g_conn)); + exit_nicely(g_conn); + } + + g_last_builtin_oid = findLastBuiltinOid(); + +if (g_verbose) + fprintf(stderr, "%s last builtin oid is %d %s\n", + g_comment_start, g_last_builtin_oid, g_comment_end); + + tblinfo = dumpSchema(g_fout, &numTables); + + if (!schemaOnly) { + +if (g_verbose) fprintf(stderr,"%s dumping out the contents of each table %s\n", + g_comment_start, g_comment_end); + + dumpClasses(tblinfo, numTables, g_fout); + } + + fflush(g_fout); + fclose(g_fout); + + PQfinish(g_conn); + exit(0); +} + + +/* + * getTypes: + * read all base types in the system catalogs and return them in the + * TypeInfo* structure + * + * numTypes is set to the number of types read in + * + */ +TypeInfo* +getTypes(int *numTypes) +{ + PGresult *res; + int ntups; + int i; + char query[MAXQUERYLEN]; + TypeInfo *tinfo; + + int i_oid; + int i_typowner; + int i_typname; + int i_typlen; + int i_typprtlen; + int i_typinput; + int i_typoutput; + int i_typreceive; + int i_typsend; + int i_typelem; + int i_typdelim; + int i_typdefault; + int i_typrelid; + int i_typbyval; + + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + /* find all base types */ + /* we include even the built-in types + because those may be used as array elements by user-defined types */ + /* we filter out the built-in types when + we dump out the types */ + + sprintf(query, "SELECT oid, typowner,typname, typlen, typprtlen, typinput, typoutput, typreceive, typsend, typelem, typdelim, typdefault, typrelid,typbyval from pg_type"); + + res = PQexec(g_conn,query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getTypes(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + tinfo = (TypeInfo*)malloc(ntups * sizeof(TypeInfo)); + + i_oid = PQfnumber(res,"oid"); + i_typowner = PQfnumber(res,"typowner"); + i_typname = PQfnumber(res,"typname"); + i_typlen = PQfnumber(res,"typlen"); + i_typprtlen = PQfnumber(res,"typprtlen"); + i_typinput = PQfnumber(res,"typinput"); + i_typoutput = PQfnumber(res,"typoutput"); + i_typreceive = PQfnumber(res,"typreceive"); + i_typsend = PQfnumber(res,"typsend"); + i_typelem = PQfnumber(res,"typelem"); + i_typdelim = PQfnumber(res,"typdelim"); + i_typdefault = PQfnumber(res,"typdefault"); + i_typrelid = PQfnumber(res,"typrelid"); + i_typbyval = PQfnumber(res,"typbyval"); + + for (i=0;i<ntups;i++) { + tinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid)); + tinfo[i].typowner = dupstr(PQgetvalue(res,i,i_typowner)); + tinfo[i].typname = dupstr(PQgetvalue(res,i,i_typname)); + tinfo[i].typlen = dupstr(PQgetvalue(res,i,i_typlen)); + tinfo[i].typprtlen = dupstr(PQgetvalue(res,i,i_typprtlen)); + tinfo[i].typinput = dupstr(PQgetvalue(res,i,i_typinput)); + tinfo[i].typoutput = dupstr(PQgetvalue(res,i,i_typoutput)); + tinfo[i].typreceive = dupstr(PQgetvalue(res,i,i_typreceive)); + tinfo[i].typsend = dupstr(PQgetvalue(res,i,i_typsend)); + tinfo[i].typelem = dupstr(PQgetvalue(res,i,i_typelem)); + tinfo[i].typdelim = dupstr(PQgetvalue(res,i,i_typdelim)); + tinfo[i].typdefault = dupstr(PQgetvalue(res,i,i_typdefault)); + tinfo[i].typrelid = dupstr(PQgetvalue(res,i,i_typrelid)); + + if (strcmp(PQgetvalue(res,i,i_typbyval), "f") == 0) + tinfo[i].passedbyvalue = 0; + else + tinfo[i].passedbyvalue = 1; + + /* check for user-defined array types, + omit system generated ones */ + if ( (strcmp(tinfo[i].typelem, "0") != 0) && + tinfo[i].typname[0] != '_') + tinfo[i].isArray = 1; + else + tinfo[i].isArray = 0; + } + + *numTypes = ntups; + + PQclear(res); + + res = PQexec(g_conn,"end"); + PQclear(res); + + return tinfo; +} + +/* + * getOperators: + * read all operators in the system catalogs and return them in the + * OprInfo* structure + * + * numOprs is set to the number of operators read in + * + * + */ +OprInfo* +getOperators(int *numOprs) +{ + PGresult *res; + int ntups; + int i; + char query[MAXQUERYLEN]; + + OprInfo* oprinfo; + + int i_oid; + int i_oprname; + int i_oprkind; + int i_oprcode; + int i_oprleft; + int i_oprright; + int i_oprcom; + int i_oprnegate; + int i_oprrest; + int i_oprjoin; + int i_oprcanhash; + int i_oprlsortop; + int i_oprrsortop; + + /* find all operators, including builtin operators, + filter out system-defined operators at dump-out time */ + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, "SELECT oid, oprname, oprkind, oprcode, oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, oprcanhash, oprlsortop, oprrsortop from pg_operator"); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getOperators(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + *numOprs = ntups; + + oprinfo = (OprInfo*)malloc(ntups * sizeof(OprInfo)); + + i_oid = PQfnumber(res,"oid"); + i_oprname = PQfnumber(res,"oprname"); + i_oprkind = PQfnumber(res,"oprkind"); + i_oprcode = PQfnumber(res,"oprcode"); + i_oprleft = PQfnumber(res,"oprleft"); + i_oprright = PQfnumber(res,"oprright"); + i_oprcom = PQfnumber(res,"oprcom"); + i_oprnegate = PQfnumber(res,"oprnegate"); + i_oprrest = PQfnumber(res,"oprrest"); + i_oprjoin = PQfnumber(res,"oprjoin"); + i_oprcanhash = PQfnumber(res,"oprcanhash"); + i_oprlsortop = PQfnumber(res,"oprlsortop"); + i_oprrsortop = PQfnumber(res,"oprrsortop"); + + for (i=0;i<ntups;i++) { + oprinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid)); + oprinfo[i].oprname = dupstr(PQgetvalue(res,i,i_oprname)); + oprinfo[i].oprkind = dupstr(PQgetvalue(res,i,i_oprkind)); + oprinfo[i].oprcode = dupstr(PQgetvalue(res,i,i_oprcode)); + oprinfo[i].oprleft = dupstr(PQgetvalue(res,i,i_oprleft)); + oprinfo[i].oprright = dupstr(PQgetvalue(res,i,i_oprright)); + oprinfo[i].oprcom = dupstr(PQgetvalue(res,i,i_oprcom)); + oprinfo[i].oprnegate = dupstr(PQgetvalue(res,i,i_oprnegate)); + oprinfo[i].oprrest = dupstr(PQgetvalue(res,i,i_oprrest)); + oprinfo[i].oprjoin = dupstr(PQgetvalue(res,i,i_oprjoin)); + oprinfo[i].oprcanhash = dupstr(PQgetvalue(res,i,i_oprcanhash)); + oprinfo[i].oprlsortop = dupstr(PQgetvalue(res,i,i_oprlsortop)); + oprinfo[i].oprrsortop = dupstr(PQgetvalue(res,i,i_oprrsortop)); + } + + PQclear(res); + res = PQexec(g_conn, "end"); + PQclear(res); + + return oprinfo; +} + + +/* + * getAggregates: + * read all the user-defined aggregates in the system catalogs and + * return them in the AggInfo* structure + * + * numAggs is set to the number of aggregates read in + * + * + */ +AggInfo* +getAggregates(int *numAggs) +{ + PGresult* res; + int ntups; + int i; + char query[MAXQUERYLEN]; + AggInfo *agginfo; + + int i_oid; + int i_aggname; + int i_aggtransfn1; + int i_aggtransfn2; + int i_aggfinalfn; + int i_aggtranstype1; + int i_aggbasetype; + int i_aggtranstype2; + int i_agginitval1; + int i_agginitval2; + + /* find all user-defined aggregates */ + + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, + "SELECT oid, aggname, aggtransfn1, aggtransfn2, aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, agginitval1, agginitval2 from pg_aggregate;"); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getAggregates(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + *numAggs = ntups; + + agginfo = (AggInfo*)malloc(ntups * sizeof(AggInfo)); + + i_oid = PQfnumber(res,"oid"); + i_aggname = PQfnumber(res,"aggname"); + i_aggtransfn1 = PQfnumber(res,"aggtransfn1"); + i_aggtransfn2 = PQfnumber(res,"aggtransfn2"); + i_aggfinalfn = PQfnumber(res,"aggfinalfn"); + i_aggtranstype1 = PQfnumber(res,"aggtranstype1"); + i_aggbasetype = PQfnumber(res,"aggbasetype"); + i_aggtranstype2 = PQfnumber(res,"aggtranstype2"); + i_agginitval1 = PQfnumber(res,"agginitval1"); + i_agginitval2 = PQfnumber(res,"agginitval2"); + + for (i=0;i<ntups;i++) { + agginfo[i].oid = dupstr(PQgetvalue(res,i,i_oid)); + agginfo[i].aggname = dupstr(PQgetvalue(res,i,i_aggname)); + agginfo[i].aggtransfn1 = dupstr(PQgetvalue(res,i,i_aggtransfn1)); + agginfo[i].aggtransfn2 = dupstr(PQgetvalue(res,i,i_aggtransfn2)); + agginfo[i].aggfinalfn = dupstr(PQgetvalue(res,i,i_aggfinalfn)); + agginfo[i].aggtranstype1 = dupstr(PQgetvalue(res,i,i_aggtranstype1)); + agginfo[i].aggbasetype = dupstr(PQgetvalue(res,i,i_aggbasetype)); + agginfo[i].aggtranstype2 = dupstr(PQgetvalue(res,i,i_aggtranstype2)); + agginfo[i].agginitval1 = dupstr(PQgetvalue(res,i,i_agginitval1)); + agginfo[i].agginitval2 = dupstr(PQgetvalue(res,i,i_agginitval2)); + } + + PQclear(res); + + res = PQexec(g_conn, "end"); + PQclear(res); + return agginfo; +} + +/* + * getFuncs: + * read all the user-defined functions in the system catalogs and + * return them in the FuncInfo* structure + * + * numFuncs is set to the number of functions read in + * + * + */ +FuncInfo* +getFuncs(int *numFuncs) +{ + PGresult *res; + int ntups; + int i; + char query[MAXQUERYLEN]; + FuncInfo *finfo; + + int i_oid; + int i_proname; + int i_proowner; + int i_prolang; + int i_pronargs; + int i_proargtypes; + int i_prorettype; + int i_proretset; + int i_prosrc; + int i_probin; + + /* find all user-defined funcs */ + + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, + "SELECT oid, proname, proowner, prolang, pronargs, prorettype, proretset, proargtypes, prosrc, probin from pg_proc where oid > '%d'::oid", + g_last_builtin_oid); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getFuncs(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + *numFuncs = ntups; + + finfo = (FuncInfo*)malloc(ntups * sizeof(FuncInfo)); + + i_oid = PQfnumber(res,"oid"); + i_proname = PQfnumber(res,"proname"); + i_proowner = PQfnumber(res,"proowner"); + i_prolang = PQfnumber(res,"prolang"); + i_pronargs = PQfnumber(res,"pronargs"); + i_proargtypes = PQfnumber(res,"proargtypes"); + i_prorettype = PQfnumber(res,"prorettype"); + i_proretset = PQfnumber(res,"proretset"); + i_prosrc = PQfnumber(res,"prosrc"); + i_probin = PQfnumber(res,"probin"); + + for (i=0;i<ntups;i++) { + finfo[i].oid = dupstr(PQgetvalue(res,i,i_oid)); + finfo[i].proname = dupstr(PQgetvalue(res,i,i_proname)); + finfo[i].proowner = dupstr(PQgetvalue(res,i,i_proowner)); + + finfo[i].prosrc = checkForQuote(PQgetvalue(res,i,i_prosrc)); + finfo[i].probin = dupstr(PQgetvalue(res,i,i_probin)); + + finfo[i].prorettype = dupstr(PQgetvalue(res,i,i_prorettype)); + finfo[i].retset = (strcmp(PQgetvalue(res,i,i_proretset),"t") == 0); + finfo[i].nargs = atoi(PQgetvalue(res,i,i_pronargs)); + finfo[i].lang = (atoi(PQgetvalue(res,i,i_prolang)) == C_PROLANG_OID); + + parseArgTypes(finfo[i].argtypes, PQgetvalue(res,i,i_proargtypes)); + + finfo[i].dumped = 0; + } + + PQclear(res); + res = PQexec(g_conn, "end"); + PQclear(res); + + return finfo; + +} + +/* + * getTables + * read all the user-defined tables (no indices, no catalogs) + * in the system catalogs return them in the TableInfo* structure + * + * numTables is set to the number of tables read in + * + * + */ +TableInfo* +getTables(int *numTables) +{ + PGresult *res; + int ntups; + int i; + char query[MAXQUERYLEN]; + TableInfo *tblinfo; + + int i_oid; + int i_relname; + int i_relarch; + + /* find all the user-defined tables (no indices and no catalogs), + ordering by oid is important so that we always process the parent + tables before the child tables when traversing the tblinfo* + + we ignore tables that start with Xinv */ + + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, + "SELECT oid, relname, relarch from pg_class where relkind = 'r' and relname !~ '^pg_' and relname !~ '^Xinv' order by oid;"); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getTables(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + *numTables = ntups; + + tblinfo = (TableInfo*)malloc(ntups * sizeof(TableInfo)); + + i_oid = PQfnumber(res,"oid"); + i_relname = PQfnumber(res,"relname"); + i_relarch = PQfnumber(res,"relarch"); + + for (i=0;i<ntups;i++) { + tblinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid)); + tblinfo[i].relname = dupstr(PQgetvalue(res,i,i_relname)); + tblinfo[i].relarch = dupstr(PQgetvalue(res,i,i_relarch)); + } + + PQclear(res); + res = PQexec(g_conn, "end"); + PQclear(res); + + return tblinfo; + +} + +/* + * getInherits + * read all the inheritance information + * from the system catalogs return them in the InhInfo* structure + * + * numInherits is set to the number of tables read in + * + * + */ +InhInfo* +getInherits(int *numInherits) +{ + PGresult *res; + int ntups; + int i; + char query[MAXQUERYLEN]; + InhInfo *inhinfo; + + int i_inhrel; + int i_inhparent; + + /* find all the inheritance information */ + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, "SELECT inhrel, inhparent from pg_inherits"); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getInherits(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + *numInherits = ntups; + + inhinfo = (InhInfo*)malloc(ntups * sizeof(InhInfo)); + + i_inhrel = PQfnumber(res,"inhrel"); + i_inhparent = PQfnumber(res,"inhparent"); + + for (i=0;i<ntups;i++) { + inhinfo[i].inhrel = dupstr(PQgetvalue(res,i,i_inhrel)); + inhinfo[i].inhparent = dupstr(PQgetvalue(res,i,i_inhparent)); + } + + PQclear(res); + res = PQexec(g_conn, "end"); + PQclear(res); + return inhinfo; +} + +/* + * getTableAttrs - + * for each table in tblinfo, read its attributes types and names + * + * this is implemented in a very inefficient way right now, looping + * through the tblinfo and doing a join per table to find the attrs and their + * types + * + * modifies tblinfo + */ +void +getTableAttrs(TableInfo* tblinfo, int numTables) +{ + int i,j; + char q[MAXQUERYLEN]; + int i_attname; + int i_typname; + PGresult *res; + int ntups; + + for (i=0;i<numTables;i++) { + + /* skip archive tables */ + if (isArchiveName(tblinfo[i].relname)) + continue; + + /* find all the user attributes and their types*/ + /* we must read the attribute names in attribute number order! */ + /* because we will use the attnum to index into the attnames array + later */ +if (g_verbose) + fprintf(stderr,"%s finding the attrs and types for table: %s %s\n", + g_comment_start, + tblinfo[i].relname, + g_comment_end); + + sprintf(q,"SELECT a.attnum, a.attname, t.typname from pg_attribute a, pg_type t where a.attrelid = '%s'::oid and a.atttypid = t.oid and a.attnum > 0 order by attnum",tblinfo[i].oid); + res = PQexec(g_conn, q); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getTableAttrs(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + i_attname = PQfnumber(res,"attname"); + i_typname = PQfnumber(res,"typname"); + + tblinfo[i].numatts = ntups; + tblinfo[i].attnames = (char**) malloc( ntups * sizeof(char*)); + tblinfo[i].typnames = (char**) malloc( ntups * sizeof(char*)); + tblinfo[i].inhAttrs = (int*) malloc (ntups * sizeof(int)); + tblinfo[i].parentRels = NULL; + tblinfo[i].numParents = 0; + for (j=0;j<ntups;j++) { + tblinfo[i].attnames[j] = dupstr(PQgetvalue(res,j,i_attname)); + tblinfo[i].typnames[j] = dupstr(PQgetvalue(res,j,i_typname)); + tblinfo[i].inhAttrs[j] = 0; /* this flag is set in flagInhAttrs()*/ + } + PQclear(res); + } +} + + +/* + * getIndices + * read all the user-defined indices information + * from the system catalogs return them in the InhInfo* structure + * + * numIndices is set to the number of indices read in + * + * + */ +IndInfo* +getIndices(int *numIndices) +{ + int i; + char query[MAXQUERYLEN]; + PGresult *res; + int ntups; + IndInfo *indinfo; + + int i_indexrelname; + int i_indrelname; + int i_indamname; + int i_indproc; + int i_indkey; + int i_indclassname; + + /* find all the user-defined indices. + We do not handle partial indices. + We also assume that only single key indices + + skip 'Xinx*' - indices on inversion objects + + this is a 5-way join !! + */ + + res = PQexec(g_conn, "begin"); + if (!res || + PQresultStatus(res) != PGRES_COMMAND_OK) { + fprintf(stderr,"BEGIN command failed\n"); + exit_nicely(g_conn); + } + PQclear(res); + + sprintf(query, + "SELECT t1.relname as indexrelname, t2.relname as indrelname, i.indproc, i.indkey[0], o.opcname as indclassname, a.amname as indamname from pg_index i, pg_class t1, pg_class t2, pg_opclass o, pg_am a where t1.oid = i.indexrelid and t2.oid = i.indrelid and o.oid = i.indclass[0] and t1.relam = a.oid and i.indexrelid > '%d'::oid and t2.relname !~ '^pg_' and t1.relname !~ '^Xinx' ;", + g_last_builtin_oid); + + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"getIndices(): SELECT failed"); + exit_nicely(g_conn); + } + + ntups = PQntuples(res); + + *numIndices = ntups; + + indinfo = (IndInfo*)malloc(ntups * sizeof (IndInfo)); + + i_indexrelname = PQfnumber(res,"indexrelname"); + i_indrelname = PQfnumber(res,"indrelname"); + i_indamname = PQfnumber(res,"indamname"); + i_indproc = PQfnumber(res,"indproc"); + i_indkey = PQfnumber(res,"indkey"); + i_indclassname = PQfnumber(res,"indclassname"); + + for (i=0;i<ntups;i++) { + indinfo[i].indexrelname = dupstr(PQgetvalue(res,i,i_indexrelname)); + indinfo[i].indrelname = dupstr(PQgetvalue(res,i,i_indrelname)); + indinfo[i].indamname = dupstr(PQgetvalue(res,i,i_indamname)); + indinfo[i].indproc = dupstr(PQgetvalue(res,i,i_indproc)); + indinfo[i].indkey = dupstr(PQgetvalue(res,i,i_indkey)); + indinfo[i].indclassname = dupstr(PQgetvalue(res,i,i_indclassname)); + } + PQclear(res); + res = PQexec(g_conn,"end"); + + return indinfo; +} + +/* + * dumpTypes + * writes out to fout the queries to recreate all the user-defined types + * + */ +void +dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs, + TypeInfo* tinfo, int numTypes) +{ + int i; + char q[MAXQUERYLEN]; + int funcInd; + + for (i=0;i<numTypes;i++) { + + /* skip all the builtin types */ + if (atoi(tinfo[i].oid) < g_last_builtin_oid) + continue; + + /* skip relation types */ + if (atoi(tinfo[i].typrelid) != 0) + continue; + + /* skip all array types that start w/ underscore */ + if ( (tinfo[i].typname[0] == '_') && + (strcmp(tinfo[i].typinput, "array_in") == 0)) + continue; + + /* before we create a type, we need to create the input and + output functions for it, if they haven't been created already */ + funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput); + if (funcInd != -1) + dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes); + + funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput); + if (funcInd != -1) + dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes); + + sprintf(q, + "CREATE TYPE %s ( internallength = %s, externallength = %s, input = %s, output = %s, send = %s, receive = %s, default = '%s'", + tinfo[i].typname, + tinfo[i].typlen, + tinfo[i].typprtlen, + tinfo[i].typinput, + tinfo[i].typoutput, + tinfo[i].typsend, + tinfo[i].typreceive, + tinfo[i].typdefault); + + if (tinfo[i].isArray) { + char* elemType; + + elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem); + + sprintf(q,"%s, element = %s, delimiter = '%s'", + q, elemType,tinfo[i].typdelim); + } + if (tinfo[i].passedbyvalue) + strcat(q,",passedbyvalue);\n"); + else + strcat(q,");\n"); + + fputs(q,fout); + } +} + +/* + * dumpFuncs + * writes out to fout the queries to recreate all the user-defined functions + * + */ +void +dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs, + TypeInfo *tinfo, int numTypes) +{ + int i; + for (i=0;i<numFuncs;i++) { + dumpOneFunc(fout,finfo,i,tinfo,numTypes); + } +} + +/* + * dumpOneFunc: + * dump out only one function, the index of which is given in the third + * argument + * + */ + +void +dumpOneFunc(FILE* fout, FuncInfo* finfo, int i, + TypeInfo *tinfo, int numTypes) +{ + char q[MAXQUERYLEN]; + int j; + + if (finfo[i].dumped) + return; + else + finfo[i].dumped = 1; + + sprintf(q,"CREATE FUNCTION %s (",finfo[i].proname); + for (j=0;j<finfo[i].nargs;j++) { + char* typname; + typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]); + sprintf(q, "%s%s%s", + q, + (j > 0) ? "," : "", + typname); + } + sprintf(q,"%s ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n", + q, + finfo[i].retset ? " SETOF " : "", + findTypeByOid(tinfo, numTypes, finfo[i].prorettype), + (finfo[i].lang) ? finfo[i].probin : finfo[i].prosrc, + (finfo[i].lang) ? "C" : "SQL"); + + fputs(q,fout); + +} + +/* + * dumpOprs + * writes out to fout the queries to recreate all the user-defined operators + * + */ +void +dumpOprs(FILE* fout, OprInfo* oprinfo, int numOperators, + TypeInfo *tinfo, int numTypes) +{ + int i; + char q[MAXQUERYLEN]; + char leftarg[MAXQUERYLEN]; + char rightarg[MAXQUERYLEN]; + char commutator[MAXQUERYLEN]; + char negator[MAXQUERYLEN]; + char restrict[MAXQUERYLEN]; + char join[MAXQUERYLEN]; + char sortop[MAXQUERYLEN]; + + for (i=0;i<numOperators;i++) { + + /* skip all the builtin oids */ + if (atoi(oprinfo[i].oid) < g_last_builtin_oid) + continue; + + /* some operator are invalid because they were the result + of user defining operators before commutators exist */ + if (strcmp(oprinfo[i].oprcode, "-") == 0) + continue; + + leftarg[0] = '\0'; + rightarg[0] = '\0'; + /* right unary means there's a left arg + and left unary means there's a right arg */ + if (strcmp(oprinfo[i].oprkind, "r") == 0 || + strcmp(oprinfo[i].oprkind, "b") == 0 ) { + sprintf(leftarg, ", LEFTARG = %s ", + findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft)); + } + if (strcmp(oprinfo[i].oprkind, "l") == 0 || + strcmp(oprinfo[i].oprkind, "b") == 0 ) { + sprintf(rightarg, ", RIGHTARG = %s ", + findTypeByOid(tinfo, numTypes, oprinfo[i].oprright)); + } + if (strcmp(oprinfo[i].oprcom, "0") == 0) + commutator[0] = '\0'; + else + sprintf(commutator,", COMMUTATOR = %s ", + findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom)); + + if (strcmp(oprinfo[i].oprnegate, "0") == 0) + negator[0] = '\0'; + else + sprintf(negator,", NEGATOR = %s ", + findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate)); + + if (strcmp(oprinfo[i].oprrest, "-") == 0) + restrict[0] = '\0'; + else + sprintf(restrict,", RESTRICT = %s ", oprinfo[i].oprrest); + + if (strcmp(oprinfo[i].oprjoin,"-") == 0) + join[0] = '\0'; + else + sprintf(join,", JOIN = %s ", oprinfo[i].oprjoin); + + if (strcmp(oprinfo[i].oprlsortop, "0") == 0) + sortop[0] = '\0'; + else + { + sprintf(sortop,", SORT = %s ", + findOprByOid(oprinfo, numOperators, + oprinfo[i].oprlsortop)); + if (strcmp(oprinfo[i].oprrsortop, "0") != 0) + sprintf(sortop, "%s , %s", sortop, + findOprByOid(oprinfo, numOperators, + oprinfo[i].oprlsortop)); + } + + sprintf(q, + "CREATE OPERATOR %s (PROCEDURE = %s %s %s %s %s %s %s %s %s);\n ", + oprinfo[i].oprname, + oprinfo[i].oprcode, + leftarg, + rightarg, + commutator, + negator, + restrict, + (strcmp(oprinfo[i].oprcanhash, "t")) ? ", HASHES" : "", + join, + sortop); + + fputs(q,fout); + } +} + +/* + * dumpAggs + * writes out to fout the queries to create all the user-defined aggregates + * + */ +void +dumpAggs(FILE* fout, AggInfo* agginfo, int numAggs, + TypeInfo *tinfo, int numTypes) +{ + int i; + char q[MAXQUERYLEN]; + char sfunc1[MAXQUERYLEN]; + char sfunc2[MAXQUERYLEN]; + char finalfunc[MAXQUERYLEN]; + char comma1[2], comma2[2]; + + for (i=0;i<numAggs;i++) { + /* skip all the builtin oids */ + if (atoi(agginfo[i].oid) < g_last_builtin_oid) + continue; + + if ( strcmp(agginfo[i].aggtransfn1, "-") == 0) + sfunc1[0] = '\0'; + else { + sprintf(sfunc1, + "SFUNC1 = %s, BASETYPE = %s, STYPE1 = %s", + agginfo[i].aggtransfn1, + findTypeByOid(tinfo,numTypes,agginfo[i].aggbasetype), + findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype1)); + if (agginfo[i].agginitval1) + sprintf(sfunc1, "%s ,INITCOND1 = '%s'", + sfunc1, agginfo[i].agginitval1); + + } + + if ( strcmp(agginfo[i].aggtransfn2, "-") == 0) + sfunc2[0] = '\0'; + else { + sprintf(sfunc2, + "SFUNC2 = %s, STYPE2 = %s", + agginfo[i].aggtransfn2, + findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype2)); + if (agginfo[i].agginitval2) + sprintf(sfunc2,"%s ,INITCOND2 = '%s'", + sfunc2, agginfo[i].agginitval2); + } + + if ( strcmp(agginfo[i].aggfinalfn, "-") == 0) + finalfunc[0] = '\0'; + else { + sprintf(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn); + } + if (sfunc1[0] != '\0' && sfunc2[0] != '\0') { + comma1[0] = ','; comma1[1] = '\0'; + } else + comma1[0] = '\0'; + + if (finalfunc[0] != '\0' && (sfunc1[0] != '\0' || sfunc2[0] != '\0')) { + comma2[0] = ',';comma2[1] = '\0'; + } else + comma2[0] = '\0'; + + sprintf(q,"CREATE AGGREGATE %s ( %s %s %s %s %s );\n", + agginfo[i].aggname, + sfunc1, + comma1, + sfunc2, + comma2, + finalfunc); + + fputs(q,fout); + } +} + +/* + * dumpTables: + * write out to fout all the user-define tables + */ +void +dumpTables(FILE* fout, TableInfo *tblinfo, int numTables, + InhInfo *inhinfo, int numInherits, + TypeInfo *tinfo, int numTypes) +{ + int i,j,k; + char q[MAXQUERYLEN]; + char **parentRels; /* list of names of parent relations */ + int numParents; + int actual_atts; /* number of attrs in this CREATE statment */ + char *archiveMode; + + for (i=0;i<numTables;i++) { + + /* skip archive names*/ + if (isArchiveName(tblinfo[i].relname)) + continue; + + parentRels = tblinfo[i].parentRels; + numParents = tblinfo[i].numParents; + + sprintf(q, "CREATE TABLE %s (", tblinfo[i].relname); + actual_atts = 0; + for (j=0;j<tblinfo[i].numatts;j++) { + if (tblinfo[i].inhAttrs[j] == 0) { + sprintf(q, "%s%s%s %s", + q, + (actual_atts > 0) ? ", " : "", + tblinfo[i].attnames[j], + tblinfo[i].typnames[j]); + actual_atts++; + } + } + + strcat(q,")"); + + if (numParents > 0) { + sprintf(q, "%s inherits ( ",q); + for (k=0;k<numParents;k++){ + sprintf(q, "%s%s%s", + q, + (k>0) ? ", " : "", + parentRels[k]); + } + strcat(q,")"); + } + + switch(tblinfo[i].relarch[0]) { + case 'n': + archiveMode = "none"; + break; + case 'h': + archiveMode = "heavy"; + break; + case 'l': + archiveMode = "light"; + break; + default: + fprintf(stderr, "unknown archive mode\n"); + archiveMode = "none"; + break; + } + + sprintf(q, "%s archive = %s;\n", + q, + archiveMode); + fputs(q,fout); + } +} + +/* + * dumpIndices: + * write out to fout all the user-define indices + */ +void +dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices, + TableInfo* tblinfo, int numTables) +{ + int i; + int tableInd; + char *attname; /* the name of the indexed attribute */ + char *funcname; /* the name of the function to comput the index key from*/ + int indkey; + + char q[MAXQUERYLEN]; + PGresult *res; + + for (i=0;i<numIndices;i++) { + tableInd = findTableByName(tblinfo, numTables, + indinfo[i].indrelname); + indkey = atoi(indinfo[i].indkey) - 1; + attname = tblinfo[tableInd].attnames[indkey]; + if (strcmp(indinfo[i].indproc,"0") == 0) { + funcname = NULL; + } else { + /* the funcname is an oid which we use to + find the name of the pg_proc. We need to do this + because getFuncs() only reads in the user-defined funcs + not all the funcs. We might not find what we want + by looking in FuncInfo**/ + sprintf(q, + "SELECT proname from pg_proc where pg_proc.oid = '%s'::oid", + indinfo[i].indproc); + res = PQexec(g_conn, q); + funcname = dupstr(PQgetvalue(res, 0, + PQfnumber(res,"proname"))); + PQclear(res); + } + sprintf(q,"CREATE INDEX %s on %s using %s (", + indinfo[i].indexrelname, + indinfo[i].indrelname, + indinfo[i].indamname); + if (funcname) { + sprintf(q, "%s %s(%s) %s);\n", + q,funcname, attname, indinfo[i].indclassname); + free(funcname); + } else + sprintf(q, "%s %s %s);\n", + q,attname,indinfo[i].indclassname); + + fputs(q,fout); + } + +} + + + + + +/* + * DumpClasses - + * dump the contents of all the classes. + */ +void +dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout) +{ + char query[255]; +#define COPYBUFSIZ 8192 + char copybuf[COPYBUFSIZ]; + PGresult *res; + int i; + int ret; + int copydone; + + for(i = 0; i < numTables; i++) { + char *classname = tblinfo[i].relname; + + /* skip archive names*/ + if (isArchiveName(classname)) + continue; + + fprintf(fout, "COPY %s from stdin;\n", classname); + sprintf(query, "COPY %s to stdout;\n", classname); + res = PQexec(g_conn, query); + if (!res || + PQresultStatus(res) != PGRES_COPY_OUT) { + fprintf(stderr,"dumpClasses(): COPY to stdout failed"); + exit_nicely(g_conn); + } + copydone = 0; + while (!copydone) { + ret = PQgetline(res->conn, copybuf, COPYBUFSIZ); + + if (copybuf[0] == '.' && copybuf[1] =='\0') { + copydone = true; /* don't print this... */ + } else { + fputs(copybuf, stdout); + switch (ret) { + case EOF: + copydone = true; + /*FALLTHROUGH*/ + case 0: + fputc('\n', stdout); + break; + case 1: + break; + } + } + } + fprintf(fout, ".\n"); + PQclear(res); + PQendcopy(res->conn); + } + +} + +/* + * dumpTuples -- + * prints out the tuples in ASCII representation. The output is a valid + * input to COPY FROM stdin. + * + * We only need to do this for POSTGRES 4.2 databases since the + * COPY TO statment doesn't escape newlines properly. It's been fixed + * in Postgres95. + * + * the attrmap passed in tells how to map the attributes copied in to the + * attributes copied out + */ +void +dumpTuples(PGresult *res, FILE *fout, int* attrmap) +{ + int j, k; + int m, n; + char **outVals = NULL; /* values to copy out */ + + n = PQntuples(res); + m = PQnfields(res); + + if ( m > 0 ) { + /* + * Print out the tuples but only print tuples with at least + * 1 field. + */ + outVals = (char**)malloc(m * sizeof(char*)); + + for (j = 0; j < n; j++) { + for (k = 0; k < m; k++) { + outVals[attrmap[k]] = PQgetvalue(res, j, k); + } + for (k = 0; k < m; k++) { + char *pval = outVals[k]; + + if (k!=0) + fputc('\t', fout); /* delimiter for attribute */ + + if (pval) { + while (*pval != '\0') { + /* escape tabs, newlines and backslashes */ + if (*pval=='\t' || *pval=='\n' || *pval=='\\') + fputc('\\', fout); + fputc(*pval, fout); + pval++; + } + } + } + fputc('\n', fout); /* delimiter for a tuple */ + } + free (outVals); + } +} + + + +/* + * findLastBuiltInOid - + * find the last built in oid + * we do this by looking up the oid of 'template1' in pg_database, + * this is probably not foolproof but comes close +*/ + +int +findLastBuiltinOid() +{ + PGresult* res; + int ntups; + int last_oid; + + res = PQexec(g_conn, + "SELECT oid from pg_database where datname = 'template1';"); + if (res == NULL || + PQresultStatus(res) != PGRES_TUPLES_OK) { + fprintf(stderr,"pg_dump error in finding the template1 database"); + exit_nicely(g_conn); + } + ntups = PQntuples(res); + if (ntups != 1) { + fprintf(stderr,"pg_dump: couldn't find the template1 database. You are really hosed\nGiving up\n"); + exit_nicely(g_conn); + } + last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid"))); + PQclear(res); + return last_oid; +} + + +/* + * checkForQuote: + * checks a string for quote characters and quotes them + */ +char* +checkForQuote(char* s) +{ + char *r; + char c; + char *result; + + int j = 0; + + r = malloc(strlen(s)*3 + 1); /* definitely long enough */ + + while ( (c = *s) != '\0') { + + if (c == '\'') { + r[j++] = '\''; /* quote the single quotes */ + } + r[j++] = c; + s++; + } + r[j] = '\0'; + + result = dupstr(r); + free(r); + + return result; + +} diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h new file mode 100644 index 0000000000..e77960afe4 --- /dev/null +++ b/src/bin/pg_dump/pg_dump.h @@ -0,0 +1,195 @@ +/*------------------------------------------------------------------------- + * + * pg_dump.h + * header file for the pg_dump utility + * + * Copyright (c) 1994, Regents of the University of California + * + * $Id: pg_dump.h,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ + + +/* The *Info data structures run-time C structures used to store + system catalog information */ + +typedef struct _typeInfo { + char* oid; + char* typowner; + char* typname; + char* typlen; + char* typprtlen; + char* typinput; + char* typoutput; + char* typreceive; + char* typsend; + char* typelem; + char* typdelim; + char* typdefault; + char* typrelid; + int passedbyvalue; + int isArray; +} TypeInfo; + +typedef struct _funcInfo { + char* oid; + char* proname; + char* proowner; + int lang; /* 1 if C, else SQL */ + int nargs; + char* argtypes[8]; /* should be derived from obj/fmgr.h instead of hardwired*/ + char* prorettype; + int retset; /* 1 if the function returns a set, 0 otherwise */ + char* prosrc; + char* probin; + int dumped; /* 1 if already dumped */ +} FuncInfo; + +typedef struct _tableInfo { + char *oid; + char *relname; + char *relarch; + int numatts; /* number of attributes */ + int *inhAttrs; /* an array of flags, one for each attribute + if the value is 1, then this attribute is + an inherited attribute */ + char **attnames; /* the attribute names */ + char **typnames; /* fill out attributes */ + int numParents; /* number of (immediate) parent supertables */ + char **parentRels; /* names of parent relations, NULL + if numParents == 0 */ + char **out_attnames; /* the attribute names, in the order they would + be in, when the table is created in the + target query language. + this is needed because the SQL tables will + not have the same order of attributes as + the POSTQUEL tables */ + +} TableInfo; + +typedef struct _inhInfo { + char *oid; + char *inhrel; + char *inhparent; +} InhInfo; + +typedef struct _indInfo { + char *indexrelname; /* name of the secondary index class */ + char *indrelname; /* name of the indexed heap class */ + char *indamname; /* name of the access method (e.g. btree, rtree, etc.) */ + char *indproc; /* oid of the function to compute the index, 0 if none*/ + char *indkey; /* attribute number of the key attribute */ + char *indclassname; /* name of the opclass of the key */ +} IndInfo; + +typedef struct _aggInfo { + char *oid; + char *aggname; + char *aggtransfn1; + char *aggtransfn2; + char *aggfinalfn; + char *aggtranstype1; + char *aggbasetype; + char *aggtranstype2; + char *agginitval1; + char *agginitval2; +} AggInfo; + +typedef struct _oprInfo { + char *oid; + char *oprname; + char *oprkind; /* "b" = binary, "l" = left unary, "r" = right unary */ + char *oprcode; /* operator function name */ + char *oprleft; /* left operand type */ + char *oprright; /* right operand type */ + char *oprcom; /* oid of the commutator operator */ + char *oprnegate; /* oid of the negator operator */ + char *oprrest; /* name of the function to calculate operator restriction + selectivity */ + char *oprjoin; /* name of the function to calculate operator join + selectivity */ + char *oprcanhash; /* can we use hash join strategy ? */ + char *oprlsortop; /* oid's of the left and right sort operators */ + char *oprrsortop; +} OprInfo; + + +/* global decls */ +extern int g_verbose; /* verbose flag */ +extern int g_last_builtin_oid; /* value of the last builtin oid */ +extern FILE *g_fout; /* the script file */ + +/* placeholders for comment starting and ending delimiters */ +extern char g_comment_start[10]; +extern char g_comment_end[10]; + +extern char g_opaque_type[10]; /* name for the opaque type */ + +/* pg_dump is really two programs in one + one version works with postgres v4r2 + and the other works with postgres95 + the common routines are declared here +*/ +/* + * common utility functions +*/ + +extern TableInfo* dumpSchema(FILE* fout, int *numTablesPtr); + +extern char* findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid); +extern char* findOprByOid(OprInfo *oprinfo, int numOprs, char *oid); +extern int findFuncByName(FuncInfo* finfo, int numFuncs, char* name); +extern char** findParentsByOid(TableInfo* tbinfo, int numTables, + InhInfo* inhinfo, int numInherits, + char *oid, + int *numParents); +extern int findTableByName(TableInfo *tbinfo, int numTables, char *relname); +extern int findTableByOid(TableInfo *tbinfo, int numTables, char *oid); +extern void flagInhAttrs(TableInfo* tbinfo, int numTables, + InhInfo* inhinfo, int numInherits); + +extern void check_conn_and_db(); +extern char* dupstr(char *s); +extern int strInArray(char* pattern, char** arr, int arr_size); +extern void parseArgTypes(char **argtypes, char* str); +extern int isArchiveName(char*); + +/* + * version specific routines + */ +extern TypeInfo* getTypes(int *numTypes); +extern FuncInfo* getFuncs(int *numFuncs); +extern AggInfo* getAggregates(int *numAggregates); +extern OprInfo* getOperators(int *numOperators); +extern TableInfo* getTables(int *numTables); +extern InhInfo* getInherits(int *numInherits); +extern void getTableAttrs(TableInfo* tbinfo, int numTables); +extern IndInfo* getIndices(int *numIndices); +extern void dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs, + TypeInfo* tinfo, int numTypes); +extern void dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs, + TypeInfo *tinfo, int numTypes); +extern void dumpAggs(FILE* fout, AggInfo* agginfo, int numAggregates, + TypeInfo *tinfo, int numTypes); +extern void dumpOprs(FILE* fout, OprInfo* agginfo, int numOperators, + TypeInfo *tinfo, int numTypes); +extern void dumpOneFunc(FILE* fout, FuncInfo* finfo, int i, + TypeInfo *tinfo, int numTypes); +extern void dumpTables(FILE* fout, TableInfo* tbinfo, int numTables, + InhInfo *inhinfo, int numInherits, + TypeInfo *tinfo, int numTypes); +extern void dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices, + TableInfo* tbinfo, int numTables); + +extern void dumpClasses(TableInfo *tbinfo, int numTables, FILE *fout); +extern void dumpTuples(PGresult *res, FILE *fout, int *attrmap); +extern char* checkForQuote(char* s); +extern int findLastBuiltinOid(); + + +/* largest query string size */ +#define MAXQUERYLEN 5000 + +/* these voodoo constants are from the backend */ +#define C_PROLANG_OID 13 |
