diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index c5d75c4c65..fe14a60426 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13588,10 +13588,10 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33);
- col_description returns the comment for a table column,
- which is specified by the OID of its table and its column number.
- obj_description cannot be used for table columns since
- columns do not have OIDs of their own.
+ col_description returns the comment for a table
+ column, which is specified by the OID of its table and its column number.
+ (obj_description cannot be used for table columns
+ since columns do not have OIDs of their own.)
@@ -13610,8 +13610,8 @@ SELECT typlen FROM pg_type WHERE oid = pg_typeof(33);
shobj_description is used just like
obj_description except it is used for retrieving
comments on shared objects. Some system catalogs are global to all
- databases within each cluster and their descriptions are stored globally
- as well.
+ databases within each cluster, and the descriptions for objects in them
+ are stored globally as well.
diff --git a/doc/src/sgml/ref/comment.sgml b/doc/src/sgml/ref/comment.sgml
index 2610fd5b8d..bc848b3069 100644
--- a/doc/src/sgml/ref/comment.sgml
+++ b/doc/src/sgml/ref/comment.sgml
@@ -65,11 +65,18 @@ COMMENT ON
- To modify a comment, issue a new COMMENT> command for the
- same object. Only one comment string is stored for each object.
- To remove a comment, write NULL in place of the text
- string.
- Comments are automatically dropped when the object is dropped.
+ Only one comment string is stored for each object, so to modify a comment,
+ issue a new COMMENT> command for the same object. To remove a
+ comment, write NULL in place of the text string.
+ Comments are automatically dropped when their object is dropped.
+
+
+
+ For most kinds of object, only the object's owner can set the comment.
+ Roles don't have owners, so the rule for COMMENT ON ROLE> is
+ that you must be superuser to comment on a superuser role, or have the
+ CREATEROLE> privilege to comment on non-superuser roles.
+ Of course, a superuser can comment on anything.
@@ -93,15 +100,15 @@ COMMENT ON
agg_name
constraint_name
function_name
- op
+ operator_name
rule_name
trigger_name
The name of the object to be commented. Names of tables,
- aggregates, domains, foreign tables, functions, indexes, operators,
- operator classes, operator families, sequences, text search objects,
- types, and views can be schema-qualified.
+ aggregates, collations, conversions, domains, foreign tables, functions,
+ indexes, operators, operator classes, operator families, sequences,
+ text search objects, types, and views can be schema-qualified.
@@ -137,7 +144,6 @@ COMMENT ON
argmode
-
The mode of a function argument: IN>, OUT>,
@@ -154,7 +160,6 @@ COMMENT ON
argname
-
The name of a function argument.
@@ -167,7 +172,6 @@ COMMENT ON
argtype
-
The data type(s) of the function's arguments (optionally
@@ -185,9 +189,20 @@ COMMENT ON
+
+ left_type
+ right_type
+
+
+ The data type(s) of the operator's arguments (optionally
+ schema-qualified). Write NONE> for the missing argument
+ of a prefix or postfix operator.
+
+
+
+
PROCEDURAL
-
This is a noise word.
@@ -212,12 +227,11 @@ COMMENT ON
Notes
- There is presently no security mechanism for comments: any user
+ There is presently no security mechanism for viewing comments: any user
connected to a database can see all the comments for objects in
- that database (although only superusers can change comments for
- objects that they don't own). For shared objects such as
- databases, roles, and tablespaces comments are stored globally
- and any user connected to any database can see all the comments
+ that database. For shared objects such as
+ databases, roles, and tablespaces, comments are stored globally so any
+ user connected to any database in the cluster can see all the comments
for shared objects. Therefore, don't put security-critical
information in comments.
@@ -257,7 +271,7 @@ COMMENT ON INDEX my_index IS 'Enforces uniqueness on employee ID';
COMMENT ON LANGUAGE plpython IS 'Python support for stored procedures';
COMMENT ON LARGE OBJECT 346344 IS 'Planning document';
COMMENT ON OPERATOR ^ (text, text) IS 'Performs intersection of two texts';
-COMMENT ON OPERATOR - (NONE, text) IS 'This is a prefix operator on text';
+COMMENT ON OPERATOR - (NONE, integer) IS 'Unary minus';
COMMENT ON OPERATOR CLASS int4ops USING btree IS '4 byte integer operators for btrees';
COMMENT ON OPERATOR FAMILY integer_ops USING btree IS 'all integer operators for btrees';
COMMENT ON ROLE my_role IS 'Administration group for finance tables';
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index a98f918a23..48fa6d48b7 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -4735,6 +4735,36 @@ pg_extension_ownercheck(Oid ext_oid, Oid roleid)
return has_privs_of_role(roleid, ownerId);
}
+/*
+ * Check whether specified role has CREATEROLE privilege (or is a superuser)
+ *
+ * Note: roles do not have owners per se; instead we use this test in
+ * places where an ownership-like permissions test is needed for a role.
+ * Be sure to apply it to the role trying to do the operation, not the
+ * role being operated on! Also note that this generally should not be
+ * considered enough privilege if the target role is a superuser.
+ * (We don't handle that consideration here because we want to give a
+ * separate error message for such cases, so the caller has to deal with it.)
+ */
+bool
+has_createrole_privilege(Oid roleid)
+{
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
+ ReleaseSysCache(utup);
+ }
+ return result;
+}
+
/*
* Fetch pg_default_acl entry for given role, namespace and object type
* (object type must be given in pg_default_acl's encoding).
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index b8b89ab7c1..880b95df02 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -808,13 +808,6 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
NameListToString(objname));
break;
- case OBJECT_ROLE:
- if (!has_privs_of_role(roleid, address.objectId))
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("must be member of role \"%s\"",
- NameListToString(objname))));
- break;
case OBJECT_TSDICTIONARY:
if (!pg_ts_dict_ownercheck(address.objectId, roleid))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
@@ -825,6 +818,26 @@ check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
NameListToString(objname));
break;
+ case OBJECT_ROLE:
+ /*
+ * We treat roles as being "owned" by those with CREATEROLE priv,
+ * except that superusers are only owned by superusers.
+ */
+ if (superuser_arg(address.objectId))
+ {
+ if (!superuser_arg(roleid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser")));
+ }
+ else
+ {
+ if (!has_createrole_privilege(roleid))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must have CREATEROLE privilege")));
+ }
+ break;
case OBJECT_FDW:
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 63f22d8adc..f13eb2891e 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -58,20 +58,7 @@ static void DelRoleMems(const char *rolename, Oid roleid,
static bool
have_createrole_privilege(void)
{
- bool result = false;
- HeapTuple utup;
-
- /* Superusers can always do everything */
- if (superuser())
- return true;
-
- utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
- if (HeapTupleIsValid(utup))
- {
- result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
- ReleaseSysCache(utup);
- }
- return result;
+ return has_createrole_privilege(GetUserId());
}
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index c0f7b64d80..e96323efcc 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -317,5 +317,6 @@ extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid);
extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
+extern bool has_createrole_privilege(Oid roleid);
#endif /* ACL_H */