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.c943
1 files changed, 135 insertions, 808 deletions
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 6653495176c..4a801858b6b 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -7,7 +7,7 @@
* Copyright (c) 1996-2010, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.117 2010/08/05 15:25:35 rhaas Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.118 2010/08/27 11:47:41 rhaas Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,83 +17,30 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "catalog/indexing.h"
-#include "catalog/pg_authid.h"
-#include "catalog/pg_cast.h"
-#include "catalog/pg_constraint.h"
-#include "catalog/pg_conversion.h"
-#include "catalog/pg_database.h"
+#include "catalog/objectaddress.h"
#include "catalog/pg_description.h"
-#include "catalog/pg_language.h"
-#include "catalog/pg_largeobject.h"
-#include "catalog/pg_largeobject_metadata.h"
-#include "catalog/pg_namespace.h"
-#include "catalog/pg_opclass.h"
-#include "catalog/pg_operator.h"
-#include "catalog/pg_opfamily.h"
-#include "catalog/pg_proc.h"
-#include "catalog/pg_rewrite.h"
#include "catalog/pg_shdescription.h"
-#include "catalog/pg_tablespace.h"
-#include "catalog/pg_trigger.h"
-#include "catalog/pg_ts_config.h"
-#include "catalog/pg_ts_dict.h"
-#include "catalog/pg_ts_parser.h"
-#include "catalog/pg_ts_template.h"
-#include "catalog/pg_type.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
-#include "commands/defrem.h"
-#include "commands/proclang.h"
-#include "commands/tablespace.h"
-#include "commands/trigger.h"
#include "libpq/be-fsstubs.h"
#include "miscadmin.h"
-#include "nodes/makefuncs.h"
#include "parser/parse_func.h"
-#include "parser/parse_oper.h"
#include "parser/parse_type.h"
-#include "rewrite/rewriteSupport.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
-#include "utils/lsyscache.h"
#include "utils/rel.h"
-#include "utils/syscache.h"
#include "utils/tqual.h"
-
/*
- * Static Function Prototypes --
- *
- * The following prototypes 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.
+ * For most object types, the permissions-checking logic is simple enough
+ * that it makes sense to just include it in CommentObject(). However, a few
+ * object types require something more complex; for those, we define helper
+ * functions.
*/
-
-static void CommentRelation(int objtype, List *relname, char *comment);
-static void CommentAttribute(List *qualname, char *comment);
-static void CommentDatabase(List *qualname, char *comment);
-static void CommentNamespace(List *qualname, char *comment);
-static void CommentRule(List *qualname, char *comment);
-static void CommentType(List *typename, char *comment);
-static void CommentAggregate(List *aggregate, List *arguments, char *comment);
-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 CommentOpFamily(List *qualname, List *arguments, char *comment);
-static void CommentLargeObject(List *qualname, char *comment);
-static void CommentCast(List *qualname, List *arguments, char *comment);
-static void CommentTablespace(List *qualname, char *comment);
-static void CommentRole(List *qualname, char *comment);
-static void CommentTSParser(List *qualname, char *comment);
-static void CommentTSDictionary(List *qualname, char *comment);
-static void CommentTSTemplate(List *qualname, char *comment);
-static void CommentTSConfiguration(List *qualname, char *comment);
+static void CheckRelationComment(int objtype, Relation relation);
+static void CheckAttributeComment(Relation relation);
+static void CheckCastComment(List *qualname, List *arguments);
/*
@@ -105,84 +52,175 @@ static void CommentTSConfiguration(List *qualname, char *comment);
void
CommentObject(CommentStmt *stmt)
{
+ ObjectAddress address;
+ Relation relation;
+
+ /*
+ * When loading a dump, we may see a COMMENT ON DATABASE for the old name
+ * of the database. Erroring out would prevent pg_restore from completing
+ * (which is really pg_restore's fault, but for now we will work around
+ * the problem here). Consensus is that the best fix is to treat wrong
+ * database name as a WARNING not an ERROR; hence, the following special
+ * case. (If the length of stmt->objname is not 1, get_object_address will
+ * throw an error below; that's OK.)
+ */
+ if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1)
+ {
+ char *database = strVal(linitial(stmt->objname));
+ if (!OidIsValid(get_database_oid(database, true)))
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_UNDEFINED_DATABASE),
+ errmsg("database \"%s\" does not exist", database)));
+ return;
+ }
+ }
+
+ /*
+ * Translate the parser representation which identifies this object into
+ * an ObjectAddress. get_object_address() will throw an error if the
+ * object does not exist, and will also acquire a lock on the target
+ * to guard against concurrent DROP operations.
+ */
+ address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
+ &relation, ShareUpdateExclusiveLock);
+
+ /* Privilege and integrity checks. */
switch (stmt->objtype)
{
case OBJECT_INDEX:
case OBJECT_SEQUENCE:
case OBJECT_TABLE:
case OBJECT_VIEW:
- CommentRelation(stmt->objtype, stmt->objname, stmt->comment);
+ CheckRelationComment(stmt->objtype, relation);
break;
case OBJECT_COLUMN:
- CommentAttribute(stmt->objname, stmt->comment);
+ CheckAttributeComment(relation);
break;
case OBJECT_DATABASE:
- CommentDatabase(stmt->objname, stmt->comment);
- break;
- case OBJECT_RULE:
- CommentRule(stmt->objname, stmt->comment);
+ if (!pg_database_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ strVal(linitial(stmt->objname)));
break;
case OBJECT_TYPE:
- CommentType(stmt->objname, stmt->comment);
+ if (!pg_type_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+ format_type_be(address.objectId));
break;
case OBJECT_AGGREGATE:
- CommentAggregate(stmt->objname, stmt->objargs, stmt->comment);
- break;
case OBJECT_FUNCTION:
- CommentProc(stmt->objname, stmt->objargs, stmt->comment);
+ if (!pg_proc_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+ NameListToString(stmt->objname));
break;
case OBJECT_OPERATOR:
- CommentOperator(stmt->objname, stmt->objargs, stmt->comment);
+ if (!pg_oper_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+ NameListToString(stmt->objname));
break;
+ case OBJECT_RULE:
case OBJECT_TRIGGER:
- CommentTrigger(stmt->objname, stmt->comment);
+ case OBJECT_CONSTRAINT:
+ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+ RelationGetRelationName(relation));
break;
case OBJECT_SCHEMA:
- CommentNamespace(stmt->objname, stmt->comment);
- break;
- case OBJECT_CONSTRAINT:
- CommentConstraint(stmt->objname, stmt->comment);
+ if (!pg_namespace_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ strVal(linitial(stmt->objname)));
break;
case OBJECT_CONVERSION:
- CommentConversion(stmt->objname, stmt->comment);
+ if (!pg_conversion_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+ NameListToString(stmt->objname));
break;
case OBJECT_LANGUAGE:
- CommentLanguage(stmt->objname, stmt->comment);
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to comment on procedural language")));
break;
case OBJECT_OPCLASS:
- CommentOpClass(stmt->objname, stmt->objargs, stmt->comment);
+ if (!pg_opclass_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+ NameListToString(stmt->objname));
break;
case OBJECT_OPFAMILY:
- CommentOpFamily(stmt->objname, stmt->objargs, stmt->comment);
+ if (!pg_opfamily_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
+ NameListToString(stmt->objname));
break;
case OBJECT_LARGEOBJECT:
- CommentLargeObject(stmt->objname, stmt->comment);
+ if (!lo_compat_privileges &&
+ !pg_largeobject_ownercheck(address.objectId, GetUserId()))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be owner of large object %u",
+ address.objectId)));
break;
case OBJECT_CAST:
- CommentCast(stmt->objname, stmt->objargs, stmt->comment);
+ CheckCastComment(stmt->objname, stmt->objargs);
break;
case OBJECT_TABLESPACE:
- CommentTablespace(stmt->objname, stmt->comment);
+ if (!pg_tablespace_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
+ strVal(linitial(stmt->objname)));
break;
case OBJECT_ROLE:
- CommentRole(stmt->objname, stmt->comment);
+ if (!has_privs_of_role(GetUserId(), address.objectId))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be member of role \"%s\" to comment upon it",
+ strVal(linitial(stmt->objname)))));
break;
case OBJECT_TSPARSER:
- CommentTSParser(stmt->objname, stmt->comment);
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to comment on text search parser")));
break;
case OBJECT_TSDICTIONARY:
- CommentTSDictionary(stmt->objname, stmt->comment);
+ if (!pg_ts_dict_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
+ NameListToString(stmt->objname));
break;
case OBJECT_TSTEMPLATE:
- CommentTSTemplate(stmt->objname, stmt->comment);
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to comment on text search template")));
break;
case OBJECT_TSCONFIGURATION:
- CommentTSConfiguration(stmt->objname, stmt->comment);
+ if (!pg_ts_config_ownercheck(address.objectId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
+ NameListToString(stmt->objname));
break;
default:
elog(ERROR, "unrecognized object type: %d",
(int) stmt->objtype);
}
+
+ /*
+ * Databases, tablespaces, and roles are cluster-wide objects, so any
+ * comments on those objects are recorded in the shared pg_shdescription
+ * catalog. Comments on all other objects are recorded in pg_description.
+ */
+ if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE
+ || stmt->objtype == OBJECT_ROLE)
+ CreateSharedComments(address.objectId, address.classId, stmt->comment);
+ else
+ CreateComments(address.objectId, address.classId, address.objectSubId,
+ stmt->comment);
+
+ /*
+ * If get_object_address() opened the relation for us, we close it to keep
+ * the reference count correct - but we retain any locks acquired by
+ * get_object_address() until commit time, to guard against concurrent
+ * activity.
+ */
+ if (relation != NULL)
+ relation_close(relation, NoLock);
}
/*
@@ -524,36 +562,17 @@ GetComment(Oid oid, Oid classoid, int32 subid)
}
/*
- * 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.
+ * Check whether the user is allowed to comment on this relation.
*/
static void
-CommentRelation(int objtype, List *relname, char *comment)
+CheckRelationComment(int objtype, Relation relation)
{
- Relation relation;
- RangeVar *tgtrel;
-
- tgtrel = makeRangeVarFromNameList(relname);
-
- /*
- * Open the relation. We do this mainly to acquire a lock that ensures no
- * one else drops the relation before we commit. (If they did, they'd
- * fail to remove the entry we are about to make in pg_description.)
- */
- relation = relation_openrv(tgtrel, AccessShareLock);
-
/* Check object security */
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(relation));
/* Next, verify that the relation type matches the intent */
-
switch (objtype)
{
case OBJECT_INDEX:
@@ -585,48 +604,15 @@ CommentRelation(int objtype, List *relname, char *comment)
RelationGetRelationName(relation))));
break;
}
-
- /* Create the comment using the relation's oid */
- CreateComments(RelationGetRelid(relation), RelationRelationId,
- 0, comment);
-
- /* Done, but hold lock until commit */
- relation_close(relation, NoLock);
}
/*
- * 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 look up the specified
- * attribute. If successful, a comment is added/dropped, else an
- * ereport() exception is thrown. The parameters are the relation
- * and attribute names, and the comment
+ * Check whether the user is allowed to comment on an attribute of the
+ * specified relation.
*/
static void
-CommentAttribute(List *qualname, char *comment)
+CheckAttributeComment(Relation relation)
{
- int nnames;
- List *relname;
- char *attrname;
- RangeVar *rel;
- Relation relation;
- AttrNumber attnum;
-
- /* Separate relname and attr name */
- nnames = list_length(qualname);
- if (nnames < 2) /* parser messed up */
- elog(ERROR, "must specify relation and attribute");
- relname = list_truncate(list_copy(qualname), nnames - 1);
- attrname = strVal(lfirst(list_tail(qualname)));
-
- /* Open the containing relation to ensure it won't go away meanwhile */
- rel = makeRangeVarFromNameList(relname);
- relation = relation_openrv(rel, AccessShareLock);
-
- /* Check object security */
-
if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(relation));
@@ -645,613 +631,18 @@ CommentAttribute(List *qualname, char *comment)
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a table, view, or composite type",
RelationGetRelationName(relation))));
-
- /* Now, fetch the attribute number from the system cache */
-
- attnum = get_attnum(RelationGetRelid(relation), attrname);
- if (attnum == InvalidAttrNumber)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" of relation \"%s\" does not exist",
- attrname, RelationGetRelationName(relation))));
-
- /* Create the comment using the relation's oid */
- CreateComments(RelationGetRelid(relation), RelationRelationId,
- (int32) attnum, comment);
-
- /* Done, but hold lock until commit */
-
- relation_close(relation, NoLock);
-}
-
-/*
- * 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 successful, will then
- * attempt to find the oid of the database specified. Once found,
- * a comment is added/dropped using the CreateSharedComments() routine.
- */
-static void
-CommentDatabase(List *qualname, char *comment)
-{
- char *database;
- Oid oid;
-
- if (list_length(qualname) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("database name cannot be qualified")));
- database = strVal(linitial(qualname));
-
- /*
- * When loading a dump, we may see a COMMENT ON DATABASE for the old name
- * of the database. Erroring out would prevent pg_restore from completing
- * (which is really pg_restore's fault, but for now we will work around
- * the problem here). Consensus is that the best fix is to treat wrong
- * database name as a WARNING not an ERROR (thus, we tell get_database_oid
- * to ignore the error so that we can handle it differently here).
- */
- oid = get_database_oid(database, true);
- if (!OidIsValid(oid))
- {
- ereport(WARNING,
- (errcode(ERRCODE_UNDEFINED_DATABASE),
- errmsg("database \"%s\" does not exist", database)));
- return;
- }
-
- /* Check object security */
- if (!pg_database_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- database);
-
- /* Call CreateSharedComments() to create/drop the comments */
- CreateSharedComments(oid, DatabaseRelationId, comment);
}
/*
- * CommentTablespace --
- *
- * This routine is used to add/drop any user-comments a user might
- * have regarding a tablespace. The tablepace is specified by name
- * and, if found, and the user has appropriate permissions, a
- * comment will be added/dropped using the CreateSharedComments() routine.
- *
+ * Check whether the user is allowed to comment on the specified cast.
*/
static void
-CommentTablespace(List *qualname, char *comment)
-{
- char *tablespace;
- Oid oid;
-
- if (list_length(qualname) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("tablespace name cannot be qualified")));
- tablespace = strVal(linitial(qualname));
-
- oid = get_tablespace_oid(tablespace, false);
-
- /* Check object security */
- if (!pg_tablespace_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, tablespace);
-
- /* Call CreateSharedComments() to create/drop the comments */
- CreateSharedComments(oid, TableSpaceRelationId, comment);
-}
-
-/*
- * CommentRole --
- *
- * This routine is used to add/drop any user-comments a user might
- * have regarding a role. The role is specified by name
- * and, if found, and the user has appropriate permissions, a
- * comment will be added/dropped using the CreateSharedComments() routine.
- */
-static void
-CommentRole(List *qualname, char *comment)
-{
- char *role;
- Oid oid;
-
- if (list_length(qualname) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("role name cannot be qualified")));
- role = strVal(linitial(qualname));
-
- oid = get_role_oid(role, false);
-
- /* Check object security */
- if (!has_privs_of_role(GetUserId(), oid))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be member of role \"%s\" to comment upon it", role)));
-
- /* Call CreateSharedComments() to create/drop the comments */
- CreateSharedComments(oid, AuthIdRelationId, comment);
-}
-
-/*
- * CommentNamespace --
- *
- * This routine is used to add/drop any user-comments a user might
- * have regarding the specified namespace. The routine will check
- * security for owner permissions, and, if successful, will then
- * attempt to find the oid of the namespace specified. Once found,
- * a comment is added/dropped using the CreateComments() routine.
- */
-static void
-CommentNamespace(List *qualname, char *comment)
-{
- Oid oid;
- char *namespace;
-
- if (list_length(qualname) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("schema name cannot be qualified")));
- namespace = strVal(linitial(qualname));
-
- oid = get_namespace_oid(namespace, false);
-
- /* Check object security */
- if (!pg_namespace_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
- namespace);
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, NamespaceRelationId, 0, comment);
-}
-
-/*
- * CommentRule --
- *
- * This routine is used to add/drop any user-comments a user might
- * have regarding a specified RULE. The rule for commenting is determined by
- * both its name and the relation to which it refers. The arguments to this
- * function are the rule name and relation name (merged into a qualified
- * name), and the comment to add/drop.
- *
- * Before PG 7.3, rules had unique names across the whole database, and so
- * the syntax was just COMMENT ON RULE rulename, with no relation name.
- * For purposes of backwards compatibility, we support that as long as there
- * is only one rule by the specified name in the database.
- */
-static void
-CommentRule(List *qualname, char *comment)
-{
- int nnames;
- List *relname;
- char *rulename;
- RangeVar *rel;
- Relation relation;
- Oid reloid;
- Oid ruleoid;
-
- /* Separate relname and trig name */
- nnames = list_length(qualname);
- if (nnames == 1)
- {
- rulename = strVal(linitial(qualname));
- ruleoid = get_rewrite_oid_without_relid(rulename, &reloid);
-
- /* Open the owning relation to ensure it won't go away meanwhile */
- relation = heap_open(reloid, AccessShareLock);
- }
- else
- {
- /* New-style: rule and relname both provided */
- Assert(nnames >= 2);
- relname = list_truncate(list_copy(qualname), nnames - 1);
- rulename = strVal(lfirst(list_tail(qualname)));
-
- /* Open the owning relation to ensure it won't go away meanwhile */
- rel = makeRangeVarFromNameList(relname);
- relation = heap_openrv(rel, AccessShareLock);
- reloid = RelationGetRelid(relation);
-
- /* Find the rule's pg_rewrite tuple, get its OID */
- ruleoid = get_rewrite_oid(reloid, rulename, false);
- }
-
- /* Check object security */
- if (!pg_class_ownercheck(reloid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
- get_rel_name(reloid));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(ruleoid, RewriteRelationId, 0, comment);
-
- heap_close(relation, NoLock);
-}
-
-/*
- * 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 parameters to this routine.
- */
-static void
-CommentType(List *typename, char *comment)
-{
- TypeName *tname;
- Oid oid;
-
- /* XXX a bit of a crock; should accept TypeName in COMMENT syntax */
- tname = makeTypeNameFromNameList(typename);
-
- /* Find the type's oid */
-
- oid = typenameTypeId(NULL, tname, NULL);
-
- /* Check object security */
-
- if (!pg_type_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
- format_type_be(oid));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, TypeRelationId, 0, 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(s).
- */
-static void
-CommentAggregate(List *aggregate, List *arguments, char *comment)
-{
- Oid oid;
-
- /* Look up function and make sure it's an aggregate */
- oid = LookupAggNameTypeNames(aggregate, arguments, false);
-
- /* Next, validate the user's attempt to comment */
- if (!pg_proc_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
- NameListToString(aggregate));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, ProcedureRelationId, 0, 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.
- */
-static void
-CommentProc(List *function, List *arguments, char *comment)
-{
- Oid oid;
-
- /* Look up the procedure */
-
- oid = LookupFuncNameTypeNames(function, arguments, false);
-
- /* Now, validate the user's ability to comment on this function */
-
- if (!pg_proc_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
- NameListToString(function));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, ProcedureRelationId, 0, 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.
- */
-static void
-CommentOperator(List *opername, List *arguments, char *comment)
-{
- TypeName *typenode1 = (TypeName *) linitial(arguments);
- TypeName *typenode2 = (TypeName *) lsecond(arguments);
- Oid oid;
-
- /* Look up the operator */
- oid = LookupOperNameTypeNames(NULL, opername,
- typenode1, typenode2,
- false, -1);
-
- /* Check user's privilege to comment on this operator */
- if (!pg_oper_ownercheck(oid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
- NameListToString(opername));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, OperatorRelationId, 0, 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 and relation name (merged into a qualified
- * name), and the comment to add/drop.
- */
-static void
-CommentTrigger(List *qualname, char *comment)
-{
- int nnames;
- List *relname;
- char *trigname;
- RangeVar *rel;
- Relation relation;
- Oid oid;
-
- /* Separate relname and trig name */
- nnames = list_length(qualname);
- if (nnames < 2) /* parser messed up */
- elog(ERROR, "must specify relation and trigger");
- relname = list_truncate(list_copy(qualname), nnames - 1);
- trigname = strVal(lfirst(list_tail(qualname)));
-
- /* Open the owning relation to ensure it won't go away meanwhile */
- rel = makeRangeVarFromNameList(relname);
- relation = heap_openrv(rel, AccessShareLock);
-
- /* Check object security */
- if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
- RelationGetRelationName(relation));
-
- oid = get_trigger_oid(RelationGetRelid(relation), trigname, false);
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, TriggerRelationId, 0, comment);
-
- /* Done, but hold lock on relation */
- heap_close(relation, NoLock);
-}
-
-
-/*
- * CommentConstraint --
- *
- * Enable commenting on constraints held within the pg_constraint
- * table. A qualified name is required as constraint names are
- * unique per relation.
- */
-static void
-CommentConstraint(List *qualname, char *comment)
-{
- int nnames;
- List *relName;
- char *conName;
- RangeVar *rel;
- Relation relation;
- Oid conOid;
-
- /* Separate relname and constraint name */
- nnames = list_length(qualname);
- if (nnames < 2) /* parser messed up */
- elog(ERROR, "must specify relation and constraint");
- relName = list_truncate(list_copy(qualname), nnames - 1);
- conName = strVal(lfirst(list_tail(qualname)));
-
- /* Open the owning relation to ensure it won't go away meanwhile */
- rel = makeRangeVarFromNameList(relName);
- relation = heap_openrv(rel, AccessShareLock);
-
- /* Check object security */
-
- if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
- RelationGetRelationName(relation));
-
- conOid = get_constraint_oid(RelationGetRelid(relation), conName, false);
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(conOid, ConstraintRelationId, 0, comment);
-
- /* Done, but hold lock on relation */
- 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;
-
- conversionOid = get_conversion_oid(qualname, false);
-
- /* Check object security */
- if (!pg_conversion_ownercheck(conversionOid, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
- NameListToString(qualname));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(conversionOid, ConversionRelationId, 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;
- char *language;
-
- if (list_length(qualname) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("language name cannot be qualified")));
- language = strVal(linitial(qualname));
-
- oid = get_language_oid(language, false);
-
- /* Check object security */
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to comment on procedural language")));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(oid, LanguageRelationId, 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;
- Oid amID;
- Oid opcID;
-
- Assert(list_length(arguments) == 1);
- amname = strVal(linitial(arguments));
-
- /*
- * Get the operator class OID.
- */
- amID = get_am_oid(amname, false);
- opcID = get_opclass_oid(amID, qualname, false);
-
- /* Permission check: must own opclass */
- if (!pg_opclass_ownercheck(opcID, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
- NameListToString(qualname));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(opcID, OperatorClassRelationId, 0, comment);
-}
-
-/*
- * CommentOpFamily --
- *
- * This routine is used to allow a user to provide comments on an
- * operator family. The operator family for commenting is determined by both
- * its name and its argument list which defines the index method
- * the operator family is used for. The argument list is expected to contain
- * a single name (represented as a string Value node).
- */
-static void
-CommentOpFamily(List *qualname, List *arguments, char *comment)
-{
- char *amname;
- Oid amID;
- Oid opfID;
-
- Assert(list_length(arguments) == 1);
- amname = strVal(linitial(arguments));
-
- /* Get the opfamily OID. */
- amID = get_am_oid(amname, false);
- opfID = get_opfamily_oid(amID, qualname, false);
-
- /* Permission check: must own opfamily */
- if (!pg_opfamily_ownercheck(opfID, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
- NameListToString(qualname));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(opfID, OperatorFamilyRelationId, 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;
-
- Assert(list_length(qualname) == 1);
- loid = oidparse((Node *) linitial(qualname));
-
- /* check that the large object exists */
- if (!LargeObjectExists(loid))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("large object %u does not exist", loid)));
-
- /* Permission checks */
- if (!lo_compat_privileges &&
- !pg_largeobject_ownercheck(loid, GetUserId()))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be owner of large object %u", loid)));
-
- /*
- * Call CreateComments() to create/drop the comments
- *
- * See the comment in the inv_create() which describes the reason why
- * LargeObjectRelationId is used instead of LargeObjectMetadataRelationId.
- */
- CreateComments(loid, LargeObjectRelationId, 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)
+CheckCastComment(List *qualname, List *arguments)
{
TypeName *sourcetype;
TypeName *targettype;
Oid sourcetypeid;
Oid targettypeid;
- Oid castOid;
Assert(list_length(qualname) == 1);
sourcetype = (TypeName *) linitial(qualname);
@@ -1263,9 +654,6 @@ CommentCast(List *qualname, List *arguments, char *comment)
sourcetypeid = typenameTypeId(NULL, sourcetype, NULL);
targettypeid = typenameTypeId(NULL, targettype, NULL);
- /* Get the OID of the cast */
- castOid = get_cast_oid(sourcetypeid, targettypeid, false);
-
/* Permission check */
if (!pg_type_ownercheck(sourcetypeid, GetUserId())
&& !pg_type_ownercheck(targettypeid, GetUserId()))
@@ -1274,65 +662,4 @@ CommentCast(List *qualname, List *arguments, char *comment)
errmsg("must be owner of type %s or type %s",
format_type_be(sourcetypeid),
format_type_be(targettypeid))));
-
- /* Call CreateComments() to create/drop the comments */
- CreateComments(castOid, CastRelationId, 0, comment);
-}
-
-static void
-CommentTSParser(List *qualname, char *comment)
-{
- Oid prsId;
-
- prsId = get_ts_parser_oid(qualname, false);
-
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to comment on text search parser")));
-
- CreateComments(prsId, TSParserRelationId, 0, comment);
-}
-
-static void
-CommentTSDictionary(List *qualname, char *comment)
-{
- Oid dictId;
-
- dictId = get_ts_dict_oid(qualname, false);
-
- if (!pg_ts_dict_ownercheck(dictId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
- NameListToString(qualname));
-
- CreateComments(dictId, TSDictionaryRelationId, 0, comment);
-}
-
-static void
-CommentTSTemplate(List *qualname, char *comment)
-{
- Oid tmplId;
-
- tmplId = get_ts_template_oid(qualname, false);
-
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be superuser to comment on text search template")));
-
- CreateComments(tmplId, TSTemplateRelationId, 0, comment);
-}
-
-static void
-CommentTSConfiguration(List *qualname, char *comment)
-{
- Oid cfgId;
-
- cfgId = get_ts_config_oid(qualname, false);
-
- if (!pg_ts_config_ownercheck(cfgId, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
- NameListToString(qualname));
-
- CreateComments(cfgId, TSConfigRelationId, 0, comment);
}