Update pg_dump to support dumping operator families.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2007 17:54:50 +0000 (17:54 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2007 17:54:50 +0000 (17:54 +0000)
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dump_sort.c

index 409add66c5cee3ad31bda16e8200f4a94c9f7897..212c952d2c6f4284bbaaf1b1d37ce1ef6d668645 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.95 2007/01/05 22:19:48 momjian Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.96 2007/01/23 17:54:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -77,6 +77,7 @@ getSchemaData(int *numTablesPtr)
        ProcLangInfo *proclanginfo;
        CastInfo   *castinfo;
        OpclassInfo *opcinfo;
+       OpfamilyInfo *opfinfo;
        ConvInfo   *convinfo;
        int                     numNamespaces;
        int                     numAggregates;
@@ -85,6 +86,7 @@ getSchemaData(int *numTablesPtr)
        int                     numProcLangs;
        int                     numCasts;
        int                     numOpclasses;
+       int                     numOpfamilies;
        int                     numConversions;
 
        if (g_verbose)
@@ -117,6 +119,10 @@ getSchemaData(int *numTablesPtr)
                write_msg(NULL, "reading user-defined operator classes\n");
        opcinfo = getOpclasses(&numOpclasses);
 
+       if (g_verbose)
+               write_msg(NULL, "reading user-defined operator families\n");
+       opfinfo = getOpfamilies(&numOpfamilies);
+
        if (g_verbose)
                write_msg(NULL, "reading user-defined conversions\n");
        convinfo = getConversions(&numConversions);
index 9b99cb8826f5fc00933ce368bff3a1447da7f87b..a4c5d6d712851666193b441dced503fbca76b94f 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.138 2006/11/21 22:19:46 tgl Exp $
+ *             $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.139 2007/01/23 17:54:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2443,7 +2443,8 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
        if (strcmp(type, "AGGREGATE") == 0 ||
                strcmp(type, "FUNCTION") == 0 ||
                strcmp(type, "OPERATOR") == 0 ||
-               strcmp(type, "OPERATOR CLASS") == 0)
+               strcmp(type, "OPERATOR CLASS") == 0 ||
+               strcmp(type, "OPERATOR FAMILY") == 0)
        {
                /* Chop "DROP " off the front and make a modifiable copy */
                char       *first = strdup(te->dropStmt + 5);
@@ -2571,6 +2572,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
                        strcmp(te->desc, "FUNCTION") == 0 ||
                        strcmp(te->desc, "OPERATOR") == 0 ||
                        strcmp(te->desc, "OPERATOR CLASS") == 0 ||
+                       strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
                        strcmp(te->desc, "SCHEMA") == 0 ||
                        strcmp(te->desc, "TABLE") == 0 ||
                        strcmp(te->desc, "TYPE") == 0 ||
index 808777eb7cb40de9575fb62335ea5c51221cbb4f..c8b3e3916a29af82e498be949d387b98eb5c8bcc 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.457 2007/01/22 01:35:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.458 2007/01/23 17:54:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -145,6 +145,7 @@ static void dumpFunc(Archive *fout, FuncInfo *finfo);
 static void dumpCast(Archive *fout, CastInfo *cast);
 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
+static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
 static void dumpRule(Archive *fout, RuleInfo *rinfo);
 static void dumpAgg(Archive *fout, AggInfo *agginfo);
@@ -2447,6 +2448,93 @@ getOpclasses(int *numOpclasses)
        return opcinfo;
 }
 
+/*
+ * getOpfamilies:
+ *       read all opfamilies in the system catalogs and return them in the
+ * OpfamilyInfo* structure
+ *
+ *     numOpfamilies is set to the number of opfamilies read in
+ */
+OpfamilyInfo *
+getOpfamilies(int *numOpfamilies)
+{
+       PGresult   *res;
+       int                     ntups;
+       int                     i;
+       PQExpBuffer query;
+       OpfamilyInfo *opfinfo;
+       int                     i_tableoid;
+       int                     i_oid;
+       int                     i_opfname;
+       int                     i_opfnamespace;
+       int                     i_rolname;
+
+       /* Before 8.3, there is no separate concept of opfamilies */
+       if (g_fout->remoteVersion < 80300)
+       {
+               *numOpfamilies = 0;
+               return NULL;
+       }
+
+       query = createPQExpBuffer();
+
+       /*
+        * find all opfamilies, including builtin opfamilies; we filter out
+        * system-defined opfamilies at dump-out time.
+        */
+
+       /* Make sure we are in proper schema */
+       selectSourceSchema("pg_catalog");
+
+       appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
+                                         "opfnamespace, "
+                                         "(%s opfowner) as rolname "
+                                         "FROM pg_opfamily",
+                                         username_subquery);
+
+       res = PQexec(g_conn, query->data);
+       check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+       ntups = PQntuples(res);
+       *numOpfamilies = ntups;
+
+       opfinfo = (OpfamilyInfo *) malloc(ntups * sizeof(OpfamilyInfo));
+
+       i_tableoid = PQfnumber(res, "tableoid");
+       i_oid = PQfnumber(res, "oid");
+       i_opfname = PQfnumber(res, "opfname");
+       i_opfnamespace = PQfnumber(res, "opfnamespace");
+       i_rolname = PQfnumber(res, "rolname");
+
+       for (i = 0; i < ntups; i++)
+       {
+               opfinfo[i].dobj.objType = DO_OPFAMILY;
+               opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+               opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+               AssignDumpId(&opfinfo[i].dobj);
+               opfinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_opfname));
+               opfinfo[i].dobj.namespace = findNamespace(atooid(PQgetvalue(res, i, i_opfnamespace)),
+                                                                                                 opfinfo[i].dobj.catId.oid);
+               opfinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+
+               /* Decide whether we want to dump it */
+               selectDumpableObject(&(opfinfo[i].dobj));
+
+               if (g_fout->remoteVersion >= 70300)
+               {
+                       if (strlen(opfinfo[i].rolname) == 0)
+                               write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
+                                                 opfinfo[i].dobj.name);
+               }
+       }
+
+       PQclear(res);
+
+       destroyPQExpBuffer(query);
+
+       return opfinfo;
+}
+
 /*
  * getAggregates:
  *       read all the user-defined aggregates in the system catalogs and
@@ -3771,7 +3859,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
                else if (g_fout->remoteVersion >= 70100)
                {
                        appendPQExpBuffer(query,
-                                                         "SELECT tgname, tgfoid::regproc as tgfname, "
+                                                         "SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, "
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
                                                          "tgconstrrelid, tginitdeferred, tableoid, oid, "
@@ -3784,7 +3872,7 @@ getTriggers(TableInfo tblinfo[], int numTables)
                else
                {
                        appendPQExpBuffer(query,
-                                                         "SELECT tgname, tgfoid::regproc as tgfname, "
+                                                         "SELECT tgname, tgfoid::pg_catalog.regproc as tgfname, "
                                                          "tgtype, tgnargs, tgargs, tgenabled, "
                                                          "tgisconstraint, tgconstrname, tgdeferrable, "
                                                          "tgconstrrelid, tginitdeferred, "
@@ -4864,6 +4952,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
                case DO_OPCLASS:
                        dumpOpclass(fout, (OpclassInfo *) dobj);
                        break;
+               case DO_OPFAMILY:
+                       dumpOpfamily(fout, (OpfamilyInfo *) dobj);
+                       break;
                case DO_CONVERSION:
                        dumpConversion(fout, (ConvInfo *) dobj);
                        break;
@@ -6644,6 +6735,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        int                     i_opcintype;
        int                     i_opckeytype;
        int                     i_opcdefault;
+       int                     i_opcfamily;
+       int                     i_opcfamilynsp;
        int                     i_amname;
        int                     i_amopstrategy;
        int                     i_amopreqcheck;
@@ -6653,6 +6746,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        char       *opcintype;
        char       *opckeytype;
        char       *opcdefault;
+       char       *opcfamily;
+       char       *opcfamilynsp;
        char       *amname;
        char       *amopstrategy;
        char       *amopreqcheck;
@@ -6687,9 +6782,13 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
                                                  "opckeytype::pg_catalog.regtype, "
                                                  "opcdefault, "
+                                                 "opfname AS opcfamily, "
+                                                 "nspname AS opcfamilynsp, "
                                                  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
-                                                 "FROM pg_catalog.pg_opclass "
-                                                 "WHERE oid = '%u'::pg_catalog.oid",
+                                                 "FROM pg_catalog.pg_opclass c "
+                                                 "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
+                                                 "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
+                                                 "WHERE c.oid = '%u'::pg_catalog.oid",
                                                  opcinfo->dobj.catId.oid);
        }
        else
@@ -6697,6 +6796,8 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
                                                  "opckeytype::pg_catalog.regtype, "
                                                  "opcdefault, "
+                                                 "NULL AS opcfamily, "
+                                                 "NULL AS opcfamilynsp, "
                                                  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
                                                  "FROM pg_catalog.pg_opclass "
                                                  "WHERE oid = '%u'::pg_catalog.oid",
@@ -6718,11 +6819,15 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        i_opcintype = PQfnumber(res, "opcintype");
        i_opckeytype = PQfnumber(res, "opckeytype");
        i_opcdefault = PQfnumber(res, "opcdefault");
+       i_opcfamily = PQfnumber(res, "opcfamily");
+       i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
        i_amname = PQfnumber(res, "amname");
 
        opcintype = PQgetvalue(res, 0, i_opcintype);
        opckeytype = PQgetvalue(res, 0, i_opckeytype);
        opcdefault = PQgetvalue(res, 0, i_opcdefault);
+       opcfamily = PQgetvalue(res, 0, i_opcfamily);
+       opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
        /* amname will still be needed after we PQclear res */
        amname = strdup(PQgetvalue(res, 0, i_amname));
 
@@ -6741,9 +6846,19 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                                          fmtId(opcinfo->dobj.name));
        if (strcmp(opcdefault, "t") == 0)
                appendPQExpBuffer(q, "DEFAULT ");
-       appendPQExpBuffer(q, "FOR TYPE %s USING %s AS\n    ",
+       appendPQExpBuffer(q, "FOR TYPE %s USING %s",
                                          opcintype,
                                          fmtId(amname));
+       if (strlen(opcfamily) > 0 &&
+               (strcmp(opcfamily, opcinfo->dobj.name) != 0 ||
+                strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0))
+       {
+               appendPQExpBuffer(q, " FAMILY ");
+               if (strcmp(opcfamilynsp, opcinfo->dobj.namespace->dobj.name) != 0)
+                       appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
+               appendPQExpBuffer(q, "%s", fmtId(opcfamily));
+       }
+       appendPQExpBuffer(q, " AS\n    ");
 
        needComma = false;
 
@@ -6770,9 +6885,9 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
                                                  "amopopr::pg_catalog.regoperator "
                                                  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
-                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
-                                                 "AND classid = 'pg_catalog.pg_amop'::regclass "
+                                                 "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
                                                  "AND objid = ao.oid "
                                                  "ORDER BY amopstrategy",
                                                  opcinfo->dobj.catId.oid);
@@ -6829,9 +6944,9 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
                appendPQExpBuffer(query, "SELECT amprocnum, "
                                                  "amproc::pg_catalog.regprocedure "
                                                  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
-                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::regclass "
+                                                 "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
                                                  "AND refobjid = '%u'::pg_catalog.oid "
-                                                 "AND classid = 'pg_catalog.pg_amproc'::regclass "
+                                                 "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
                                                  "AND objid = ap.oid "
                                                  "ORDER BY amprocnum",
                                                  opcinfo->dobj.catId.oid);
@@ -6897,6 +7012,264 @@ dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
        destroyPQExpBuffer(delq);
 }
 
+/*
+ * dumpOpfamily
+ *       write out a single operator family definition
+ */
+static void
+dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
+{
+       PQExpBuffer query;
+       PQExpBuffer q;
+       PQExpBuffer delq;
+       PGresult   *res;
+       PGresult   *res_ops;
+       PGresult   *res_procs;
+       int                     ntups;
+       int                     i_amname;
+       int                     i_amopstrategy;
+       int                     i_amopreqcheck;
+       int                     i_amopopr;
+       int                     i_amprocnum;
+       int                     i_amproc;
+       int                     i_amproclefttype;
+       int                     i_amprocrighttype;
+       char       *amname;
+       char       *amopstrategy;
+       char       *amopreqcheck;
+       char       *amopopr;
+       char       *amprocnum;
+       char       *amproc;
+       char       *amproclefttype;
+       char       *amprocrighttype;
+       bool            needComma;
+       int                     i;
+
+       /* Skip if not to be dumped */
+       if (!opfinfo->dobj.dump || dataOnly)
+               return;
+
+       /*
+        * We want to dump the opfamily only if (1) it contains "loose" operators
+        * or functions, or (2) it contains an opclass with a different name or
+        * owner.  Otherwise it's sufficient to let it be created during creation
+        * of the contained opclass, and not dumping it improves portability of
+        * the dump.  Since we have to fetch the loose operators/funcs anyway,
+        * do that first.
+        */
+
+       query = createPQExpBuffer();
+       q = createPQExpBuffer();
+       delq = createPQExpBuffer();
+
+       /* Make sure we are in proper schema so regoperator works correctly */
+       selectSourceSchema(opfinfo->dobj.namespace->dobj.name);
+
+       /*
+        * Fetch only those opfamily members that are tied directly to the opfamily
+        * by pg_depend entries.
+        */
+       appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
+                                         "amopopr::pg_catalog.regoperator "
+                                         "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
+                                         "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+                                         "AND refobjid = '%u'::pg_catalog.oid "
+                                         "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
+                                         "AND objid = ao.oid "
+                                         "ORDER BY amopstrategy",
+                                         opfinfo->dobj.catId.oid);
+
+       res_ops = PQexec(g_conn, query->data);
+       check_sql_result(res_ops, g_conn, query->data, PGRES_TUPLES_OK);
+
+       resetPQExpBuffer(query);
+
+       appendPQExpBuffer(query, "SELECT amprocnum, "
+                                         "amproc::pg_catalog.regprocedure, "
+                                         "amproclefttype::pg_catalog.regtype, "
+                                         "amprocrighttype::pg_catalog.regtype "
+                                         "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
+                                         "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+                                         "AND refobjid = '%u'::pg_catalog.oid "
+                                         "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
+                                         "AND objid = ap.oid "
+                                         "ORDER BY amprocnum",
+                                         opfinfo->dobj.catId.oid);
+
+       res_procs = PQexec(g_conn, query->data);
+       check_sql_result(res_procs, g_conn, query->data, PGRES_TUPLES_OK);
+
+       if (PQntuples(res_ops) == 0 && PQntuples(res_procs) == 0)
+       {
+               /* No loose members, so check contained opclasses */
+               resetPQExpBuffer(query);
+
+               appendPQExpBuffer(query, "SELECT 1 "
+                                                 "FROM pg_catalog.pg_opclass c, pg_catalog.pg_opfamily f, pg_catalog.pg_depend "
+                                                 "WHERE f.oid = '%u'::pg_catalog.oid "
+                                                 "AND refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
+                                                 "AND refobjid = f.oid "
+                                                 "AND classid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
+                                                 "AND objid = c.oid "
+                                                 "AND (opcname != opfname OR opcnamespace != opfnamespace OR opcowner != opfowner) "
+                                                 "LIMIT 1",
+                                                 opfinfo->dobj.catId.oid);
+
+               res = PQexec(g_conn, query->data);
+               check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+               if (PQntuples(res) == 0)
+               {
+                       /* no need to dump it, so bail out */
+                       PQclear(res);
+                       PQclear(res_ops);
+                       PQclear(res_procs);
+                       destroyPQExpBuffer(query);
+                       destroyPQExpBuffer(q);
+                       destroyPQExpBuffer(delq);
+                       return;
+               }
+
+               PQclear(res);
+       }
+
+       /* Get additional fields from the pg_opfamily row */
+       resetPQExpBuffer(query);
+
+       appendPQExpBuffer(query, "SELECT "
+                                         "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
+                                         "FROM pg_catalog.pg_opfamily "
+                                         "WHERE oid = '%u'::pg_catalog.oid",
+                                         opfinfo->dobj.catId.oid);
+
+       res = PQexec(g_conn, query->data);
+       check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+       /* 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_amname = PQfnumber(res, "amname");
+
+       /* amname will still be needed after we PQclear res */
+       amname = strdup(PQgetvalue(res, 0, i_amname));
+
+       /*
+        * DROP must be fully qualified in case same name appears in pg_catalog
+        */
+       appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
+                                         fmtId(opfinfo->dobj.namespace->dobj.name));
+       appendPQExpBuffer(delq, ".%s",
+                                         fmtId(opfinfo->dobj.name));
+       appendPQExpBuffer(delq, " USING %s;\n",
+                                         fmtId(amname));
+
+       /* Build the fixed portion of the CREATE command */
+       appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
+                                         fmtId(opfinfo->dobj.name));
+       appendPQExpBuffer(q, " USING %s;\n",
+                                         fmtId(amname));
+
+       PQclear(res);
+
+       /* Do we need an ALTER to add loose members? */
+       if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
+       {
+               appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
+                                                 fmtId(opfinfo->dobj.name));
+               appendPQExpBuffer(q, " USING %s ADD\n    ",
+                                                 fmtId(amname));
+
+               needComma = false;
+
+               /*
+                * Now fetch and print the OPERATOR entries (pg_amop rows).
+                */
+               ntups = PQntuples(res_ops);
+
+               i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
+               i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
+               i_amopopr = PQfnumber(res_ops, "amopopr");
+
+               for (i = 0; i < ntups; i++)
+               {
+                       amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
+                       amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
+                       amopopr = PQgetvalue(res_ops, i, i_amopopr);
+
+                       if (needComma)
+                               appendPQExpBuffer(q, " ,\n    ");
+
+                       appendPQExpBuffer(q, "OPERATOR %s %s",
+                                                         amopstrategy, amopopr);
+                       if (strcmp(amopreqcheck, "t") == 0)
+                               appendPQExpBuffer(q, " RECHECK");
+
+                       needComma = true;
+               }
+
+               /*
+                * Now fetch and print the FUNCTION entries (pg_amproc rows).
+                */
+               ntups = PQntuples(res_procs);
+
+               i_amprocnum = PQfnumber(res_procs, "amprocnum");
+               i_amproc = PQfnumber(res_procs, "amproc");
+               i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
+               i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
+
+               for (i = 0; i < ntups; i++)
+               {
+                       amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
+                       amproc = PQgetvalue(res_procs, i, i_amproc);
+                       amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
+                       amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
+
+                       if (needComma)
+                               appendPQExpBuffer(q, " ,\n    ");
+
+                       appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
+                                                         amprocnum, amproclefttype, amprocrighttype,
+                                                         amproc);
+
+                       needComma = true;
+               }
+
+               appendPQExpBuffer(q, ";\n");
+       }
+
+       ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
+                                opfinfo->dobj.name,
+                                opfinfo->dobj.namespace->dobj.name,
+                                NULL,
+                                opfinfo->rolname,
+                                false, "OPERATOR FAMILY", q->data, delq->data, NULL,
+                                opfinfo->dobj.dependencies, opfinfo->dobj.nDeps,
+                                NULL, NULL);
+
+       /* Dump Operator Family Comments */
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "OPERATOR FAMILY %s",
+                                         fmtId(opfinfo->dobj.name));
+       appendPQExpBuffer(q, " USING %s",
+                                         fmtId(amname));
+       dumpComment(fout, q->data,
+                               NULL, opfinfo->rolname,
+                               opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
+
+       free(amname);
+       PQclear(res_ops);
+       PQclear(res_procs);
+       destroyPQExpBuffer(query);
+       destroyPQExpBuffer(q);
+       destroyPQExpBuffer(delq);
+}
+
 /*
  * dumpConversion
  *       write out a single conversion definition
index 0949ae2731f109da9980c1adffb7001d0e468c13..9ba74aa98eefd1f7881ca1d25bd2e4cf5eeaec6c 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.131 2007/01/05 22:19:48 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.132 2007/01/23 17:54:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,6 +96,7 @@ typedef enum
        DO_AGG,
        DO_OPERATOR,
        DO_OPCLASS,
+       DO_OPFAMILY,
        DO_CONVERSION,
        DO_TABLE,
        DO_ATTRDEF,
@@ -192,6 +193,12 @@ typedef struct _opclassInfo
        char       *rolname;
 } OpclassInfo;
 
+typedef struct _opfamilyInfo
+{
+       DumpableObject dobj;
+       char       *rolname;
+} OpfamilyInfo;
+
 typedef struct _convInfo
 {
        DumpableObject dobj;
@@ -421,6 +428,7 @@ extern FuncInfo *getFuncs(int *numFuncs);
 extern AggInfo *getAggregates(int *numAggregates);
 extern OprInfo *getOperators(int *numOperators);
 extern OpclassInfo *getOpclasses(int *numOpclasses);
+extern OpfamilyInfo *getOpfamilies(int *numOpfamilies);
 extern ConvInfo *getConversions(int *numConversions);
 extern TableInfo *getTables(int *numTables);
 extern InhInfo *getInherits(int *numInherits);
index 5425bda230000d1532ef11dce4e4b07b6f393270..2d51ace1923cb269873ecf02111c8c94f3ce41ac 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.16 2007/01/05 22:19:48 momjian Exp $
+ *       $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.17 2007/01/23 17:54:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,6 +33,7 @@ static const int oldObjectTypePriority[] =
        3,                                                      /* DO_AGG */
        3,                                                      /* DO_OPERATOR */
        4,                                                      /* DO_OPCLASS */
+       4,                                                      /* DO_OPFAMILY */
        5,                                                      /* DO_CONVERSION */
        6,                                                      /* DO_TABLE */
        8,                                                      /* DO_ATTRDEF */
@@ -62,6 +63,7 @@ static const int newObjectTypePriority[] =
        5,                                                      /* DO_AGG */
        6,                                                      /* DO_OPERATOR */
        7,                                                      /* DO_OPCLASS */
+       7,                                                      /* DO_OPFAMILY */
        9,                                                      /* DO_CONVERSION */
        10,                                                     /* DO_TABLE */
        12,                                                     /* DO_ATTRDEF */
@@ -996,6 +998,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
                                         "OPERATOR CLASS %s  (ID %d OID %u)",
                                         obj->name, obj->dumpId, obj->catId.oid);
                        return;
+               case DO_OPFAMILY:
+                       snprintf(buf, bufsize,
+                                        "OPERATOR FAMILY %s  (ID %d OID %u)",
+                                        obj->name, obj->dumpId, obj->catId.oid);
+                       return;
                case DO_CONVERSION:
                        snprintf(buf, bufsize,
                                         "CONVERSION %s  (ID %d OID %u)",