diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index bd0a8668d0..eb934f6d3d 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.104 1999/10/15 01:49:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.105 1999/10/26 03:12:33 momjian Exp $ * * * INTERFACE ROUTINES @@ -45,6 +45,7 @@ #include "catalog/pg_proc.h" #include "catalog/pg_relcheck.h" #include "catalog/pg_type.h" +#include "commands/comment.h" #include "commands/trigger.h" #include "optimizer/clauses.h" #include "optimizer/planmain.h" @@ -1276,148 +1277,20 @@ DeleteAttributeTuples(Relation rel) Int16GetDatum(attnum), 0, 0))) { - DeleteComments(tup->t_data->t_oid); - heap_delete(pg_attribute_desc, &tup->t_self, NULL); - pfree(tup); + + /*** Delete any comments associated with this attribute ***/ + + DeleteComments(tup->t_data->t_oid); + + heap_delete(pg_attribute_desc, &tup->t_self, NULL); + pfree(tup); + } } heap_close(pg_attribute_desc, RowExclusiveLock); } -/* ---------------------------------------------------------- - * CreateComments - * - * This routine is handed the oid and the command associated - * with that id and will insert, update, or delete (if the - * comment is an empty string or a NULL pointer) the associated - * comment from the system cataloge, pg_description. - * - * ---------------------------------------------------------- - */ - -void -CreateComments(Oid oid, char *comment) -{ - - Relation description; - TupleDesc tupDesc; - HeapScanDesc scan; - ScanKeyData entry; - HeapTuple desctuple, searchtuple; - Datum values[Natts_pg_description]; - char nulls[Natts_pg_description]; - char replaces[Natts_pg_description]; - bool modified = false; - int i; - - /*** Open pg_description, form a new tuple, if necessary ***/ - - description = heap_openr(DescriptionRelationName, RowExclusiveLock); - tupDesc = description->rd_att; - if ((comment != NULL) && (strlen(comment) > 0)) { - for (i = 0; i < Natts_pg_description; i++) { - nulls[i] = ' '; - replaces[i] = 'r'; - values[i] = (Datum) NULL; - } - i = 0; - values[i++] = ObjectIdGetDatum(oid); - values[i++] = (Datum) fmgr(F_TEXTIN, comment); - } - - /*** Now, open pg_description and attempt to find the old tuple ***/ - - ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ, - ObjectIdGetDatum(oid)); - scan = heap_beginscan(description, false, SnapshotNow, 1, &entry); - searchtuple = heap_getnext(scan, 0); - - /*** If a previous tuple exists, either delete it or prepare a replacement ***/ - - if (HeapTupleIsValid(searchtuple)) { - - /*** If the comment is blank, call heap_delete, else heap_replace ***/ - - if ((comment == NULL) || (strlen(comment) == 0)) { - heap_delete(description, &searchtuple->t_self, NULL); - } else { - desctuple = heap_modifytuple(searchtuple, description, values, nulls, replaces); - setheapoverride(true); - heap_replace(description, &searchtuple->t_self, desctuple, NULL); - setheapoverride(false); - modified = TRUE; - } - - } else { - desctuple = heap_formtuple(tupDesc, values, nulls); - heap_insert(description, desctuple); - modified = TRUE; - } - - /*** Complete the scan, update indices, if necessary ***/ - - heap_endscan(scan); - - if (modified) { - if (RelationGetForm(description)->relhasindex) { - Relation idescs[Num_pg_description_indices]; - - CatalogOpenIndices(Num_pg_description_indices, Name_pg_description_indices, idescs); - CatalogIndexInsert(idescs, Num_pg_description_indices, description, desctuple); - CatalogCloseIndices(Num_pg_description_indices, idescs); - } - pfree(desctuple); - - } - - heap_close(description, RowExclusiveLock); - -} - -/* -------------------------------- - * DeleteComments - * - * This routine is used to purge any comments - * associated with the Oid handed to this routine, - * regardless of the actual object type. It is - * called, for example, when a relation is destroyed. - * -------------------------------- - */ - -void -DeleteComments(Oid oid) -{ - - Relation description; - TupleDesc tupDesc; - ScanKeyData entry; - HeapScanDesc scan; - HeapTuple searchtuple; - - description = heap_openr(DescriptionRelationName, RowExclusiveLock); - tupDesc = description->rd_att; - - /*** Now, open pg_description and attempt to find the old tuple ***/ - - ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ, - ObjectIdGetDatum(oid)); - scan = heap_beginscan(description, false, SnapshotNow, 1, &entry); - searchtuple = heap_getnext(scan, 0); - - /*** If a previous tuple exists, delete it ***/ - - if (HeapTupleIsValid(searchtuple)) { - heap_delete(description, &searchtuple->t_self, NULL); - } - - /*** Complete the scan, update indices, if necessary ***/ - - heap_endscan(scan); - heap_close(description, RowExclusiveLock); - -} - /* -------------------------------- * DeleteTypeTuple * @@ -1529,6 +1402,7 @@ DeleteTypeTuple(Relation rel) * we release the read lock on pg_type. -mer 13 Aug 1991 * ---------------- */ + heap_delete(pg_type_desc, &tup->t_self, NULL); heap_endscan(pg_type_scan); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index f8c4dac95e..9e7850f8f6 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.91 1999/09/24 00:24:11 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.92 1999/10/26 03:12:33 momjian Exp $ * * * INTERFACE ROUTINES @@ -32,6 +32,7 @@ #include "catalog/pg_index.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/comment.h" #include "executor/executor.h" #include "miscadmin.h" #include "optimizer/clauses.h" @@ -1127,6 +1128,13 @@ index_destroy(Oid indexId) if (IsTransactionBlock() && ! userindexRelation->rd_myxactonly) elog(NOTICE, "Caution: DROP INDEX cannot be rolled back, so don't abort now"); + /* ---------------- + * fix DESCRIPTION relation + * ---------------- + */ + + DeleteComments(indexId); + /* ---------------- * fix RELATION relation * ---------------- diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile index 3b4d3a8d31..fa1c4495e5 100644 --- a/src/backend/commands/Makefile +++ b/src/backend/commands/Makefile @@ -4,7 +4,7 @@ # Makefile for commands # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.18 1999/02/27 21:42:33 tgl Exp $ +# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.19 1999/10/26 03:12:34 momjian Exp $ # #------------------------------------------------------------------------- @@ -17,7 +17,7 @@ ifdef MULTIBYTE CFLAGS+= $(MBFLAGS) endif -OBJS = async.o creatinh.o command.o copy.o indexcmds.o define.o \ +OBJS = async.o creatinh.o command.o comment.o copy.o indexcmds.o define.o \ remove.o rename.o vacuum.o view.o cluster.o \ explain.o sequence.o trigger.o user.o proclang.o \ dbcommands.o variable.o @@ -27,6 +27,12 @@ all: SUBSYS.o SUBSYS.o: $(OBJS) $(LD) -r -o SUBSYS.o $(OBJS) +# The following declares a hard-coded dependency on parse.h since, +# if compiled without make dep, comment.c would get compiled before +# the parser. + +comment.o: ../parse.h + depend dep: $(CC) -MM $(CFLAGS) *.c >depend diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c new file mode 100644 index 0000000000..c2dacaa848 --- /dev/null +++ b/src/backend/commands/comment.c @@ -0,0 +1,796 @@ +/*------------------------------------------------------------------------- + * + * comment.c + * + * PostgreSQL object comments utility code. + * + * Copyright (c) 1999, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "access/heapam.h" +#include "catalog/catname.h" +#include "catalog/indexing.h" +#include "catalog/heap.h" +#include "catalog/pg_aggregate.h" +#include "catalog/pg_database.h" +#include "catalog/pg_description.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_rewrite.h" +#include "catalog/pg_shadow.h" +#include "catalog/pg_trigger.h" +#include "catalog/pg_type.h" +#include "commands/comment.h" +#include "miscadmin.h" +#include "rewrite/rewriteRemove.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/syscache.h" + +#include "../backend/parser/parse.h" + +/*------------------------------------------------------------------ + * Static Function Prototypes -- + * + * The following protoypes are declared static so as not to conflict + * with any other routines outside this module. These routines are + * called by the public function CommentObject() routine to create + * the appropriate comment for the specific object type. + *------------------------------------------------------------------ + */ + +static void CommentRelation(int objtype, char *relation, char *comment); +static void CommentAttribute(char *relation, char *attrib, char *comment); +static void CommentDatabase(char *database, char *comment); +static void CommentRewrite(char *rule, char *comment); +static void CommentType(char *type, char *comment); +static void CommentAggregate(char *aggregate, char *aggtype, char *comment); +static void CommentProc(char *function, List *arguments, char *comment); +static void CommentOperator(char *opname, List *arguments, char *comment); +static void CommentTrigger(char *trigger, char *relation, char *comments); + +/*------------------------------------------------------------------ + * CommentObject -- + * + * This routine is used to add the associated comment into + * pg_description for the object specified by the paramters handed + * to this routine. If the routine cannot determine an Oid to + * associated with the parameters handed to this routine, an + * error is thrown. Otherwise the comment is added to pg_description + * by calling the CreateComments() routine. If the comments were + * empty, CreateComments() will drop any comments associated with + * the object. + *------------------------------------------------------------------ +*/ + +void CommentObject(int objtype, char *objname, char *objproperty, + List *objlist, char *comment) { + + switch (objtype) { + case (INDEX): + case (SEQUENCE): + case (TABLE): + case (VIEW): + CommentRelation(objtype, objname, comment); + break; + case (COLUMN): + CommentAttribute(objname, objproperty, comment); + break; + case (DATABASE): + CommentDatabase(objname, comment); + break; + case (RULE): + CommentRewrite(objname, comment); + break; + case (TYPE_P): + CommentType(objname, comment); + break; + case (AGGREGATE): + CommentAggregate(objname, objproperty, comment); + break; + case (FUNCTION): + CommentProc(objname, objlist, comment); + break; + case (OPERATOR): + CommentOperator(objname, objlist, comment); + break; + case (TRIGGER): + CommentTrigger(objname, objproperty, comment); + break; + default: + elog(ERROR, "An attempt was made to comment on a unkown type: %i", + objtype); + } + +} + +/*------------------------------------------------------------------ + * CreateComments -- + * + * This routine is handed the oid and the command associated + * with that id and will insert, update, or delete (if the + * comment is an empty string or a NULL pointer) the associated + * comment from the system cataloge, pg_description. + * + *------------------------------------------------------------------ + */ + +void CreateComments(Oid oid, char *comment) { + + Relation description; + TupleDesc tupDesc; + HeapScanDesc scan; + ScanKeyData entry; + HeapTuple desctuple = NULL, searchtuple; + Datum values[Natts_pg_description]; + char nulls[Natts_pg_description]; + char replaces[Natts_pg_description]; + bool modified = false; + int i; + + /*** Open pg_description, form a new tuple, if necessary ***/ + + description = heap_openr(DescriptionRelationName, RowExclusiveLock); + tupDesc = description->rd_att; + if ((comment != NULL) && (strlen(comment) > 0)) { + for (i = 0; i < Natts_pg_description; i++) { + nulls[i] = ' '; + replaces[i] = 'r'; + values[i] = (Datum) NULL; + } + i = 0; + values[i++] = ObjectIdGetDatum(oid); + values[i++] = (Datum) fmgr(F_TEXTIN, comment); + } + + /*** Now, open pg_description and attempt to find the old tuple ***/ + + ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ, + ObjectIdGetDatum(oid)); + scan = heap_beginscan(description, false, SnapshotNow, 1, &entry); + searchtuple = heap_getnext(scan, 0); + + /*** If a previous tuple exists, either delete or prep replacement ***/ + + if (HeapTupleIsValid(searchtuple)) { + + /*** If the comment is blank, call heap_delete, else heap_replace ***/ + + if ((comment == NULL) || (strlen(comment) == 0)) { + heap_delete(description, &searchtuple->t_self, NULL); + } else { + desctuple = heap_modifytuple(searchtuple, description, values, + nulls, replaces); + setheapoverride(true); + heap_replace(description, &searchtuple->t_self, desctuple, NULL); + setheapoverride(false); + modified = TRUE; + } + + } else { + desctuple = heap_formtuple(tupDesc, values, nulls); + heap_insert(description, desctuple); + modified = TRUE; + } + + /*** Complete the scan, update indices, if necessary ***/ + + heap_endscan(scan); + + if (modified) { + if (RelationGetForm(description)->relhasindex) { + Relation idescs[Num_pg_description_indices]; + + CatalogOpenIndices(Num_pg_description_indices, + Name_pg_description_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_description_indices, description, + desctuple); + CatalogCloseIndices(Num_pg_description_indices, idescs); + } + pfree(desctuple); + + } + + heap_close(description, RowExclusiveLock); + +} + +/*------------------------------------------------------------------ + * DeleteComments -- + * + * This routine is used to purge any comments + * associated with the Oid handed to this routine, + * regardless of the actual object type. It is + * called, for example, when a relation is destroyed. + *------------------------------------------------------------------ + */ + +void DeleteComments(Oid oid) { + + Relation description; + TupleDesc tupDesc; + ScanKeyData entry; + HeapScanDesc scan; + HeapTuple searchtuple; + + description = heap_openr(DescriptionRelationName, RowExclusiveLock); + tupDesc = description->rd_att; + + /*** Now, open pg_description and attempt to find the old tuple ***/ + + ScanKeyEntryInitialize(&entry, 0x0, Anum_pg_description_objoid, F_OIDEQ, + ObjectIdGetDatum(oid)); + scan = heap_beginscan(description, false, SnapshotNow, 1, &entry); + searchtuple = heap_getnext(scan, 0); + + /*** If a previous tuple exists, delete it ***/ + + if (HeapTupleIsValid(searchtuple)) { + heap_delete(description, &searchtuple->t_self, NULL); + } + + /*** Complete the scan, update indices, if necessary ***/ + + heap_endscan(scan); + heap_close(description, RowExclusiveLock); + +} + +/*------------------------------------------------------------------ + * CommentRelation -- + * + * This routine is used to add/drop a comment from a relation, where + * a relation is a TABLE, SEQUENCE, VIEW or INDEX. The routine simply + * finds the relation name by searching the system cache, locating + * the appropriate tuple, and inserting a comment using that + * tuple's oid. Its parameters are the relation name and comments. + *------------------------------------------------------------------ +*/ + +void CommentRelation(int reltype, char *relname, char *comment) { + + HeapTuple reltuple; + Oid oid; + char relkind; + + /*** First, check object security ***/ + + #ifndef NO_SECURITY + if (!pg_ownercheck(GetPgUserName(), relname, RELNAME)) { + elog(ERROR, "you are not permitted to comment on class '%s'", relname); + } + #endif + + /*** Now, attempt to find the oid in the cached version of pg_class ***/ + + reltuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname), + 0, 0, 0); + if (!HeapTupleIsValid(reltuple)) { + elog(ERROR, "relation '%s' does not exist", relname); + } + + oid = reltuple->t_data->t_oid; + + /*** Next, verify that the relation type matches the intent ***/ + + relkind = ((Form_pg_class) GETSTRUCT(reltuple))->relkind; + + switch (reltype) { + case (INDEX): + if (relkind != 'i') { + elog(ERROR, "relation '%s' is not an index", relname); + } + break; + case (TABLE): + if (relkind != 'r') { + elog(ERROR, "relation '%s' is not a table", relname); + } + break; + case (VIEW): + if (relkind != 'r') { + elog(ERROR, "relation '%s' is not a view", relname); + } + break; + case (SEQUENCE): + if (relkind != 'S') { + elog(ERROR, "relation '%s' is not a sequence", relname); + } + break; + } + + /*** Create the comments using the tuple's oid ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentAttribute -- + * + * This routine is used to add/drop a comment from an attribute + * such as a table's column. The routine will check security + * restrictions and then attempt to fetch the oid of the associated + * attribute. If successful, a comment is added/dropped, else an + * elog() exception is thrown. The parameters are the relation + * and attribute names, and the comments + *------------------------------------------------------------------ +*/ + +void CommentAttribute(char *relname, char *attrname, char *comment) { + + Relation relation; + HeapTuple attrtuple; + Oid oid; + + /*** First, check object security ***/ + + #ifndef NO_SECURITY + if (!pg_ownercheck(GetPgUserName(), relname, RELNAME)) { + elog(ERROR, "you are not permitted to comment on class '%s\'", relname); + } + #endif + + /*** Now, fetch the attribute oid from the system cache ***/ + + relation = heap_openr(relname, AccessShareLock); + attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id), + PointerGetDatum(attrname), 0, 0); + if (!HeapTupleIsValid(attrtuple)) { + elog(ERROR, "'%s' is not an attribute of class '%s'", + attrname, relname); + } + oid = attrtuple->t_data->t_oid; + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + + /*** Now, close the heap relation and return ***/ + + heap_close(relation, AccessShareLock); + +} + +/*------------------------------------------------------------------ + * CommentDatabase -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding the specified database. The routine will check + * security for owner permissions, and, if succesful, will then + * attempt to find the oid of the database specified. Once found, + * a comment is added/dropped using the CreateComments() routine. + *------------------------------------------------------------------ +*/ + +void CommentDatabase(char *database, char *comment) { + + Relation pg_database; + HeapTuple dbtuple, usertuple; + ScanKeyData entry; + HeapScanDesc scan; + Oid oid; + bool superuser; + int4 dba, userid; + char *username; + + /*** First find the tuple in pg_database for the database ***/ + + pg_database = heap_openr(DatabaseRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_database_datname, + F_NAMEEQ, NameGetDatum(database)); + scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry); + dbtuple = heap_getnext(scan, 0); + + /*** Validate database exists, and fetch the dba id and oid ***/ + + if (!HeapTupleIsValid(dbtuple)) { + elog(ERROR, "database '%s' does not exist", database); + } + dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba; + oid = dbtuple->t_data->t_oid; + + /*** Now, fetch user information ***/ + + username = GetPgUserName(); + usertuple = SearchSysCacheTuple(USENAME, PointerGetDatum(username), + 0, 0, 0); + if (!HeapTupleIsValid(usertuple)) { + elog(ERROR, "current user '%s' does not exist", username); + } + userid = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesysid; + superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper; + + /*** Allow if the userid matches the database dba or is a superuser ***/ + + #ifndef NO_SECURITY + if (!(superuser || (userid == dba))) { + elog(ERROR, "you are not permitted to comment on database '%s'", + database); + } + #endif + + /*** Create the comments with the pg_database oid ***/ + + CreateComments(oid, comment); + + /*** Complete the scan and close any opened relations ***/ + + heap_endscan(scan); + heap_close(pg_database, AccessShareLock); + +} + +/*------------------------------------------------------------------ + * CommentRewrite -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a specified RULE. The rule is specified by name + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + *------------------------------------------------------------------ +*/ + +void CommentRewrite(char *rule, char *comment) { + + HeapTuple rewritetuple; + Oid oid; + char *user, *relation; + int aclcheck; + + /*** First, validate user ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + relation = RewriteGetRuleEventRel(rule); + aclcheck = pg_aclcheck(relation, user, ACL_RU); + if (aclcheck != ACLCHECK_OK) { + elog(ERROR, "you are not permitted to comment on rule '%s'", + rule); + } + #endif + + /*** Next, find the rule's oid ***/ + + rewritetuple = SearchSysCacheTuple(REWRITENAME, PointerGetDatum(rule), + 0, 0, 0); + if (!HeapTupleIsValid(rewritetuple)) { + elog(ERROR, "rule '%s' does not exist", rule); + } + + oid = rewritetuple->t_data->t_oid; + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentType -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a TYPE. The type is specified by name + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + * The type's name and the comments are the paramters to this routine. + *------------------------------------------------------------------ +*/ + +void CommentType(char *type, char *comment) { + + HeapTuple typetuple; + Oid oid; + char *user; + + /*** First, validate user ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + if (!pg_ownercheck(user, type, TYPNAME)) { + elog(ERROR, "you are not permitted to comment on type '%s'", + type); + } + #endif + + /*** Next, find the type's oid ***/ + + typetuple = SearchSysCacheTuple(TYPNAME, PointerGetDatum(type), + 0, 0, 0); + if (!HeapTupleIsValid(typetuple)) { + elog(ERROR, "type '%s' does not exist", type); + } + + oid = typetuple->t_data->t_oid; + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentAggregate -- + * + * This routine is used to allow a user to provide comments on an + * aggregate function. The aggregate function is determined by both + * its name and its argument type, which, with the comments are + * the three parameters handed to this routine. + *------------------------------------------------------------------ +*/ + +void CommentAggregate(char *aggregate, char *argument, char *comment) { + + HeapTuple aggtuple; + Oid baseoid, oid; + bool defined; + char *user; + + /*** First, attempt to determine the base aggregate oid ***/ + + if (argument) { + baseoid = TypeGet(argument, &defined); + if (!OidIsValid(baseoid)) { + elog(ERROR, "aggregate type '%s' does not exist", argument); + } + } else { + baseoid = 0; + } + + /*** Next, validate the user's attempt to comment ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + if (!pg_aggr_ownercheck(user, aggregate, baseoid)) { + if (argument) { + elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'", + aggregate, "with type", argument); + } else { + elog(ERROR, "you are not permitted to comment on aggregate '%s'", + aggregate); + } + } + #endif + + /*** Now, attempt to find the actual tuple in pg_aggregate ***/ + + aggtuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggregate), + ObjectIdGetDatum(baseoid), 0, 0); + if (!HeapTupleIsValid(aggtuple)) { + if (argument) { + elog(ERROR, "aggregate type '%s' does not exist for aggregate '%s'", + argument, aggregate); + } else { + elog(ERROR, "aggregate '%s' does not exist", aggregate); + } + } + + oid = aggtuple->t_data->t_oid; + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentProc -- + * + * This routine is used to allow a user to provide comments on an + * procedure (function). The procedure is determined by both + * its name and its argument list. The argument list is expected to + * be a series of parsed nodes pointed to by a List object. If the + * comments string is empty, the associated comment is dropped. + *------------------------------------------------------------------ +*/ + +void CommentProc(char *function, List *arguments, char *comment) { + + HeapTuple argtuple, functuple; + Oid oid, argoids[8]; + char *user, *argument; + int i, argcount; + + /*** First, initialize function's argument list with their type oids ***/ + + argcount = length(arguments); + if (argcount > 0) { + MemSet(argoids, 0, 8 * sizeof(Oid)); + for (i = 0; i < argcount; i++) { + argument = strVal(lfirst(arguments)); + arguments = lnext(arguments); + if (strcmp(argument, "opaque") == 0) { + argoids[i] = 0; + } else { + argtuple = SearchSysCacheTuple(TYPNAME, PointerGetDatum(argument), + 0, 0, 0); + if (!HeapTupleIsValid(argtuple)) { + elog(ERROR, "function argument type '%s' does not exist", + argument); + } + argoids[i] = argtuple->t_data->t_oid; + } + } + } + + /*** Now, validate the user's ability to comment on this function ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + if (!pg_func_ownercheck(user, function, argcount, argoids)) { + elog(ERROR, "you are not permitted to comment on function '%s'", + function); + } + #endif + + /*** Now, find the corresponding oid for this procedure ***/ + + functuple = SearchSysCacheTuple(PRONAME, PointerGetDatum(function), + Int32GetDatum(argcount), + PointerGetDatum(argoids), 0); + + /*** Deallocate our argument oids and check the function tuple ***/ + + if (!HeapTupleIsValid(functuple)) { + elog(ERROR, "function '%s' with the supplied %s does not exist", + function, "argument list"); + } + + oid = functuple->t_data->t_oid; + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentOperator -- + * + * This routine is used to allow a user to provide comments on an + * operator. The operator for commenting is determined by both + * its name and its argument list which defines the left and right + * hand types the operator will operate on. The argument list is + * expected to be a couple of parse nodes pointed to be a List + * object. If the comments string is empty, the associated comment + * is dropped. + *------------------------------------------------------------------ +*/ + +void CommentOperator(char *opername, List *arguments, char *comment) { + + HeapTuple optuple; + Oid oid, leftoid = InvalidOid, rightoid = InvalidOid; + bool defined; + char oprtype = 0, *user, *lefttype = NULL, *righttype = NULL; + + /*** Initialize our left and right argument types ***/ + + if (lfirst(arguments) != NULL) { + lefttype = strVal(lfirst(arguments)); + } + if (lsecond(arguments) != NULL) { + righttype = strVal(lsecond(arguments)); + } + + /*** Attempt to fetch the left oid, if specified ***/ + + if (lefttype != NULL) { + leftoid = TypeGet(lefttype, &defined); + if (!OidIsValid(leftoid)) { + elog(ERROR, "left type '%s' does not exist", lefttype); + } + } + + /*** Attempt to fetch the right oid, if specified ***/ + + if (righttype != NULL) { + rightoid = TypeGet(righttype, &defined); + if (!OidIsValid(rightoid)) { + elog(ERROR, "right type '%s' does not exist", righttype); + } + } + + /*** Determine operator type ***/ + + if (OidIsValid(leftoid) && (OidIsValid(rightoid))) oprtype = 'b'; + else if (OidIsValid(leftoid)) oprtype = 'l'; + else if (OidIsValid(rightoid)) oprtype = 'r'; + else elog(ERROR, "operator '%s' is of an illegal type'", opername); + + /*** Attempt to fetch the operator oid ***/ + + optuple = SearchSysCacheTupleCopy(OPRNAME, PointerGetDatum(opername), + ObjectIdGetDatum(leftoid), + ObjectIdGetDatum(rightoid), + CharGetDatum(oprtype)); + if (!HeapTupleIsValid(optuple)) { + elog(ERROR, "operator '%s' does not exist", opername); + } + + oid = optuple->t_data->t_oid; + + /*** Valid user's ability to comment on this operator ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + if (!pg_ownercheck(user, (char *) ObjectIdGetDatum(oid), OPROID)) { + elog(ERROR, "you are not permitted to comment on operator '%s'", + opername); + } + #endif + + /*** Call CreateComments() to create/drop the comments ***/ + + CreateComments(oid, comment); + +} + +/*------------------------------------------------------------------ + * CommentTrigger -- + * + * This routine is used to allow a user to provide comments on a + * trigger event. The trigger for commenting is determined by both + * its name and the relation to which it refers. The arguments to this + * function are the trigger name, the relation name, and the comments + * to add/drop. + *------------------------------------------------------------------ +*/ + +void CommentTrigger(char *trigger, char *relname, char *comment) { + + Form_pg_trigger data; + Relation pg_trigger, relation; + HeapTuple triggertuple; + HeapScanDesc scan; + ScanKeyData entry; + Oid oid = InvalidOid; + char *user; + + /*** First, validate the user's action ***/ + + #ifndef NO_SECURITY + user = GetPgUserName(); + if (!pg_ownercheck(user, relname, RELNAME)) { + elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'", + trigger, "defined for relation", relname); + } + #endif + + /*** Now, fetch the trigger oid from pg_trigger ***/ + + relation = heap_openr(relname, AccessShareLock); + pg_trigger = heap_openr(TriggerRelationName, AccessShareLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_trigger_tgrelid, + F_OIDEQ, RelationGetRelid(relation)); + scan = heap_beginscan(pg_trigger, 0, SnapshotNow, 1, &entry); + triggertuple = heap_getnext(scan, 0); + while (HeapTupleIsValid(triggertuple)) { + data = (Form_pg_trigger) GETSTRUCT(triggertuple); + if (namestrcmp(&(data->tgname), trigger) == 0) { + oid = triggertuple->t_data->t_oid; + break; + } + triggertuple = heap_getnext(scan, 0); + } + + /*** If no trigger exists for the relation specified, notify user ***/ + + if (oid == InvalidOid) { + elog(ERROR, "trigger '%s' defined for relation '%s' does not exist", + trigger, relname); + } + + /*** Create the comments with the pg_trigger oid ***/ + + CreateComments(oid, comment); + + /*** Complete the scan and close any opened relations ***/ + + heap_endscan(scan); + heap_close(pg_trigger, AccessShareLock); + heap_close(relation, AccessShareLock); + +} diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c index 9463d55a6a..f07586dac0 100644 --- a/src/backend/commands/creatinh.c +++ b/src/backend/commands/creatinh.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.49 1999/10/15 01:49:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.50 1999/10/26 03:12:34 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -234,52 +234,6 @@ TruncateRelation(char *name) heap_truncate(name); } -/*------------------------------------------------------------------ - * CommentRelation -- - * Adds a comment to pg_description for the associated - * relation or relation attribute. - * - * Note: - * The comment is dropped on the relation or attribute if - * the comment is an empty string. - *------------------------------------------------------------------ - */ -void -CommentRelation(char *relname, char *attrname, char *comments) -{ - - Relation relation; - HeapTuple attrtuple; - Oid oid; - - /*** First ensure relname is valid ***/ - - relation = heap_openr(relname, AccessShareLock); - - /*** Now, if an attribute was specified, fetch its oid, else use relation's oid ***/ - - if (attrname != NULL) { - attrtuple = SearchSysCacheTuple(ATTNAME, ObjectIdGetDatum(relation->rd_id), - PointerGetDatum(attrname), 0, 0); - if (!HeapTupleIsValid(attrtuple)) { - elog(ERROR, "CommentRelation: attribute \"%s\" is not an attribute of relation \"%s\"", - attrname, relname); - } - oid = attrtuple->t_data->t_oid; - } else { - oid = RelationGetRelid(relation); - } - - /*** Call CreateComments() to create/drop the comments ***/ - - CreateComments(oid, comments); - - /*** Now, close the heap relation ***/ - - heap_close(relation, AccessShareLock); - -} - /* * MergeAttributes * Returns new schema given initial schema and supers. diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index 75a917092a..fc3bff2e4f 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.42 1999/10/25 03:07:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.43 1999/10/26 03:12:34 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ #include "catalog/catname.h" #include "catalog/pg_database.h" #include "catalog/pg_shadow.h" +#include "commands/comment.h" #include "commands/dbcommands.h" #include "miscadmin.h" #include "storage/sinval.h" @@ -149,6 +150,10 @@ destroydb(char *dbname, CommandDest dest) dbname, db_id); } + /*** Delete any comments associated with the database ***/ + + DeleteComments(db_id); + /* * Houston, we have launch commit... * diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c index a73964cb02..67cd5c8c2a 100644 --- a/src/backend/commands/remove.c +++ b/src/backend/commands/remove.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.37 1999/09/18 19:06:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.38 1999/10/26 03:12:34 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,7 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" +#include "commands/comment.h" #include "commands/defrem.h" #include "miscadmin.h" #include "parser/parse_func.h" @@ -93,7 +94,14 @@ RemoveOperator(char *operatorName, /* operator name */ elog(ERROR, "RemoveOperator: operator '%s': permission denied", operatorName); #endif + + + /*** Delete any comments associated with this operator ***/ + + DeleteComments(tup->t_data->t_oid); + heap_delete(relation, &tup->t_self, NULL); + } else { @@ -147,8 +155,17 @@ SingleOpOperatorRemove(Oid typeOid) { key[0].sk_attno = attnums[i]; scan = heap_beginscan(rel, 0, SnapshotNow, 1, key); - while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) - heap_delete(rel, &tup->t_self, NULL); + while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) { + + /*** This is apparently a routine not in use, but remove ***/ + /*** any comments anyways ***/ + + DeleteComments(tup->t_data->t_oid); + + heap_delete(rel, &tup->t_self, NULL); + + } + heap_endscan(scan); } heap_close(rel, RowExclusiveLock); @@ -259,6 +276,11 @@ RemoveType(char *typeName) /* type name to be removed */ } typeOid = tup->t_data->t_oid; + + /*** Delete any comments associated with this type ***/ + + DeleteComments(typeOid); + heap_delete(relation, &tup->t_self, NULL); /* Now, Delete the "array of" that type */ @@ -347,6 +369,10 @@ RemoveFunction(char *functionName, /* function name to be removed */ elog(ERROR, "RemoveFunction: function \"%s\" is built-in", functionName); } + /*** Delete any comments associated with this function ***/ + + DeleteComments(tup->t_data->t_oid); + heap_delete(relation, &tup->t_self, NULL); heap_close(relation, RowExclusiveLock); @@ -418,6 +444,11 @@ RemoveAggregate(char *aggName, char *aggType) aggName); } } + + /*** Remove any comments related to this aggregate ***/ + + DeleteComments(tup->t_data->t_oid); + heap_delete(relation, &tup->t_self, NULL); heap_close(relation, RowExclusiveLock); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 17a26c3c8e..1bec6aa762 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -16,6 +16,7 @@ #include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "catalog/pg_trigger.h" +#include "commands/comment.h" #include "commands/trigger.h" #include "executor/executor.h" #include "miscadmin.h" @@ -297,8 +298,14 @@ DropTrigger(DropTrigStmt *stmt) if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0) { - heap_delete(tgrel, &tuple->t_self, NULL); - tgfound++; + + /*** Delete any comments associated with this trigger ***/ + + DeleteComments(tuple->t_data->t_oid); + + heap_delete(tgrel, &tuple->t_self, NULL); + tgfound++; + } else found++; @@ -355,8 +362,15 @@ RelationRemoveTriggers(Relation rel) tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); - while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0))) - heap_delete(tgrel, &tup->t_self, NULL); + while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0))) { + + /*** Delete any comments associated with this trigger ***/ + + DeleteComments(tup->t_data->t_oid); + + heap_delete(tgrel, &tup->t_self, NULL); + + } heap_endscan(tgscan); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 16a4efa2ba..a4a0c721ea 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.109 1999/10/15 01:49:41 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.110 1999/10/26 03:12:34 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -196,7 +196,8 @@ Oid param_type(int t); /* used in parse_expr.c */ %type opt_cursor %type copy_dirn, def_type, opt_direction, remove_type, - opt_column, event + opt_column, event, comment_type, comment_cl, + comment_ag, comment_fn, comment_op, comment_tg %type fetch_how_many @@ -1542,28 +1543,101 @@ TruncateStmt: TRUNCATE TABLE relation_name /***************************************************************************** * - * QUERY: - * comment on [ table | column . ] - * is 'text' + * The COMMENT ON statement can take different forms based upon the type of + * the object associated with the comment. The form of the statement is: + * + * COMMENT ON [ [ DATABASE | INDEX | RULE | SEQUENCE | TABLE | TYPE | VIEW ] + * | AGGREGATE | FUNCTION + * (arg1, arg2, ...) | OPERATOR + * (leftoperand_typ rightoperand_typ) | TRIGGER ON + * ] IS 'text' * *****************************************************************************/ -CommentStmt: COMMENT ON COLUMN relation_name '.' attr_name IS Sconst +CommentStmt: COMMENT ON comment_type name IS Sconst { CommentStmt *n = makeNode(CommentStmt); - n->relname = $4; - n->attrname = $6; - n->comment = $8; - $$ = (Node *) n; - } - | COMMENT ON TABLE relation_name IS Sconst - { - CommentStmt *n = makeNode(CommentStmt); - n->relname = $4; - n->attrname = NULL; + n->objtype = $3; + n->objname = $4; + n->objproperty = NULL; + n->objlist = NULL; n->comment = $6; $$ = (Node *) n; } + | COMMENT ON comment_cl relation_name '.' attr_name IS Sconst + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = $3; + n->objname = $4; + n->objproperty = $6; + n->objlist = NULL; + n->comment = $8; + $$ = (Node *) n; + } + | COMMENT ON comment_ag name aggr_argtype IS Sconst + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = $3; + n->objname = $4; + n->objproperty = $5; + n->objlist = NULL; + n->comment = $7; + $$ = (Node *) n; + } + | COMMENT ON comment_fn func_name func_args IS Sconst + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = $3; + n->objname = $4; + n->objproperty = NULL; + n->objlist = $5; + n->comment = $7; + $$ = (Node *) n; + } + | COMMENT ON comment_op all_Op '(' oper_argtypes ')' IS Sconst + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = $3; + n->objname = $4; + n->objproperty = NULL; + n->objlist = $6; + n->comment = $9; + $$ = (Node *) n; + } + | COMMENT ON comment_tg name ON relation_name IS Sconst + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = $3; + n->objname = $4; + n->objproperty = $6; + n->objlist = NULL; + n->comment = $8; + $$ = (Node *) n; + } + ; + +comment_type: DATABASE { $$ = DATABASE; } + | INDEX { $$ = INDEX; } + | RULE { $$ = RULE; } + | SEQUENCE { $$ = SEQUENCE; } + | TABLE { $$ = TABLE; } + | TYPE_P { $$ = TYPE_P; } + | VIEW { $$ = VIEW; } + ; + +comment_cl: COLUMN { $$ = COLUMN; } + ; + +comment_ag: AGGREGATE { $$ = AGGREGATE; } + ; + +comment_fn: FUNCTION { $$ = FUNCTION; } + ; + +comment_op: OPERATOR { $$ = OPERATOR; } + ; + +comment_tg: TRIGGER { $$ = TRIGGER; } ; /***************************************************************************** diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index 50e6c62c02..c751550e49 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.29 1999/09/18 19:07:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.30 1999/10/26 03:12:35 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/pg_rewrite.h" +#include "commands/comment.h" #include "rewrite/rewriteRemove.h" #include "rewrite/rewriteSupport.h" #include "utils/syscache.h" @@ -119,6 +120,13 @@ RemoveRewriteRule(char *ruleName) */ prs2_deleteFromRelation(eventRelationOid, ruleId); + /* + * Delete any comments associated with this rule + * + */ + + DeleteComments(ruleId); + /* * Now delete the tuple... */ @@ -158,8 +166,15 @@ RelationRemoveRules(Oid relid) scanDesc = heap_beginscan(RewriteRelation, 0, SnapshotNow, 1, &scanKeyData); - while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0))) - heap_delete(RewriteRelation, &tuple->t_self, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0))) { + + /*** Delete any comments associated with this relation ***/ + + DeleteComments(tuple->t_data->t_oid); + + heap_delete(RewriteRelation, &tuple->t_self, NULL); + + } heap_endscan(scanDesc); heap_close(RewriteRelation, RowExclusiveLock); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index ec617d7536..6035c89b2e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.70 1999/10/15 01:49:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.71 1999/10/26 03:12:36 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "commands/async.h" #include "commands/cluster.h" #include "commands/command.h" +#include "commands/comment.h" #include "commands/copy.h" #include "commands/creatinh.h" #include "commands/dbcommands.h" @@ -38,7 +39,6 @@ #include "rewrite/rewriteRemove.h" #include "tcop/utility.h" #include "utils/acl.h" -#include "utils/acl.h" #include "utils/ps_status.h" #include "utils/syscache.h" @@ -242,14 +242,9 @@ ProcessUtility(Node *parsetree, PS_SET_STATUS(commandTag = "COMMENT"); CHECK_IF_ABORTED(); - -#ifndef NO_SECURITY - if (!pg_ownercheck(userName, statement->relname, RELNAME)) - elog(ERROR, "you do not own class \"%s\"", statement->relname); -#endif - - CommentRelation(statement->relname, statement->attrname, - statement->comment); + CommentObject(statement->objtype, statement->objname, + statement->objproperty, statement->objlist, + statement->comment); } break; diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 4720013160..1cb86b501c 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: heap.h,v 1.23 1999/10/15 01:49:44 momjian Exp $ + * $Id: heap.h,v 1.24 1999/10/26 03:12:37 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -21,23 +21,20 @@ typedef struct RawColumnDefault Node *raw_default; /* default value (untransformed parse tree) */ } RawColumnDefault; -extern Oid RelnameFindRelid(char *relname); +extern Oid RelnameFindRelid(char *relname); extern Relation heap_create(char *relname, TupleDesc att, - bool isnoname, bool istemp); + bool isnoname, bool istemp); -extern Oid heap_create_with_catalog(char *relname, - TupleDesc tupdesc, char relkind, bool istemp); +extern Oid heap_create_with_catalog(char *relname, TupleDesc tupdesc, + char relkind, bool istemp); extern void heap_destroy_with_catalog(char *relname); extern void heap_truncate(char *relname); extern void heap_destroy(Relation rel); -extern void CreateComments(Oid object, char *comments); -extern void DeleteComments(Oid object); - extern void AddRelationRawConstraints(Relation rel, - List *rawColDefaults, - List *rawConstraints); + List *rawColDefaults, + List *rawConstraints); extern void InitNoNameRelList(void); extern void DestroyNoNameRels(void); diff --git a/src/include/commands/comment.h b/src/include/commands/comment.h new file mode 100644 index 0000000000..93ed200a74 --- /dev/null +++ b/src/include/commands/comment.h @@ -0,0 +1,31 @@ +/*------------------------------------------------------------------------- + * + * comment.h + * + * Prototypes for functions in commands/comment.c + * + * Copyright (c) 1999, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ + +#ifndef COMMENT_H +#define COMMENT_H + +/*------------------------------------------------------------------ + * Function Prototypes -- + * + * The following protoypes define the public functions of the comment + * related routines. CreateComments() is used to create/drop a comment + * for any object with a valid oid. DeleteComments() deletes, if any, + * the comments associated with the object. CommentObject() is used to + * create comments to be identified by the specific type. + *------------------------------------------------------------------ + */ + +void CreateComments(Oid oid, char *comment); +void DeleteComments(Oid oid); +void CommentObject(int objtype, char *objname, char *objproperty, + List *objlist, char *comment); + +#endif /* COMMENT_H */ diff --git a/src/include/commands/creatinh.h b/src/include/commands/creatinh.h index 11d5fdb7a0..8bfe142a1f 100644 --- a/src/include/commands/creatinh.h +++ b/src/include/commands/creatinh.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: creatinh.h,v 1.11 1999/10/15 01:49:46 momjian Exp $ + * $Id: creatinh.h,v 1.12 1999/10/26 03:12:38 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,5 @@ extern void DefineRelation(CreateStmt *stmt, char relkind); extern void RemoveRelation(char *name); extern void TruncateRelation(char *name); -extern void CommentRelation(char *name, char *attr, char *comment); #endif /* CREATINH_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 208b31d740..aac3ef7de5 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.85 1999/10/15 01:49:47 momjian Exp $ + * $Id: parsenodes.h,v 1.86 1999/10/26 03:12:39 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -316,10 +316,12 @@ typedef struct TruncateStmt */ typedef struct CommentStmt { - NodeTag type; - char *relname; /* relation to create/drop comment */ - char *attrname; /* attribute to comment on */ - char *comment; /* the actual comment */ + NodeTag type; + int objtype; /* Object's type */ + char *objname; /* Name of the object */ + char *objproperty; /* Property Id (such as column) */ + List *objlist; /* Arguments for VAL objects */ + char *comment; /* The comment to insert */ } CommentStmt; /* ----------------------