1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-06 13:46:51 +03:00

Allow CURRENT/SESSION_USER to be used in certain commands

Commands such as ALTER USER, ALTER GROUP, ALTER ROLE, GRANT, and the
various ALTER OBJECT / OWNER TO, as well as ad-hoc clauses related to
roles such as the AUTHORIZATION clause of CREATE SCHEMA, the FOR clause
of CREATE USER MAPPING, and the FOR ROLE clause of ALTER DEFAULT
PRIVILEGES can now take the keywords CURRENT_USER and SESSION_USER as
user specifiers in place of an explicit user name.

This commit also fixes some quite ugly handling of special standards-
mandated syntax in CREATE USER MAPPING, which in particular would fail
to work in presence of a role named "current_user".

The special role specifiers PUBLIC and NONE also have more consistent
handling now.

Also take the opportunity to add location tracking to user specifiers.

Authors: Kyotaro Horiguchi.  Heavily reworked by Álvaro Herrera.
Reviewed by: Rushabh Lathia, Adam Brightwell, Marti Raudsepp.
This commit is contained in:
Alvaro Herrera
2015-03-09 15:41:54 -03:00
parent fa83f80945
commit 31eae6028e
52 changed files with 2000 additions and 347 deletions

View File

@@ -5105,7 +5105,7 @@ select_best_grantor(Oid roleId, AclMode privileges,
/*
* get_role_oid - Given a role name, look up the role's OID.
*
* If missing_ok is false, throw an error if tablespace name not found. If
* If missing_ok is false, throw an error if role name not found. If
* true, just return InvalidOid.
*/
Oid
@@ -5133,3 +5133,117 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
/*
* Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
* true, return InvalidOid if the role does not exist.
*
* PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
* case must check the case separately.
*/
Oid
get_rolespec_oid(const Node *node, bool missing_ok)
{
RoleSpec *role;
Oid oid;
if (!IsA(node, RoleSpec))
elog(ERROR, "invalid node type %d", node->type);
role = (RoleSpec *) node;
switch (role->roletype)
{
case ROLESPEC_CSTRING:
Assert(role->rolename);
oid = get_role_oid(role->rolename, missing_ok);
break;
case ROLESPEC_CURRENT_USER:
oid = GetUserId();
break;
case ROLESPEC_SESSION_USER:
oid = GetSessionUserId();
break;
case ROLESPEC_PUBLIC:
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", "public")));
oid = InvalidOid; /* make compiler happy */
break;
default:
elog(ERROR, "unexpected role type %d", role->roletype);
}
return oid;
}
/*
* Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
* Caller must ReleaseSysCache when done with the result tuple.
*/
HeapTuple
get_rolespec_tuple(const Node *node)
{
RoleSpec *role;
HeapTuple tuple;
role = (RoleSpec *) node;
if (!IsA(node, RoleSpec))
elog(ERROR, "invalid node type %d", node->type);
switch (role->roletype)
{
case ROLESPEC_CSTRING:
Assert(role->rolename);
tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", role->rolename)));
break;
case ROLESPEC_CURRENT_USER:
tuple = SearchSysCache1(AUTHOID, GetUserId());
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for role %u", GetUserId());
break;
case ROLESPEC_SESSION_USER:
tuple = SearchSysCache1(AUTHOID, GetSessionUserId());
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
break;
case ROLESPEC_PUBLIC:
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("role \"%s\" does not exist", "public")));
tuple = NULL; /* make compiler happy */
default:
elog(ERROR, "unexpected role type %d", role->roletype);
}
return tuple;
}
/*
* Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
*/
char *
get_rolespec_name(const Node *node)
{
HeapTuple tp;
Form_pg_authid authForm;
char *rolename;
tp = get_rolespec_tuple(node);
authForm = (Form_pg_authid) GETSTRUCT(tp);
rolename = pstrdup(NameStr(authForm->rolname));
ReleaseSysCache(tp);
return rolename;
}