aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-07-30 21:56:04 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-07-30 21:56:04 +0000
commit4ad658cac9aa990f29c23e632d3578ed30aa9232 (patch)
treea351656d2fbdd4d76d6dee64de91797b1881415d /src
parent2c2c43d05ff7f899d2e27f3705d786dd556d3d43 (diff)
downloadpostgresql-4ad658cac9aa990f29c23e632d3578ed30aa9232.tar.gz
postgresql-4ad658cac9aa990f29c23e632d3578ed30aa9232.zip
Teach pg_dump to dump user-defined operator classes. For the moment,
this only works against 7.3 or later databases; the pushups required to do it without regprocedure/regtype/etc seem more trouble than they're worth, considering that existing users aren't expecting pg_dump support for this.
Diffstat (limited to 'src')
-rw-r--r--src/bin/pg_dump/common.c15
-rw-r--r--src/bin/pg_dump/pg_dump.c317
-rw-r--r--src/bin/pg_dump/pg_dump.h13
3 files changed, 342 insertions, 3 deletions
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 123ef3df056..0e3ffe91e5c 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.66 2002/07/18 23:11:29 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.67 2002/07/30 21:56:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -60,6 +60,7 @@ dumpSchema(Archive *fout,
int numInherits;
int numAggregates;
int numOperators;
+ int numOpclasses;
NamespaceInfo *nsinfo;
TypeInfo *tinfo;
FuncInfo *finfo;
@@ -67,6 +68,7 @@ dumpSchema(Archive *fout,
TableInfo *tblinfo;
InhInfo *inhinfo;
OprInfo *oprinfo;
+ OpclassInfo *opcinfo;
if (g_verbose)
write_msg(NULL, "reading namespaces\n");
@@ -89,6 +91,10 @@ dumpSchema(Archive *fout,
oprinfo = getOperators(&numOperators);
if (g_verbose)
+ write_msg(NULL, "reading user-defined operator classes\n");
+ opcinfo = getOpclasses(&numOpclasses);
+
+ if (g_verbose)
write_msg(NULL, "reading user-defined tables\n");
tblinfo = getTables(&numTables);
@@ -173,6 +179,13 @@ dumpSchema(Archive *fout,
if (!dataOnly)
{
if (g_verbose)
+ write_msg(NULL, "dumping out user-defined operator classes\n");
+ dumpOpclasses(fout, opcinfo, numOpclasses);
+ }
+
+ if (!dataOnly)
+ {
+ if (g_verbose)
write_msg(NULL, "dumping out user-defined casts\n");
dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
}
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 00725ae95ff..76623f61835 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.276 2002/07/25 20:52:59 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.277 2002/07/30 21:56:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -118,6 +118,7 @@ static void dumpOneOpr(Archive *fout, OprInfo *oprinfo,
static const char *convertRegProcReference(const char *proc);
static const char *convertOperatorReference(const char *opr,
OprInfo *g_oprinfo, int numOperators);
+static void dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo);
static void dumpOneAgg(Archive *fout, AggInfo *agginfo);
static Oid findLastBuiltinOid_V71(const char *);
static Oid findLastBuiltinOid_V70(void);
@@ -1755,6 +1756,90 @@ getOperators(int *numOprs)
}
/*
+ * getOpclasses:
+ * read all opclasses in the system catalogs and return them in the
+ * OpclassInfo* structure
+ *
+ * numOpclasses is set to the number of opclasses read in
+ */
+OpclassInfo *
+getOpclasses(int *numOpclasses)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ OpclassInfo *opcinfo;
+ int i_oid;
+ int i_opcname;
+ int i_opcnamespace;
+ int i_usename;
+
+ /*
+ * find all opclasses, including builtin opclasses;
+ * we filter out system-defined opclasses at dump-out time.
+ */
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ if (g_fout->remoteVersion >= 70300)
+ {
+ appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
+ "opcnamespace, "
+ "(select usename from pg_user where opcowner = usesysid) as usename "
+ "from pg_opclass");
+ }
+ else
+ {
+ appendPQExpBuffer(query, "SELECT pg_opclass.oid, opcname, "
+ "0::oid as opcnamespace, "
+ "''::name as usename "
+ "from pg_opclass");
+ }
+
+ res = PQexec(g_conn, query->data);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ write_msg(NULL, "query to obtain list of opclasses failed: %s", PQerrorMessage(g_conn));
+ exit_nicely();
+ }
+
+ ntups = PQntuples(res);
+ *numOpclasses = ntups;
+
+ opcinfo = (OpclassInfo *) malloc(ntups * sizeof(OpclassInfo));
+
+ i_oid = PQfnumber(res, "oid");
+ i_opcname = PQfnumber(res, "opcname");
+ i_opcnamespace = PQfnumber(res, "opcnamespace");
+ i_usename = PQfnumber(res, "usename");
+
+ for (i = 0; i < ntups; i++)
+ {
+ opcinfo[i].oid = strdup(PQgetvalue(res, i, i_oid));
+ opcinfo[i].opcname = strdup(PQgetvalue(res, i, i_opcname));
+ opcinfo[i].opcnamespace = findNamespace(PQgetvalue(res, i, i_opcnamespace),
+ opcinfo[i].oid);
+ opcinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
+
+ if (g_fout->remoteVersion >= 70300)
+ {
+ if (strlen(opcinfo[i].usename) == 0)
+ write_msg(NULL, "WARNING: owner of opclass \"%s\" appears to be invalid\n",
+ opcinfo[i].opcname);
+ }
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return opcinfo;
+}
+
+/*
* getAggregates:
* read all the user-defined aggregates in the system catalogs and
* return them in the AggInfo* structure
@@ -3981,6 +4066,236 @@ convertOperatorReference(const char *opr,
return name;
}
+
+/*
+ * dumpOpclasses
+ * writes out to fout the queries to recreate all the user-defined
+ * operator classes
+ */
+void
+dumpOpclasses(Archive *fout, OpclassInfo *opcinfo, int numOpclasses)
+{
+ int i;
+
+ for (i = 0; i < numOpclasses; i++)
+ {
+ /* Dump only opclasses in dumpable namespaces */
+ if (!opcinfo[i].opcnamespace->dump)
+ continue;
+
+ /* OK, dump it */
+ dumpOneOpclass(fout, &opcinfo[i]);
+ }
+}
+
+/*
+ * dumpOneOpclass
+ * write out a single operator class definition
+ */
+static void
+dumpOneOpclass(Archive *fout, OpclassInfo *opcinfo)
+{
+ PQExpBuffer query = createPQExpBuffer();
+ PQExpBuffer q = createPQExpBuffer();
+ PQExpBuffer delq = createPQExpBuffer();
+ PGresult *res;
+ int ntups;
+ int i_opcintype;
+ int i_opckeytype;
+ int i_opcdefault;
+ int i_amname;
+ int i_amopstrategy;
+ int i_amopreqcheck;
+ int i_amopopr;
+ int i_amprocnum;
+ int i_amproc;
+ char *opcintype;
+ char *opckeytype;
+ char *opcdefault;
+ char *amname;
+ char *amopstrategy;
+ char *amopreqcheck;
+ char *amopopr;
+ char *amprocnum;
+ char *amproc;
+ bool needComma;
+ int i;
+
+ /*
+ * XXX currently we do not implement dumping of operator classes from
+ * pre-7.3 databases. This could be done but it seems not worth the
+ * trouble.
+ */
+ if (g_fout->remoteVersion < 70300)
+ return;
+
+ /* Make sure we are in proper schema so regoperator works correctly */
+ selectSourceSchema(opcinfo->opcnamespace->nspname);
+
+ /* Get additional fields from the pg_opclass row */
+ appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
+ "opckeytype::pg_catalog.regtype, "
+ "opcdefault, "
+ "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
+ "FROM pg_catalog.pg_opclass "
+ "WHERE oid = '%s'::pg_catalog.oid",
+ opcinfo->oid);
+
+ res = PQexec(g_conn, query->data);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ write_msg(NULL, "query to obtain opclass details failed: %s", PQerrorMessage(g_conn));
+ exit_nicely();
+ }
+
+ /* Expecting a single result only */
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "Got %d rows instead of one from: %s",
+ ntups, query->data);
+ exit_nicely();
+ }
+
+ i_opcintype = PQfnumber(res, "opcintype");
+ i_opckeytype = PQfnumber(res, "opckeytype");
+ i_opcdefault = PQfnumber(res, "opcdefault");
+ i_amname = PQfnumber(res, "amname");
+
+ opcintype = PQgetvalue(res, 0, i_opcintype);
+ opckeytype = PQgetvalue(res, 0, i_opckeytype);
+ opcdefault = PQgetvalue(res, 0, i_opcdefault);
+ amname = PQgetvalue(res, 0, i_amname);
+
+ /* DROP must be fully qualified in case same name appears in pg_catalog */
+ appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
+ fmtId(opcinfo->opcnamespace->nspname, force_quotes));
+ appendPQExpBuffer(delq, ".%s",
+ fmtId(opcinfo->opcname, force_quotes));
+ appendPQExpBuffer(delq, " USING %s;\n",
+ fmtId(amname, force_quotes));
+
+ /* Build the fixed portion of the CREATE command */
+ appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n\t",
+ fmtId(opcinfo->opcname, force_quotes));
+ if (strcmp(opcdefault, "t") == 0)
+ appendPQExpBuffer(q, "DEFAULT ");
+ appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n\t",
+ opcintype,
+ fmtId(amname, force_quotes));
+
+ needComma = false;
+
+ if (strcmp(opckeytype, "-") != 0)
+ {
+ appendPQExpBuffer(q, "STORAGE\t%s",
+ opckeytype);
+ needComma = true;
+ }
+
+ PQclear(res);
+
+ /*
+ * Now fetch and print the OPERATOR entries (pg_amop rows).
+ */
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+ "amopopr::pg_catalog.regoperator "
+ "FROM pg_catalog.pg_amop "
+ "WHERE amopclaid = '%s'::pg_catalog.oid "
+ "ORDER BY amopstrategy",
+ opcinfo->oid);
+
+ res = PQexec(g_conn, query->data);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ write_msg(NULL, "query to obtain opclass operators failed: %s", PQerrorMessage(g_conn));
+ exit_nicely();
+ }
+
+ ntups = PQntuples(res);
+
+ i_amopstrategy = PQfnumber(res, "amopstrategy");
+ i_amopreqcheck = PQfnumber(res, "amopreqcheck");
+ i_amopopr = PQfnumber(res, "amopopr");
+
+ for (i = 0; i < ntups; i++)
+ {
+ amopstrategy = PQgetvalue(res, i, i_amopstrategy);
+ amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
+ amopopr = PQgetvalue(res, i, i_amopopr);
+
+ if (needComma)
+ appendPQExpBuffer(q, " ,\n\t");
+
+ appendPQExpBuffer(q, "OPERATOR\t%s\t%s",
+ amopstrategy, amopopr);
+ if (strcmp(amopreqcheck, "t") == 0)
+ appendPQExpBuffer(q, "\tRECHECK");
+
+ needComma = true;
+ }
+
+ PQclear(res);
+
+ /*
+ * Now fetch and print the FUNCTION entries (pg_amproc rows).
+ */
+ resetPQExpBuffer(query);
+
+ appendPQExpBuffer(query, "SELECT amprocnum, "
+ "amproc::pg_catalog.regprocedure "
+ "FROM pg_catalog.pg_amproc "
+ "WHERE amopclaid = '%s'::pg_catalog.oid "
+ "ORDER BY amprocnum",
+ opcinfo->oid);
+
+ res = PQexec(g_conn, query->data);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ write_msg(NULL, "query to obtain opclass functions failed: %s", PQerrorMessage(g_conn));
+ exit_nicely();
+ }
+
+ ntups = PQntuples(res);
+
+ i_amprocnum = PQfnumber(res, "amprocnum");
+ i_amproc = PQfnumber(res, "amproc");
+
+ for (i = 0; i < ntups; i++)
+ {
+ amprocnum = PQgetvalue(res, i, i_amprocnum);
+ amproc = PQgetvalue(res, i, i_amproc);
+
+ if (needComma)
+ appendPQExpBuffer(q, " ,\n\t");
+
+ appendPQExpBuffer(q, "FUNCTION\t%s\t%s",
+ amprocnum, amproc);
+
+ needComma = true;
+ }
+
+ PQclear(res);
+
+ appendPQExpBuffer(q, " ;\n");
+
+ ArchiveEntry(fout, opcinfo->oid, opcinfo->opcname,
+ opcinfo->opcnamespace->nspname, opcinfo->usename,
+ "OPERATOR CLASS", NULL,
+ q->data, delq->data,
+ NULL, NULL, NULL);
+
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+
/*
* dumpAggs
* writes out to fout the queries to create all the user-defined aggregates
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 732fdfb74e4..b3b943dde08 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_dump.h,v 1.91 2002/07/18 23:11:29 petere Exp $
+ * $Id: pg_dump.h,v 1.92 2002/07/30 21:56:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -86,6 +86,14 @@ typedef struct _oprInfo
char *oprcode; /* as OID, not regproc name */
} OprInfo;
+typedef struct _opclassInfo
+{
+ char *oid;
+ char *opcname;
+ NamespaceInfo *opcnamespace; /* link to containing namespace */
+ char *usename;
+} OpclassInfo;
+
typedef struct _tableInfo
{
/*
@@ -192,6 +200,7 @@ extern TypeInfo *getTypes(int *numTypes);
extern FuncInfo *getFuncs(int *numFuncs);
extern AggInfo *getAggregates(int *numAggregates);
extern OprInfo *getOperators(int *numOperators);
+extern OpclassInfo *getOpclasses(int *numOpclasses);
extern TableInfo *getTables(int *numTables);
extern InhInfo *getInherits(int *numInherits);
@@ -207,6 +216,8 @@ extern void dumpCasts(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes);
extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
+extern void dumpOpclasses(Archive *fout,
+ OpclassInfo *opcinfo, int numOpclasses);
extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,
const bool aclsSkip,
const bool schemaOnly, const bool dataOnly);