Update pg_dump to support dumping operator families.
authorTom Lane
Tue, 23 Jan 2007 17:54:50 +0000 (17:54 +0000)
committerTom Lane
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)",