]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Teach pg_dump to dump user-defined operator classes. For the moment,
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jul 2002 21:56:04 +0000 (21:56 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 30 Jul 2002 21:56:04 +0000 (21:56 +0000)
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.

src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h

index 123ef3df056dcbb41c19330567dced91436383a8..0e3ffe91e5ce03ac5cd011dffd01b83aa6e234c9 100644 (file)
@@ -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");
@@ -88,6 +90,10 @@ dumpSchema(Archive *fout,
                write_msg(NULL, "reading user-defined operators\n");
        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);
@@ -170,6 +176,13 @@ dumpSchema(Archive *fout,
                dumpOprs(fout, oprinfo, numOperators);
        }
 
+       if (!dataOnly)
+       {
+               if (g_verbose)
+                       write_msg(NULL, "dumping out user-defined operator classes\n");
+               dumpOpclasses(fout, opcinfo, numOpclasses);
+       }
+
        if (!dataOnly)
        {
                if (g_verbose)
index 00725ae95ff48602929b2323641a56af0f5c6ce8..76623f61835ba76cdba29982656802d8b115572c 100644 (file)
@@ -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);
@@ -1754,6 +1755,90 @@ getOperators(int *numOprs)
        return oprinfo;
 }
 
+/*
+ * 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
@@ -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
index 732fdfb74e411aa2ee6d611e955481827032ddf5..b3b943dde08c4516543efc727797474a633f21c5 100644 (file)
@@ -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);