diff options
Diffstat (limited to 'src/bin/pg4_dump')
| -rw-r--r-- | src/bin/pg4_dump/Makefile | 13 | ||||
| -rw-r--r-- | src/bin/pg4_dump/README | 87 | ||||
| -rw-r--r-- | src/bin/pg4_dump/common.c | 417 | ||||
| -rw-r--r-- | src/bin/pg4_dump/pg4_dump.c | 1602 | ||||
| -rw-r--r-- | src/bin/pg4_dump/pg_dump.h | 195 |
5 files changed, 2314 insertions, 0 deletions
diff --git a/src/bin/pg4_dump/Makefile b/src/bin/pg4_dump/Makefile new file mode 100644 index 00000000000..286f96ea299 --- /dev/null +++ b/src/bin/pg4_dump/Makefile @@ -0,0 +1,13 @@ +# +# /usr/local/devel/pglite/cvs/src/bin/pg_dump/Makefile.v4r2,v 1.1 1995/05/17 18:57:10 jolly Exp +# + +.include <postgres.global.mk> + +CFLAGS+= -I${.CURDIR}/../../backend/tmp + +PROG= pg4_dump + +SRCS= pg4_dump.c common.c + +.include <postgres.prog.mk> diff --git a/src/bin/pg4_dump/README b/src/bin/pg4_dump/README new file mode 100644 index 00000000000..4ac54517096 --- /dev/null +++ b/src/bin/pg4_dump/README @@ -0,0 +1,87 @@ +pg4_dump is a utility for dumping out a postgres (version 4, release 2) +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. + +The sources in this directory can be used to build two different +versions of the program. The two versions require different +versions of libpq, and the same binary cannot serve both purposes. + + + To build: + + % bmake clean install + + This version of the program will read in your postgres v4r2 +database and output the schema and the data tuples in one of two +formats: POSTQUEL or SQL. The POSTQUEL->POSTQUEL dumps are useful +for moving from one v4r2 installation to another. The POSTQUEL->SQL +dumps are useful for migrating from v4r2 to postgres95. + +Use the -o [SQL|POSTQUEL] option to specify output query language. + + +How to use pg4_dump: +------------------- + +The command line options are fairly self explanatory. Use -help to +see the command line options. I recommend using -v to get more +verbose descriptions of what pg_dump is doing. + +After running pg4_dump, one should examine the output script file for any +warnings, especially in light of the limitations listed below. + +A typical use of pg4_dump: + + % pg4_dump -v -f oldDB.dump oldDB + % createdb newDB + % monitor newDB < oldDB.dump + + +Caveats and limitations: +------------------------ + +pg4_dump has a few limitations. The limitations mostly stem from +difficulty in extracting certain meta-information from the system +catalogs. + + rules and views: + pg4_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: + pg4_dump does not understand partial indices. (The reason is + the same as above. Partial index predicates are stored as plans) + + source text of POSTQUEL functions: + pg4_dump does not convert the source text of a user-defined + POSTQUEL function into SQL. Manual intervention is required. + + large objects: + pg4_dump does not handle large objects. Inversion large + objects are ignored and must be dealt with manually. + + oid preservation: + pg4_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. + +pg4_dump has not been tested and will probably not work properly for +versions of postgres prior to 4.2. + +Bug-reporting +-------------- + +If you should find a problem with pg4_dump, it is very important that +you provide a (small) sample database which illustrates the problem. +Please send bugs, questions, and feedback to the + + + diff --git a/src/bin/pg4_dump/common.c b/src/bin/pg4_dump/common.c new file mode 100644 index 00000000000..f485c152c67 --- /dev/null +++ b/src/bin/pg4_dump/common.c @@ -0,0 +1,417 @@ +/*------------------------------------------------------------------------- + * + * common.c-- + * common routines between pg_dump and pg4_dump + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * /usr/local/devel/pglite/cvs/src/bin/pg_dump/common.c,v 1.5 1995/06/28 22:32:35 jolly 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 "libpq/auth.h" + +#include "pg_dump.h" + +/* + * check_conn_and_db checks the connection and the database + */ +void +check_conn_and_db() +{ + char *string= PQexec(" "); + switch(*string) { + case 'E': + case 'R': + PQfinish(); + exit(2); + break; + } +} + + +/* 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 i, 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; + char *parentRels; + int numParents; + + /* 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/pg4_dump/pg4_dump.c b/src/bin/pg4_dump/pg4_dump.c new file mode 100644 index 00000000000..6e6ee6fa573 --- /dev/null +++ b/src/bin/pg4_dump/pg4_dump.c @@ -0,0 +1,1602 @@ +/*------------------------------------------------------------------------- + * + * pg4_dump.c-- + * pg4_dump is an utility for dumping out a postgres database + * into a script file. + * + * pg4_dump will read the system catalogs from a postgresV4r2 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 either POSTQUEL or SQL + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * /usr/local/devel/pglite/cvs/src/bin/pg_dump/pg4_dump.c,v 1.1 1995/05/18 19:23:53 jolly 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 "tmp/postgres.h" +#include "tmp/libpq-fe.h" +#include "libpq/auth.h" + +#include "pg_dump.h" + +extern char *optarg; +extern int optind, opterr; + +/* these are used in libpq */ +extern char *PQhost; /* machine on which the backend is running */ +extern char *PQport; /* comm. port with the postgres backend. */ +extern char *PQtty; /* the tty where postgres msgs are displayed */ +extern char *PQdatabase; /* the postgres db to access. */ + +/* global decls */ +int g_verbose; /* verbose flag */ +int g_last_builtin_oid; /* value of the last builtin oid */ +FILE *g_fout; /* the script file */ + +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]; + +int g_outputSQL; /* if 1, output SQL, otherwise , output Postquel */ + +static +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 -o [SQL|POSTQUEL} \t\t output format\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, "\tpg4_dump dumps out postgres databases and produces a script file\n"); + fprintf(stderr, "\tof query commands to regenerate the schema\n"); + fprintf(stderr, "\tThe output format is either POSTQUEL or SQL. The default is SQL\n"); + exit(1); +} + +void +main(int argc, char** argv) +{ + int c; + char* progname; + char* filename; + char* dbname; + char *username, usernamebuf[NAMEDATALEN + 1]; + char hostbuf[MAXHOSTNAMELEN]; + int schemaOnly; + + TableInfo *tblinfo; + int numTables; + + + dbname = NULL; + filename = NULL; + g_verbose = 0; + g_outputSQL = 1; + schemaOnly = 0; + + progname = *argv; + + while ((c = getopt(argc, argv,"f:H:o:p:vSD")) != EOF) { + switch(c) { + case 'f': /* output file name */ + filename = optarg; + break; + case 'H' : /* server host */ + PQhost = optarg; + break; + case 'o': + { + char *lang = optarg; + if (lang) { + if (strcmp(lang,"SQL") != 0) + g_outputSQL = 0; + } + } + break; + case 'p' : /* server port */ + PQport = 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); + } + } + + /* Determine our username (according to the authentication system, if + * there is one). + */ + if ((username = fe_getauthname()) == (char *) NULL) { + fprintf(stderr, "%s: could not find a valid user name\n",progname); + exit(2); + } + memset(usernamebuf, 0, sizeof(usernamebuf)); + (void) strncpy(usernamebuf, username, NAMEDATALEN); + username = usernamebuf; + + /* + * Determine the hostname of the database server. Try to avoid using + * "localhost" if at all possible. + */ + if (!PQhost && !(PQhost = getenv("PGHOST"))) + PQhost = "localhost"; + if (!strcmp(PQhost, "localhost")) { + if (gethostname(hostbuf, MAXHOSTNAMELEN) != -1) + PQhost = hostbuf; + } + + + /* find database */ + if (!(dbname = argv[optind]) && + !(dbname = getenv("DATABASE")) && + !(dbname = username)) { + fprintf(stderr, "%s: no database name specified\n",progname); + exit (2); + } + + PQsetdb(dbname); + + /* make sure things are ok before giving users a warm welcome! */ + check_conn_and_db(); + + if (g_outputSQL) { + strcpy(g_comment_start,"-- "); + g_comment_end[0] = '\0'; + strcpy(g_opaque_type, "opaque"); + } else { + strcpy(g_comment_start,"/* "); + strcpy(g_comment_end,"*/ "); + strcpy(g_opaque_type, "any"); + } + + 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 ); + fprintf(stderr, "%s the output language is %s %s\n", + g_comment_start, + (g_outputSQL) ? "SQL" : "POSTQUEL", + g_comment_end); +} + + dumpClasses(tblinfo, numTables, g_fout); + } + + fflush(g_fout); + fclose(g_fout); + 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) +{ + char* res; + PortalBuffer* pbuf; + 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; + + PQexec("begin"); + + /* 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"); +*/ + sprintf(query, "retrieve (t.oid, t.typowner, t.typname, t.typlen, t.typprtlen, t.typinput, t.typoutput, t.typreceive, t.typsend, t.typelem, t.typdelim, t.typdefault, t.typrelid, t.typbyval) from t in pg_type"); + + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + tinfo = (TypeInfo*)malloc(ntups * sizeof(TypeInfo)); + + i_oid = PQfnumberGroup(pbuf,0,"oid"); + i_typowner = PQfnumberGroup(pbuf,0,"typowner"); + i_typname = PQfnumberGroup(pbuf,0,"typname"); + i_typlen = PQfnumberGroup(pbuf,0,"typlen"); + i_typprtlen = PQfnumberGroup(pbuf,0,"typprtlen"); + i_typinput = PQfnumberGroup(pbuf,0,"typinput"); + i_typoutput = PQfnumberGroup(pbuf,0,"typoutput"); + i_typreceive = PQfnumberGroup(pbuf,0,"typreceive"); + i_typsend = PQfnumberGroup(pbuf,0,"typsend"); + i_typelem = PQfnumberGroup(pbuf,0,"typelem"); + i_typdelim = PQfnumberGroup(pbuf,0,"typdelim"); + i_typdefault = PQfnumberGroup(pbuf,0,"typdefault"); + i_typrelid = PQfnumberGroup(pbuf,0,"typrelid"); + i_typbyval = PQfnumberGroup(pbuf,0,"typbyval"); + + for (i=0;i<ntups;i++) { + tinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid)); + tinfo[i].typowner = dupstr(PQgetvalue(pbuf,i,i_typowner)); + tinfo[i].typname = dupstr(PQgetvalue(pbuf,i,i_typname)); + tinfo[i].typlen = dupstr(PQgetvalue(pbuf,i,i_typlen)); + tinfo[i].typprtlen = dupstr(PQgetvalue(pbuf,i,i_typprtlen)); + tinfo[i].typinput = dupstr(PQgetvalue(pbuf,i,i_typinput)); + tinfo[i].typoutput = dupstr(PQgetvalue(pbuf,i,i_typoutput)); + tinfo[i].typreceive = dupstr(PQgetvalue(pbuf,i,i_typreceive)); + tinfo[i].typsend = dupstr(PQgetvalue(pbuf,i,i_typsend)); + tinfo[i].typelem = dupstr(PQgetvalue(pbuf,i,i_typelem)); + tinfo[i].typdelim = dupstr(PQgetvalue(pbuf,i,i_typdelim)); + tinfo[i].typdefault = dupstr(PQgetvalue(pbuf,i,i_typdefault)); + tinfo[i].typrelid = dupstr(PQgetvalue(pbuf,i,i_typrelid)); + + if (strcmp(PQgetvalue(pbuf,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; + + PQexec("end"); + PQclear(res+1); + 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) +{ + char *res; + PortalBuffer *pbuf; + 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 */ + PQexec("begin"); +/* + sprintf(query, "SELECT oid, oprname, oprkind, oprcode, oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, oprcanhash, oprlsortop, oprrsortop from pg_operator"); +*/ + sprintf(query, "retrieve (o.oid, o.oprname, o.oprkind, o.oprcode, o.oprleft, o.oprright, o.oprcom, o.oprnegate, o.oprrest, o.oprjoin, o.oprcanhash, o.oprlsortop, o.oprrsortop) from o in pg_operator"); + + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + *numOprs = ntups; + + oprinfo = (OprInfo*)malloc(ntups * sizeof(OprInfo)); + + i_oid = PQfnumberGroup(pbuf,0,"oid"); + i_oprname = PQfnumberGroup(pbuf,0,"oprname"); + i_oprkind = PQfnumberGroup(pbuf,0,"oprkind"); + i_oprcode = PQfnumberGroup(pbuf,0,"oprcode"); + i_oprleft = PQfnumberGroup(pbuf,0,"oprleft"); + i_oprright = PQfnumberGroup(pbuf,0,"oprright"); + i_oprcom = PQfnumberGroup(pbuf,0,"oprcom"); + i_oprnegate = PQfnumberGroup(pbuf,0,"oprnegate"); + i_oprrest = PQfnumberGroup(pbuf,0,"oprrest"); + i_oprjoin = PQfnumberGroup(pbuf,0,"oprjoin"); + i_oprcanhash = PQfnumberGroup(pbuf,0,"oprcanhash"); + i_oprlsortop = PQfnumberGroup(pbuf,0,"oprlsortop"); + i_oprrsortop = PQfnumberGroup(pbuf,0,"oprrsortop"); + + for (i=0;i<ntups;i++) { + oprinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid)); + oprinfo[i].oprname = dupstr(PQgetvalue(pbuf,i,i_oprname)); + oprinfo[i].oprkind = dupstr(PQgetvalue(pbuf,i,i_oprkind)); + oprinfo[i].oprcode = dupstr(PQgetvalue(pbuf,i,i_oprcode)); + oprinfo[i].oprleft = dupstr(PQgetvalue(pbuf,i,i_oprleft)); + oprinfo[i].oprright = dupstr(PQgetvalue(pbuf,i,i_oprright)); + oprinfo[i].oprcom = dupstr(PQgetvalue(pbuf,i,i_oprcom)); + oprinfo[i].oprnegate = dupstr(PQgetvalue(pbuf,i,i_oprnegate)); + oprinfo[i].oprrest = dupstr(PQgetvalue(pbuf,i,i_oprrest)); + oprinfo[i].oprjoin = dupstr(PQgetvalue(pbuf,i,i_oprjoin)); + oprinfo[i].oprcanhash = dupstr(PQgetvalue(pbuf,i,i_oprcanhash)); + oprinfo[i].oprlsortop = dupstr(PQgetvalue(pbuf,i,i_oprlsortop)); + oprinfo[i].oprrsortop = dupstr(PQgetvalue(pbuf,i,i_oprrsortop)); + } + + PQclear(res+1); + PQexec("end"); + + 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) +{ + char* res; + PortalBuffer *pbuf; + 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 */ + + PQexec("begin"); +/* + sprintf(query, + "SELECT oid, aggname, aggtransfn1, aggtransfn2, aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, agginitval1, agginitval2 from pg_aggregate;"); +*/ + sprintf(query, + "retrieve (a.oid, a.aggname, a.aggtransfn1, a.aggtransfn2, a.aggfinalfn, a.aggtranstype1, a.aggbasetype, a.aggtranstype2, a.agginitval1, a.agginitval2) from a in pg_aggregate"); + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + *numAggs = ntups; + + agginfo = (AggInfo*)malloc(ntups * sizeof(AggInfo)); + + i_oid = PQfnumberGroup(pbuf,0,"oid"); + i_aggname = PQfnumberGroup(pbuf,0,"aggname"); + i_aggtransfn1 = PQfnumberGroup(pbuf,0,"aggtransfn1"); + i_aggtransfn2 = PQfnumberGroup(pbuf,0,"aggtransfn2"); + i_aggfinalfn = PQfnumberGroup(pbuf,0,"aggfinalfn"); + i_aggtranstype1 = PQfnumberGroup(pbuf,0,"aggtranstype1"); + i_aggbasetype = PQfnumberGroup(pbuf,0,"aggbasetype"); + i_aggtranstype2 = PQfnumberGroup(pbuf,0,"aggtranstype2"); + i_agginitval1 = PQfnumberGroup(pbuf,0,"agginitval1"); + i_agginitval2 = PQfnumberGroup(pbuf,0,"agginitval2"); + + for (i=0;i<ntups;i++) { + agginfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid)); + agginfo[i].aggname = dupstr(PQgetvalue(pbuf,i,i_aggname)); + agginfo[i].aggtransfn1 = dupstr(PQgetvalue(pbuf,i,i_aggtransfn1)); + agginfo[i].aggtransfn2 = dupstr(PQgetvalue(pbuf,i,i_aggtransfn2)); + agginfo[i].aggfinalfn = dupstr(PQgetvalue(pbuf,i,i_aggfinalfn)); + agginfo[i].aggtranstype1 = dupstr(PQgetvalue(pbuf,i,i_aggtranstype1)); + agginfo[i].aggbasetype = dupstr(PQgetvalue(pbuf,i,i_aggbasetype)); + agginfo[i].aggtranstype2 = dupstr(PQgetvalue(pbuf,i,i_aggtranstype2)); + agginfo[i].agginitval1 = dupstr(PQgetvalue(pbuf,i,i_agginitval1)); + agginfo[i].agginitval2 = dupstr(PQgetvalue(pbuf,i,i_agginitval2)); + } + + PQclear(res+1); + PQexec("end"); + + 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) +{ + char* res; + PortalBuffer *pbuf; + int ntups; + int i, j; + char query[MAXQUERYLEN]; + FuncInfo *finfo; + char *proargtypes; + + 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 */ + + PQexec("begin"); + +/* + sprintf(query, + "SELECT oid, proname, proowner, prolang, pronargs, prorettype, proretset, proargtypes, prosrc, probin from pg_proc where oid > '%d'::oid", + g_last_builtin_oid); +*/ + sprintf(query, + "retrieve (f.oid, f.proname, f.proowner, f.prolang, f.pronargs, f.prorettype, f.proretset, f.proargtypes, f.prosrc, f.probin) from f in pg_proc where f.oid > \"%d\"::oid", + g_last_builtin_oid); + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + *numFuncs = ntups; + + finfo = (FuncInfo*)malloc(ntups * sizeof(FuncInfo)); + + i_oid = PQfnumberGroup(pbuf,0,"oid"); + i_proname = PQfnumberGroup(pbuf,0,"proname"); + i_proowner = PQfnumberGroup(pbuf,0,"proowner"); + i_prolang = PQfnumberGroup(pbuf,0,"prolang"); + i_pronargs = PQfnumberGroup(pbuf,0,"pronargs"); + i_proargtypes = PQfnumberGroup(pbuf,0,"proargtypes"); + i_prorettype = PQfnumberGroup(pbuf,0,"prorettype"); + i_proretset = PQfnumberGroup(pbuf,0,"proretset"); + i_prosrc = PQfnumberGroup(pbuf,0,"prosrc"); + i_probin = PQfnumberGroup(pbuf,0,"probin"); + + for (i=0;i<ntups;i++) { + finfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid)); + finfo[i].proname = dupstr(PQgetvalue(pbuf,i,i_proname)); + finfo[i].proowner = dupstr(PQgetvalue(pbuf,i,i_proowner)); + + finfo[i].prosrc = checkForQuote(PQgetvalue(pbuf,i,i_prosrc)); + finfo[i].probin = dupstr(PQgetvalue(pbuf,i,i_probin)); + + finfo[i].prorettype = dupstr(PQgetvalue(pbuf,i,i_prorettype)); + finfo[i].retset = (strcmp(PQgetvalue(pbuf,i,i_proretset),"t") == 0); + finfo[i].nargs = atoi(PQgetvalue(pbuf,i,i_pronargs)); + finfo[i].lang = (atoi(PQgetvalue(pbuf,i,i_prolang)) == C_PROLANG_OID); + + parseArgTypes(finfo[i].argtypes, PQgetvalue(pbuf,i,i_proargtypes)); + + finfo[i].dumped = 0; + } + + PQclear(res+1); + PQexec("end"); + + 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) +{ + char* res; + PortalBuffer* pbuf; + int ntups; + int i, j; + 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* */ + PQexec("begin"); +/* + sprintf(query, + "SELECT oid, relname, relarch from pg_class where relkind = 'r' and relname !~ '^pg_' order by oid;"); +*/ + sprintf(query, + "retrieve (r.oid, r.relname, r.relarch) from r in pg_class where r.relkind = \"r\" and r.relname !~ \"^pg_\" and r.relname !~ \"^Xinv\" sort by oid"); + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + *numTables = ntups; + + tblinfo = (TableInfo*)malloc(ntups * sizeof(TableInfo)); + + i_oid = PQfnumberGroup(pbuf,0,"oid"); + i_relname = PQfnumberGroup(pbuf,0,"relname"); + i_relarch = PQfnumberGroup(pbuf,0,"relarch"); + + for (i=0;i<ntups;i++) { + tblinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid)); + tblinfo[i].relname = dupstr(PQgetvalue(pbuf,i,i_relname)); + tblinfo[i].relarch = dupstr(PQgetvalue(pbuf,i,i_relarch)); + } + + PQclear(res+1); + PQexec("end"); + + 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) +{ + char* res; + PortalBuffer* pbuf; + int ntups; + int i; + char query[MAXQUERYLEN]; + InhInfo *inhinfo; + + int i_inhrel; + int i_inhparent; + + /* find all the inheritance information */ + PQexec("begin"); +/* + sprintf(query, "SELECT inhrel, inhparent from pg_inherits"); +*/ + sprintf(query, "retrieve (i.inhrel, i.inhparent) from i in pg_inherits"); + + res = PQexec(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + *numInherits = ntups; + + inhinfo = (InhInfo*)malloc(ntups * sizeof(InhInfo)); + + i_inhrel = PQfnumberGroup(pbuf,0,"inhrel"); + i_inhparent = PQfnumberGroup(pbuf,0,"inhparent"); + + for (i=0;i<ntups;i++) { + inhinfo[i].inhrel = dupstr(PQgetvalue(pbuf,i,i_inhrel)); + inhinfo[i].inhparent = dupstr(PQgetvalue(pbuf,i,i_inhparent)); + } + + PQclear(res+1); + PQexec("end"); + 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; + char *res; + PortalBuffer *pbuf; + int ntups; + + for (i=0;i<numTables;i++) { + + /* 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 */ +/* + sprintf(q,"SELECT a.attnum, a.attname, t.typname from pg_attribute a, pg_type t where a.attrelid = '%s' and a.atttypid = t.oid and a.attnum > 0 order by attnum",tblinfo[i].oid); +*/ +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,"retrieve (a.attnum, a.attname, t.typname) from a in pg_attribute, t in pg_type where a.attrelid = \"%s\" and a.atttypid = t.oid and a.attnum > 0 sort by attnum",tblinfo[i].oid); + + res = PQexec(q); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + i_attname = PQfnumberGroup(pbuf,0,"attname"); + i_typname = PQfnumberGroup(pbuf,0,"typname"); + + tblinfo[i].numatts = ntups; + tblinfo[i].attnames = (char**) malloc( ntups * sizeof(char*)); + tblinfo[i].out_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(pbuf,j,i_attname)); + tblinfo[i].typnames[j] = dupstr(PQgetvalue(pbuf,j,i_typname)); + tblinfo[i].inhAttrs[j] = 0; /* this flag is set in flagInhAttrs()*/ + } + PQclear(res+1); + } +} + + +/* + * 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]; + char *res; + PortalBuffer *pbuf; + 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-define indices. + We do not handle partial indices. + We also assume that only single key indices + + this is a 5-way join !! + */ + + PQexec("begin"); +/* + 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_';", + g_last_builtin_oid); +*/ + + sprintf(query, + "retrieve (indexrelname = t1.relname, indrelname = t2.relname, i.indproc, i.indkey[0], indclassname = o.opcname, indamname = a.amname) from i in pg_index, t1 in pg_class, t2 in pg_class, o in pg_opclass, a in pg_am 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(query); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + + *numIndices = ntups; + + indinfo = (IndInfo*)malloc(ntups * sizeof (IndInfo)); + + i_indexrelname = PQfnumberGroup(pbuf,0,"indexrelname"); + i_indrelname = PQfnumberGroup(pbuf,0,"indrelname"); + i_indamname = PQfnumberGroup(pbuf,0,"indamname"); + i_indproc = PQfnumberGroup(pbuf,0,"indproc"); + i_indkey = PQfnumberGroup(pbuf,0,"indkey"); + i_indclassname = PQfnumberGroup(pbuf,0,"indclassname"); + + for (i=0;i<ntups;i++) { + indinfo[i].indexrelname = dupstr(PQgetvalue(pbuf,i,i_indexrelname)); + indinfo[i].indrelname = dupstr(PQgetvalue(pbuf,i,i_indrelname)); + indinfo[i].indamname = dupstr(PQgetvalue(pbuf,i,i_indamname)); + indinfo[i].indproc = dupstr(PQgetvalue(pbuf,i,i_indproc)); + indinfo[i].indkey = dupstr(PQgetvalue(pbuf,i,i_indkey)); + indinfo[i].indclassname = dupstr(PQgetvalue(pbuf,i,i_indclassname)); + } + PQclear(res+1); + PQexec("end"); + + return indinfo; +} + +/* + * dumpTypes + * writes out to fout 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); + + if (g_outputSQL) { + 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); + } else { + sprintf(q, + "define type %s ( internallength = %s, externallength = %s, input = %s, output = %s, send = %s, receive = %s, default = \"%s\"", + tinfo[i].typname, + (strcmp(tinfo[i].typlen, "-1") == 0) ? "variable" : tinfo[i].typlen, + (strcmp(tinfo[i].typprtlen, "-1") == 0) ? "variable " :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); + + if (g_outputSQL) + sprintf(q,"%s, element = %s, delimiter = '%s'", + q, elemType,tinfo[i].typdelim); + else + sprintf(q,"%s, element = %s, delimiter = \"%s\"", + q, elemType,tinfo[i].typdelim); + } + if (tinfo[i].passedbyvalue) + strcat(q,",passedbyvalue"); + else + strcat(q,")"); + + if (g_outputSQL) + strcat(q,";\n"); + else + strcat(q,"\\g\n"); + + fputs(q,fout); + } + fflush(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; + char q[MAXQUERYLEN]; + 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; + + if (g_outputSQL) { + 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"); +if (finfo[i].lang != 1) { + fprintf(stderr, + "%s WARNING: text of function named %s is in POSTQUEL %s\n", + g_comment_start, + finfo[i].proname, + g_comment_end); +} + + } else { + sprintf(q,"define function %s ( language = \"%s\", returntype = %s%s) arg is (", + finfo[i].proname, + (finfo[i].lang) ? "c" : "postquel", + finfo[i].retset ? " setof " : "", + findTypeByOid(tinfo, numTypes, finfo[i].prorettype) + ); + + 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 ) as \"%s\"\\g\n", + q, + (finfo[i].lang) ? finfo[i].probin : finfo[i].prosrc); + } + + fputs(q,fout); + fflush(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]; + char comma[2]; + + 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, ", %s = %s ", + (g_outputSQL) ? "LEFTARG" : "arg1", + findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft)); + } + if (strcmp(oprinfo[i].oprkind, "l") == 0 || + strcmp(oprinfo[i].oprkind, "b") == 0 ) { + sprintf(rightarg, ", %s = %s ", + (g_outputSQL) ? "RIGHTARG" : "arg2", + 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)); + } + + if (g_outputSQL) { + 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); + } else + sprintf(q, + "define operator %s (procedure = %s %s %s %s %s %s %s %s %s)\\g\n ", + oprinfo[i].oprname, + oprinfo[i].oprcode, + leftarg, + rightarg, + commutator, + negator, + restrict, + (strcmp(oprinfo[i].oprcanhash, "t")) ? ", hashes" : "", + join, + sortop); + + fputs(q,fout); + } + fflush(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 *basetype; + char *stype1; + char *stype2; + 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) { + if (g_outputSQL) + sprintf(sfunc1, "%s ,INITCOND1 = '%s'", + sfunc1, agginfo[i].agginitval1); + else + 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) { + if (g_outputSQL) + sprintf(sfunc2,"%s ,initcond2 = '%s'", + sfunc2, agginfo[i].agginitval2); + else + 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'; + + if (g_outputSQL) { + sprintf(q,"CREATE AGGREGATE %s ( %s %s %s %s %s );\n", + agginfo[i].aggname, + sfunc1, + comma1, + sfunc2, + comma2, + finalfunc); + } else { + sprintf(q,"define aggregate %s ( %s %s %s %s %s )\\g\n", + agginfo[i].aggname, + sfunc1, + comma1, + sfunc2, + comma2, + finalfunc); + } + + fputs(q,fout); + } + fflush(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; + char *res; + PortalBuffer *pbuf; + int ntups; + int actual_atts; /* number of attrs in this CREATE statment */ + char *archiveMode; + + for (i=0;i<numTables;i++) { + parentRels = tblinfo[i].parentRels; + numParents = tblinfo[i].numParents; + + if (g_outputSQL) { + sprintf(q, "CREATE TABLE %s (", tblinfo[i].relname); + } else { + sprintf(q, "create %s (", tblinfo[i].relname); + } + + actual_atts = 0; + for (j=0;j<tblinfo[i].numatts;j++) { + if (tblinfo[i].inhAttrs[j] == 0) { + if (g_outputSQL) { + sprintf(q, "%s%s%s %s", + q, + (actual_atts > 0) ? ", " : "", + tblinfo[i].attnames[j], + tblinfo[i].typnames[j]); + } + else { + 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) { + int oa = 0; /* index for the out_attnames array */ + int l; + int parentInd; + + sprintf(q, "%s inherits ( ",q); + for (k=0;k<numParents;k++){ + sprintf(q, "%s%s%s", + q, + (k>0) ? ", " : "", + parentRels[k]); + parentInd = findTableByName(tblinfo,numTables,parentRels[k]); + + /* the out_attnames are in order of the out_attnames + of the parent tables */ + for (l=0; l<tblinfo[parentInd].numatts;l++) + tblinfo[i].out_attnames[oa++] = + tblinfo[parentInd].out_attnames[l]; + } + + /* include non-inherited attrs in out_attnames also, + oa should never exceed numatts */ + for (l=0; l < tblinfo[i].numatts && oa < tblinfo[i].numatts ; l++) + if (tblinfo[i].inhAttrs[l] == 0) { + tblinfo[i].out_attnames[oa++] = + tblinfo[i].attnames[l]; + } + + strcat(q,")"); + } else { /* for non-inherited tables, out_attnames + and attnames are the same */ + tblinfo[i].out_attnames = tblinfo[i].attnames; + } + + 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; + } + + if (g_outputSQL) { + sprintf(q, "%s archive = %s;\n", + q, + archiveMode); + } else { + sprintf(q, "%s archive = %s\\g\n", + q, + archiveMode); + } + + fputs(q,fout); + } + fflush(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,j; + int tableInd; + char *attname; /* the name of the indexed attribute */ + char *funcname; /* the name of the function to compute the index key from*/ + int indkey; + + char q[MAXQUERYLEN]; + char *res; + PortalBuffer *pbuf; + + 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, + "retrieve(p.proname) from p in pg_proc where p.oid = \"%s\"::oid", + indinfo[i].indproc); + res = PQexec(q); + pbuf = PQparray(res+1); + funcname = dupstr(PQgetvalue(pbuf,0, + PQfnumberGroup(pbuf,0,"proname"))); + PQclear(res+1); + } + if (g_outputSQL) { + sprintf(q,"CREATE INDEX %s on %s using %s (", + indinfo[i].indexrelname, + indinfo[i].indrelname, + indinfo[i].indamname); + } else { + sprintf(q,"define index %s on %s using %s (", + indinfo[i].indexrelname, + indinfo[i].indrelname, + indinfo[i].indamname); + + } + if (funcname) { + sprintf(q, "%s %s(%s) %s", + q,funcname, attname, indinfo[i].indclassname); + free(funcname); + } else + sprintf(q, "%s %s %s", + q,attname,indinfo[i].indclassname); + + if (g_outputSQL) { + strcat(q,");\n"); + } else + strcat(q,")\\g\n"); + + fputs(q,fout); + } + fflush(fout); +} + + +/* + * dumpClasses - + * dump the contents of all the classes. + */ +void +dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout) +{ + char query[255]; + char *res; + int i,j; + + int *attrmap; /* this is an vector map of how the actual attributes + map to the corresponding output attributes. + This is necessary because of a difference between + SQL and POSTQUEL in the order of inherited attributes */ + + for(i = 0; i < numTables; i++) { + char *classname = tblinfo[i].relname; + + if (g_outputSQL) + fprintf(fout, "copy %s from stdin;\n", classname); + else + fprintf(fout, "copy %s from stdin\\g\n", classname); + + sprintf(query, "retrieve (p.all) from p in %s", classname); + res = PQexec(query); + + attrmap = (int*)malloc(tblinfo[i].numatts * sizeof(int)); + if (tblinfo[i].numParents == 0) { + /* table with no inheritance use an identity mapping */ + for (j=0;j<tblinfo[i].numatts;j++) + attrmap[j] = j; + } else { + int n = tblinfo[i].numatts; + for (j=0;j < n;j++) { + attrmap[j] = strInArray(tblinfo[i].attnames[j], + tblinfo[i].out_attnames, + n); + } + } + +/* + { + int j; + for (j=0;j<tblinfo[i].numatts;j++) { + fprintf(stderr,":%s\t",tblinfo[i].out_attnames[j]); + } + fprintf(stderr,"\n"); + } +*/ + + fflush(stdout); + fflush(stderr); + switch (*res) { + case 'P': + dumpTuples(&(res[1]), fout, attrmap); + PQclear(&(res[1])); + break; + case 'E': + case 'R': + fprintf(stderr, "Error while dumping %s\n", classname); + exit(1); + break; + } + + fprintf(fout, ".\n"); + free(attrmap); + } +} + +/* + * dumpTuples -- + * prints out the tuples in ASCII representaiton. 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 statement 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(char *portalname, FILE *fout, int* attrmap) +{ + PortalBuffer *pbuf; + int i, j, k; + int m, n, t; + char **outVals = NULL; /* values to copy out */ + + /* Now to examine all tuples fetched. */ + pbuf = PQparray(portalname); + + n = PQntuplesGroup(pbuf,0); /* always assume only one group */ + m = PQnfieldsGroup(pbuf,0); + + 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(pbuf, 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() +{ + char *res; + PortalBuffer* pbuf; + int ntups; + int last_oid; + + res = PQexec("retrieve (d.oid) from d in pg_database where d.datname = \"template1\""); + pbuf = PQparray(res+1); + ntups = PQntuplesGroup(pbuf,0); + if (ntups != 1) { + fprintf(stderr,"pg_dump: couldn't find the template1 database. You are really hosed\nGiving up\n"); + exit(2); + } + return (atoi(PQgetvalue(pbuf,0, PQfnumberGroup(pbuf,0,"oid")))); + +} + + +/* + * checkForQuote: + * checks a string for quote characters and backslashes 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 == '\"') { + /* backslash the double quotes */ + if (g_outputSQL) { + r[j++] = '\\'; + c = '\''; + } else { + r[j++] = '\\'; + r[j++] = '\\'; + } + } + r[j++] = c; + s++; + } + r[j] = '\0'; + + result = dupstr(r); + free(r); + + return result; + +} diff --git a/src/bin/pg4_dump/pg_dump.h b/src/bin/pg4_dump/pg_dump.h new file mode 100644 index 00000000000..0708f671be9 --- /dev/null +++ b/src/bin/pg4_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 + * + * pg_dump.h,v 1.5 1995/06/28 22:32:36 jolly 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(char *portalname, 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 |
