From 2eebcddeaa2a60fe836a8a10ac6c697bdd36bf8e Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Tue, 18 Jan 2000 18:09:02 +0000 Subject: [PATCH] Bruce, 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 | 10 ++ src/bin/pg_dump/common.c | 10 +- src/bin/pg_dump/pg_dump.c | 211 +++++++++++++++++++++++++++++++-- src/bin/pg_dump/pg_dump.h | 7 +- 4 files changed, 229 insertions(+), 9 deletions(-) diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 9ebf207199..dc8247691a 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -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); diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 9b6d641418..f111ca57ab 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -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 - dave@bensoft.com - 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) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 82e55c3bfc..a4f2676edd 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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 - dave@bensoft.com - 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); } } diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 80c6e4928c..5b5e296e5c 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -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 - dave@bensoft.com - 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,