diff options
Diffstat (limited to 'src/backend/commands/comment.c')
-rw-r--r-- | src/backend/commands/comment.c | 943 |
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); } |