aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/comment.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/comment.c')
-rw-r--r--src/backend/commands/comment.c322
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);
+}