diff options
Diffstat (limited to 'src/backend/commands/comment.c')
-rw-r--r-- | src/backend/commands/comment.c | 322 |
1 files changed, 320 insertions, 2 deletions
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 62765a96e0a..2283c563790 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1996-2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.73 2003/11/12 21:15:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.74 2003/11/21 22:32:48 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "catalog/namespace.h" #include "catalog/pg_constraint.h" #include "catalog/pg_description.h" +#include "catalog/pg_largeobject.h" #include "catalog/pg_operator.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_trigger.h" @@ -58,6 +59,11 @@ static void CommentProc(List *function, List *arguments, char *comment); static void CommentOperator(List *opername, List *arguments, char *comment); static void CommentTrigger(List *qualname, char *comment); static void CommentConstraint(List *qualname, char *comment); +static void CommentConversion(List *qualname, char *comment); +static void CommentLanguage(List *qualname, char *comment); +static void CommentOpClass(List *qualname, List *arguments, char *comment); +static void CommentLargeObject(List *qualname, char *comment); +static void CommentCast(List *qualname, List *arguments, char *comment); /* @@ -107,6 +113,21 @@ CommentObject(CommentStmt *stmt) case OBJECT_CONSTRAINT: CommentConstraint(stmt->objname, stmt->comment); break; + case OBJECT_CONVERSION: + CommentConversion(stmt->objname, stmt->comment); + break; + case OBJECT_LANGUAGE: + CommentLanguage(stmt->objname, stmt->comment); + break; + case OBJECT_OPCLASS: + CommentOpClass(stmt->objname, stmt->objargs, stmt->comment); + break; + case OBJECT_LARGEOBJECT: + CommentLargeObject(stmt->objname, stmt->comment); + break; + case OBJECT_CAST: + CommentCast(stmt->objname, stmt->objargs, stmt->comment); + break; default: elog(ERROR, "unrecognized object type: %d", (int) stmt->objtype); @@ -592,7 +613,10 @@ CommentRule(List *qualname, char *comment) PointerGetDatum(rulename), 0, 0); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for rule \"%s\"", rulename); + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("rule \"%s\" for relation \"%s\" does not exist", + rulename, RelationGetRelationName(relation)))); Assert(reloid == ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class); ruleoid = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); @@ -910,3 +934,297 @@ CommentConstraint(List *qualname, char *comment) heap_close(pg_constraint, AccessShareLock); heap_close(relation, NoLock); } + +/* + * CommentConversion -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a CONVERSION. The conversion is specified by name + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + * The conversion's name and the comment are the parameters to this routine. + */ +static void +CommentConversion(List *qualname, char *comment) +{ + Oid conversionOid; + Oid classoid; + + conversionOid = FindConversionByName(qualname); + if (!OidIsValid(conversionOid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("conversion \"%s\" does not exist", + NameListToString(qualname)))); + + /* Check object security */ + if (!pg_conversion_ownercheck(conversionOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION, + NameListToString(qualname)); + + /* pg_conversion doesn't have a hard-coded OID, so must look it up */ + classoid = get_system_catalog_relid(ConversionRelationName); + + /* Call CreateComments() to create/drop the comments */ + CreateComments(conversionOid, classoid, 0, comment); +} + +/* + * CommentLanguage -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a LANGUAGE. The language is specified by name + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + * The language's name and the comment are the parameters to this routine. + */ +static void +CommentLanguage(List *qualname, char *comment) +{ + Oid oid; + Oid classoid; + char *language; + + if (length(qualname) != 1) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("language name may not be qualified"))); + language = strVal(lfirst(qualname)); + + oid = GetSysCacheOid(LANGNAME, + CStringGetDatum(language), + 0, 0, 0); + if (!OidIsValid(oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("language \"%s\" does not exist", language))); + + /* Check object security */ + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to comment on procedural language"))); + + /* pg_language doesn't have a hard-coded OID, so must look it up */ + classoid = get_system_catalog_relid(LanguageRelationName); + + /* Call CreateComments() to create/drop the comments */ + CreateComments(oid, classoid, 0, comment); +} + +/* + * CommentOpClass -- + * + * This routine is used to allow a user to provide comments on an + * operator class. The operator class for commenting is determined by both + * its name and its argument list which defines the index method + * the operator class is used for. The argument list is expected to contain + * a single name (represented as a string Value node). + */ +static void +CommentOpClass(List *qualname, List *arguments, char *comment) +{ + char *amname; + char *schemaname; + char *opcname; + Oid amID; + Oid opcID; + Oid classoid; + HeapTuple tuple; + + Assert(length(arguments) == 1); + amname = strVal(lfirst(arguments)); + + /* + * Get the access method's OID. + */ + amID = GetSysCacheOid(AMNAME, + CStringGetDatum(amname), + 0, 0, 0); + if (!OidIsValid(amID)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("access method \"%s\" does not exist", + amname))); + + /* + * Look up the opclass. + */ + + /* deconstruct the name list */ + DeconstructQualifiedName(qualname, &schemaname, &opcname); + + if (schemaname) + { + /* Look in specific schema only */ + Oid namespaceId; + + namespaceId = LookupExplicitNamespace(schemaname); + tuple = SearchSysCache(CLAAMNAMENSP, + ObjectIdGetDatum(amID), + PointerGetDatum(opcname), + ObjectIdGetDatum(namespaceId), + 0); + } + else + { + /* Unqualified opclass name, so search the search path */ + opcID = OpclassnameGetOpcid(amID, opcname); + if (!OidIsValid(opcID)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator class \"%s\" does not exist for access method \"%s\"", + opcname, amname))); + tuple = SearchSysCache(CLAOID, + ObjectIdGetDatum(opcID), + 0, 0, 0); + } + + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("operator class \"%s\" does not exist for access method \"%s\"", + NameListToString(qualname), amname))); + + opcID = HeapTupleGetOid(tuple); + + /* Permission check: must own opclass */ + if (!pg_opclass_ownercheck(opcID, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS, + NameListToString(qualname)); + + ReleaseSysCache(tuple); + + /* pg_opclass doesn't have a hard-coded OID, so must look it up */ + classoid = get_system_catalog_relid(OperatorClassRelationName); + + /* Call CreateComments() to create/drop the comments */ + CreateComments(opcID, classoid, 0, comment); +} + +/* + * CommentLargeObject -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a LARGE OBJECT. The large object is specified by OID + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + * The large object's OID and the comment are the parameters to this routine. + */ +static void +CommentLargeObject(List *qualname, char *comment) +{ + Oid loid; + Oid classoid; + Node *node; + + Assert(length(qualname) == 1); + node = (Node *) lfirst(qualname); + + switch (nodeTag(node)) + { + case T_Integer: + loid = intVal(node); + break; + case T_Float: + /* + * Values too large for int4 will be represented as Float + * constants by the lexer. Accept these if they are valid + * OID strings. + */ + loid = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(strVal(node)))); + break; + default: + elog(ERROR, "unrecognized node type: %d", + (int) nodeTag(node)); + /* keep compiler quiet */ + loid = InvalidOid; + } + + /* check that the large object exists */ + if (!LargeObjectExists(loid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("large object %u does not exist", loid))); + + /* pg_largeobject doesn't have a hard-coded OID, so must look it up */ + classoid = get_system_catalog_relid(LargeObjectRelationName); + + /* Call CreateComments() to create/drop the comments */ + CreateComments(loid, classoid, 0, comment); +} + +/* + * CommentCast -- + * + * This routine is used to add/drop any user-comments a user might + * have regarding a CAST. The cast is specified by source and destination types + * and, if found, and the user has appropriate permissions, a + * comment will be added/dropped using the CreateComments() routine. + * The cast's source type is passed as the "name", the destination type + * as the "arguments". + */ +static void +CommentCast(List *qualname, List *arguments, char *comment) +{ + TypeName *sourcetype; + TypeName *targettype; + Oid sourcetypeid; + Oid targettypeid; + HeapTuple tuple; + Oid castOid; + Oid classoid; + + Assert(length(qualname) == 1); + sourcetype = (TypeName *) lfirst(qualname); + Assert(IsA(sourcetype, TypeName)); + Assert(length(arguments) == 1); + targettype = (TypeName *) lfirst(arguments); + Assert(IsA(targettype, TypeName)); + + sourcetypeid = typenameTypeId(sourcetype); + if (!OidIsValid(sourcetypeid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("source data type %s does not exist", + TypeNameToString(sourcetype)))); + + targettypeid = typenameTypeId(targettype); + if (!OidIsValid(targettypeid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("target data type %s does not exist", + TypeNameToString(targettype)))); + + tuple = SearchSysCache(CASTSOURCETARGET, + ObjectIdGetDatum(sourcetypeid), + ObjectIdGetDatum(targettypeid), + 0, 0); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("cast from type %s to type %s does not exist", + TypeNameToString(sourcetype), + TypeNameToString(targettype)))); + + /* Get the OID of the cast */ + castOid = HeapTupleGetOid(tuple); + + /* Permission check */ + if (!pg_type_ownercheck(sourcetypeid, GetUserId()) + && !pg_type_ownercheck(targettypeid, GetUserId())) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be owner of type %s or type %s", + TypeNameToString(sourcetype), + TypeNameToString(targettype)))); + + ReleaseSysCache(tuple); + + /* pg_cast doesn't have a hard-coded OID, so must look it up */ + classoid = get_system_catalog_relid(CastRelationName); + + /* Call CreateComments() to create/drop the comments */ + CreateComments(castOid, classoid, 0, comment); +} |