Bruce,
authorBruce Momjian
Tue, 18 Jan 2000 18:09:02 +0000 (18:09 +0000)
committerBruce Momjian
Tue, 18 Jan 2000 18:09:02 +0000 (18:09 +0000)
Attached is a patch which patches cleanly against the Sunday afternoon
snapshot. It modifies pg_dump to dump COMMENT ON statements for
user-definable descriptions. In addition, it also modifies comment.c so
that the operator behavior is as Peter E. would like: a comment on an
operator is applied to the underlying function.

Thanks,

Mike Mascari

src/backend/commands/comment.c
src/bin/pg_dump/common.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h

index 9ebf207199c4f895300c58d43821a317903bb694..dc8247691ab8c504f581b3adc64c2e2bfe84794e 100644 (file)
@@ -19,6 +19,7 @@
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_description.h"
+#include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
 #include "catalog/pg_shadow.h"
@@ -658,6 +659,7 @@ void CommentProc(char *function, List *arguments, char *comment)
 
 void CommentOperator(char *opername, List *arguments, char *comment) {
 
+  Form_pg_operator data;
   HeapTuple optuple;
   Oid oid, leftoid = InvalidOid, rightoid = InvalidOid;
   bool defined;
@@ -719,6 +721,14 @@ void CommentOperator(char *opername, List *arguments, char *comment) {
   }
   #endif
 
+  /*** Get the procedure associated with the operator ***/
+
+  data = (Form_pg_operator) GETSTRUCT(optuple);
+  oid = regproctooid(data->oprcode);
+  if (oid == InvalidOid) {
+     elog(ERROR, "operator '%s' does not have an underlying function", opername);
+  }
+  
   /*** Call CreateComments() to create/drop the comments ***/
 
   CreateComments(oid, comment);
index 9b6d6414188530346bc51145627f2c0d3a3275d0..f111ca57ab7c0ea6d4f0e24122a9874f47ae4d9e 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.38 2000/01/18 07:29:58 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.39 2000/01/18 18:09:02 momjian Exp $
  *
  * Modifications - 6/12/96 - [email protected] - version 1.13.dhb.2
  *
@@ -289,6 +289,14 @@ dumpSchema(FILE *fout,
                g_comment_start, g_comment_end);
    flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
 
+   if (!tablename && fout)
+   {
+       if (g_verbose)
+           fprintf(stderr, "%s dumping out database comment %s\n",
+                   g_comment_start, g_comment_end);
+       dumpDBComment(fout);
+   }
+
    if (!tablename && fout)
    {
        if (g_verbose)
index 82e55c3bfcbad2c2d663b940144856411150298f..a4f2676edd71e9989a6f2b0f70ffdbc688c959f2 100644 (file)
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.134 2000/01/18 07:29:58 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.135 2000/01/18 18:09:02 momjian Exp $
  *
  * Modifications - 6/10/96 - [email protected] - version 1.13.dhb
  *
@@ -78,6 +78,7 @@
 
 #include "pg_dump.h"
 
+static void dumpComment(FILE *outfile, const char *target, const char *oid);
 static void dumpSequence(FILE *fout, TableInfo tbinfo);
 static void dumpACL(FILE *fout, TableInfo tbinfo);
 static void dumpTriggers(FILE *fout, const char *tablename,
@@ -1136,6 +1137,8 @@ clearTableInfo(TableInfo *tblinfo, int numTables)
        /* Process Attributes */
        for (j = 0; j < tblinfo[i].numatts; j++)
        {
+           if (tblinfo[i].attoids[j])
+               free(tblinfo[i].attoids[j]);
            if (tblinfo[i].attnames[j])
                free(tblinfo[i].attnames[j]);
            if (tblinfo[i].typnames[j])
@@ -1225,6 +1228,8 @@ clearIndInfo(IndInfo *ind, int numIndices)
        return;
    for (i = 0; i < numIndices; ++i)
    {
+       if (ind[i].indoid)
+           free(ind[i].indoid);
        if (ind[i].indexrelname)
            free(ind[i].indexrelname);
        if (ind[i].indrelname)
@@ -1692,7 +1697,8 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
        if (tblinfo[i].ntrig > 0)
        {
            PGresult   *res2;
-           int         i_tgname,
+           int         i_tgoid,
+                       i_tgname,
                        i_tgfoid,
                        i_tgtype,
                        i_tgnargs,
@@ -1707,7 +1713,7 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                        g_comment_end);
 
            resetPQExpBuffer(query);
-           appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs "
+           appendPQExpBuffer(query, "SELECT tgname, tgfoid, tgtype, tgnargs, tgargs, oid "
                    "from pg_trigger "
                    "where tgrelid = '%s'::oid ",
                    tblinfo[i].oid);
@@ -1730,7 +1736,10 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
            i_tgtype = PQfnumber(res2, "tgtype");
            i_tgnargs = PQfnumber(res2, "tgnargs");
            i_tgargs = PQfnumber(res2, "tgargs");
+           i_tgoid = PQfnumber(res2, "oid");
            tblinfo[i].triggers = (char **) malloc(ntups2 * sizeof(char *));
+           tblinfo[i].trcomments = (char **) malloc(ntups2 * sizeof(char *));
+           tblinfo[i].troids = (char **) malloc(ntups2 * sizeof(char *));
            resetPQExpBuffer(query);
            for (i2 = 0; i2 < ntups2; i2++)
            {
@@ -1842,11 +1851,27 @@ getTables(int *numTables, FuncInfo *finfo, int numFuncs)
                }
                appendPQExpBuffer(query, ");\n");
                tblinfo[i].triggers[i2] = strdup(query->data);
+
+               /*** Initialize trcomments and troids ***/
+               
+               resetPQExpBuffer(query);
+               appendPQExpBuffer(query, "TRIGGER %s ", 
+                                 fmtId(PQgetvalue(res2, i2, i_tgname), force_quotes));
+               appendPQExpBuffer(query, "ON %s",
+                                 fmtId(tblinfo[i].relname, force_quotes));
+               tblinfo[i].trcomments[i2] = strdup(query->data);
+               tblinfo[i].troids[i2] = strdup(PQgetvalue(res2, i2, i_tgoid));
+
            }
            PQclear(res2);
        }
        else
+       {
            tblinfo[i].triggers = NULL;
+           tblinfo[i].trcomments = NULL;
+           tblinfo[i].troids = NULL;
+       }
+         
    }
 
    PQclear(res);
@@ -1928,6 +1953,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
    int         i_atttypmod;
    int         i_attnotnull;
    int         i_atthasdef;
+   int         i_attoid;
    PGresult    *res;
    int         ntups;
 
@@ -1951,7 +1977,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
                    g_comment_end);
 
        resetPQExpBuffer(q);
-       appendPQExpBuffer(q, "SELECT a.attnum, a.attname, t.typname, a.atttypmod, "
+       appendPQExpBuffer(q, "SELECT a.oid as attoid, a.attnum, a.attname, t.typname, a.atttypmod, "
                "a.attnotnull, a.atthasdef "
                "from pg_attribute a, pg_type t "
                "where a.attrelid = '%s'::oid and a.atttypid = t.oid "
@@ -1967,6 +1993,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
 
        ntups = PQntuples(res);
 
+       i_attoid = PQfnumber(res, "attoid");
        i_attname = PQfnumber(res, "attname");
        i_typname = PQfnumber(res, "typname");
        i_atttypmod = PQfnumber(res, "atttypmod");
@@ -1974,6 +2001,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
        i_atthasdef = PQfnumber(res, "atthasdef");
 
        tblinfo[i].numatts = ntups;
+       tblinfo[i].attoids = (char **) malloc(ntups * sizeof(char *));
        tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *));
        tblinfo[i].typnames = (char **) malloc(ntups * sizeof(char *));
        tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int));
@@ -1984,6 +2012,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables)
        tblinfo[i].numParents = 0;
        for (j = 0; j < ntups; j++)
        {
+           tblinfo[i].attoids[j] = strdup(PQgetvalue(res, j, i_attoid));
            tblinfo[i].attnames[j] = strdup(PQgetvalue(res, j, i_attname));
            tblinfo[i].typnames[j] = strdup(PQgetvalue(res, j, i_typname));
            tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
@@ -2047,6 +2076,7 @@ getIndices(int *numIndices)
    int         i_indkey;
    int         i_indclass;
    int         i_indisunique;
+   int         i_indoid;
 
    /*
     * find all the user-defined indices. We do not handle partial
@@ -2058,7 +2088,7 @@ getIndices(int *numIndices)
     */
 
    appendPQExpBuffer(query,
-       "SELECT t1.relname as indexrelname, t2.relname as indrelname, "
+       "SELECT t1.oid as indoid, t1.relname as indexrelname, t2.relname as indrelname, "
            "i.indproc, i.indkey, i.indclass, "
            "a.amname as indamname, i.indisunique "
            "from pg_index i, pg_class t1, pg_class t2, pg_am a "
@@ -2083,6 +2113,7 @@ getIndices(int *numIndices)
 
    memset((char *) indinfo, 0, ntups * sizeof(IndInfo));
 
+   i_indoid = PQfnumber(res, "indoid");
    i_indexrelname = PQfnumber(res, "indexrelname");
    i_indrelname = PQfnumber(res, "indrelname");
    i_indamname = PQfnumber(res, "indamname");
@@ -2093,6 +2124,7 @@ getIndices(int *numIndices)
 
    for (i = 0; i < ntups; i++)
    {
+       indinfo[i].indoid = strdup(PQgetvalue(res, i, i_indoid));
        indinfo[i].indexrelname = strdup(PQgetvalue(res, i, i_indexrelname));
        indinfo[i].indrelname = strdup(PQgetvalue(res, i, i_indrelname));
        indinfo[i].indamname = strdup(PQgetvalue(res, i, i_indamname));
@@ -2109,6 +2141,100 @@ getIndices(int *numIndices)
    return indinfo;
 }
 
+/*------------------------------------------------------------------
+ * dumpComments -- 
+ *
+ * This routine is used to dump any comments associated with the 
+ * oid handed to this routine. The routine takes a constant character
+ * string for the target part of the object and the oid of the object
+ * whose comments are to be dumped. It is perfectly acceptable
+ * to hand an oid to this routine which has not been commented. In
+ * addition, the routine takes the stdio FILE handle to which the 
+ * output should be written.
+ *------------------------------------------------------------------
+*/
+
+void dumpComment(FILE *fout, const char *target, const char *oid) {
+
+   PGresult *res;
+   PQExpBuffer query;
+   int i_description;
+
+   /*** Build query to find comment ***/
+
+   query = createPQExpBuffer();
+   appendPQExpBuffer(query, "SELECT description FROM pg_description WHERE objoid = ");
+   appendPQExpBuffer(query, oid);
+
+   /*** Execute query ***/
+
+   res = PQexec(g_conn, query->data);
+   if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
+       fprintf(stderr, "DumpComment: SELECT failed: '%s'.\n",
+               PQerrorMessage(g_conn));
+       exit_nicely(g_conn);
+   }
+
+   /*** If a comment exists, build COMMENT ON statement ***/
+
+   if (PQntuples(res) != 0) {
+       i_description = PQfnumber(res, "description");
+       fprintf(fout, "COMMENT ON %s IS '%s';\n", 
+               target, checkForQuote(PQgetvalue(res, 0, i_description)));
+   }
+
+   /*** Clear the statement buffer and return ***/
+
+   PQclear(res);
+    
+}
+
+/*------------------------------------------------------------------
+ * dumpDBComment -- 
+ *
+ * This routine is used to dump any comments associated with the 
+ * database to which we are currently connected. If the user chose 
+ * to dump the schema of the database, then this is the first
+ * statement issued.
+ *------------------------------------------------------------------
+*/
+
+void dumpDBComment(FILE *fout) {
+
+   PGresult *res;
+   PQExpBuffer query;
+   int i_oid;
+
+   /*** Build query to find comment ***/
+
+   query = createPQExpBuffer();
+   appendPQExpBuffer(query, "SELECT oid FROM pg_database WHERE datname = '%s'",
+                     PQdb(g_conn));
+
+   /*** Execute query ***/
+
+   res = PQexec(g_conn, query->data);
+   if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) {
+       fprintf(stderr, "dumpDBComment: SELECT failed: '%s'.\n",
+               PQerrorMessage(g_conn));
+       exit_nicely(g_conn);
+   }
+
+   /*** If a comment exists, build COMMENT ON statement ***/
+
+   if (PQntuples(res) != 0) {
+       i_oid = PQfnumber(res, "oid");
+       resetPQExpBuffer(query);
+       appendPQExpBuffer(query, "DATABASE %s", fmtId(PQdb(g_conn), force_quotes));
+       dumpComment(fout, query->data, PQgetvalue(res, 0, i_oid));
+   }
+
+   /*** Clear the statement buffer and return ***/
+
+   PQclear(res);
+   
+}
+
 /*
  * dumpTypes
  *   writes out to fout the queries to recreate all the user-defined types
@@ -2188,6 +2314,13 @@ dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
            appendPQExpBuffer(q, ");\n");
 
        fputs(q->data, fout);
+
+       /*** Dump Type Comments ***/
+
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "TYPE %s", fmtId(tinfo[i].typname, force_quotes));
+       dumpComment(fout, q->data, tinfo[i].oid);
+
    }
 }
 
@@ -2294,6 +2427,7 @@ dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
            TypeInfo *tinfo, int numTypes)
 {
    PQExpBuffer q = createPQExpBuffer();
+   PQExpBuffer fnlist = createPQExpBuffer();
    int         j;
    char        *func_def;
    char        func_lang[NAMEDATALEN + 1];
@@ -2381,6 +2515,9 @@ dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
        appendPQExpBuffer(q, "%s%s",
                (j > 0) ? "," : "",
                fmtId(typname, false));
+       appendPQExpBuffer(fnlist, "%s%s",
+                         (j > 0) ? "," : "",
+                         fmtId(typname, false));
    }
    appendPQExpBuffer(q, " ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n",
            (finfo[i].retset) ? " SETOF " : "",
@@ -2389,6 +2526,14 @@ dumpOneFunc(FILE *fout, FuncInfo *finfo, int i,
 
    fputs(q->data, fout);
 
+   /*** Dump Function Comments ***/
+
+   resetPQExpBuffer(q);
+   appendPQExpBuffer(q, "FUNCTION %s ",
+                     fmtId(finfo[i].proname, force_quotes));
+   appendPQExpBuffer(q, "( %s )", fnlist->data);
+   dumpComment(fout, q->data, finfo[i].oid);
+
 }
 
 /*
@@ -2602,6 +2747,14 @@ dumpAggs(FILE *fout, AggInfo *agginfo, int numAggs,
                finalfunc->data);
 
        fputs(q->data, fout);
+
+       /*** Dump Aggregate Comments ***/
+
+       resetPQExpBuffer(q);
+       appendPQExpBuffer(q, "AGGREGATE %s %s", agginfo[i].aggname, 
+                         fmtId(findTypeByOid(tinfo, numTypes, agginfo[i].aggbasetype), false));
+       dumpComment(fout, q->data, agginfo[i].oid);
+
    }
 }
 
@@ -2918,6 +3071,22 @@ dumpTables(FILE *fout, TableInfo *tblinfo, int numTables,
            if (!aclsSkip)
                dumpACL(fout, tblinfo[i]);
 
+             /* Dump Field Comments */
+
+           for (j = 0; j < tblinfo[i].numatts; j++) {             
+               resetPQExpBuffer(q);
+               appendPQExpBuffer(q, "COLUMN %s", fmtId(tblinfo[i].relname, force_quotes));
+               appendPQExpBuffer(q, ".");
+               appendPQExpBuffer(q, "%s", fmtId(tblinfo[i].attnames[j], force_quotes));
+               dumpComment(fout, q->data, tblinfo[i].attoids[j]);
+           }
+     
+           /* Dump Table Comments */
+           
+           resetPQExpBuffer(q);
+           appendPQExpBuffer(q, "TABLE %s", fmtId(tblinfo[i].relname, force_quotes));
+           dumpComment(fout, q->data, tblinfo[i].oid);
+           
        }
    }
 }
@@ -3086,6 +3255,13 @@ dumpIndices(FILE *fout, IndInfo *indinfo, int numIndices,
            }
            else
                fprintf(fout, " %s );\n", attlist->data);
+
+           /* Dump Index Comments */
+
+           resetPQExpBuffer(q);
+           appendPQExpBuffer(q, "INDEX %s", id1->data);
+           dumpComment(fout, q->data, indinfo[i].indoid);
+           
        }
    }
 
@@ -3354,6 +3530,12 @@ dumpSequence(FILE *fout, TableInfo tbinfo)
 
    fputs(query->data, fout);
 
+   /* Dump Sequence Comments */
+
+   resetPQExpBuffer(query);
+   appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo.relname, force_quotes));
+   dumpComment(fout, query->data, tbinfo.oid);
+
    if (called == 'f')
        return;                 /* nothing to do more */
 
@@ -3383,6 +3565,7 @@ dumpTriggers(FILE *fout, const char *tablename,
        {
            becomeUser(fout, tblinfo[i].usename);
            fputs(tblinfo[i].triggers[j], fout);
+           dumpComment(fout, tblinfo[i].trcomments[j], tblinfo[i].troids[j]);
        }
    }
 }
@@ -3399,6 +3582,8 @@ dumpRules(FILE *fout, const char *tablename,
    PQExpBuffer query = createPQExpBuffer();
 
    int         i_definition;
+   int         i_oid;
+   int         i_rulename;
 
    if (g_verbose)
        fprintf(stderr, "%s dumping out rules %s\n",
@@ -3417,7 +3602,7 @@ dumpRules(FILE *fout, const char *tablename,
         */
        resetPQExpBuffer(query);
        appendPQExpBuffer(query, "SELECT pg_get_ruledef(pg_rewrite.rulename) "
-               "AS definition FROM pg_rewrite, pg_class "
+               "AS definition, pg_rewrite.oid, pg_rewrite.rulename FROM pg_rewrite, pg_class "
                "WHERE pg_class.relname = '%s' "
                "AND pg_rewrite.ev_class = pg_class.oid "
                "ORDER BY pg_rewrite.oid",
@@ -3433,13 +3618,25 @@ dumpRules(FILE *fout, const char *tablename,
 
        nrules = PQntuples(res);
        i_definition = PQfnumber(res, "definition");
+       i_oid = PQfnumber(res, "oid");
+       i_rulename = PQfnumber(res, "rulename");
 
        /*
         * Dump them out
         */
-       for (i = 0; i < nrules; i++)
+
+       for (i = 0; i < nrules; i++) {
+           
            fprintf(fout, "%s\n", PQgetvalue(res, i, i_definition));
 
+           /* Dump rule comments */
+
+           resetPQExpBuffer(query);
+           appendPQExpBuffer(query, "RULE %s", fmtId(PQgetvalue(res, i, i_rulename), force_quotes));
+           dumpComment(fout, query->data, PQgetvalue(res, i, i_oid));
+           
+       }
+
        PQclear(res);
    }
 }
index 80c6e4928cca8782f933e00fbe9d9f7fb8ac7fdd..5b5e296e5c1d3352908a513a99018caee3fa15b3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_dump.h,v 1.45 2000/01/16 03:54:58 tgl Exp $
+ * $Id: pg_dump.h,v 1.46 2000/01/18 18:09:02 momjian Exp $
  *
  * Modifications - 6/12/96 - [email protected] - version 1.13.dhb.2
  *
@@ -74,6 +74,7 @@ typedef struct _tableInfo
                                 * attribute if the value is 1, then this
                                 * attribute is an inherited attribute */
    char      **attnames;       /* the attribute names */
+   char      **attoids;        /* oids of the various attributes */
    char      **typnames;       /* fill out attributes */
    bool       *notnull;        /* Not null constraints of an attribute */
    char      **adef_expr;      /* DEFAULT expressions */
@@ -93,6 +94,8 @@ typedef struct _tableInfo
    char      **check_expr;     /* [CONSTRAINT name] CHECK expressions */
    int         ntrig;          /* # of triggers */
    char      **triggers;       /* CREATE TRIGGER ... */
+   char      **trcomments;     /* COMMENT ON TRIGGER ... */
+   char      **troids;         /* TRIGGER oids */
     char       *primary_key;    /* PRIMARY KEY of the table, if any */
 } TableInfo;
 
@@ -104,6 +107,7 @@ typedef struct _inhInfo
 
 typedef struct _indInfo
 {
+   char       *indoid;         /* oid of the pg_class entry for the index */
    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,
@@ -210,6 +214,7 @@ extern TableInfo *getTables(int *numTables, FuncInfo *finfo, int numFuncs);
 extern InhInfo *getInherits(int *numInherits);
 extern void getTableAttrs(TableInfo *tbinfo, int numTables);
 extern IndInfo *getIndices(int *numIndices);
+extern void dumpDBComment(FILE *outfile);
 extern void dumpTypes(FILE *fout, FuncInfo *finfo, int numFuncs,
          TypeInfo *tinfo, int numTypes);
 extern void dumpProcLangs(FILE *fout, FuncInfo *finfo, int numFuncs,