alter user/role CURRENT_USER
Hello, on the way considering alter role set .., I found that
ALTER ROLE/USER cannot take CURRENT_USER as the role name.
In addition to that, documents of ALTER ROLE / USER are
inconsistent with each other in spite of ALTER USER is said to be
an alias for ALTER ROLE. Plus, ALTER USER cannot take ALL as user
name although ALTER ROLE can.
This patch does following things,
- ALTER USER/ROLE now takes CURRENT_USER as user name.
- Rewrite sysnopsis of the documents for ALTER USER and ALTER
ROLE so as to they have exactly same syntax.
- Modify syntax of ALTER USER so as to be an alias of ALTER ROLE.
- Added CURRENT_USER/CURRENT_ROLE syntax to both.
- Added ALL syntax as user name to ALTER USER.
- Added IN DATABASE syntax to ALTER USER.
x Integrating ALTER ROLE/USER syntax could not be done because of
shift/reduce error of bison.
x This patch contains no additional regressions. Is it needed?
SESSION_USER/USER also can be made usable for this command, but
this patch doesn't so (yet).
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0002-ALTER-ROLE-CURRENT_USER-document.patchtext/x-patch; charset=us-asciiDownload
>From d12f479de845f55f77096e79fea69930bd665416 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Tue, 9 Sep 2014 19:26:33 +0900
Subject: [PATCH 2/2] ALTER ROLE CURRENT_USER document
---
doc/src/sgml/ref/alter_role.sgml | 15 ++++++++-------
doc/src/sgml/ref/alter_user.sgml | 13 +++++++------
2 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml
index 0471daa..e6f8093 100644
--- a/doc/src/sgml/ref/alter_role.sgml
+++ b/doc/src/sgml/ref/alter_role.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
+ALTER ROLE { <replaceable class="parameter">name</replaceable> | CURRENT_USER } [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase>
@@ -37,12 +37,12 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replace
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ALTER ROLE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="parameter">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
</synopsis>
</refsynopsisdiv>
@@ -123,7 +123,8 @@ ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATA
<term><replaceable class="PARAMETER">name</replaceable></term>
<listitem>
<para>
- The name of the role whose attributes are to be altered.
+ The name of the role whose attributes are to be
+ altered. <literal>CURRENT_USER</> matches the name of the current user.
</para>
</listitem>
</varlistentry>
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 58ae1da..feb1197 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
+ALTER USER { <replaceable class="parameter">name</replaceable> | CURRENT_USER } [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase>
@@ -32,16 +32,17 @@ ALTER USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replace
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
+ | BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT <replaceable class="PARAMETER">connlimit</replaceable>
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD '<replaceable class="PARAMETER">password</replaceable>'
| VALID UNTIL '<replaceable class="PARAMETER">timestamp</replaceable>'
-ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ALTER USER <replaceable class="parameter">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET ALL
+ALTER USER { <replaceable class="parameter">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="parameter">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="parameter">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="parameter">name</replaceable> | CURRENT_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
</synopsis>
</refsynopsisdiv>
--
1.7.1
0001-ALTER-ROLE-CURRENT_USER.patchtext/x-patch; charset=us-asciiDownload
>From 9be0ca6f7961ccadf665867c52233079a1024737 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Tue, 9 Sep 2014 19:26:24 +0900
Subject: [PATCH 1/2] ALTER ROLE CURRENT_USER
---
src/backend/commands/user.c | 48 ++++++++++++++++++++++++++++++++----------
src/backend/parser/gram.y | 27 +++++++++++++++++------
2 files changed, 56 insertions(+), 19 deletions(-)
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..8630323 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -649,13 +649,25 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ if (strcmp(stmt->role, "current_user") == 0)
+ {
+ roleid = GetUserId();
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", roleid)));
+ }
+ else
+ {
+ tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role)));
- roleid = HeapTupleGetOid(tuple);
+ roleid = HeapTupleGetOid(tuple);
+ }
/*
* To mess with a superuser you gotta be superuser; else you need
@@ -870,14 +882,26 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ if (strcmp(stmt->role, "current_user") == 0)
+ {
+ roleid = GetUserId();
+ roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(roletuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", roleid)));
+ }
+ else
+ {
+ roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ if (!HeapTupleIsValid(roletuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role)));
- roleid = HeapTupleGetOid(roletuple);
+ roleid = HeapTupleGetOid(roletuple);
+ }
/*
* Obtain a lock on the role and make sure it didn't go away in the
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c98c27a..f007aea 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -474,7 +474,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId RoleId_or_curruser
+%type <str> opt_granted_by opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -1036,7 +1037,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1052,7 +1053,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleId_or_curruser opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1078,7 +1079,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1090,12 +1091,20 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleId_or_curruser opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = NULL;
- n->setstmt = $4;
+ n->database = $4;
+ n->setstmt = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER USER ALL opt_in_database SetResetClause
+ {
+ AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+ n->role = NULL;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
}
;
@@ -12958,6 +12967,10 @@ Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
RoleId: NonReservedWord { $$ = $1; };
+RoleId_or_curruser: RoleId { $$ = $1; }
+ | CURRENT_USER { $$ = "current_user"; };
+ | CURRENT_ROLE { $$ = "current_user"; };
+
role_list: RoleId
{ $$ = list_make1(makeString($1)); }
| role_list ',' RoleId
--
1.7.1
I gone through patch and here is the review for this patch:
.) patch go applied on master branch with patch -p1 command
(git apply failed)
.) regression make check run fine
.) testcase coverage is missing in the patch
.) Over all coding/patch looks good.
Few comments:
1) Any particular reason for not adding SESSION_USER/USER also made usable
for this command ?
2) I think RoleId_or_curruser can be used for following role:
/* ALTER TABLE <name> OWNER TO RoleId */
| OWNER TO RoleId
3) In the documentation patch, added for CURRENT_USER but CURRENT_ROLE is
missing.
On Fri, Oct 10, 2014 at 1:57 PM, Kyotaro HORIGUCHI <
horiguchi.kyotaro@lab.ntt.co.jp> wrote:
Hello, on the way considering alter role set .., I found that
ALTER ROLE/USER cannot take CURRENT_USER as the role name.In addition to that, documents of ALTER ROLE / USER are
inconsistent with each other in spite of ALTER USER is said to be
an alias for ALTER ROLE. Plus, ALTER USER cannot take ALL as user
name although ALTER ROLE can.This patch does following things,
- ALTER USER/ROLE now takes CURRENT_USER as user name.
- Rewrite sysnopsis of the documents for ALTER USER and ALTER
ROLE so as to they have exactly same syntax.- Modify syntax of ALTER USER so as to be an alias of ALTER ROLE.
- Added CURRENT_USER/CURRENT_ROLE syntax to both.
- Added ALL syntax as user name to ALTER USER.
- Added IN DATABASE syntax to ALTER USER.x Integrating ALTER ROLE/USER syntax could not be done because of
shift/reduce error of bison.x This patch contains no additional regressions. Is it needed?
SESSION_USER/USER also can be made usable for this command, but
this patch doesn't so (yet).regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
--
Rushabh Lathia
Kyotaro,
Food for thought. Couldn't you reduce the following block:
+ if (strcmp(stmt->role, "current_user") == 0)
+ {
+ roleid = GetUserId();
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", roleid)));
+ }
+ else
+ {
+ tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role)));
To:
if (strcmp(stmt->role, "current_user") == 0)
roleid = GetUserId();
else
roleid = get_role_oid(stmt->role, false);
tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("roleid %d does not exist", roleid)));
I think this makes it a bit cleaner. It also reuses existing code as
'get_role_oid()' already does a valid role name check and will raise the
proper error.
-Adam
On Mon, Oct 20, 2014 at 3:40 AM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:
I gone through patch and here is the review for this patch:
.) patch go applied on master branch with patch -p1 command
(git apply failed)
.) regression make check run fine
.) testcase coverage is missing in the patch
.) Over all coding/patch looks good.Few comments:
1) Any particular reason for not adding SESSION_USER/USER also made usable
for this command ?2) I think RoleId_or_curruser can be used for following role:
/* ALTER TABLE <name> OWNER TO RoleId */
| OWNER TO RoleId3) In the documentation patch, added for CURRENT_USER but CURRENT_ROLE is
missing.On Fri, Oct 10, 2014 at 1:57 PM, Kyotaro HORIGUCHI <
horiguchi.kyotaro@lab.ntt.co.jp> wrote:Hello, on the way considering alter role set .., I found that
ALTER ROLE/USER cannot take CURRENT_USER as the role name.In addition to that, documents of ALTER ROLE / USER are
inconsistent with each other in spite of ALTER USER is said to be
an alias for ALTER ROLE. Plus, ALTER USER cannot take ALL as user
name although ALTER ROLE can.This patch does following things,
- ALTER USER/ROLE now takes CURRENT_USER as user name.
- Rewrite sysnopsis of the documents for ALTER USER and ALTER
ROLE so as to they have exactly same syntax.- Modify syntax of ALTER USER so as to be an alias of ALTER ROLE.
- Added CURRENT_USER/CURRENT_ROLE syntax to both.
- Added ALL syntax as user name to ALTER USER.
- Added IN DATABASE syntax to ALTER USER.x Integrating ALTER ROLE/USER syntax could not be done because of
shift/reduce error of bison.x This patch contains no additional regressions. Is it needed?
SESSION_USER/USER also can be made usable for this command, but
this patch doesn't so (yet).regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers--
Rushabh Lathia
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
Thank you for reviewing,
2014 13:10:57 +0530, Rushabh Lathia <rushabh.lathia@gmail.com> wrote in <CAGPqQf0kDFAJiZx0vCA_-wAZwU+Xj5MDNL-HGg1SEz9AW3ck7w@mail.gmail.com>
I gone through patch and here is the review for this patch:
.) patch go applied on master branch with patch -p1 command
(git apply failed)
.) regression make check run fine
.) testcase coverage is missing in the patch
.) Over all coding/patch looks good.Few comments:
1) Any particular reason for not adding SESSION_USER/USER also made usable
for this command ?
No particular reson. This patch was the first step and if this is
the adequate way and adding them is desirable, I will add them.
2) I think RoleId_or_curruser can be used for following role:
/* ALTER TABLE <name> OWNER TO RoleId */
| OWNER TO RoleId
Good catch. I'll try it.
3) In the documentation patch, added for CURRENT_USER but CURRENT_ROLE is
missing.
Mmm.. I didn't added CURRENT_ROLE in the previous patch.
I suppose CURRENT_ROLE is an implicit alias of CURRENT_USER
because it is not explained in the page below in spite of
existing in syntax.
http://www.postgresql.org/docs/9.4/static/functions-info.html
and it is currently usable only in expressions, so the following
SQL failed and all syntax using auth_ident will fail.
postgres=# CREATE USER MAPPING FOR CURRENT_ROLE SERVER s1;
ERROR: syntax error at or near "current_role"
share/doc/html/sql-createusermapping.html
| Synopsis
|
| CREATE USER MAPPING FOR { user_name | USER | CURRENT_USER | PUBLIC }
I don't know why the 'USER' is added here, but anyway I can add
'CURRENT_ROLE' there in gram.y but it seems not necessary to add
it to document.
Ok, I'll modify this patch so that,
- Make CURRENT_USER/ROLE usable in TABLE OWNER TO.
and since adding CURRENT_ROLE is the another thing, I'll do the
following things as additional patch.
- Add USER, CURRENT_ROLE and SESSION_* for the place where
CURRENT_USER is usable now. auth_ident and
RoleId_or_curruser.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello,
Kyotaro,
Food for thought. Couldn't you reduce the following block:
+ if (strcmp(stmt->role, "current_user") == 0) + { + roleid = GetUserId(); + tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("roleid %d does not exist", roleid))); + } + else + { + tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role)); + if (!HeapTupleIsValid(tuple)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", stmt->role)));To:
if (strcmp(stmt->role, "current_user") == 0)
roleid = GetUserId();
else
roleid = get_role_oid(stmt->role, false);tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("roleid %d does not exist", roleid)));I think this makes it a bit cleaner. It also reuses existing code as
'get_role_oid()' already does a valid role name check and will raise the
proper error.
Year, far cleaner. I missed the function. Thank you.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi, here is the revised patch.
Attached files are the followings
- 0001-ALTER-ROLE-CURRENT_USER_v2.patch - the patch.
- testset.tar.bz2 - test set. Run by typing 'make check' as a
superuser of the running postgreSQL server. It creates "testdb"
and some roles.
Documents are not edited this time.
----
Considering your comments, I found more points to modify.
- CREATE SCHEMA (IF NOT EXISTS) .. AUTHORIZATION <role> ...
- ALTER AGGREAGE/COLLATION/etc... OWNER TO <role>
- CREATE/ALTER/DROP USER MAPPING FOR <role> SERVER ..
GRANT/REVOKE also takes role as an arguemnt but CURRENT_USER and
the similar keywords seem to be useless for them.
Finally, the new patch modifies the following points.
In gram.y,
- RoleId's are replaced with RoleId_or_curruser in more places.
It accepts CURRENT_USER/USER/CURRENT_ROLE/SESSION_USER.
- ALTER USER ALL syntax is added. (not changed from the previous patch)
- The non-terminal auth_ident now uses RoleId_or_curruser
instead of RoleId. This affects CREATE/ALTER/DROP USER MAPPING
In user.c, new function ResolveRoleId() is added and used for all
role ID resolutions that correspond to the syntax changes in
parser. It is AlterRole() in user.c.
In foreigncmds.c, GetUserOidFromMapping() is removed and
ResolveRoleId is used instead.
In alter.c and tablecmds.c, all calls to get_role_oid()
correspond the the grammer change were replaced with
ResolveRoleId().
The modifications are a bit complicated so I provided a
comprehensive test set.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0001-ALTER-ROLE-CURRENT_USER_v2.patchtext/x-patch; charset=us-asciiDownload
>From f55494a49b6d4c7eb32665ea9cc63634f5000c99 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Tue, 9 Sep 2014 19:26:24 +0900
Subject: [PATCH] ALTER ROLE CURRENT_USER
---
src/backend/commands/alter.c | 2 +-
src/backend/commands/foreigncmds.c | 25 ++----------
src/backend/commands/schemacmds.c | 3 +-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/user.c | 56 ++++++++++++++++++---------
src/backend/parser/gram.y | 78 ++++++++++++++++++++++----------------
src/include/commands/dbcommands.h | 1 +
src/include/commands/user.h | 2 +
8 files changed, 96 insertions(+), 73 deletions(-)
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..15f254e 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -678,7 +678,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = ResolveRoleId(stmt->newowner, false, NULL);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index ab4ed6c..9878fca 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -27,6 +27,7 @@
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
+#include "commands/user.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
@@ -198,24 +199,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1099,7 +1082,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ useId = ResolveRoleId(stmt->username, false, NULL);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1194,7 +1177,7 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ useId = ResolveRoleId(stmt->username, false, NULL);
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1276,7 +1259,7 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid umId;
ForeignServer *srv;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
+ useId = ResolveRoleId(stmt->username, stmt->missing_ok, NULL);
srv = GetForeignServerByName(stmt->servername, true);
if (stmt->username && !OidIsValid(useId))
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 03f5514..4f97f23 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -25,6 +25,7 @@
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
#include "commands/schemacmds.h"
+#include "commands/user.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
#include "tcop/utility.h"
@@ -59,7 +60,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
* Who is supposed to own the new schema?
*/
if (authId)
- owner_uid = get_role_oid(authId, false);
+ owner_uid = ResolveRoleId(authId, false, NULL);
else
owner_uid = saved_uid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ecdff1e..9ebff24 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3473,7 +3473,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ ResolveRoleId(cmd->name, false, NULL),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..33c4477 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -63,6 +63,41 @@ have_createrole_privilege(void)
return has_createrole_privilege(GetUserId());
}
+/*
+ * ResolveRoleId - Resolving role id with treating some special keywords which
+ * appears as RoleId_or_curruser in gram.y.
+ *
+ * If missing_ok is false, throw an error if tablespace name not found. If
+ * true, just return InvalidOid.
+ *
+ * If roletuple is not NULL, return the tuple for the role in pg_roles.
+ */
+Oid ResolveRoleId(const char *name, bool missing_ok, HeapTuple *roletuple)
+{
+ Oid roleid;
+
+ if (roletuple) *roletuple = NULL;
+
+ if (!name) /* PUBLIC user mapping */
+ return InvalidOid;
+ else if (strcmp(name, "current_user") == 0)
+ roleid = GetUserId();
+ else if (strcmp(name, "session_user") == 0)
+ roleid = GetSessionUserId();
+ else
+ roleid = get_role_oid(name, missing_ok);
+
+ if (OidIsValid(roleid) && roletuple)
+ {
+ *roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(*roletuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", roleid)));
+ }
+ return roleid;
+}
+
/*
* CREATE ROLE
@@ -649,13 +684,7 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(tuple);
+ roleid = ResolveRoleId(stmt->role, false, &tuple);
/*
* To mess with a superuser you gotta be superuser; else you need
@@ -864,26 +893,19 @@ AlterRole(AlterRoleStmt *stmt)
Oid
AlterRoleSet(AlterRoleSetStmt *stmt)
{
- HeapTuple roletuple;
+ HeapTuple roletuple;
Oid databaseid = InvalidOid;
Oid roleid = InvalidOid;
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(roletuple);
+ roleid = ResolveRoleId(stmt->role, false, &roletuple);
/*
* Obtain a lock on the role and make sure it didn't go away in the
* meantime.
*/
- shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
+ shdepLockAndCheckObject(AuthIdRelationId, roleid);
/*
* To mess with a superuser you gotta be superuser; else you need
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0de9584..54544c7 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -474,7 +474,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId RoleId_or_curruser
+%type <str> opt_granted_by opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -1036,7 +1037,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1052,7 +1053,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleId_or_curruser opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1078,7 +1079,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1090,12 +1091,20 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleId_or_curruser opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
- n->database = NULL;
- n->setstmt = $4;
+ n->database = $4;
+ n->setstmt = $5;
+ $$ = (Node *)n;
+ }
+ | ALTER USER ALL opt_in_database SetResetClause
+ {
+ AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
+ n->role = NULL;
+ n->database = $4;
+ n->setstmt = $5;
$$ = (Node *)n;
}
;
@@ -1227,7 +1236,7 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId_or_curruser OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
@@ -1250,7 +1259,7 @@ CreateSchemaStmt:
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId_or_curruser OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
@@ -2259,7 +2268,7 @@ alter_table_cmd:
$$ = (Node *)n;
}
/* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ | OWNER TO RoleId_or_curruser
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
@@ -4458,9 +4467,8 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
/* User mapping authorization identifier */
auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+ RoleId_or_curruser { $$ = (strcmp($1, "public") == 0) ?
+ NULL : $1; }
;
/*****************************************************************************
@@ -7941,7 +7949,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -7950,7 +7958,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -7958,7 +7966,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -7966,7 +7974,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -7974,7 +7982,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -7982,7 +7990,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -7991,7 +7999,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -7999,7 +8007,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8007,7 +8015,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8016,7 +8024,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8025,7 +8033,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8034,7 +8042,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8042,7 +8050,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8050,7 +8058,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8058,7 +8066,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8066,7 +8074,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8074,7 +8082,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8082,7 +8090,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8090,7 +8098,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -12922,6 +12930,12 @@ Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
RoleId: NonReservedWord { $$ = $1; };
+RoleId_or_curruser: RoleId { $$ = $1; }
+ | CURRENT_USER { $$ = "current_user";};
+ | USER { $$ = "current_user";};
+ | CURRENT_ROLE { $$ = "current_user";};
+ | SESSION_USER { $$ = "session_user";};
+
role_list: RoleId
{ $$ = list_make1(makeString($1)); }
| role_list ',' RoleId
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index 811713f..6773c67 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -16,6 +16,7 @@
#include "access/xlog.h"
#include "nodes/parsenodes.h"
+#include "access/htup.h"
/* XLOG stuff */
#define XLOG_DBASE_CREATE 0x00
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..ea9f9b5 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -22,6 +22,8 @@ typedef void (*check_password_hook_type) (const char *username, const char *pass
extern PGDLLIMPORT check_password_hook_type check_password_hook;
+extern Oid ResolveRoleId(const char *name, bool missing_ok,
+ HeapTuple *roletuple);
extern Oid CreateRole(CreateRoleStmt *stmt);
extern Oid AlterRole(AlterRoleStmt *stmt);
extern Oid AlterRoleSet(AlterRoleSetStmt *stmt);
--
2.1.0.GIT
Thanks Kyotaro,
I just did quickly looked at the patch and it does cover more syntax then
earlier patch. But still if doesn't not cover the all the part of syntax
where
we can use CURRENT_USER/CURRENT_ROLE/USER/SESSION_USER. For example:
-- Not working
alter default privileges for role current_user grant SELECT ON TABLES TO
current_user ;
-- Not working
grant user1 TO current_user;
Their might few more syntax like this.
I understand that patch is sightly getting bigger and complex then what it
was
originally proposed. Before going back to more review on latest patch I
would
like to understand the requirement of this new feature. Also would like
others
to comment on where/how we should restrict this feature ?
On Fri, Oct 24, 2014 at 1:59 PM, Kyotaro HORIGUCHI <
horiguchi.kyotaro@lab.ntt.co.jp> wrote:
Hi, here is the revised patch.
Attached files are the followings
- 0001-ALTER-ROLE-CURRENT_USER_v2.patch - the patch.
- testset.tar.bz2 - test set. Run by typing 'make check' as a
superuser of the running postgreSQL server. It creates "testdb"
and some roles.Documents are not edited this time.
----
Considering your comments, I found more points to modify.
- CREATE SCHEMA (IF NOT EXISTS) .. AUTHORIZATION <role> ...
- ALTER AGGREAGE/COLLATION/etc... OWNER TO <role>
- CREATE/ALTER/DROP USER MAPPING FOR <role> SERVER ..
GRANT/REVOKE also takes role as an arguemnt but CURRENT_USER and
the similar keywords seem to be useless for them.Finally, the new patch modifies the following points.
In gram.y,
- RoleId's are replaced with RoleId_or_curruser in more places.
It accepts CURRENT_USER/USER/CURRENT_ROLE/SESSION_USER.- ALTER USER ALL syntax is added. (not changed from the previous patch)
- The non-terminal auth_ident now uses RoleId_or_curruser
instead of RoleId. This affects CREATE/ALTER/DROP USER MAPPINGIn user.c, new function ResolveRoleId() is added and used for all
role ID resolutions that correspond to the syntax changes in
parser. It is AlterRole() in user.c.In foreigncmds.c, GetUserOidFromMapping() is removed and
ResolveRoleId is used instead.In alter.c and tablecmds.c, all calls to get_role_oid()
correspond the the grammer change were replaced with
ResolveRoleId().The modifications are a bit complicated so I provided a
comprehensive test set.regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Rushabh Lathia
All,
I just ran through the patch giving it a good once over, some items to
address/consider/discuss:
* Trailing whitespace.
* Why are you making changes in foreigncmds.c? These seem like unnecessary
changes. I see that you are trying to consolidate but this refactor seems
potentially out of scope.
* To the above point, is ResolveRoleId really necessary? Also, I'm not
sure I agree with passing in the tuple, I don't see any reason to pull that
look up into this function. Also, couldn't you simply just add a short
circuit in "get_role_oid" to check for "current_user" and return
GetUserId() and similar for "session_user"?
* In gram.y, is there really a need to have a separate RoleId_or_curruser?
Why not:
-RoleId: NonReservedWord { $$ = $1; };
+RoleId: CURRENT_USER { $$ =
"current_user";}
+ | USER { $$ = "current_user";}
+ | CURRENT_ROLE { $$ = "current_user";}
+ | SESSION_USER { $$ = "session_user";}
+ | NonReservedWord { $$ = $1; }
+ ;
This would certainly reduce the number of changes to the grammar but might
also help with covering the cases mentioned by Rushabh? Also are there
cases when we don't want CURRENT_USER to be considered a RoleId?
* The following seems like an unnecessary change:
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1;
}
+ RoleId { $$ = (strcmp($1, "public") == 0) ?
+ NULL : $1; }
* Why is htup.h included in dbcommands.h?
* What's up with the following in user.c, did you replace tab with spaces?
- HeapTuple roletuple;
+ HeapTuple roletuple;
-- Not working
alter default privileges for role current_user grant SELECT ON TABLES TO
current_user ;
-- Not working
grant user1 TO current_user;
Agreed. The latter of the two seems like an interesting case to me
though. But they both kind of jump out at me as potential for security
concerns (but perhaps not given the role id checks, etc). At any rate, I'd
still expect these to behave accordingly with notification/error messages
when appropriate.
Their might few more syntax like this.
I think this can be "covered" inherently by the grammar changes recommended
above (if such changes are appropriate). Though, I'd also recommend
investigating which commands are affected via the grammar (or RoleId) and
then making sure to update the regression tests and the documentation
accordingly.
I understand that patch is sightly getting bigger and complex then what
it was
originally proposed.
IMHO, I think this patch has become more complex than is required.
Before going back to more review on latest patch I would
like to understand the requirement of this new feature. Also would like
others
to comment on where/how we should restrict this feature ?
I think this is a fair request. I believe I can see the potential
convenience of these changes, however, I'm uncertain of the necessity of
them and whether or not it opens any security concerns (again, perhaps not,
but I think it is worth asking). Also, how would this affect items like
auditing?
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
On Fri, Oct 24, 2014 at 11:29 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
- 0001-ALTER-ROLE-CURRENT_USER_v2.patch - the patch.
+RoleId: CURRENT_USER { $$ = "current_user";}
+ | USER { $$ = "current_user";}
+ | CURRENT_ROLE { $$ = "current_user";}
+ | SESSION_USER { $$ = "session_user";}
This is kind of ugly, and it means you can't distinguish between a
CURRENT_USER keyword and a quoted user name "current_user". It's a
legitimate user name, so the behavior of the following now changes:
CREATE ROLE "current_user";
ALTER ROLE "current_user" SET work_mem='10MB';
There ought to be a better way to represent this than using magic string values.
----
It accepts CURRENT_USER/USER/CURRENT_ROLE/SESSION_USER.
On a stylistic note, do we really want to support the alternative
spellings of CURRENT_USER, like CURRENT_ROLE and USER? The SQL
standard is well-hated for inventing more keywords than necessary.
There is no precedent for using/allowing these aliases in PostgreSQL
DDL commands, and ALTER USER & ROLE aren't SQL standard anyway. So
maybe we should stick with just accepting one canonical syntax
instead.
I think the word USER may reasonably arise from an editing mistake,
ALTER USER USER does not seem like sane syntax that should be
accepted.
----
From your original email:
- Modify syntax of ALTER USER so as to be an alias of ALTER ROLE.
- Added ALL syntax as user name to ALTER USER.
But should ALTER USER ALL and ALTER ROLE ALL really do the same thing?
A user is a role with the LOGIN option. Every user is a role, but not
every role is a user. I suspect that ambiguity was why ALTER USER ALL
wasn't originally implemented.
Regards,
Marti
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Marti Raudsepp wrote
On Fri, Oct 24, 2014 at 11:29 AM, Kyotaro HORIGUCHI
<
horiguchi.kyotaro@.co
> wrote:
But should ALTER USER ALL and ALTER ROLE ALL really do the same thing?
A user is a role with the LOGIN option. Every user is a role, but not
every role is a user. I suspect that ambiguity was why ALTER USER ALL
wasn't originally implemented.
There is no system level distinction here - only semantic and only during
the issuance of a CREATE without specifying an explicit value for
LOGIN/NOLGIN.
The documentation states user and group are aliases for ROLE, not subsets
that require or disallow login privileges.
I am OK with not making them true aliases in order to minimize user
confusion w.r.t. the semantics implied by user and group but then I'd submit
we simply note those two forms as deprecated in favor of role and that all
new role-based functionality will only be attached to role-based commands.
Since all of user, current_user and session_user have special syntactic
consideration in SQL [1] I'd be generally in favor of trying to keep that
dynamic intact while implementing this feature. And for the same reason I
would not allow current_role as a keyword. We didn't add a current_role
function but instead chose to rely on the standard keywords even when we
introduced ROLE.
I'm not clear on the keyword confusion since while "current_user" is a valid
literal it requires quotation while the token current_user does not.
1. http://www.postgresql.org/docs/9.4/static/functions-info.html
David J.
--
View this message in context: http://postgresql.1045698.n5.nabble.com/alter-user-role-CURRENT-USER-tp5822520p5824528.html
Sent from the PostgreSQL - hackers mailing list archive at Nabble.com.
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
+RoleId: CURRENT_USER { $$ = "current_user";} + | USER { $$ = "current_user";} + | CURRENT_ROLE { $$ = "current_user";} + | SESSION_USER { $$ = "session_user";}This is kind of ugly, and it means you can't distinguish between a
CURRENT_USER keyword and a quoted user name "current_user".
You are right. I'm not sure I have an opinion on how clean it is, but
FWIW, it is similar to the way that the 'auth_ident' type in the grammar is
defined (though, not to imply that it makes it right). As well, the
originally proposed "RoleId_or_curruser" suffers from the same issue. I'm
going to go out on a limb here, but is it not possible to consider
"current_user", etc. reserved in the same sense that we do with PUBLIC and
NONE and disallow users/roles from being created as them? I mean, after
all, they *are* already reserved keywords. Perhaps there is a very good
reason why we wouldn't want to do that and I am sure there is since they
have not been treated this way thus far. If anyone would like to share
why, then I'd very much appreciate the "lesson".
It's a legitimate user name, so the behavior of the following now changes:
CREATE ROLE "current_user";
Well, it does allow this one.
ALTER ROLE "current_user" SET work_mem='10MB';
However, you are right, it does interfere with this command (and pretty
much ALTER ROLE in general). :-/ Not sure what to offer there.
ALTER USER USER does not seem like sane syntax that should be
accepted.
I think that I agree, I can't imagine this being acceptable.
Taking a step back, I'm still not sure I understand the need for this
feature or the use case. It seems to have started as a potential fix to an
inconsistency between ALTER USER and ALTER ROLE syntax (which I think I
could see some value in). However, I think it has been taken beyond just
resolving the inconsistency and started to cross over into feature creep.
Is the intent simply to resolve inconsistencies between what is now an
alias of another command? Or is it to add new functionality? I think the
original proposal needs to be revisited and more time needs to be spent
defining the scope and purpose of this patch.
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
Marti Raudsepp wrote:
On Fri, Oct 24, 2014 at 11:29 AM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:- 0001-ALTER-ROLE-CURRENT_USER_v2.patch - the patch.
+RoleId: CURRENT_USER { $$ = "current_user";} + | USER { $$ = "current_user";} + | CURRENT_ROLE { $$ = "current_user";} + | SESSION_USER { $$ = "session_user";}This is kind of ugly, and it means you can't distinguish between a
CURRENT_USER keyword and a quoted user name "current_user". It's a
legitimate user name, so the behavior of the following now changes:CREATE ROLE "current_user";
ALTER ROLE "current_user" SET work_mem='10MB';There ought to be a better way to represent this than using magic string values.
Agreed. Since the current_user disease has already infected the USER
MAPPING stuff, I think we need to solve that problem -- how about having
this production return a new node which has either a string name or
flags for the various acceptable keywords?
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Adam Brightwell (adam.brightwell@crunchydatasolutions.com) wrote:
+RoleId: CURRENT_USER { $$ = "current_user";} + | USER { $$ = "current_user";} + | CURRENT_ROLE { $$ = "current_user";} + | SESSION_USER { $$ = "session_user";}This is kind of ugly, and it means you can't distinguish between a
CURRENT_USER keyword and a quoted user name "current_user".You are right. I'm not sure I have an opinion on how clean it is, but
FWIW, it is similar to the way that the 'auth_ident' type in the grammar is
defined (though, not to imply that it makes it right).
No, it's not right and it's an existing problem. :(
=*# create extension postgres_fdw;
CREATE EXTENSION
=# create server s1 foreign data wrapper postgres_fdw ;
CREATE SERVER
=*# create user mapping for "current_user" server s1;
CREATE USER MAPPING
=*# table pg_user_mappings;
-[ RECORD 1 ]-----
umid | 24623
srvid | 24622
srvname | s1
umuser | 16384
usename | sfrost
umoptions |
As well, the
originally proposed "RoleId_or_curruser" suffers from the same issue. I'm
going to go out on a limb here, but is it not possible to consider
"current_user", etc. reserved in the same sense that we do with PUBLIC and
NONE and disallow users/roles from being created as them?
Maybe we could in some future release, but we can't for back-branches so
I'm afraid we're going to have to figure out how to fix this to work
regardless.
I mean, after
all, they *are* already reserved keywords. Perhaps there is a very good
reason why we wouldn't want to do that and I am sure there is since they
have not been treated this way thus far. If anyone would like to share
why, then I'd very much appreciate the "lesson".
You can still double-quote reserved words and use them in general. What
we're talking about here are cases where a word can't be used even if
it's double-quoted, and we try really hard to keep those cases at an
absolute minimum. We should also really be keeping a list of those
cases somewhere, now that I think about it..
Taking a step back, I'm still not sure I understand the need for this
feature or the use case. It seems to have started as a potential fix to an
inconsistency between ALTER USER and ALTER ROLE syntax (which I think I
could see some value in). However, I think it has been taken beyond just
resolving the inconsistency and started to cross over into feature creep.
Is the intent simply to resolve inconsistencies between what is now an
alias of another command? Or is it to add new functionality? I think the
original proposal needs to be revisited and more time needs to be spent
defining the scope and purpose of this patch.
I agree that we should probably seperate the concerns here. Personally,
I like the idea of being able to say "CURRENT_USER" in utility commands
to refer to the current user where a role would normally be expected, as
I could see it simplifying things for some applications, but that's a
new feature and independent of making role-vs-user cases more
consistent.
Thanks!
Stephen
Stephen Frost <sfrost@snowman.net> wrote:
You can still double-quote reserved words and use them in general. What
we're talking about here are cases where a word can't be used even if
it's double-quoted, and we try really hard to keep those cases at an
absolute minimum. We should also really be keeping a list of those
cases somewhere, now that I think about it..
It is very important that a quoted identifier not be treated as a
keyword. I would be very interested in seeing that list, and in
ensuring that it doesn't get any longer.
I agree that we should probably seperate the concerns here. Personally,
I like the idea of being able to say "CURRENT_USER" in utility commands
to refer to the current user where a role would normally be expected, as
I could see it simplifying things for some applications, but that's a
new feature and independent of making role-vs-user cases more
consistent.
Yeah, let's not mix those in the same patch.
--
Kevin Grittner
EDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
On Tue, Oct 28, 2014 at 2:40 AM, Adam Brightwell
<adam.brightwell@crunchydatasolutions.com> wrote:
Taking a step back, I'm still not sure I understand the need for this
feature or the use case. It seems to have started as a potential fix to an
inconsistency between ALTER USER and ALTER ROLE syntax (which I think I
could see some value in). However, I think it has been taken beyond just
resolving the inconsistency and started to cross over into feature creep.
Is the intent simply to resolve inconsistencies between what is now an alias
of another command? Or is it to add new functionality? I think the
original proposal needs to be revisited and more time needs to be spent
defining the scope and purpose of this patch.
+1. I've been reading this thread with some bemusement, but couldn't
find a way articulate what you just said nearly as well as you just
said it.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
* Kevin Grittner (kgrittn@ymail.com) wrote:
Stephen Frost <sfrost@snowman.net> wrote:
You can still double-quote reserved words and use them in general. What
we're talking about here are cases where a word can't be used even if
it's double-quoted, and we try really hard to keep those cases at an
absolute minimum. We should also really be keeping a list of those
cases somewhere, now that I think about it..It is very important that a quoted identifier not be treated as a
keyword. I would be very interested in seeing that list, and in
ensuring that it doesn't get any longer.
It's object specific and not handled through the grammar, so that gets
pretty annoying. :/
The ones I could find by a quick look through backend/commands are:
roles
public
none
schemas
pg_*
operator
=> (throws a warning at least)
There may be other cases that my quick review didn't find, of course.
Thanks,
Stephen
Hello, thank you all for many comments.
At the first, I removed changes for role-vs-user consistency and
remove all added role named other than current_user.
The followings are one-by-one answer for the comments so far,
please let me know if I missed anything.
- The necessity of the new function ResolveRoleId()
It is very brief function but used in many place where the role
name should be treated in the same way, so I think encapsulation
is needed in some extent and in any form. It could be merged
with get_role_oid.
- About changes in foreigncmds.c
I removed the refactoring using ResolveRoleId() in this patch.
- RoleId_or_curruser separate from RoleId.
There seems to be places where 'current_user' and like is not
appropraite to occur such as CREATE USER. I don't mind to remove
the non-terminal if it is needless consideration.
- GRANT is not modified.
I thought GRANT is not appropriate but it seems appropriate
seeing your example. And grantee takes "public". I changed
GRANT/REVOKE to take current_user in this patch.
- (not a comment) CREATE SCHEMA needed additonal aid
Schema name can be omitted in CREATE SCHEMA and role name is
used for it, so "CREATE SCHEMA AUTHORIZATION current_user"
crates the schema "current_user" in the previous patch. This
should be the real name of current_user.
This patch is for reviewing at a glance for food of discussion
and tested very briefly (and what is worse, it might even not be
applicable). I'll repost more refined version in this way and
other portions.
At Tue, 28 Oct 2014 12:16:13 -0400, Stephen Frost <sfrost@snowman.net> wrote in <20141028161613.GT28859@tamriel.snowman.net>
* Kevin Grittner (kgrittn@ymail.com) wrote:
It is very important that a quoted identifier not be treated as a
keyword. I would be very interested in seeing that list, and in
ensuring that it doesn't get any longer.It's object specific and not handled through the grammar, so that gets
pretty annoying. :/The ones I could find by a quick look through backend/commands are:
roles
public
noneschemas
pg_*operator
=> (throws a warning at least)There may be other cases that my quick review didn't find, of course.
Hmm... This seems to be another issue, though. I'll be careful
not to make it worse..
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0001-CURRENT_USER_WIP_v1.patchtext/x-patch; charset=us-asciiDownload
>From ebe2d8b5549eddbd073b65aabe15af9299b948f6 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Wed, 29 Oct 2014 17:38:46 +0900
Subject: [PATCH] CURRENT_USER_WIP_v1
---
src/backend/commands/alter.c | 2 +-
src/backend/commands/schemacmds.c | 20 ++++++++++-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/user.c | 48 ++++++++++++++++++--------
src/backend/parser/gram.y | 71 ++++++++++++++++++++-------------------
src/include/commands/dbcommands.h | 1 +
src/include/commands/user.h | 1 +
7 files changed, 93 insertions(+), 52 deletions(-)
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..1f598f6 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -678,7 +678,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = ResolveRoleId(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 03f5514..d67789a 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -23,8 +23,10 @@
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
+#include "catalog/pg_authid.h"
#include "commands/dbcommands.h"
#include "commands/schemacmds.h"
+#include "commands/user.h"
#include "miscadmin.h"
#include "parser/parse_utilcmd.h"
#include "tcop/utility.h"
@@ -59,10 +61,26 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
* Who is supposed to own the new schema?
*/
if (authId)
- owner_uid = get_role_oid(authId, false);
+ owner_uid = ResolveRoleId(authId, false);
else
owner_uid = saved_uid;
+ /* Use the name for the owner_uid as the schema name if it is omitted */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", owner_uid)));
+
+ schemaName =
+ strdup(((Form_pg_authid) GETSTRUCT(tuple))->rolname.data);
+ ReleaseSysCache(tuple);
+ }
+
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ecdff1e..0b82765 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3473,7 +3473,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ ResolveRoleId(cmd->name, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..ab0612e 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -63,6 +63,27 @@ have_createrole_privilege(void)
return has_createrole_privilege(GetUserId());
}
+/*
+ * ResolveRoleId - Resolving role id with treating some special keywords which
+ * appears as RoleId_or_curruser in gram.y.
+ *
+ * If missing_ok is false, throw an error if tablespace name not found. If
+ * true, just return InvalidOid.
+ */
+Oid ResolveRoleId(const char *name, bool missing_ok)
+{
+ Oid roleid;
+
+ if (!name) /* PUBLIC user mapping */
+ return InvalidOid;
+ else if (strcmp(name, "current_user") == 0)
+ roleid = GetUserId();
+ else
+ roleid = get_role_oid(name, missing_ok);
+
+ return roleid;
+}
+
/*
* CREATE ROLE
@@ -649,13 +670,13 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ roleid = ResolveRoleId(stmt->role, false);
+
+ tuple = SearchSysCache1(AUTHOID, PointerGetDatum(roleid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(tuple);
+ errmsg("role \"%s\" does not exist", roleid)));
/*
* To mess with a superuser you gotta be superuser; else you need
@@ -870,21 +891,20 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(roletuple);
+ roleid = ResolveRoleId(stmt->role, false);
/*
* Obtain a lock on the role and make sure it didn't go away in the
* meantime.
*/
- shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));
+ shdepLockAndCheckObject(AuthIdRelationId, roleid);
+ roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(roletuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("roleid %d does not exist", roleid)));
+
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own settings
@@ -1268,7 +1288,7 @@ GrantRole(GrantRoleStmt *stmt)
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
- roleid = get_role_oid(rolename, false);
+ roleid = ResolveRoleId(rolename, false);
if (stmt->is_grant)
AddRoleMems(rolename, roleid,
stmt->grantee_roles, grantee_ids,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0de9584..da82073 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -474,7 +474,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId RoleId_or_curruser
+%type <str> opt_granted_by opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -1036,7 +1037,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1052,7 +1053,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleId_or_curruser opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1078,7 +1079,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleId_or_curruser opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1090,7 +1091,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleId_or_curruser SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1227,14 +1228,11 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId_or_curruser OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
+ /* schemaname will be completed using authid if NULL */
+ n->schemaname = $3;
n->authid = $5;
n->schemaElts = $6;
n->if_not_exists = false;
@@ -1250,7 +1248,7 @@ CreateSchemaStmt:
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId_or_curruser OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
@@ -2259,7 +2257,7 @@ alter_table_cmd:
$$ = (Node *)n;
}
/* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ | OWNER TO RoleId_or_curruser
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
@@ -6218,7 +6216,7 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
+grantee: RoleId_or_curruser
{
PrivGrantee *n = makeNode(PrivGrantee);
/* This hack lets us avoid reserving PUBLIC as a keyword*/
@@ -6228,7 +6226,7 @@ grantee: RoleId
n->rolname = $1;
$$ = (Node *)n;
}
- | GROUP_P RoleId
+ | GROUP_P RoleId_or_curruser
{
PrivGrantee *n = makeNode(PrivGrantee);
/* Treat GROUP PUBLIC as a synonym for PUBLIC */
@@ -6308,7 +6306,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleId_or_curruser { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -7941,7 +7939,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -7950,7 +7948,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -7958,7 +7956,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -7966,7 +7964,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -7974,7 +7972,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -7982,7 +7980,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -7991,7 +7989,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -7999,7 +7997,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8007,7 +8005,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8016,7 +8014,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8025,7 +8023,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8034,7 +8032,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8042,7 +8040,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8050,7 +8048,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8058,7 +8056,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8066,7 +8064,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8074,7 +8072,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8082,7 +8080,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8090,7 +8088,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleId_or_curruser
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -12922,6 +12920,9 @@ Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
RoleId: NonReservedWord { $$ = $1; };
+RoleId_or_curruser: RoleId { $$ = $1; }
+ | CURRENT_USER { $$ = "current_user";};
+
role_list: RoleId
{ $$ = list_make1(makeString($1)); }
| role_list ',' RoleId
diff --git a/src/include/commands/dbcommands.h b/src/include/commands/dbcommands.h
index 811713f..7c1df8e 100644
--- a/src/include/commands/dbcommands.h
+++ b/src/include/commands/dbcommands.h
@@ -16,6 +16,7 @@
#include "access/xlog.h"
#include "nodes/parsenodes.h"
+//#include "access/htup.h"
/* XLOG stuff */
#define XLOG_DBASE_CREATE 0x00
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..9e1f2a5 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -22,6 +22,7 @@ typedef void (*check_password_hook_type) (const char *username, const char *pass
extern PGDLLIMPORT check_password_hook_type check_password_hook;
+extern Oid ResolveRoleId(const char *name, bool missing_ok);
extern Oid CreateRole(CreateRoleStmt *stmt);
extern Oid AlterRole(AlterRoleStmt *stmt);
extern Oid AlterRoleSet(AlterRoleSetStmt *stmt);
--
2.1.0.GIT
Hello,
At Tue, 28 Oct 2014 09:05:20 -0400, Stephen Frost <sfrost@snowman.net> wrote in <20141028130520.GL28859@tamriel.snowman.net>
As well, the
originally proposed "RoleId_or_curruser" suffers from the same issue. I'm
going to go out on a limb here, but is it not possible to consider
"current_user", etc. reserved in the same sense that we do with PUBLIC and
NONE and disallow users/roles from being created as them?Maybe we could in some future release, but we can't for back-branches so
I'm afraid we're going to have to figure out how to fix this to work
regardless.
Zero-length identifiers are rejected in scanner so RoleId cannot
be a valid pointer to a zero-length string. (NULL is used as
PUBLIC in auth_ident)
| postgres=# create role "";
| ERROR: zero-length delimited identifier at or near """"
| postgres=# create role U&"\00";
| ERROR: invalid Unicode escape value at or near "\00""
As a dirty and quick hack we can use some integer values prfixed
by single zero byte to represent special roles such as
CURRENT_USER.
| RoleId_or_curruser: RoleId { $$ = $1; }
| | CURRENT_USER { $$ = "\x00\x01";};
....
| Oid ResolveRoleId(const char *name, bool missing_ok)
| {
| Oid roleid;
|
| if (name[0] == 0 && name[1] == 1)
| roleid = GetUserId();
This is ugly but needs no additional struct member or special
logics. (Macros could make them look better.)
Taking a step back, I'm still not sure I understand the need for this
feature or the use case. It seems to have started as a potential fix to an
inconsistency between ALTER USER and ALTER ROLE syntax (which I think I
could see some value in). However, I think it has been taken beyond just
resolving the inconsistency and started to cross over into feature creep.
Is the intent simply to resolve inconsistencies between what is now an
alias of another command? Or is it to add new functionality? I think the
original proposal needs to be revisited and more time needs to be spent
defining the scope and purpose of this patch.I agree that we should probably seperate the concerns here. Personally,
I like the idea of being able to say "CURRENT_USER" in utility commands
to refer to the current user where a role would normally be expected, as
I could see it simplifying things for some applications, but that's a
new feature and independent of making role-vs-user cases more
consistent.
I agree that role-vs-user compatibility is another problem.
In a sense, the "CURRENT_USER" problem is also a separate problem
but simplly spreading current "current_user" mechanism (which
cannot allow using the words literally even if double-quoted) out
to other commands is a kind of pandemic so it should be fixed
before making current_user usable in other commands.
From a view of comptibility (specification stability), fixing
this problem could break someone's application if he/she uses
"current_user" in the meaning of CURRENT_USER intentionally but I
think it is least likely.
As another problem, in the defenition of grantee, there is the
following comment.
| /* This hack lets us avoid reserving PUBLIC as a keyword*/
| if (strcmp($1, "public") == 0)
Please let me know the reason to avoid registering new keyword
making the word unusable as an literal identifier, if any?
PUBLIC and NONE ought to can be identifiers but in reality
unusable because they are handled as keywords in literal
form. Thses are fixed by making them real keywords.
So if there's no particular reason, I will register new keywords
"PUBLIC" and "NONE" as another patch.
# However, I don't think that considerable number of people want
# to do that..
On the other hand, "pg_*" as shcmea names and operators are cases
simply of special names, which cannot be identifiers from the
first so it should be as it is, I think.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Kyotaro,
Zero-length identifiers are rejected in scanner so RoleId cannot
be a valid pointer to a zero-length string. (NULL is used as
PUBLIC in auth_ident)| postgres=# create role "";
| ERROR: zero-length delimited identifier at or near """"
| postgres=# create role U&"\00";
| ERROR: invalid Unicode escape value at or near "\00""
Err... what? I'm not sure what you are getting at here? Why would we ever
have/want a zero-length identifier for a RoleId? Seems to me that anything
requiring a RoleId should be explicit.
As a dirty and quick hack we can use some integer values prfixed
by single zero byte to represent special roles such as
CURRENT_USER.| RoleId_or_curruser: RoleId { $$ = $1; }
| | CURRENT_USER { $$ = "\x00\x01";};
....
| Oid ResolveRoleId(const char *name, bool missing_ok)
| {
| Oid roleid;
|
| if (name[0] == 0 && name[1] == 1)
| roleid = GetUserId();This is ugly but needs no additional struct member or special
logics. (Macros could make them look better.)
Yeah, that's pretty ugly. I think Alvaro's recommendation of having the
production return a node with a name or flag is the better approach.
| /* This hack lets us avoid reserving PUBLIC as a keyword*/
| if (strcmp($1, "public") == 0)
Please let me know the reason to avoid registering new keyword
making the word unusable as an literal identifier, if any?
FWIW, I found the following in the archives:
/messages/by-id/15516.1038718413@sss.pgh.pa.us
Now this is from 2002 and it appears it wasn't necessary to change at the
time, but I haven't yet found anything else related (it's a big archive).
Though, as I understand it, PUBLIC is now non-reserved as of SQL:2011 which
might make a compelling argument to leave it as is?
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
* Adam Brightwell (adam.brightwell@crunchydatasolutions.com) wrote:
| RoleId_or_curruser: RoleId { $$ = $1; }
| | CURRENT_USER { $$ = "\x00\x01";};
[...]
This is ugly but needs no additional struct member or special
logics. (Macros could make them look better.)Yeah, that's pretty ugly. I think Alvaro's recommendation of having the
production return a node with a name or flag is the better approach.
That's more than just 'ugly', in my view. I don't think there's any
reason to avoid making this into a node with a field that can be set to
indicate it's something special if we're going to support this.
The other idea which comes to mind is- could we try to actually resolve
what the 'right' answer is here, instead of setting a special value and
then having to detect and fix it later? Perhaps have a Oid+Rolename
structure and then fill in the Oid w/ GetUserId(), if we're called with
CURRENT_USER, and otherwise just populate the Rolename field and have
code later which fills in the Oid if it's InvalidOid.
Please let me know the reason to avoid registering new keyword
making the word unusable as an literal identifier, if any?
We really don't want to introduce new keywords without very good reason,
and adding to the list of "can't be used even if quoted" is all but
completely forbidden.
Thanks,
Stephen
Stephen Frost <sfrost@snowman.net> writes:
The other idea which comes to mind is- could we try to actually resolve
what the 'right' answer is here, instead of setting a special value and
then having to detect and fix it later?
No, absolutely not. Read the NOTES at the head of gram.y. Or if you
need it spelled out: when we run the bison parser, we may not be inside a
transaction at all, and even if we are, we aren't necessarily going to
be seeing the same current user that will apply when the parsetree is
ultimately executed. (Consider a query inside a plpgsql function, which
might be called under multiple userids over the course of a session.)
I think Alvaro's suggestion is a perfectly appropriate solution.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Adam Brightwell <adam.brightwell@crunchydatasolutions.com> writes:
FWIW, I found the following in the archives:
Now this is from 2002 and it appears it wasn't necessary to change at the
time, but I haven't yet found anything else related (it's a big archive).
Though, as I understand it, PUBLIC is now non-reserved as of SQL:2011 which
might make a compelling argument to leave it as is?
The current spec does list PUBLIC as a non-reserved keyword, but it also
says (5.4 "Names and identifiers" syntax rules)
20) No <authorization identifier> shall specify "PUBLIC".
which, oddly enough, seems to license us to handle "PUBLIC" the way
we are doing. OTOH, it lists CURRENT_USER as a reserved word, suggesting
that they don't think the same type of hack should be used for that.
I'd be inclined to leave the grammar as such alone (ie CURRENT_USER is
a keyword, PUBLIC isn't). Changing that has more downside than upside,
and we do have justification in the spec for treating the two cases
differently. However, I agree that we should fix the subsequent
processing so that "current_user" is not confused with CURRENT_USER.
regards, tom lane
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
All,
I agree that we should probably seperate the concerns here. Personally,
I like the idea of being able to say "CURRENT_USER" in utility commands
to refer to the current user where a role would normally be expected, as
I could see it simplifying things for some applications, but that's a
new feature and independent of making role-vs-user cases more
consistent.
So, I've been doing a little digging and it would appear that the ALTER
ROLE/USER consistency was brought up earlier in the year.
/messages/by-id/CADyrUxMv-tvSBV7mTtcs+qEdNy6xj1+KRtzfowVuHdJC5mGjfg@mail.gmail.com
It was returned with feedback in Commitfest 2014-06 and apparently lost
steam:
https://commitfest.postgresql.org/action/patch_view?id=1408
Tom put forward a suggestion for how to fix it:
/messages/by-id/21570.1408832605@sss.pgh.pa.us
I have taken that patch and updated the documentation (attached) and ran it
through some cursory testing.
At any rate, this is probably a good starting point for those changes.
-Adam
--
Adam Brightwell - adam.brightwell@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
Attachments:
alter-role-or-user-v1.patchtext/x-patch; charset=US-ASCII; name=alter-role-or-user-v1.patchDownload
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
new file mode 100644
index 58ae1da..ac05682
*** a/doc/src/sgml/ref/alter_user.sgml
--- b/doc/src/sgml/ref/alter_user.sgml
*************** ALTER USER <replaceable class="PARAMETER
*** 38,47 ****
ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
! ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
! ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
! ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
! ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET ALL
</synopsis>
</refsynopsisdiv>
--- 38,47 ----
ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
! ALTER USER <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
! ALTER USER { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
! ALTER USER { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
! ALTER USER { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 0de9584..d7c0586
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static Node *makeRecursiveViewSelect(cha
*** 230,236 ****
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
! AlterCompositeTypeStmt AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
AlterDefaultPrivilegesStmt DefACLAction
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
--- 230,236 ----
AlterFdwStmt AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterSystemStmt AlterTableStmt
AlterTblSpcStmt AlterExtensionStmt AlterExtensionContentsStmt AlterForeignTableStmt
! AlterCompositeTypeStmt AlterUserMappingStmt
AlterRoleStmt AlterRoleSetStmt AlterPolicyStmt
AlterDefaultPrivilegesStmt DefACLAction
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
*************** static Node *makeRecursiveViewSelect(cha
*** 520,525 ****
--- 520,527 ----
%type <str> opt_existing_window_name
%type <boolean> opt_if_not_exists
+ %type <str> role_or_user
+
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
* They must be listed first so that their numeric codes do not depend on
*************** stmt :
*** 756,763 ****
| AlterTSConfigurationStmt
| AlterTSDictionaryStmt
| AlterUserMappingStmt
- | AlterUserSetStmt
- | AlterUserStmt
| AnalyzeStmt
| CheckPointStmt
| ClosePortalStmt
--- 758,763 ----
*************** CreateUserStmt:
*** 1033,1042 ****
*
* Alter a postgresql DBMS role
*
*****************************************************************************/
AlterRoleStmt:
! ALTER ROLE RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
--- 1033,1044 ----
*
* Alter a postgresql DBMS role
*
+ * ALTER USER is accepted interchangeably with ALTER ROLE.
+ *
*****************************************************************************/
AlterRoleStmt:
! ALTER role_or_user RoleId opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
*************** AlterRoleStmt:
*** 1046,1058 ****
}
;
opt_in_database:
/* EMPTY */ { $$ = NULL; }
| IN_P DATABASE database_name { $$ = $3; }
;
AlterRoleSetStmt:
! ALTER ROLE RoleId opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
--- 1048,1065 ----
}
;
+ role_or_user:
+ ROLE {}
+ | USER {}
+ ;
+
opt_in_database:
/* EMPTY */ { $$ = NULL; }
| IN_P DATABASE database_name { $$ = $3; }
;
AlterRoleSetStmt:
! ALTER role_or_user RoleId opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
*************** AlterRoleSetStmt:
*** 1060,1066 ****
n->setstmt = $5;
$$ = (Node *)n;
}
! | ALTER ROLE ALL opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
--- 1067,1073 ----
n->setstmt = $5;
$$ = (Node *)n;
}
! | ALTER role_or_user ALL opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = NULL;
*************** AlterRoleSetStmt:
*** 1073,1108 ****
/*****************************************************************************
*
- * Alter a postgresql DBMS user
- *
- *****************************************************************************/
-
- AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
- {
- AlterRoleStmt *n = makeNode(AlterRoleStmt);
- n->role = $3;
- n->action = +1; /* add, if there are members */
- n->options = $5;
- $$ = (Node *)n;
- }
- ;
-
-
- AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
- {
- AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
- n->role = $3;
- n->database = NULL;
- n->setstmt = $4;
- $$ = (Node *)n;
- }
- ;
-
-
- /*****************************************************************************
- *
* Drop a postgresql DBMS role
*
* XXX Ideally this would have CASCADE/RESTRICT options, but since a role
--- 1080,1085 ----
*************** DropUserMappingStmt: DROP USER MAPPING F
*** 4493,4501 ****
* QUERY :
* ALTER USER MAPPING FOR auth_ident SERVER name OPTIONS
*
****************************************************************************/
! AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
n->username = $5;
--- 4470,4483 ----
* QUERY :
* ALTER USER MAPPING FOR auth_ident SERVER name OPTIONS
*
+ * Note: we also accept "ALTER ROLE MAPPING", because distinguishing that
+ * case in the grammar would require us to distinguish ROLE from USER in all
+ * other ALTER cases, and we don't want to do that. However, that spelling
+ * of the command is nonstandard and is not documented.
+ *
****************************************************************************/
! AlterUserMappingStmt: ALTER role_or_user MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
n->username = $5;
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 7611,7626 ****
n->newname = $7;
$$ = (Node *)n;
}
! | ALTER ROLE RoleId RENAME TO RoleId
! {
! RenameStmt *n = makeNode(RenameStmt);
! n->renameType = OBJECT_ROLE;
! n->subname = $3;
! n->newname = $6;
! n->missing_ok = false;
! $$ = (Node *)n;
! }
! | ALTER USER RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_ROLE;
--- 7593,7599 ----
n->newname = $7;
$$ = (Node *)n;
}
! | ALTER role_or_user RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_ROLE;
Hello,
Adam Brightwell <adam.brightwell@crunchydatasolutions.com> writes:
FWIW, I found the following in the archives:
Now this is from 2002 and it appears it wasn't necessary to change at the
time, but I haven't yet found anything else related (it's a big archive).
Though, as I understand it, PUBLIC is now non-reserved as of SQL:2011 which
might make a compelling argument to leave it as is?The current spec does list PUBLIC as a non-reserved keyword, but it also
says (5.4 "Names and identifiers" syntax rules)20) No <authorization identifier> shall specify "PUBLIC".
which, oddly enough, seems to license us to handle "PUBLIC" the way
we are doing. OTOH, it lists CURRENT_USER as a reserved word, suggesting
that they don't think the same type of hack should be used for that.I'd be inclined to leave the grammar as such alone (ie CURRENT_USER is
a keyword, PUBLIC isn't). Changing that has more downside than upside,
and we do have justification in the spec for treating the two cases
differently. However, I agree that we should fix the subsequent
processing so that "current_user" is not confused with CURRENT_USER.
Sure, maybe.
- PUBLIC should be left as it is, as an supecial identifier
which cannot be used even if quoted under some syntax.
- CURRENT_USER should be a kayword as it is, but we shouldn't
inhibit it from being used as an identifier if
quoted. SESSION_USER and USER should be treated in the same way.
We don't want to use something other than string (prefixed by
zero-byte) as a matter of course:). And resolving the name to
roleid instantly in gram.y is not allowed for the reason shown
upthread.
So it is necessary to add a new member for the struct, say
"int special_role;:... Let me have more sane name for it :(
- USER and CURRENT_ROLE are not needed for the syntax other than
them which already uses them.
I will work on this way. Let me know if something is not acceptable.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello, This is the new version. (WIP v2)
The first attachment is the patch and the second is test sql
script.
- Behavior changing
Almost all syntax taking role accepts CURRENT_USER and
SESSION_USER and they are distinguished from "current_user" and
"session_user". The exceptions are follows.
- CREATE USER/GROUP <roleid>
- ALTER ROLE/GROUP/USER <roleid> RENAME TO <newname>
These syntax still do not accept the keywords like CURRENT_USER
and special names like "public" at all, but accepts
"current_user". The error message is changed as follows.
| postgres=# create user current_user;
| ERROR: role name should not be a keyword nor reserved name.
| LINE 1: create user current_user;
| ^
# Some other messages may changed...
USER and CURRENT_ROLE haven't been extended to other syntax. The
former still can be used only in CREATE/ALTER/DROP USER MAPPING
and the latter cannot be used out of function expressions.
- Storage for new information
The new struct NameId stores an identifier which telling what it
logically is using the new enum NameIdTypes.
This is still be a bit suffered by the difference between
CURRENT_USER and PUBLIC but now it makes distinction between
current_user and "current_user". User oid does not have the room
for representing the difference among PUBLIC, NONE and 'not
found' as the result of get_nameid_oid(), so members of NameId is
exposed in foreigncmds.c and it gets a bit uglier.
- Changes of related structs and grammar.
Type of role member is changed to NameId in some of parser
structs. AlterTableCmd.name has many other usage so I added new
member NameId *newowner for exclusive usage.
Type of OWNER clause of CREATE TABLESPACE is changed to RoleId. I
suppose there's no particular reason that the non-terminal was
"name".
Usage of "public" and "none" had been blocked for CREATE/RENAME
USER in user.c but now it is blocked in gram.y
- New function to resolve NameId
New function get_nameid_oid() is added. It is an alternative of
get_role_oid which can handle current_user and "current_user"
properly. get_role_oid() still be used in many places having no
direct relation to syntax.
- Others
No doc provided for now.
regards,
Adam Brightwell <adam.brightwell@crunchydatasolutions.com> writes:
FWIW, I found the following in the archives:
Now this is from 2002 and it appears it wasn't necessary to change at the
time, but I haven't yet found anything else related (it's a big archive).
Though, as I understand it, PUBLIC is now non-reserved as of SQL:2011 which
might make a compelling argument to leave it as is?The current spec does list PUBLIC as a non-reserved keyword, but it also
says (5.4 "Names and identifiers" syntax rules)20) No <authorization identifier> shall specify "PUBLIC".
which, oddly enough, seems to license us to handle "PUBLIC" the way
we are doing. OTOH, it lists CURRENT_USER as a reserved word, suggesting
that they don't think the same type of hack should be used for that.I'd be inclined to leave the grammar as such alone (ie CURRENT_USER is
a keyword, PUBLIC isn't). Changing that has more downside than upside,
and we do have justification in the spec for treating the two cases
differently. However, I agree that we should fix the subsequent
processing so that "current_user" is not confused with CURRENT_USER.Sure, maybe.
- PUBLIC should be left as it is, as an supecial identifier
which cannot be used even if quoted under some syntax.- CURRENT_USER should be a kayword as it is, but we shouldn't
inhibit it from being used as an identifier if
quoted. SESSION_USER and USER should be treated in the same way.We don't want to use something other than string (prefixed by
zero-byte) as a matter of course:). And resolving the name to
roleid instantly in gram.y is not allowed for the reason shown
upthread.So it is necessary to add a new member for the struct, say
"int special_role;:... Let me have more sane name for it :(- USER and CURRENT_ROLE are not needed for the syntax other than
them which already uses them.I will work on this way. Let me know if something is not acceptable.
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0001-ALTER-USER-CURRENT_USER-v2.patchtext/x-patch; charset=us-asciiDownload
>From f18d078d5e6e4005e803ecc954e59c899dbfd557 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Mon, 10 Nov 2014 19:08:42 +0900
Subject: [PATCH] ALTER USER CURRENT_USER v2
---
src/backend/catalog/aclchk.c | 13 ++-
src/backend/commands/alter.c | 2 +-
src/backend/commands/foreigncmds.c | 39 ++++-----
src/backend/commands/schemacmds.c | 26 +++++-
src/backend/commands/tablecmds.c | 2 +-
src/backend/commands/tablespace.c | 2 +-
src/backend/commands/user.c | 70 +++++++--------
src/backend/nodes/copyfuncs.c | 37 +++++---
src/backend/nodes/equalfuncs.c | 35 +++++---
src/backend/parser/gram.y | 174 ++++++++++++++++++++++++++++---------
src/backend/parser/parse_utilcmd.c | 2 +-
src/backend/utils/adt/acl.c | 31 +++++++
src/include/nodes/nodes.h | 1 +
src/include/nodes/parsenodes.h | 44 +++++++---
src/include/utils/acl.h | 2 +-
15 files changed, 338 insertions(+), 142 deletions(-)
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index d30612c..a2b6a70 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -434,9 +434,14 @@ ExecuteGrantStmt(GrantStmt *stmt)
if (grantee->rolname == NULL)
istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ {
+ Oid grantee_uid = get_nameid_oid(grantee->rolname, false);
+
+ if (grantee_uid == InvalidOid)
+ grantee_uid = ACL_ID_PUBLIC;
+
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
+ }
}
/*
@@ -919,7 +924,7 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
else
iacls.grantees =
lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ get_nameid_oid(grantee->rolname, false));
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..5117a35 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -678,7 +678,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_nameid_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index ab4ed6c..d5eb4cc 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1099,13 +1081,17 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ useId = get_nameid_oid(stmt->username, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
+ /* XXX: Inhibit none to be used explicitly*/
+ if (!OidIsValid(useId) && stmt->username->idtype != NAMEID_PUBLIC)
+ elog(ERROR, "role \"%s\" does not exist", stmt->username->str);
+
/*
* Check that the user mapping is unique within server.
*/
@@ -1194,9 +1180,13 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ useId = get_nameid_oid(stmt->username, false);
srv = GetForeignServerByName(stmt->servername, false);
+ /* XXX: Inhibit none to be used explicitly*/
+ if (!OidIsValid(useId) && stmt->username->idtype != NAMEID_PUBLIC)
+ elog(ERROR, "role \"%s\" does not exist", stmt->username->str);
+
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
ObjectIdGetDatum(useId),
ObjectIdGetDatum(srv->serverid));
@@ -1276,16 +1266,19 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid umId;
ForeignServer *srv;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
+ useId = get_nameid_oid(stmt->username, stmt->missing_ok);
srv = GetForeignServerByName(stmt->servername, true);
- if (stmt->username && !OidIsValid(useId))
+ /* XXX: Inhibit none to be used explicitly*/
+ if (!OidIsValid(useId) && stmt->username->idtype != NAMEID_PUBLIC)
{
+ if (!stmt->missing_ok)
+ elog(ERROR, "role \"%s\" does not exist", stmt->username->str);
/*
* IF EXISTS specified, role not found and not public. Notice this and
* leave.
*/
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
+ elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username->str);
return InvalidOid;
}
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 03f5514..f97183a 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -43,7 +44,7 @@ Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const NameId *authId = stmt->authid;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -59,10 +60,31 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
* Who is supposed to own the new schema?
*/
if (authId)
- owner_uid = get_role_oid(authId, false);
+ {
+ owner_uid = get_nameid_oid(authId, false);
+ if (!OidIsValid(owner_uid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", authId->str)));
+
+ }
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", owner_uid)));
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 714a9f1..27bc760 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3474,7 +3474,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_nameid_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 378e355..0e611f3 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_nameid_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..5c32c3e 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -310,13 +310,6 @@ CreateRole(CreateRoleStmt *stmt)
errmsg("permission denied to create role")));
}
- if (strcmp(stmt->role, "public") == 0 ||
- strcmp(stmt->role, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- stmt->role)));
-
/*
* Check the pg_authid relation to be certain the role doesn't already
* exist.
@@ -481,6 +474,7 @@ AlterRole(AlterRoleStmt *stmt)
HeapTuple tuple,
new_tuple;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,18 +643,25 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
+ roleid = get_nameid_oid(stmt->role, false);
+ if (!OidIsValid(roleid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(tuple);
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", roleid)));
+
+ rolename =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
{
if (!superuser())
@@ -720,12 +721,12 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
-
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
+
/*
* Build an updated tuple, perusing the information just obtained
*/
@@ -794,7 +795,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,11 +842,11 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
+ AddRoleMems(rolename, roleid,
rolemembers, roleNamesToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
+ DelRoleMems(rolename, roleid,
rolemembers, roleNamesToIds(rolemembers),
false);
@@ -870,12 +871,20 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ roleid = get_nameid_oid(stmt->role, false);
+
+ if (!OidIsValid(roleid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
+
+
+ roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roletuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ errmsg("invalid role oid: %u", roleid)));
roleid = HeapTupleGetOid(roletuple);
@@ -1163,13 +1172,6 @@ RenameRole(const char *oldname, const char *newname)
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role \"%s\" already exists", newname)));
- if (strcmp(newname, "public") == 0 ||
- strcmp(newname, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- newname)));
-
/*
* createrole is enough privilege unless you want to mess with a superuser
*/
@@ -1240,7 +1242,7 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_nameid_oid(stmt->grantor, false);
else
grantor = GetUserId();
@@ -1335,7 +1337,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_nameid_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1360,8 +1362,8 @@ roleNamesToIds(List *memberNames)
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ NameId *rolename = (NameId*) lfirst(l);
+ Oid roleid = get_nameid_oid(rolename, false);
result = lappend_oid(result, roleid);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 7b51d33..6a7efec 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2470,6 +2470,17 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static NameId *
+_copyNameId(const NameId *from)
+{
+ NameId *newnode = makeNode(NameId);
+
+ COPY_SCALAR_FIELD(idtype);
+ COPY_STRING_FIELD(str);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2616,6 +2627,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2660,7 +2672,7 @@ _copyPrivGrantee(const PrivGrantee *from)
{
PrivGrantee *newnode = makeNode(PrivGrantee);
- COPY_STRING_FIELD(rolname);
+ COPY_NODE_FIELD(rolname);
return newnode;
}
@@ -2696,7 +2708,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3003,7 +3015,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3388,7 +3400,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3525,7 +3537,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(username);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3537,7 +3549,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(username);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3549,7 +3561,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(username);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3662,7 +3674,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3674,7 +3686,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3735,7 +3747,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authid);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3820,7 +3832,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4703,6 +4715,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_NameId:
+ retval = _copyNameId(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d5db71d..407d229 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -971,6 +971,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,7 +1010,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
static bool
_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
{
- COMPARE_STRING_FIELD(rolname);
+ COMPARE_NODE_FIELD(rolname);
return true;
}
@@ -1039,7 +1040,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1292,7 +1293,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1614,7 +1615,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1731,7 +1732,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(username);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1741,7 +1742,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(username);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1751,7 +1752,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(username);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1849,7 +1850,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1859,7 +1860,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1910,7 +1911,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authid);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1981,7 +1982,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2453,6 +2454,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalNameId(const NameId *a, const NameId *b)
+{
+ COMPARE_SCALAR_FIELD(idtype);
+ COMPARE_STRING_FIELD(str);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3163,6 +3173,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_NameId:
+ retval = _equalNameId(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bd180e7..d523776 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -192,6 +192,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
int ival;
char *str;
const char *keyword;
+ NameId *nameid;
char chr;
bool boolean;
@@ -291,7 +292,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
+%type <nameid> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,7 +475,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <nameid> RoleId opt_granted_by
+%type <str> opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -494,7 +496,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <nameid> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -864,8 +867,14 @@ CreateRoleStmt:
CREATE ROLE RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ NameId *nid = $3;
+ if (nid->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_ROLE;
- n->role = $3;
+ n->role = nid->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1021,8 +1030,14 @@ CreateUserStmt:
CREATE USER RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ NameId *nid = $3;
+ if (nid->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_USER;
- n->role = $3;
+ n->role = nid->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1164,8 +1179,14 @@ CreateGroupStmt:
CREATE GROUP_P RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ NameId *nid = $3;
+ if (nid->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_GROUP;
- n->role = $3;
+ n->role = nid->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1231,10 +1252,7 @@ CreateSchemaStmt:
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
+ n->schemaname = $3;
n->authid = $5;
n->schemaElts = $6;
n->if_not_exists = false;
@@ -1254,10 +1272,7 @@ CreateSchemaStmt:
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
+ n->schemaname = $6;
n->authid = $8;
if ($9 != NIL)
ereport(ERROR,
@@ -2263,7 +2278,7 @@ alter_table_cmd:
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3727,7 +3742,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleId { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4458,9 +4473,19 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
/* User mapping authorization identifier */
auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+ RoleId
+ { $$ = $1; }
+ /*
+ * The keyword USER won't be appear in other syntxes so it is
+ * processed here, not at RoleId.
+ */
+ | USER
+ {
+ NameId *n = makeNode(NameId);
+ n->idtype = NAMEID_CURRENT_USER;
+ n->str = $1;
+ $$ = n;
+ }
;
/*****************************************************************************
@@ -5403,7 +5428,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleId
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6221,21 +6246,27 @@ grantee_list:
grantee: RoleId
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
+ NameId *nid = $1;
+ if (nid->idtype == NAMEID_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ nid->str)));
+ n->rolname = nid;
$$ = (Node *)n;
}
| GROUP_P RoleId
+ /* Treat GROUP PUBLIC as a synonym for PUBLIC */
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
+ NameId *nid = $2;
+
+ if (nid->idtype == NAMEID_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ nid->str)));
+ n->rolname = nid;
$$ = (Node *)n;
}
;
@@ -7340,9 +7371,19 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER GROUP_P RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ NameId *nold = $3;
+ NameId *nnew = $6;
+ if (nold->idtype != NAMEID_CSTRING ||
+ nnew->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->idtype != NAMEID_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
@@ -7640,18 +7681,38 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER ROLE RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ NameId *nold = $3;
+ NameId *nnew = $6;
+ if (nold->idtype != NAMEID_CSTRING ||
+ nnew->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->idtype != NAMEID_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
| ALTER USER RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ NameId *nold = $3;
+ NameId *nnew = $6;
+ if (nold->idtype != NAMEID_CSTRING ||
+ nnew->idtype != NAMEID_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->idtype != NAMEID_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
@@ -10716,7 +10777,7 @@ opt_float: '(' Iconst ')'
if ($2 < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("precision for type float must be at least 1 bit"),
+ errmsg("recision for type float must be at least 1 bit"),
parser_errposition(@2)));
else if ($2 <= 24)
$$ = SystemTypeName("float4");
@@ -12946,12 +13007,45 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
+RoleId: NonReservedWord
+ {
+ /*
+ * The name "public" and "none" are decided not to be
+ * keywords. They cannot be used as identifier by any
+ * means as the result.
+ */
+ NameId *n = makeNode(NameId);
+ char *w = pstrdup($1);
+ if (strcmp(w, "public") == 0)
+ n->idtype = NAMEID_PUBLIC;
+ else if (strcmp(w, "none") == 0)
+ n->idtype = NAMEID_NONE;
+ else
+ n->idtype = NAMEID_CSTRING;
+ n->str = w;
+ $$ = n;
+ }
+ | CURRENT_USER
+ {
+ NameId *n = makeNode(NameId);
+ n->idtype = NAMEID_CURRENT_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ | SESSION_USER
+ {
+ NameId *n = makeNode(NameId);
+ n->idtype = NAMEID_SESSION_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ ;
+
role_list: RoleId
- { $$ = list_make1(makeString($1)); }
+ { $$ = list_make1($1); }
| role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
+ { $$ = lappend($1, $3); }
;
SignedIconst: Iconst { $$ = $1; }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 7c1939f..6753aea 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ NameId *authid; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index dc6eb2c..f160dd1 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,34 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+Oid
+get_nameid_oid(const NameId *rolname, bool missing_ok)
+{
+ Oid oid;
+
+ switch (rolname->idtype)
+ {
+ case NAMEID_CSTRING:
+ oid = get_role_oid(rolname->str, missing_ok);
+ break;
+ case NAMEID_CURRENT_USER:
+ oid = GetUserId();
+ break;
+ case NAMEID_SESSION_USER:
+ oid = GetSessionUserId();
+ break;
+ case NAMEID_PUBLIC:
+ case NAMEID_NONE:
+ /*
+ * XXX: this returning oid cannot be distinguised with not found in
+ * get_role_oid when messimg_ok.
+ */
+ oid = InvalidOid;
+ break;
+ default:
+ elog(ERROR, "Unexpected nameid for role: %d", rolname->idtype);
+ }
+
+ return oid;
+}
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 154d943..0393ea6 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -410,6 +410,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_NameId,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3e4f815..1a0c35d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -278,6 +278,25 @@ typedef struct CollateClause
} CollateClause;
/*
+ * NameId - Stroes arbitrary string or predefined id number
+ */
+typedef enum NameIdTypes
+{
+ NAMEID_CSTRING,
+ NAMEID_CURRENT_USER,
+ NAMEID_SESSION_USER,
+ NAMEID_PUBLIC,
+ NAMEID_NONE
+} NameIdTypes;
+
+typedef struct NameId
+{
+ NodeTag type;
+ NameIdTypes idtype; /* Type of this identifier */
+ char *str; /* Will be filled only for NAMEID_CSTRING */
+} NameId;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1254,7 +1273,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ NameId *authid; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1353,7 +1372,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ NameId *newowner; /* new owner could be special values */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1433,7 +1453,7 @@ typedef struct GrantStmt
typedef struct PrivGrantee
{
NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
+ NameId *rolname; /* if NULL then PUBLIC */
} PrivGrantee;
/*
@@ -1478,7 +1498,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ NameId *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1690,7 +1710,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ NameId *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1816,7 +1836,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ NameId *username; /* username or PUBLIC/CURRENT_USER */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1824,7 +1844,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ NameId *username; /* username or PUBLIC/CURRENT_USER */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1832,7 +1852,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ NameId *username; /* username or PUBLIC/CURRENT_USER */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1982,7 +2002,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ NameId *role; /* role name */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1990,7 +2010,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ NameId *role; /* role name */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2365,7 +2385,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ NameId *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2813,7 +2833,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ NameId *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index a8e3164..0707f6c 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -229,7 +229,7 @@ extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
extern Oid get_role_oid(const char *rolname, bool missing_ok);
extern Oid get_role_oid_or_public(const char *rolname);
-
+extern Oid get_nameid_oid(const NameId *rolname, bool missing_ok);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
Oid *grantorId, AclMode *grantOptions);
--
2.1.0.GIT
Kyotaro HORIGUCHI wrote:
- Storage for new information
The new struct NameId stores an identifier which telling what it
logically is using the new enum NameIdTypes.
I think NameId is a bad name for this. My point is that NameId, as it
stands, might be a name for anything, not just a role; and the object it
identifies is not an Id either. Maybe RoleSpec? Do we need a public_ok
argument to get_nameid_oid() (get a better name for this function too)
so that callers don't have to check for InvalidOid argument? I think
the arrangement you propose is not very convenient; it'd be best to
avoid duplicating the check for InvalidOid in all callers of the new
function, particularly where there was no check before.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hi, this is revised version.
Kyotaro HORIGUCHI wrote:
- Storage for new information
The new struct NameId stores an identifier which telling what it
logically is using the new enum NameIdTypes.I think NameId is a bad name for this. My point is that NameId, as it
stands, might be a name for anything, not just a role; and the object it
identifies is not an Id either. Maybe RoleSpec?
Yeah! I felt it no good even if it were a generic type for
various "Name of something or its oid". RoleSpec sounds much better.
Do we need a public_ok
argument to get_nameid_oid() (get a better name for this function too)
Maybe get_rolespec_oid() as a name ofter its parameter type?
so that callers don't have to check for InvalidOid argument? I think
the arrangement you propose is not very convenient; it'd be best to
avoid duplicating the check for InvalidOid in all callers of the new
function, particularly where there was no check before.
I agree that It'd be better keeping away from duplicated
InvalidOid checks, but public_ok seems a bit myopic. Since
there's no reasonable border between functions accepting 'public'
and others, such kind of solution would not be reasonable..
What about checking it being a PUBLIC or not *before* calling
get_rolespec_oid()?
The attached patch modified in the following points.
- rename NameId to RoleSpec and NameIdType to RoleSpecTypes.
- rename get_nameid_oid() to get_rolespec_oid().
- rename roleNamesToIds() to roleSpecsToIds().
- some struct members are changed such as authname to authrole.
- check if rolespec is "public" or not before calling get_rolespec_oid()
- ExecAlterDefaultPrivilegesStmt and ExecuteGrantStmt does
slightly different things about ACL_ID_PUBLIC but I unified it
to the latter.
- rebased to the current master
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
CreateStmt->authrole = NULL => ?
Attachments:
0001-ALTER-USER-CURRENT_USER-v3.patchtext/x-patch; charset=us-asciiDownload
>From 307249654c97b6449261febbfd84190fbad9111d Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 14 Nov 2014 17:37:22 +0900
Subject: [PATCH] ALTER USER CURRENT_USER v3
---
src/backend/catalog/aclchk.c | 30 +++---
src/backend/commands/alter.c | 2 +-
src/backend/commands/extension.c | 2 +-
src/backend/commands/foreigncmds.c | 57 +++++------
src/backend/commands/schemacmds.c | 30 +++++-
src/backend/commands/tablecmds.c | 4 +-
src/backend/commands/tablespace.c | 2 +-
src/backend/commands/user.c | 86 +++++++++--------
src/backend/nodes/copyfuncs.c | 37 +++++---
src/backend/nodes/equalfuncs.c | 35 ++++---
src/backend/parser/gram.y | 190 +++++++++++++++++++++++++++----------
src/backend/parser/parse_utilcmd.c | 4 +-
src/backend/utils/adt/acl.c | 34 +++++++
src/include/commands/user.h | 2 +-
src/include/nodes/nodes.h | 1 +
src/include/nodes/parsenodes.h | 48 +++++++---
src/include/utils/acl.h | 2 +-
17 files changed, 385 insertions(+), 181 deletions(-)
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index d30612c..24811c6 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -430,13 +430,16 @@ ExecuteGrantStmt(GrantStmt *stmt)
foreach(cell, stmt->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ /* "public" is mapped to ACL_ID_PUBLIC */
+ if (grantee->role->roltype != ROLESPEC_PUBLIC)
+ {
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ if (!OidIsValid(grantee_uid))
+ grantee_uid = ACL_ID_PUBLIC;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -913,13 +916,16 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
foreach(cell, action->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ /* "public" is mapped to ACL_ID_PUBLIC */
+ if (grantee->role->roltype != ROLESPEC_PUBLIC)
+ {
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ if (!OidIsValid(grantee_uid))
+ grantee_uid = ACL_ID_PUBLIC;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..c53d4e5 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -678,7 +678,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 9a0afa4..52d4190 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index ab4ed6c..d4c4442 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1090,7 +1072,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
Datum values[Natts_pg_user_mapping];
bool nulls[Natts_pg_user_mapping];
HeapTuple tuple;
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ObjectAddress myself;
ObjectAddress referenced;
@@ -1099,7 +1081,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1188,13 +1172,16 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
Datum repl_val[Natts_pg_user_mapping];
bool repl_null[Natts_pg_user_mapping];
bool repl_repl[Natts_pg_user_mapping];
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ForeignServer *srv;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1272,23 +1259,29 @@ Oid
RemoveUserMapping(DropUserMappingStmt *stmt)
{
ObjectAddress object;
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ForeignServer *srv;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
- if (stmt->username && !OidIsValid(useId))
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ stmt->user->str);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 03f5514..3420d2d 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,8 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
+ const RoleSpec *authrole = stmt->authrole;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +59,32 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (authrole)
+ {
+ owner_uid = get_rolespec_oid(authrole, false);
+ if (!OidIsValid(owner_uid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", authrole->str)));
+
+ }
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", owner_uid)));
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 714a9f1..ce58196 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3474,7 +3474,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9330,7 +9330,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 616308b..6025dc6 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..377c7c6 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -310,13 +310,6 @@ CreateRole(CreateRoleStmt *stmt)
errmsg("permission denied to create role")));
}
- if (strcmp(stmt->role, "public") == 0 ||
- strcmp(stmt->role, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- stmt->role)));
-
/*
* Check the pg_authid relation to be certain the role doesn't already
* exist.
@@ -445,10 +438,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -481,6 +474,7 @@ AlterRole(AlterRoleStmt *stmt)
HeapTuple tuple,
new_tuple;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,18 +643,25 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
+ roleid = get_rolespec_oid(stmt->role, false);
+ if (!OidIsValid(roleid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(tuple);
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", roleid)));
+
+ rolename =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
{
if (!superuser())
@@ -720,12 +721,12 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
-
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
+
/*
* Build an updated tuple, perusing the information just obtained
*/
@@ -794,7 +795,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +842,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,12 +871,20 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ roleid = get_rolespec_oid(stmt->role, false);
+
+ if (!OidIsValid(roleid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
+
+
+ roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roletuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ errmsg("invalid role oid: %u", roleid)));
roleid = HeapTupleGetOid(roletuple);
@@ -1163,13 +1172,6 @@ RenameRole(const char *oldname, const char *newname)
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role \"%s\" already exists", newname)));
- if (strcmp(newname, "public") == 0 ||
- strcmp(newname, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- newname)));
-
/*
* createrole is enough privilege unless you want to mess with a superuser
*/
@@ -1240,11 +1242,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1295,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1319,7 +1321,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1335,7 +1337,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1353,15 +1355,15 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
* in the same order.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ RoleSpec *rolespec = (RoleSpec*) lfirst(l);
+ Oid roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e76b5b3..effb062 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2493,6 +2493,17 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roltype);
+ COPY_STRING_FIELD(str);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2639,6 +2650,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2683,7 +2695,7 @@ _copyPrivGrantee(const PrivGrantee *from)
{
PrivGrantee *newnode = makeNode(PrivGrantee);
- COPY_STRING_FIELD(rolname);
+ COPY_NODE_FIELD(role);
return newnode;
}
@@ -2719,7 +2731,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3026,7 +3038,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3411,7 +3423,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3548,7 +3560,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3560,7 +3572,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3572,7 +3584,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3685,7 +3697,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3697,7 +3709,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3758,7 +3770,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3843,7 +3855,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4729,6 +4741,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d5db71d..42a7f53 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -971,6 +971,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,7 +1010,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
static bool
_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
{
- COMPARE_STRING_FIELD(rolname);
+ COMPARE_NODE_FIELD(role);
return true;
}
@@ -1039,7 +1040,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1292,7 +1293,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1614,7 +1615,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1731,7 +1732,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1741,7 +1742,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1751,7 +1752,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1849,7 +1850,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1859,7 +1860,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1910,7 +1911,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1981,7 +1982,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2453,6 +2454,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roltype);
+ COMPARE_STRING_FIELD(str);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3163,6 +3173,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bd180e7..4d9e374 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -192,6 +192,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
int ival;
char *str;
const char *keyword;
+ RoleSpec *rolespec;
char chr;
bool boolean;
@@ -291,7 +292,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
+%type <rolespec> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,7 +475,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <rolespec> RoleId opt_granted_by
+%type <str> opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -494,7 +496,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <rolespec> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -864,8 +867,14 @@ CreateRoleStmt:
CREATE ROLE RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ RoleSpec *rolspc = $3;
+ if (rolspc->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_ROLE;
- n->role = $3;
+ n->role = rolspc->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1021,8 +1030,14 @@ CreateUserStmt:
CREATE USER RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ RoleSpec *rolspc = $3;
+ if (rolspc->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_USER;
- n->role = $3;
+ n->role = rolspc->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1164,8 +1179,14 @@ CreateGroupStmt:
CREATE GROUP_P RoleId opt_with OptRoleList
{
CreateRoleStmt *n = makeNode(CreateRoleStmt);
+ RoleSpec *rolspc = $3;
+ if (rolspc->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(@3)));
n->stmt_type = ROLESTMT_GROUP;
- n->role = $3;
+ n->role = rolspc->str;
n->options = $5;
$$ = (Node *)n;
}
@@ -1231,11 +1252,8 @@ CreateSchemaStmt:
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1245,7 +1263,7 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1254,11 +1272,8 @@ CreateSchemaStmt:
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1273,7 +1288,7 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2263,7 +2278,7 @@ alter_table_cmd:
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3727,7 +3742,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleId { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4449,7 +4464,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4458,9 +4473,19 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
/* User mapping authorization identifier */
auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+ RoleId
+ { $$ = $1; }
+ /*
+ * The keyword USER won't be appear in other syntxes so it is
+ * processed here, not at RoleId.
+ */
+ | USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_CURRENT_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
;
/*****************************************************************************
@@ -4473,7 +4498,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4481,7 +4506,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4498,7 +4523,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -5403,7 +5428,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleId
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6221,21 +6246,27 @@ grantee_list:
grantee: RoleId
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
+ RoleSpec *rolspc = $1;
+ if (rolspc->roltype == ROLESPEC_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ rolspc->str)));
+ n->role = rolspc;
$$ = (Node *)n;
}
| GROUP_P RoleId
+ /* Treat GROUP PUBLIC as a synonym for PUBLIC */
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
+ RoleSpec *rolspc = $2;
+
+ if (rolspc->roltype == ROLESPEC_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ rolspc->str)));
+ n->role = rolspc;
$$ = (Node *)n;
}
;
@@ -7340,9 +7371,19 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER GROUP_P RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ RoleSpec *nold = $3;
+ RoleSpec *nnew = $6;
+ if (nold->roltype != ROLESPEC_CSTRING ||
+ nnew->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->roltype != ROLESPEC_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
@@ -7640,18 +7681,38 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
| ALTER ROLE RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ RoleSpec *nold = $3;
+ RoleSpec *nnew = $6;
+ if (nold->roltype != ROLESPEC_CSTRING ||
+ nnew->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->roltype != ROLESPEC_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
| ALTER USER RoleId RENAME TO RoleId
{
RenameStmt *n = makeNode(RenameStmt);
+ RoleSpec *nold = $3;
+ RoleSpec *nnew = $6;
+ if (nold->roltype != ROLESPEC_CSTRING ||
+ nnew->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("role name should not be a keyword nor reserved name."),
+ parser_errposition(
+ nold->roltype != ROLESPEC_CSTRING ?
+ @3 : @6)));
n->renameType = OBJECT_ROLE;
- n->subname = $3;
- n->newname = $6;
+ n->subname = nold->str;
+ n->newname = nnew->str;
n->missing_ok = false;
$$ = (Node *)n;
}
@@ -10716,7 +10777,7 @@ opt_float: '(' Iconst ')'
if ($2 < 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("precision for type float must be at least 1 bit"),
+ errmsg("recision for type float must be at least 1 bit"),
parser_errposition(@2)));
else if ($2 <= 24)
$$ = SystemTypeName("float4");
@@ -12946,12 +13007,45 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
+RoleId: NonReservedWord
+ {
+ /*
+ * The name "public" and "none" are decided not to be
+ * keywords. They cannot be used as identifier by any
+ * means as the result.
+ */
+ RoleSpec *n = makeNode(RoleSpec);
+ char *w = pstrdup($1);
+ if (strcmp(w, "public") == 0)
+ n->roltype = ROLESPEC_PUBLIC;
+ else if (strcmp(w, "none") == 0)
+ n->roltype = ROLESPEC_NONE;
+ else
+ n->roltype = ROLESPEC_CSTRING;
+ n->str = w;
+ $$ = n;
+ }
+ | CURRENT_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_CURRENT_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ | SESSION_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_SESSION_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ ;
+
role_list: RoleId
- { $$ = list_make1(makeString($1)); }
+ { $$ = list_make1($1); }
| role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
+ { $$ = lappend($1, $3); }
;
SignedIconst: Iconst { $$ = $1; }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 7c1939f..1edc112 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2687,7 +2687,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index dc6eb2c..4a1110e 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,37 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+Oid
+get_rolespec_oid(const RoleSpec *rolname, bool missing_ok)
+{
+ Oid oid;
+
+ switch (rolname->roltype)
+ {
+ case ROLESPEC_CSTRING:
+ oid = get_role_oid(rolname->str, missing_ok);
+ break;
+ case ROLESPEC_CURRENT_USER:
+ oid = GetUserId();
+ break;
+ case ROLESPEC_SESSION_USER:
+ oid = GetSessionUserId();
+ break;
+
+ /* special roles which should not exist */
+ case ROLESPEC_PUBLIC:
+ case ROLESPEC_NONE:
+ if (!missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", rolname->str)));
+ oid = InvalidOid;
+ break;
+
+ default:
+ elog(ERROR, "Unexpected nameid for role: %d", rolname->roltype);
+ }
+
+ return oid;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern Oid RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index bc71fea..fdb217d 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3e4f815..02d4c88 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -278,6 +278,29 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - Stroes role name or id of some special values.
+ *
+ * "public" and "none" are the special role which cannot be used as role name
+ * from historical reasons.
+ */
+typedef enum RoleSpecTypes
+{
+ ROLESPEC_CSTRING, /* role name is stored in str */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC, /* role name is "public", a special value */
+ ROLESPEC_NONE /* role name is "none", a special value and this
+ * is simply unusable at all. */
+} RoleSpecTypes;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecTypes roltype; /* Type of this rolespec */
+ char *str; /* Will be filled only for ROLESPEC_CSTRING */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1254,7 +1277,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ RoleSpec *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1353,7 +1376,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ RoleSpec *newowner; /* new owner could be special values */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1433,7 +1457,7 @@ typedef struct GrantStmt
typedef struct PrivGrantee
{
NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
+ RoleSpec *role; /* if NULL then PUBLIC */
} PrivGrantee;
/*
@@ -1478,7 +1502,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ RoleSpec *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1690,7 +1714,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ RoleSpec *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1816,7 +1840,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1824,7 +1848,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1832,7 +1856,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1982,7 +2006,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1990,7 +2014,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2365,7 +2389,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ RoleSpec *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2813,7 +2837,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ RoleSpec *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index a8e3164..2863183 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -229,7 +229,7 @@ extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
extern Oid get_role_oid(const char *rolname, bool missing_ok);
extern Oid get_role_oid_or_public(const char *rolname);
-
+extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
Oid *grantorId, AclMode *grantOptions);
--
2.1.0.GIT
On Fri, Nov 14, 2014 at 5:39 PM, Kyotaro HORIGUCHI
<horiguchi.kyotaro@lab.ntt.co.jp> wrote:
Hi, this is revised version.
Kyotaro HORIGUCHI wrote:
- Storage for new information
The new struct NameId stores an identifier which telling what it
logically is using the new enum NameIdTypes.I think NameId is a bad name for this. My point is that NameId, as it
stands, might be a name for anything, not just a role; and the object it
identifies is not an Id either. Maybe RoleSpec?Yeah! I felt it no good even if it were a generic type for
various "Name of something or its oid". RoleSpec sounds much better.Do we need a public_ok
argument to get_nameid_oid() (get a better name for this function too)Maybe get_rolespec_oid() as a name ofter its parameter type?
so that callers don't have to check for InvalidOid argument? I think
the arrangement you propose is not very convenient; it'd be best to
avoid duplicating the check for InvalidOid in all callers of the new
function, particularly where there was no check before.I agree that It'd be better keeping away from duplicated
InvalidOid checks, but public_ok seems a bit myopic. Since
there's no reasonable border between functions accepting 'public'
and others, such kind of solution would not be reasonable..What about checking it being a PUBLIC or not *before* calling
get_rolespec_oid()?The attached patch modified in the following points.
- rename NameId to RoleSpec and NameIdType to RoleSpecTypes.
- rename get_nameid_oid() to get_rolespec_oid().
- rename roleNamesToIds() to roleSpecsToIds().
- some struct members are changed such as authname to authrole.
- check if rolespec is "public" or not before calling get_rolespec_oid()
- ExecAlterDefaultPrivilegesStmt and ExecuteGrantStmt does
slightly different things about ACL_ID_PUBLIC but I unified it
to the latter.
- rebased to the current master
A new patch has been sent here but no review occurred, hence moving
this item to CF 2014-12.
--
Michael
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Thank you.
A new patch has been sent here but no review occurred, hence moving
this item to CF 2014-12.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Looking at this a bit, I'm not sure completely replacing RoleId with a
node is the best idea; some of the users of that production in the
grammar are okay with accepting only normal strings as names, and don't
need all the CURRENT_USER etc stuff. Maybe we need a new production,
say RoleSpec, and we modify the few productions that need the extra
flexibility? For instance we could have ALTER USER RoleSpec instead of
ALTER USER RoleId. But we would keep CREATE USER RoleId, because it
doesn't make any sense to accept CREATE USER CURRENT_USER.
I think that would lead to a less invasive patch also.
Am I making sense?
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello, thank you for the comment.
Looking at this a bit, I'm not sure completely replacing RoleId with a
node is the best idea; some of the users of that production in the
grammar are okay with accepting only normal strings as names, and don't
need all the CURRENT_USER etc stuff.
You're right. the productions don't need RoleSpec already uses
char* for the role member in its *Stmt structs. I might have done
a bit too much.
Adding new nonterminal RoleId and using it makes a bit duplicate
of check code for "public"/"none" and others but removes other
redundant check for "!= CSTRING" from some production, CREATE
ROLE/USER/GROUP, ALTER ROLE/USER/GROUP RENAME.
RoleId in the patch still has rule components for CURRENT_USER,
SESSION_USER, and CURRENT_ROLE. Without them, the parser prints
an error ununderstandable to users.
| =# alter role current_user rename to "PuBlic";
| ERROR: syntax error at or near "rename"
| LINE 1: alter role current_user rename to "PuBlic";
| ^
With the components, the error message becomes like this.
| =# alter role current_role rename to "PuBlic";
| ERROR: reserved word cannot be used
| LINE 1: alter role current_role rename to "PuBlic";
| ^
Maybe we need a new production,
say RoleSpec, and we modify the few productions that need the extra
flexibility? For instance we could have ALTER USER RoleSpec instead of
ALTER USER RoleId. But we would keep CREATE USER RoleId, because it
doesn't make any sense to accept CREATE USER CURRENT_USER.
I think that would lead to a less invasive patch also.
Am I making sense?
I think I did what you expected. It was good as the code got
simpler but the invasive-ness dosn't seem to be reduced..
What do you think about this?
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0001-ALTER-USER-CURRENT_USER-v4.patchtext/x-patch; charset=us-asciiDownload
>From d90b7e09968f32a5b543242469fb65e304df3318 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 14 Nov 2014 17:37:22 +0900
Subject: [PATCH] ALTER USER CURRENT_USER v4
Added RoleId for the use in where CURRENT_USER-like sutff is not used.
CREATE ROLE/USER/GROUP, ALTER ROLE/USER/GROUP RENAME are changed to
use RoleId.
---
src/backend/catalog/aclchk.c | 30 +++--
src/backend/commands/alter.c | 2 +-
src/backend/commands/extension.c | 2 +-
src/backend/commands/foreigncmds.c | 57 ++++-----
src/backend/commands/schemacmds.c | 30 ++++-
src/backend/commands/tablecmds.c | 4 +-
src/backend/commands/tablespace.c | 2 +-
src/backend/commands/user.c | 86 +++++++-------
src/backend/nodes/copyfuncs.c | 37 ++++--
src/backend/nodes/equalfuncs.c | 35 ++++--
src/backend/parser/gram.y | 229 +++++++++++++++++++++++++------------
src/backend/parser/parse_utilcmd.c | 4 +-
src/backend/utils/adt/acl.c | 34 ++++++
src/include/commands/user.h | 2 +-
src/include/nodes/nodes.h | 1 +
src/include/nodes/parsenodes.h | 48 ++++++--
src/include/utils/acl.h | 2 +-
17 files changed, 400 insertions(+), 205 deletions(-)
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1e3888e..1c90626 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -430,13 +430,16 @@ ExecuteGrantStmt(GrantStmt *stmt)
foreach(cell, stmt->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ /* "public" is mapped to ACL_ID_PUBLIC */
+ if (grantee->role->roltype != ROLESPEC_PUBLIC)
+ {
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ if (!OidIsValid(grantee_uid))
+ grantee_uid = ACL_ID_PUBLIC;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -913,13 +916,16 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
foreach(cell, action->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ /* "public" is mapped to ACL_ID_PUBLIC */
+ if (grantee->role->roltype != ROLESPEC_PUBLIC)
+ {
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ if (!OidIsValid(grantee_uid))
+ grantee_uid = ACL_ID_PUBLIC;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78b54b4..1d8799b 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -679,7 +679,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3b95552..2a8b2a0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index a3aeabb..e2d8a9d 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1090,7 +1072,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
Datum values[Natts_pg_user_mapping];
bool nulls[Natts_pg_user_mapping];
HeapTuple tuple;
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ObjectAddress myself;
ObjectAddress referenced;
@@ -1099,7 +1081,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1188,13 +1172,16 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
Datum repl_val[Natts_pg_user_mapping];
bool repl_null[Natts_pg_user_mapping];
bool repl_repl[Natts_pg_user_mapping];
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ForeignServer *srv;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1272,23 +1259,29 @@ Oid
RemoveUserMapping(DropUserMappingStmt *stmt)
{
ObjectAddress object;
- Oid useId;
+ Oid useId = InvalidOid;
Oid umId;
ForeignServer *srv;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
- if (stmt->username && !OidIsValid(useId))
+ /* "public" is mapped to userId = InvalidOid */
+ if (stmt->user->roltype != ROLESPEC_PUBLIC)
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ stmt->user->str);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index a44dbf4..6667313 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,8 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
+ const RoleSpec *authrole = stmt->authrole;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +59,32 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (authrole)
+ {
+ owner_uid = get_rolespec_oid(authrole, false);
+ if (!OidIsValid(owner_uid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", authrole->str)));
+
+ }
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", owner_uid)));
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 66d5083..8b30a9a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3481,7 +3481,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9361,7 +9361,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index e098b9f..6f255a5 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2210eed..aaf2c25 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -310,13 +310,6 @@ CreateRole(CreateRoleStmt *stmt)
errmsg("permission denied to create role")));
}
- if (strcmp(stmt->role, "public") == 0 ||
- strcmp(stmt->role, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- stmt->role)));
-
/*
* Check the pg_authid relation to be certain the role doesn't already
* exist.
@@ -445,10 +438,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -481,6 +474,7 @@ AlterRole(AlterRoleStmt *stmt)
HeapTuple tuple,
new_tuple;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,18 +643,25 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
+ roleid = get_rolespec_oid(stmt->role, false);
+ if (!OidIsValid(roleid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
- roleid = HeapTupleGetOid(tuple);
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("invalid role oid: %u", roleid)));
+
+ rolename =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+
if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
{
if (!superuser())
@@ -720,12 +721,12 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
-
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
+
/*
* Build an updated tuple, perusing the information just obtained
*/
@@ -794,7 +795,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +842,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,12 +871,20 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+ roleid = get_rolespec_oid(stmt->role, false);
+
+ if (!OidIsValid(roleid))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", stmt->role->str)));
+
+
+ roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(roletuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
+ errmsg("invalid role oid: %u", roleid)));
roleid = HeapTupleGetOid(roletuple);
@@ -1163,13 +1172,6 @@ RenameRole(const char *oldname, const char *newname)
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("role \"%s\" already exists", newname)));
- if (strcmp(newname, "public") == 0 ||
- strcmp(newname, "none") == 0)
- ereport(ERROR,
- (errcode(ERRCODE_RESERVED_NAME),
- errmsg("role name \"%s\" is reserved",
- newname)));
-
/*
* createrole is enough privilege unless you want to mess with a superuser
*/
@@ -1240,11 +1242,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1295,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1319,7 +1321,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1335,7 +1337,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1353,15 +1355,15 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
* in the same order.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ RoleSpec *rolespec = (RoleSpec*) lfirst(l);
+ Oid roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f1a24f5..7a13aa1 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2500,6 +2500,17 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roltype);
+ COPY_STRING_FIELD(str);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2646,6 +2657,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2690,7 +2702,7 @@ _copyPrivGrantee(const PrivGrantee *from)
{
PrivGrantee *newnode = makeNode(PrivGrantee);
- COPY_STRING_FIELD(rolname);
+ COPY_NODE_FIELD(role);
return newnode;
}
@@ -2726,7 +2738,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3033,7 +3045,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3419,7 +3431,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3556,7 +3568,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3568,7 +3580,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3580,7 +3592,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3693,7 +3705,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3705,7 +3717,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3764,7 +3776,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3849,7 +3861,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4735,6 +4747,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 6e8b308..ba6c7a9 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -971,6 +971,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,7 +1010,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
static bool
_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
{
- COMPARE_STRING_FIELD(rolname);
+ COMPARE_NODE_FIELD(role);
return true;
}
@@ -1039,7 +1040,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1292,7 +1293,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1615,7 +1616,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1732,7 +1733,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1742,7 +1743,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1752,7 +1753,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1850,7 +1851,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1860,7 +1861,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1909,7 +1910,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1980,7 +1981,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2452,6 +2453,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roltype);
+ COMPARE_STRING_FIELD(str);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3162,6 +3172,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 36dac29..0e52669 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -192,6 +192,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
int ival;
char *str;
const char *keyword;
+ RoleSpec *rolespec;
char chr;
bool boolean;
@@ -291,7 +292,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
+%type <rolespec> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -473,8 +474,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <boolean> opt_varying opt_timezone opt_no_inherit
%type <ival> Iconst SignedIconst
-%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> Sconst comment_text notify_payload RoleId
+%type <rolespec> RoleSpec opt_granted_by
+%type <str> opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
@@ -494,7 +496,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <rolespec> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -1036,7 +1039,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1052,7 +1055,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleSpec opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1078,7 +1081,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1090,7 +1093,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleSpec SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1179,7 +1182,7 @@ CreateGroupStmt:
*****************************************************************************/
AlterGroupStmt:
- ALTER GROUP_P RoleId add_drop USER role_list
+ ALTER GROUP_P RoleSpec add_drop USER role_list
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1227,15 +1230,12 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1245,20 +1245,17 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1273,7 +1270,7 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2258,12 +2255,12 @@ alter_table_cmd:
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
- /* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3755,7 +3752,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4477,7 +4474,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4486,9 +4483,19 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
/* User mapping authorization identifier */
auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+ RoleSpec
+ { $$ = $1; }
+ /*
+ * The keyword USER won't be appear in other syntxes so it is
+ * processed here, not at RoleSpec.
+ */
+ | USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_CURRENT_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
;
/*****************************************************************************
@@ -4501,7 +4508,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4509,7 +4516,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4526,7 +4533,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -5431,7 +5438,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleSpec
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6347,24 +6354,30 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
+grantee: RoleSpec
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
+ RoleSpec *rolspc = $1;
+ if (rolspc->roltype == ROLESPEC_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ rolspc->str)));
+ n->role = rolspc;
$$ = (Node *)n;
}
- | GROUP_P RoleId
+ | GROUP_P RoleSpec
+ /* Treat GROUP PUBLIC as a synonym for PUBLIC */
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
+ RoleSpec *rolspc = $2;
+
+ if (rolspc->roltype == ROLESPEC_NONE)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as grantee name",
+ rolspc->str)));
+ n->role = rolspc;
$$ = (Node *)n;
}
;
@@ -6437,7 +6450,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -8101,7 +8114,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -8110,7 +8123,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -8118,7 +8131,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -8126,7 +8139,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -8134,7 +8147,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -8142,7 +8155,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -8151,7 +8164,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -8159,7 +8172,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8167,7 +8180,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8176,7 +8189,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8185,7 +8198,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8194,7 +8207,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8202,7 +8215,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8210,7 +8223,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8218,7 +8231,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8226,7 +8239,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8234,7 +8247,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8242,7 +8255,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8250,7 +8263,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -13080,12 +13093,84 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
+RoleId: NonReservedWord
+ {
+ if (strcmp($1, "public") == 0 ||
+ strcmp($1, "none") == 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("reserved word cannot be used"),
+ parser_errposition(@1)));
+ $$ = $1;
+ }
+ | CURRENT_USER
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("reserved word cannot be used"),
+ parser_errposition(@1)));
+ }
+ | SESSION_USER
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("reserved word cannot be used"),
+ parser_errposition(@1)));
+ }
+ | CURRENT_ROLE
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("reserved word cannot be used"),
+ parser_errposition(@1)));
+ }
+ ;
+RoleSpec: NonReservedWord
+ {
+ /*
+ * The name "public" and "none" are decided not to be
+ * keywords. They cannot be used as identifier by any
+ * means as the result.
+ */
+ RoleSpec *n = makeNode(RoleSpec);
+ char *w = pstrdup($1);
+ if (strcmp(w, "public") == 0)
+ n->roltype = ROLESPEC_PUBLIC;
+ else if (strcmp(w, "none") == 0)
+ n->roltype = ROLESPEC_NONE;
+ else
+ n->roltype = ROLESPEC_CSTRING;
+ n->str = w;
+ $$ = n;
+ }
+ | CURRENT_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_CURRENT_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ | SESSION_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_SESSION_USER;
+ n->str = pstrdup($1);
+ $$ = n;
+ }
+ | CURRENT_ROLE
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("reserved word cannot be used"),
+ parser_errposition(@1)));
+ }
+ ;
-role_list: RoleId
- { $$ = list_make1(makeString($1)); }
- | role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
;
SignedIconst: Iconst { $$ = $1; }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 3ccdbb7..6021e43 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2712,7 +2712,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 411d779..4f4716b 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,37 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+Oid
+get_rolespec_oid(const RoleSpec *rolname, bool missing_ok)
+{
+ Oid oid;
+
+ switch (rolname->roltype)
+ {
+ case ROLESPEC_CSTRING:
+ oid = get_role_oid(rolname->str, missing_ok);
+ break;
+ case ROLESPEC_CURRENT_USER:
+ oid = GetUserId();
+ break;
+ case ROLESPEC_SESSION_USER:
+ oid = GetSessionUserId();
+ break;
+
+ /* special roles which should not exist */
+ case ROLESPEC_PUBLIC:
+ case ROLESPEC_NONE:
+ if (!missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", rolname->str)));
+ oid = InvalidOid;
+ break;
+
+ default:
+ elog(ERROR, "Unexpected nameid for role: %d", rolname->roltype);
+ }
+
+ return oid;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern Oid RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 97ef0fc..38469ef 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index b1dfa85..8def76c 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -278,6 +278,29 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - Stroes role name or id of some special values.
+ *
+ * "public" and "none" are the special role which cannot be used as role name
+ * from historical reasons.
+ */
+typedef enum RoleSpecTypes
+{
+ ROLESPEC_CSTRING, /* role name is stored in str */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC, /* role name is "public", a special value */
+ ROLESPEC_NONE /* role name is "none", a special value and this
+ * is simply unusable at all. */
+} RoleSpecTypes;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecTypes roltype; /* Type of this rolespec */
+ char *str; /* Will be filled only for ROLESPEC_CSTRING */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1256,7 +1279,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ RoleSpec *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1355,7 +1378,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ RoleSpec *newowner; /* new owner could be special values */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1435,7 +1459,7 @@ typedef struct GrantStmt
typedef struct PrivGrantee
{
NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
+ RoleSpec *role; /* if NULL then PUBLIC */
} PrivGrantee;
/*
@@ -1480,7 +1504,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ RoleSpec *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1692,7 +1716,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ RoleSpec *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1818,7 +1842,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1826,7 +1850,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1834,7 +1858,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1984,7 +2008,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1992,7 +2016,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2367,7 +2391,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ RoleSpec *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2823,7 +2847,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ RoleSpec *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ab0df6c..1ef5e41 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -229,7 +229,7 @@ extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
extern Oid get_role_oid(const char *rolname, bool missing_ok);
extern Oid get_role_oid_or_public(const char *rolname);
-
+extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
Oid *grantorId, AclMode *grantOptions);
--
2.1.0.GIT
Kyotaro HORIGUCHI wrote:
Hello, thank you for the comment.
Looking at this a bit, I'm not sure completely replacing RoleId with a
node is the best idea; some of the users of that production in the
grammar are okay with accepting only normal strings as names, and don't
need all the CURRENT_USER etc stuff.You're right. the productions don't need RoleSpec already uses
char* for the role member in its *Stmt structs. I might have done
a bit too much.Adding new nonterminal RoleId and using it makes a bit duplicate
of check code for "public"/"none" and others but removes other
redundant check for "!= CSTRING" from some production, CREATE
ROLE/USER/GROUP, ALTER ROLE/USER/GROUP RENAME.
Thanks for doing the fiddly work here. Attached is a new version of
this patch. I simplified some things, including removing those rules
you added to RoleId. It seems to me that this problem:
RoleId in the patch still has rule components for CURRENT_USER,
SESSION_USER, and CURRENT_ROLE. Without them, the parser prints
an error ununderstandable to users.| =# alter role current_user rename to "PuBlic";
| ERROR: syntax error at or near "rename"
| LINE 1: alter role current_user rename to "PuBlic";
| ^
can be fixed without complicating the rest of the stuff simply by using
RoleSpec instead of RoleId and doing the error checks at the RenameStmt
production. Altering the current user and session user is disallowed
downstream, so there's no reason we can't just have gram.y throw the
same error when special node types are used; so we end up passing the
role name only (just as currently) and the error message remains clear.
I couldn't find any further problems with this version of the code,
though I also noticed that a lot of things are not being tested in the
regression tests, such as "create user public" or "alter user none". It
would be good to have tests for such cases, to avoid breaking them
accidentally. If you can spare some time to submit test cases for such
commands, I would be thankful.
I'm pretty sure, thought I haven't tried yet, that we can now remove the
PrivGrantee node completely.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-ALTER-USER-CURRENT_USER-v5.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1e3888e..56cafa8 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -422,21 +422,24 @@ ExecuteGrantStmt(GrantStmt *stmt)
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, stmt->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->role->roltype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ break;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -905,21 +908,24 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
/*
* Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, action->grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ Oid grantee_uid = ACL_ID_PUBLIC;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->role->roltype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid(grantee->role, false);
+ break;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78b54b4..1d8799b 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -679,7 +679,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3b95552..2a8b2a0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 537e31c..83ba840 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1151,7 +1133,10 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (stmt->user->roltype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1246,7 +1231,11 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (stmt->user->roltype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1328,19 +1317,26 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid umId;
ForeignServer *srv;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
- if (stmt->username && !OidIsValid(useId))
+ if (stmt->user->roltype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ stmt->user->rolname);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index d98da0d..2b6400d 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -129,13 +129,7 @@ parse_policy_command(const char *cmd_name)
/*
* policy_role_list_to_array
- * helper function to convert a list of role names in to an array of
- * role ids.
- *
- * Note: If PUBLIC is provided as a role name, then ACL_ID_PUBLIC is
- * used as the role id.
- *
- * roles - the list of role names to convert.
+ * helper function to convert a list of RoleSpecs to an array of role ids.
*/
static ArrayType *
policy_role_list_to_array(List *roles)
@@ -162,25 +156,24 @@ policy_role_list_to_array(List *roles)
foreach(cell, roles)
{
- Oid roleid = get_role_oid_or_public(strVal(lfirst(cell)));
+ RoleSpec *spec = lfirst(cell);
/*
* PUBLIC covers all roles, so it only makes sense alone.
*/
- if (roleid == ACL_ID_PUBLIC)
+ if (spec->roltype == ROLESPEC_PUBLIC)
{
if (num_roles != 1)
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ignoring roles specified other than public"),
errhint("All roles are members of the public role.")));
-
- temp_array[0] = ObjectIdGetDatum(roleid);
+ temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
num_roles = 1;
break;
}
else
- temp_array[i++] = ObjectIdGetDatum(roleid);
+ temp_array[i++] = ObjectIdGetDatum(get_rolespec_oid(spec, false));
}
role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index a44dbf4..99329f8 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,8 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
+ const RoleSpec *authrole = stmt->authrole;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +59,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (authrole)
+ owner_uid = get_rolespec_oid(authrole, false);
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for role %u", owner_uid);
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
+
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 07ab4b4..6bde084 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3486,7 +3486,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9367,7 +9367,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 03cc8fe..70cc035 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2210eed..1865dbb 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -445,10 +445,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -480,7 +480,9 @@ AlterRole(AlterRoleStmt *stmt)
TupleDesc pg_authid_dsc;
HeapTuple tuple,
new_tuple;
+ Form_pg_authid authform;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,33 +651,30 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ tuple = get_rolespec_tuple(stmt->role);
+ authform = (Form_pg_authid) GETSTRUCT(tuple);
+ rolename = pstrdup(NameStr(authform->rolname));
roleid = HeapTupleGetOid(tuple);
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
- if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
+ if (authform->rolsuper || issuper >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter superusers")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
+ else if (authform->rolreplication || isreplication >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter replication users")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
+ else if (authform->rolbypassrls || bypassrls >= 0)
{
if (!superuser())
ereport(ERROR,
@@ -720,11 +719,11 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
/*
* Build an updated tuple, perusing the information just obtained
@@ -794,7 +793,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +840,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,13 +869,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ roletuple = get_rolespec_tuple(stmt->role);
roleid = HeapTupleGetOid(roletuple);
/*
@@ -965,7 +958,8 @@ DropRole(DropRoleStmt *stmt)
foreach(item, stmt->roles)
{
- const char *role = strVal(lfirst(item));
+ RoleSpec *rolspec = lfirst(item);
+ char *role;
HeapTuple tuple,
tmp_tuple;
ScanKeyData scankey;
@@ -974,6 +968,12 @@ DropRole(DropRoleStmt *stmt)
SysScanDesc sscan;
Oid roleid;
+ if (rolspec->roltype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot use special role specifier in \"%s\"", "DROP ROLE")));
+ role = rolspec->rolname;
+
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
{
@@ -1240,11 +1240,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1293,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1319,7 +1319,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1335,7 +1335,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1347,22 +1347,24 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/*
- * roleNamesToIds
+ * roleSpecsToIds
*
- * Given a list of role names (as String nodes), generate a list of role OIDs
- * in the same order.
+ * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
+ *
+ * ROLESPEC_PUBLIC is not allowed.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ RoleSpec *rolespec = (RoleSpec *) lfirst(l);
+ Oid roleid;
+ roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
return result;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 9fe8008..d3f8a05 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2504,6 +2504,17 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roltype);
+ COPY_STRING_FIELD(rolname);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2650,6 +2661,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2694,7 +2706,7 @@ _copyPrivGrantee(const PrivGrantee *from)
{
PrivGrantee *newnode = makeNode(PrivGrantee);
- COPY_STRING_FIELD(rolname);
+ COPY_NODE_FIELD(role);
return newnode;
}
@@ -2730,7 +2742,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3038,7 +3050,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3424,7 +3436,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3561,7 +3573,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3573,7 +3585,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3585,7 +3597,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3698,7 +3710,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3710,7 +3722,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3769,7 +3781,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3854,7 +3866,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4740,6 +4752,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fe509b0..11417d4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -973,6 +973,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1011,7 +1012,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
static bool
_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
{
- COMPARE_STRING_FIELD(rolname);
+ COMPARE_NODE_FIELD(role);
return true;
}
@@ -1041,7 +1042,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1295,7 +1296,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1618,7 +1619,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1735,7 +1736,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1745,7 +1746,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1755,7 +1756,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1853,7 +1854,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1863,7 +1864,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1912,7 +1913,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1983,7 +1984,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2455,6 +2456,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roltype);
+ COMPARE_STRING_FIELD(rolname);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3165,6 +3175,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 581f7a1..64e7524 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -143,6 +143,7 @@ static Node *makeBitStringConst(char *str, int location);
static Node *makeNullAConst(int location);
static Node *makeAConst(Value *v, int location);
static Node *makeBoolAConst(bool state, int location);
+static RoleSpec *makeRoleSpec(RoleSpecType type);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
static List *check_func_name(List *names, core_yyscan_t yyscanner);
static List *check_indirection(List *indirection, core_yyscan_t yyscanner);
@@ -192,6 +193,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
int ival;
char *str;
const char *keyword;
+ RoleSpec *rolespec;
char chr;
bool boolean;
@@ -291,7 +293,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,12 +475,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
%type <str> createdb_opt_name
%type <node> var_value zone_value
+%type <rolespec> auth_ident RoleSpec opt_granted_by
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
@@ -494,7 +496,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <rolespec> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -871,7 +874,6 @@ CreateRoleStmt:
}
;
-
opt_with: WITH {}
| WITH_LA {}
| /*EMPTY*/ {}
@@ -1037,7 +1039,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1053,7 +1055,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleSpec opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1079,7 +1081,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1091,7 +1093,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleSpec SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1180,7 +1182,7 @@ CreateGroupStmt:
*****************************************************************************/
AlterGroupStmt:
- ALTER GROUP_P RoleId add_drop USER role_list
+ ALTER GROUP_P RoleSpec add_drop USER role_list
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1228,15 +1230,12 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1246,20 +1245,17 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ /* schema name can be omitted here, too */
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1272,9 +1268,9 @@ CreateSchemaStmt:
| CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* ...but not both */
+ /* ...but not here */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2259,12 +2255,12 @@ alter_table_cmd:
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
- /* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3756,7 +3752,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4478,7 +4474,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4486,10 +4482,8 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
;
/* User mapping authorization identifier */
-auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+auth_ident: RoleSpec { $$ = $1; }
+ | USER { $$ = makeRoleSpec(ROLESPEC_CURRENT_USER); }
;
/*****************************************************************************
@@ -4502,7 +4496,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4510,7 +4504,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4527,7 +4521,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4612,7 +4606,7 @@ RowSecurityOptionalWithCheck:
RowSecurityDefaultToRole:
TO role_list { $$ = $2; }
- | /* EMPTY */ { $$ = list_make1(makeString("public")); }
+ | /* EMPTY */ { $$ = list_make1(makeRoleSpec(ROLESPEC_PUBLIC)); }
;
RowSecurityOptionalToRole:
@@ -5432,7 +5426,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleSpec
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6348,24 +6342,16 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
+grantee: RoleSpec
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
+ n->role = $1;
$$ = (Node *)n;
}
- | GROUP_P RoleId
+ | GROUP_P RoleSpec
{
PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
+ n->role = $2;
$$ = (Node *)n;
}
;
@@ -6438,7 +6424,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -8104,7 +8090,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -8113,7 +8099,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -8121,7 +8107,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -8129,7 +8115,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -8137,7 +8123,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -8145,7 +8131,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -8154,7 +8140,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -8162,7 +8148,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8170,7 +8156,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8179,7 +8165,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8188,7 +8174,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8197,7 +8183,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8205,7 +8191,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8213,7 +8199,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8221,7 +8207,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8229,7 +8215,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8237,7 +8223,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8245,7 +8231,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8253,7 +8239,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -13113,19 +13099,59 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
-
-role_list: RoleId
- { $$ = list_make1(makeString($1)); }
- | role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
- ;
SignedIconst: Iconst { $$ = $1; }
| '+' Iconst { $$ = + $2; }
| '-' Iconst { $$ = - $2; }
;
+/* Role specifications */
+RoleId: NonReservedWord { $$ = $1; };
+
+RoleSpec: NonReservedWord
+ {
+ /*
+ * The name "public" and "none" are decided not to be
+ * keywords. They cannot be used as identifier by any
+ * means as the result.
+ */
+ RoleSpec *n = makeNode(RoleSpec);
+ if (strcmp($1, "public") == 0)
+ n->roltype = ROLESPEC_PUBLIC;
+ else if (strcmp($1, "none") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "none")));
+ }
+ else
+ {
+ n->roltype = ROLESPEC_CSTRING;
+ n->rolname = pstrdup($1);
+ }
+ $$ = n;
+ }
+ | CURRENT_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_CURRENT_USER;
+ $$ = n;
+ }
+ | SESSION_USER
+ {
+ RoleSpec *n = makeNode(RoleSpec);
+ n->roltype = ROLESPEC_SESSION_USER;
+ $$ = n;
+ }
+ ;
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
+ ;
+
/*
* Name classification hierarchy.
*
@@ -13812,6 +13838,19 @@ makeBoolAConst(bool state, int location)
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
+/* makeRoleSpec
+ * Create a RoleSpec with the given type
+ */
+static RoleSpec *
+makeRoleSpec(RoleSpecType type)
+{
+ RoleSpec *spec = (RoleSpec *) makeNode(RoleSpec);
+
+ spec->roltype = type;
+
+ return spec;
+}
+
/* check_qualified_name --- check the result of qualified_name production
*
* It's easiest to let the grammar production for qualified_name allow
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c29f106..db62b17 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2723,7 +2723,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 411d779..632fa71 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,89 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+/*
+ * Given a RoleSpec, return the OID it points 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 RoleSpec *role, bool missing_ok)
+{
+ Oid oid;
+
+ switch (role->roltype)
+ {
+ case ROLESPEC_CSTRING:
+ Assert(role->rolname);
+ oid = get_role_oid(role->rolname, 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->roltype);
+ }
+
+ return oid;
+}
+
+/*
+ * Return the cache tuple corresponding to the RoleSpec. Caller must call
+ * ReleaseSysCache when done with the result tuple.
+ */
+HeapTuple
+get_rolespec_tuple(const RoleSpec *role)
+{
+ HeapTuple tuple;
+
+ switch (role->roltype)
+ {
+ case ROLESPEC_CSTRING:
+ Assert(role->rolname);
+ tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolname));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("role \"%s\" does not exist", role->rolname)));
+ 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->roltype);
+ }
+
+ return tuple;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern Oid RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 97ef0fc..38469ef 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ac13302..4c7fd3f 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -285,6 +285,24 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - a role name or one of a few special values.
+ */
+typedef enum RoleSpecType
+{
+ ROLESPEC_CSTRING, /* role name is stored as a C string */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC /* role name is "public" */
+} RoleSpecType;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecType roltype; /* Type of this rolespec */
+ char *rolname; /* filled only for ROLESPEC_CSTRING */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1263,7 +1281,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ RoleSpec *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1362,7 +1380,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ RoleSpec *newowner; /* new owner could be special values */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1442,7 +1461,7 @@ typedef struct GrantStmt
typedef struct PrivGrantee
{
NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
+ RoleSpec *role;
} PrivGrantee;
/*
@@ -1487,7 +1506,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ RoleSpec *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1699,7 +1718,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ RoleSpec *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1825,7 +1844,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1833,7 +1852,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1841,7 +1860,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ RoleSpec *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1991,7 +2010,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1999,7 +2018,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ RoleSpec *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2375,7 +2394,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ RoleSpec *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2831,7 +2850,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ RoleSpec *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ab0df6c..485013c 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -24,6 +24,7 @@
#ifndef ACL_H
#define ACL_H
+#include "access/htup.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/snapshot.h"
@@ -229,6 +230,8 @@ extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
extern Oid get_role_oid(const char *rolname, bool missing_ok);
extern Oid get_role_oid_or_public(const char *rolname);
+extern Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok);
+extern HeapTuple get_rolespec_tuple(const RoleSpec *role);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
Alvaro Herrera wrote:
Kyotaro HORIGUCHI wrote:
Thanks for doing the fiddly work here. Attached is a new version of
this patch. I simplified some things, including removing those rules
you added to RoleId. It seems to me that this problem:RoleId in the patch still has rule components for CURRENT_USER,
SESSION_USER, and CURRENT_ROLE. Without them, the parser prints
an error ununderstandable to users.| =# alter role current_user rename to "PuBlic";
| ERROR: syntax error at or near "rename"
| LINE 1: alter role current_user rename to "PuBlic";
| ^can be fixed without complicating the rest of the stuff simply by using
RoleSpec instead of RoleId and doing the error checks at the RenameStmt
production.
I tried that but it's way too messy, so I readded them.
I couldn't find any further problems with this version of the code,
though I also noticed that a lot of things are not being tested in the
regression tests, such as "create user public" or "alter user none". It
would be good to have tests for such cases, to avoid breaking them
accidentally. If you can spare some time to submit test cases for such
commands, I would be thankful.
I later noticed that you had already submitted a test.sql file, so I
adopted it as rolenames.sql and added it to the schedule files. I still
have to read through the results and make sure they make sense, so the
expected file is not in this patch.
I made some more changes to the code; unless the tests uncover something
ugly, the code in this patch is what will be committed.
I'm pretty sure, thought I haven't tried yet, that we can now remove the
PrivGrantee node completely.
That's done in the attached.
Documentation is still missing. Are you submitting doc changes soon? I
would like to get this committed.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-ALTER-USER-CURRENT_USER-v6.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1e3888e..e88c8c3 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -421,22 +421,25 @@ ExecuteGrantStmt(GrantStmt *stmt)
istmt.behavior = stmt->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, stmt->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -904,22 +907,25 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
iacls.behavior = action->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, action->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78b54b4..1d8799b 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -679,7 +679,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3b95552..2a8b2a0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 537e31c..adf4c79 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1148,10 +1130,14 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
ObjectAddress referenced;
ForeignServer *srv;
ForeignDataWrapper *fdw;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1243,10 +1229,15 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
Oid useId;
Oid umId;
ForeignServer *srv;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1327,20 +1318,27 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid useId;
Oid umId;
ForeignServer *srv;
+ RoleSpec *role = (RoleSpec *) stmt->user;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
-
- if (stmt->username && !OidIsValid(useId))
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ role->rolename);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index d98da0d..103dd44 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -129,13 +129,7 @@ parse_policy_command(const char *cmd_name)
/*
* policy_role_list_to_array
- * helper function to convert a list of role names in to an array of
- * role ids.
- *
- * Note: If PUBLIC is provided as a role name, then ACL_ID_PUBLIC is
- * used as the role id.
- *
- * roles - the list of role names to convert.
+ * helper function to convert a list of RoleSpecs to an array of role ids.
*/
static ArrayType *
policy_role_list_to_array(List *roles)
@@ -162,25 +156,25 @@ policy_role_list_to_array(List *roles)
foreach(cell, roles)
{
- Oid roleid = get_role_oid_or_public(strVal(lfirst(cell)));
+ RoleSpec *spec = lfirst(cell);
/*
* PUBLIC covers all roles, so it only makes sense alone.
*/
- if (roleid == ACL_ID_PUBLIC)
+ if (spec->roletype == ROLESPEC_PUBLIC)
{
if (num_roles != 1)
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ignoring roles specified other than public"),
errhint("All roles are members of the public role.")));
-
- temp_array[0] = ObjectIdGetDatum(roleid);
+ temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
num_roles = 1;
break;
}
else
- temp_array[i++] = ObjectIdGetDatum(roleid);
+ temp_array[i++] =
+ ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
}
role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index a44dbf4..f6da883 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +58,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (stmt->authrole)
+ owner_uid = get_rolespec_oid(stmt->authrole, false);
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for role %u", owner_uid);
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
+
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 07ab4b4..6bde084 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3486,7 +3486,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9367,7 +9367,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 03cc8fe..70cc035 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2210eed..d4be7b8 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -445,10 +445,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -480,7 +480,9 @@ AlterRole(AlterRoleStmt *stmt)
TupleDesc pg_authid_dsc;
HeapTuple tuple,
new_tuple;
+ Form_pg_authid authform;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,33 +651,30 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ tuple = get_rolespec_tuple(stmt->role);
+ authform = (Form_pg_authid) GETSTRUCT(tuple);
+ rolename = pstrdup(NameStr(authform->rolname));
roleid = HeapTupleGetOid(tuple);
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
- if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
+ if (authform->rolsuper || issuper >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter superusers")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
+ else if (authform->rolreplication || isreplication >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter replication users")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
+ else if (authform->rolbypassrls || bypassrls >= 0)
{
if (!superuser())
ereport(ERROR,
@@ -720,11 +719,11 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
/*
* Build an updated tuple, perusing the information just obtained
@@ -794,7 +793,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +840,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,13 +869,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ roletuple = get_rolespec_tuple(stmt->role);
roleid = HeapTupleGetOid(roletuple);
/*
@@ -965,7 +958,8 @@ DropRole(DropRoleStmt *stmt)
foreach(item, stmt->roles)
{
- const char *role = strVal(lfirst(item));
+ RoleSpec *rolspec = lfirst(item);
+ char *role;
HeapTuple tuple,
tmp_tuple;
ScanKeyData scankey;
@@ -974,6 +968,12 @@ DropRole(DropRoleStmt *stmt)
SysScanDesc sscan;
Oid roleid;
+ if (rolspec->roletype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot use special role specifier in \"%s\"", "DROP ROLE")));
+ role = rolspec->rolename;
+
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
{
@@ -1240,11 +1240,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1293,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1319,7 +1319,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1335,7 +1335,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1347,22 +1347,24 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/*
- * roleNamesToIds
+ * roleSpecsToIds
+ *
+ * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
*
- * Given a list of role names (as String nodes), generate a list of role OIDs
- * in the same order.
+ * ROLESPEC_PUBLIC is not allowed.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ Node *rolespec = (Node *) lfirst(l);
+ Oid roleid;
+ roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
return result;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 9fe8008..3b3c5bd 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2504,6 +2504,17 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roletype);
+ COPY_STRING_FIELD(rolename);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2650,6 +2661,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2689,16 +2701,6 @@ _copyGrantStmt(const GrantStmt *from)
return newnode;
}
-static PrivGrantee *
-_copyPrivGrantee(const PrivGrantee *from)
-{
- PrivGrantee *newnode = makeNode(PrivGrantee);
-
- COPY_STRING_FIELD(rolname);
-
- return newnode;
-}
-
static FuncWithArgs *
_copyFuncWithArgs(const FuncWithArgs *from)
{
@@ -2730,7 +2732,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3038,7 +3040,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3424,7 +3426,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3561,7 +3563,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3573,7 +3575,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3585,7 +3587,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3698,7 +3700,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3710,7 +3712,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3769,7 +3771,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3854,7 +3856,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4728,9 +4730,6 @@ copyObject(const void *from)
case T_CommonTableExpr:
retval = _copyCommonTableExpr(from);
break;
- case T_PrivGrantee:
- retval = _copyPrivGrantee(from);
- break;
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
@@ -4740,6 +4739,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fe509b0..f2ef9e2 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -973,6 +973,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,14 +1010,6 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
}
static bool
-_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
-{
- COMPARE_STRING_FIELD(rolname);
-
- return true;
-}
-
-static bool
_equalFuncWithArgs(const FuncWithArgs *a, const FuncWithArgs *b)
{
COMPARE_NODE_FIELD(funcname);
@@ -1041,7 +1034,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1295,7 +1288,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1618,7 +1611,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1735,7 +1728,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1745,7 +1738,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1755,7 +1748,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1853,7 +1846,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1863,7 +1856,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1912,7 +1905,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1983,7 +1976,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2455,6 +2448,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roletype);
+ COMPARE_STRING_FIELD(rolename);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3153,9 +3155,6 @@ equal(const void *a, const void *b)
case T_CommonTableExpr:
retval = _equalCommonTableExpr(a, b);
break;
- case T_PrivGrantee:
- retval = _equalPrivGrantee(a, b);
- break;
case T_FuncWithArgs:
retval = _equalFuncWithArgs(a, b);
break;
@@ -3165,6 +3164,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 581f7a1..963becf 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -143,6 +143,7 @@ static Node *makeBitStringConst(char *str, int location);
static Node *makeNullAConst(int location);
static Node *makeAConst(Value *v, int location);
static Node *makeBoolAConst(bool state, int location);
+static Node *makeRoleSpec(RoleSpecType type);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
static List *check_func_name(List *names, core_yyscan_t yyscanner);
static List *check_indirection(List *indirection, core_yyscan_t yyscanner);
@@ -291,7 +292,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,12 +474,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
%type <str> createdb_opt_name
%type <node> var_value zone_value
+%type <node> auth_ident RoleSpec opt_granted_by
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
@@ -494,7 +495,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <node> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -871,7 +873,6 @@ CreateRoleStmt:
}
;
-
opt_with: WITH {}
| WITH_LA {}
| /*EMPTY*/ {}
@@ -1037,7 +1038,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1053,7 +1054,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleSpec opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1079,7 +1080,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1091,7 +1092,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleSpec SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1180,7 +1181,7 @@ CreateGroupStmt:
*****************************************************************************/
AlterGroupStmt:
- ALTER GROUP_P RoleId add_drop USER role_list
+ ALTER GROUP_P RoleSpec add_drop USER role_list
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1228,15 +1229,12 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1246,20 +1244,17 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ /* schema name can be omitted here, too */
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1272,9 +1267,9 @@ CreateSchemaStmt:
| CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* ...but not both */
+ /* ...but not here */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2259,12 +2254,12 @@ alter_table_cmd:
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
- /* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3756,7 +3751,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4478,7 +4473,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4486,10 +4481,8 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
;
/* User mapping authorization identifier */
-auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+auth_ident: RoleSpec { $$ = $1; }
+ | USER { $$ = makeRoleSpec(ROLESPEC_CURRENT_USER); }
;
/*****************************************************************************
@@ -4502,7 +4495,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4510,7 +4503,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4527,7 +4520,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4612,7 +4605,7 @@ RowSecurityOptionalWithCheck:
RowSecurityDefaultToRole:
TO role_list { $$ = $2; }
- | /* EMPTY */ { $$ = list_make1(makeString("public")); }
+ | /* EMPTY */ { $$ = list_make1(makeRoleSpec(ROLESPEC_PUBLIC)); }
;
RowSecurityOptionalToRole:
@@ -5432,7 +5425,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleSpec
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6348,26 +6341,9 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
- $$ = (Node *)n;
- }
- | GROUP_P RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
- $$ = (Node *)n;
- }
+grantee:
+ RoleSpec { $$ = $1; }
+ | GROUP_P RoleSpec { $$ = $2; }
;
@@ -6438,7 +6414,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -8104,7 +8080,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -8113,7 +8089,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -8121,7 +8097,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -8129,7 +8105,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -8137,7 +8113,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -8145,7 +8121,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -8154,7 +8130,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -8162,7 +8138,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8170,7 +8146,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8179,7 +8155,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8188,7 +8164,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8197,7 +8173,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8205,7 +8181,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8213,7 +8189,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8221,7 +8197,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8229,7 +8205,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8237,7 +8213,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8245,7 +8221,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8253,7 +8229,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -13113,19 +13089,72 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
-
-role_list: RoleId
- { $$ = list_make1(makeString($1)); }
- | role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
- ;
SignedIconst: Iconst { $$ = $1; }
| '+' Iconst { $$ = + $2; }
| '-' Iconst { $$ = - $2; }
;
+/* Role specifications */
+RoleId: NonReservedWord { $$ = $1; }
+ | CURRENT_USER
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as role name",
+ "CURRENT_USER")));
+ }
+ | SESSION_USER
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s cannot be used as role name",
+ "SESSION_USER")));
+ }
+ ;
+
+RoleSpec: NonReservedWord
+ {
+ /*
+ * "public" and "none" are not keywords, but they must
+ * be treated specially here.
+ */
+ RoleSpec *n;
+ if (strcmp($1, "public") == 0)
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_PUBLIC);
+ n->roletype = ROLESPEC_PUBLIC;
+ }
+ else if (strcmp($1, "none") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "none")));
+ }
+ else
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_CSTRING);
+ n->rolename = pstrdup($1);
+ }
+ $$ = (Node *) n;
+ }
+ | CURRENT_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_CURRENT_USER);
+ }
+ | SESSION_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_SESSION_USER);
+ }
+ ;
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
+ ;
+
/*
* Name classification hierarchy.
*
@@ -13812,6 +13841,19 @@ makeBoolAConst(bool state, int location)
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
+/* makeRoleSpec
+ * Create a RoleSpec with the given type
+ */
+static Node *
+makeRoleSpec(RoleSpecType type)
+{
+ RoleSpec *spec = makeNode(RoleSpec);
+
+ spec->roletype = type;
+
+ return (Node *) spec;
+}
+
/* check_qualified_name --- check the result of qualified_name production
*
* It's easiest to let the grammar production for qualified_name allow
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c29f106..1e6da9c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2723,7 +2723,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = (RoleSpec *) stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 411d779..d4b5364 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,99 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+/*
+ * Given a RoleSpec node, return the OID it points 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 cached HeapTuple it points 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;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern Oid RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 97ef0fc..38469ef 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ac13302..fe44adc 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -285,6 +285,24 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - a role name or one of a few special values.
+ */
+typedef enum RoleSpecType
+{
+ ROLESPEC_CSTRING, /* role name is stored as a C string */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC /* role name is "public" */
+} RoleSpecType;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecType roletype; /* Type of this rolespec */
+ char *rolename; /* filled only for ROLESPEC_CSTRING */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1263,7 +1281,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ Node *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1362,7 +1380,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ Node *newowner; /* RoleSpec */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1434,17 +1453,11 @@ typedef struct GrantStmt
* or plain names (as Value strings) */
List *privileges; /* list of AccessPriv nodes */
/* privileges == NIL denotes ALL PRIVILEGES */
- List *grantees; /* list of PrivGrantee nodes */
+ List *grantees; /* list of RoleSpec nodes */
bool grant_option; /* grant or revoke grant option */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantStmt;
-typedef struct PrivGrantee
-{
- NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
-} PrivGrantee;
-
/*
* Note: FuncWithArgs carries only the types of the input parameters of the
* function. So it is sufficient to identify an existing function, but it
@@ -1487,7 +1500,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ Node *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1699,7 +1712,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ Node *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1825,7 +1838,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1833,7 +1846,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1841,7 +1854,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1991,7 +2004,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1999,7 +2012,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2375,7 +2388,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ Node *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2831,7 +2844,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ Node *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ab0df6c..35f8853 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -24,6 +24,7 @@
#ifndef ACL_H
#define ACL_H
+#include "access/htup.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/snapshot.h"
@@ -227,8 +228,10 @@ extern bool is_member_of_role(Oid member, Oid role);
extern bool is_member_of_role_nosuper(Oid member, Oid role);
extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
-extern Oid get_role_oid(const char *rolname, bool missing_ok);
-extern Oid get_role_oid_or_public(const char *rolname);
+extern Oid get_role_oid(const char *rolename, bool missing_ok);
+extern Oid get_role_oid_or_public(const char *rolename);
+extern Oid get_rolespec_oid(const Node *node, bool missing_ok);
+extern HeapTuple get_rolespec_tuple(const Node *node);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e0ae2f2..6d3b865 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -59,7 +59,7 @@ test: create_index create_view
# ----------
# Another group of parallel tests
# ----------
-test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views
+test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views rolenames
# ----------
# sanity_check does a vacuum, affecting the sort order of SELECT *
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7f762bd..8326894 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -71,6 +71,7 @@ test: typed_table
test: vacuum
test: drop_if_exists
test: updatable_views
+test: rolenames
test: sanity_check
test: errors
test: select
diff --git a/src/test/regress/sql/rolenames.sql b/src/test/regress/sql/rolenames.sql
new file mode 100644
index 0000000..2bc6a30
--- /dev/null
+++ b/src/test/regress/sql/rolenames.sql
@@ -0,0 +1,459 @@
+CREATE OR REPLACE FUNCTION chkrolattr()
+ RETURNS TABLE ("role" name, rolekeyword text, canlogin bool, replication bool)
+ AS $$
+SELECT r.rolname, v.keyword, r.rolcanlogin, r.rolreplication
+ FROM pg_roles r
+ JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'),
+ ('current_user', '-'),
+ ('session_user', '-'),
+ ('Public', '-'),
+ ('None', '-'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ ORDER BY 1;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION chksetconfig()
+ RETURNS TABLE (db name, "role" name, rolkeyword text, setconfig text[])
+ AS $$
+SELECT COALESCE(d.datname, 'ALL'), COALESCE(r.rolname, 'ALL'),
+ COALESCE(v.keyword, '-'), s.setconfig
+ FROM pg_db_role_setting s
+ LEFT JOIN pg_roles r ON (r.oid = s.setrole)
+ LEFT JOIN pg_database d ON (d.oid = s.setdatabase)
+ LEFT JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ORDER BY 1, 2;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION chkumapping()
+ RETURNS TABLE (umname name, umserver name, umoptions text[])
+ AS $$
+SELECT r.rolname, s.srvname, m.umoptions
+ FROM pg_user_mapping m
+ LEFT JOIN pg_roles r ON (r.oid = m.umuser)
+ JOIN pg_foreign_server s ON (s.oid = m.umserver)
+ ORDER BY 2;
+$$ LANGUAGE SQL;
+
+CREATE ROLE "Public";
+CREATE ROLE "None";
+CREATE ROLE "current_user";
+CREATE ROLE "session_user";
+CREATE ROLE "user";
+
+CREATE ROLE current_user; -- error
+CREATE ROLE current_role; -- error
+CREATE ROLE session_user; -- error
+CREATE ROLE user; -- error
+CREATE ROLE all; -- error
+
+CREATE ROLE public; -- error
+CREATE ROLE "public"; -- error
+CREATE ROLE none; -- error
+CREATE ROLE "none"; -- error
+
+CREATE ROLE testrol0 SUPERUSER LOGIN;
+CREATE ROLE testrolx SUPERUSER LOGIN;
+CREATE ROLE testrol2 SUPERUSER;
+CREATE ROLE testrol1 SUPERUSER LOGIN IN ROLE testrol2;
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+-- ALTER ROLE
+BEGIN;
+SELECT * FROM chkrolattr();
+ALTER ROLE CURRENT_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE "current_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE SESSION_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE "session_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER "Public" WITH REPLICATION;
+ALTER USER "None" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER testrol1 WITH NOREPLICATION;
+ALTER USER testrol2 WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ROLLBACK;
+
+ALTER ROLE USER WITH LOGIN; -- error
+ALTER ROLE CURRENT_ROLE WITH LOGIN; --error
+ALTER ROLE ALL WITH REPLICATION; -- error
+ALTER ROLE SESSION_ROLE WITH NOREPLICATION; -- error
+ALTER ROLE PUBLIC WITH NOREPLICATION; -- error
+ALTER ROLE "public" WITH NOREPLICATION; -- error
+ALTER ROLE NONE WITH NOREPLICATION; -- error
+ALTER ROLE "none" WITH NOREPLICATION; -- error
+ALTER ROLE nonexistent WITH NOREPLICATION; -- error
+
+-- ALTER USER
+BEGIN;
+SELECT * FROM chkrolattr();
+ALTER USER CURRENT_USER WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'current_user' WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER SESSION_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'session_user' WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'Public' WITH REPLICATION;
+ALTER USER 'None' WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER testrol1 WITH NOREPLICATION;
+ALTER USER testrol2 WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ROLLBACK;
+
+ALTER USER USER WITH LOGIN; -- error
+ALTER USER CURRENT_ROLE WITH LOGIN; -- error
+ALTER USER ALL WITH REPLICATION; -- error
+ALTER USER SESSION_ROLE WITH NOREPLICATION; -- error
+ALTER USER PUBLIC WITH NOREPLICATION; -- error
+ALTER USER "public" WITH NOREPLICATION; -- error
+ALTER USER NONE WITH NOREPLICATION; -- error
+ALTER USER "none" WITH NOREPLICATION; -- error
+ALTER USER nonexistent WITH NOREPLICATION; -- error
+
+-- ALTER ROLE SET/RESET
+SELECT * FROM chksetconfig();
+ALTER ROLE CURRENT_USER SET application_name to 'FOO';
+ALTER ROLE SESSION_USER SET application_name to 'BAR';
+ALTER ROLE "current_user" SET application_name to 'FOOFOO';
+ALTER ROLE "Public" SET application_name to 'BARBAR';
+ALTER ROLE ALL SET application_name to 'SLAP';
+SELECT * FROM chksetconfig();
+ALTER ROLE testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ALTER ROLE CURRENT_USER RESET application_name;
+ALTER ROLE SESSION_USER RESET application_name;
+ALTER ROLE "current_user" RESET application_name;
+ALTER ROLE "Public" RESET application_name;
+ALTER ROLE ALL RESET application_name;
+SELECT * FROM chksetconfig();
+
+
+ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; -- error
+ALTER ROLE USER SET application_name to 'BOOM'; -- error
+ALTER ROLE PUBLIC SET application_name to 'BOMB'; -- error
+ALTER ROLE nonexistent SET application_name to 'BOMB'; -- error
+
+-- ALTER USER SET/RESET
+SELECT * FROM chksetconfig();
+ALTER USER CURRENT_USER SET application_name to 'FOO';
+ALTER USER SESSION_USER SET application_name to 'BAR';
+ALTER USER "current_user" SET application_name to 'FOOFOO';
+ALTER USER "Public" SET application_name to 'BARBAR';
+ALTER USER ALL SET application_name to 'SLAP';
+SELECT * FROM chksetconfig();
+ALTER USER testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ALTER USER CURRENT_USER RESET application_name;
+ALTER USER SESSION_USER RESET application_name;
+ALTER USER "current_user" RESET application_name;
+ALTER USER "Public" RESET application_name;
+ALTER USER ALL RESET application_name;
+SELECT * FROM chksetconfig();
+
+
+ALTER USER CURRENT_USER SET application_name to 'BAZ'; -- error
+ALTER USER USER SET application_name to 'BOOM'; -- error
+ALTER USER PUBLIC SET application_name to 'BOMB'; -- error
+ALTER USER NONE SET application_name to 'BOMB'; -- error
+ALTER USER nonexistent SET application_name to 'BOMB'; -- error
+
+-- CREAETE SCHEMA
+set client_min_messages to error;
+CREATE SCHEMA newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA newschema5 AUTHORIZATION "Public";
+
+CREATE SCHEMA newschema6 AUTHORIZATION USER; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION PUBLIC; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION "public"; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION NONE; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION nonexistent; -- error
+
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+
+DROP SCHEMA IF EXISTS newschema1;
+DROP SCHEMA IF EXISTS newschema2;
+DROP SCHEMA IF EXISTS newschema3;
+DROP SCHEMA IF EXISTS newschema4;
+DROP SCHEMA IF EXISTS newschema5;
+DROP SCHEMA IF EXISTS newschema6;
+
+CREATE SCHEMA IF NOT EXISTS newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA IF NOT EXISTS newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA IF NOT EXISTS newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA IF NOT EXISTS newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA IF NOT EXISTS newschema5 AUTHORIZATION "Public";
+
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION USER; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION PUBLIC; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION "public"; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION NONE; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION nonexistent; -- error
+
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+
+-- ALTER TABLE OWNER TO
+\c -
+SET SESSION AUTHORIZATION testrol0;
+set client_min_messages to error;
+CREATE TABLE testtab1 (a int);
+CREATE TABLE testtab2 (a int);
+CREATE TABLE testtab3 (a int);
+CREATE TABLE testtab4 (a int);
+CREATE TABLE testtab5 (a int);
+CREATE TABLE testtab6 (a int);
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+ALTER TABLE testtab1 OWNER TO CURRENT_USER;
+ALTER TABLE testtab2 OWNER TO "current_user";
+ALTER TABLE testtab3 OWNER TO SESSION_USER;
+ALTER TABLE testtab4 OWNER TO testrolx;
+ALTER TABLE testtab5 OWNER TO "Public";
+
+ALTER TABLE testtab6 OWNER TO CURRENT_ROLE; -- error
+ALTER TABLE testtab6 OWNER TO USER; --error
+ALTER TABLE testtab6 OWNER TO PUBLIC; -- error
+ALTER TABLE testtab6 OWNER TO "public"; -- error
+ALTER TABLE testtab6 OWNER TO nonexistent; -- error
+
+SELECT c.relname, r.rolname
+ FROM pg_class c JOIN pg_roles r ON (r.oid = c.relowner)
+ WHERE relname LIKE 'testtab_'
+ ORDER BY 1;
+
+-- ALTER TABLE, VIEW, MATERIALIZED VIEW, FOREIGN TABLE, SEQUENCE are
+-- changed their owner in the same way.
+
+-- ALTER AGGREGATE
+\c -
+SET SESSION AUTHORIZATION testrol0;
+DROP AGGREGATE IF EXISTS testagg1(int2);
+DROP AGGREGATE IF EXISTS testagg2(int2);
+DROP AGGREGATE IF EXISTS testagg3(int2);
+DROP AGGREGATE IF EXISTS testagg4(int2);
+DROP AGGREGATE IF EXISTS testagg5(int2);
+DROP AGGREGATE IF EXISTS testagg6(int2);
+DROP AGGREGATE IF EXISTS testagg7(int2);
+DROP AGGREGATE IF EXISTS testagg8(int2);
+DROP AGGREGATE IF EXISTS testagg9(int2);
+CREATE AGGREGATE testagg1(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg2(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg3(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg4(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg5(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg6(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg7(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg8(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg9(int2) (SFUNC = int2_sum, STYPE = int8);
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+ALTER AGGREGATE testagg1(int2) OWNER TO CURRENT_USER;
+ALTER AGGREGATE testagg2(int2) OWNER TO "current_user";
+ALTER AGGREGATE testagg3(int2) OWNER TO SESSION_USER;
+ALTER AGGREGATE testagg4(int2) OWNER TO testrolx;
+ALTER AGGREGATE testagg5(int2) OWNER TO "Public";
+
+ALTER AGGREGATE testagg6(int2) OWNER TO CURRENT_ROLE; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO USER; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO PUBLIC; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO "public"; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO nonexistent; -- error
+
+SELECT p.proname, r.rolname
+ FROM pg_proc p JOIN pg_roles r ON (r.oid = p.proowner)
+ WHERE proname LIKE 'testagg_'
+ ORDER BY 1;
+
+ALTER AGGREGATE testagg1(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg2(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg3(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg4(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg5(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg6(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg7(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg8(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg9(int2) OWNER TO regress_role_superuser;
+
+
+-- CREATE USER MAPPING
+CREATE FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv1 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv2 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv3 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv4 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv5 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv6 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv7 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv8 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv9 FOREIGN DATA WRAPPER test_wrapper;
+
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+
+CREATE USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (user 'CURRENT_ROLE'); -- error
+CREATE USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (user 'nonexistent'); -- error;
+
+SELECT * FROM chkumapping();
+
+-- ALTER USER MAPPING
+ALTER USER MAPPING FOR CURRENT_USER SERVER sv1
+ OPTIONS (SET user 'CURRENT_USER_alt');
+ALTER USER MAPPING FOR "current_user" SERVER sv2
+ OPTIONS (SET user '"current_user"_alt');
+ALTER USER MAPPING FOR USER SERVER sv3
+ OPTIONS (SET user 'USER_alt');
+ALTER USER MAPPING FOR "user" SERVER sv4
+ OPTIONS (SET user '"user"_alt');
+ALTER USER MAPPING FOR SESSION_USER SERVER sv5
+ OPTIONS (SET user 'SESSION_USER_alt');
+ALTER USER MAPPING FOR PUBLIC SERVER sv6
+ OPTIONS (SET user 'public_alt');
+ALTER USER MAPPING FOR "Public" SERVER sv7
+ OPTIONS (SET user '"Public"_alt');
+ALTER USER MAPPING FOR testrolx SERVER sv8
+ OPTIONS (SET user 'testrolx_alt');
+
+ALTER USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (SET user 'CURRENT_ROLE_alt');
+ALTER USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (SET user 'nonexistent_alt'); -- error
+
+SELECT * FROM chkumapping();
+
+-- DROP USER MAPPING
+DROP USER MAPPING FOR CURRENT_USER SERVER sv1;
+DROP USER MAPPING FOR "current_user" SERVER sv2;
+DROP USER MAPPING FOR USER SERVER sv3;
+DROP USER MAPPING FOR "user" SERVER sv4;
+DROP USER MAPPING FOR SESSION_USER SERVER sv5;
+DROP USER MAPPING FOR PUBLIC SERVER sv6;
+DROP USER MAPPING FOR "Public" SERVER sv7;
+DROP USER MAPPING FOR testrolx SERVER sv8;
+
+DROP USER MAPPING FOR CURRENT_ROLE SERVER sv9; -- error
+DROP USER MAPPING FOR nonexistent SERVER sv; -- error
+SELECT * FROM chkumapping();
+
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+SELECT * FROM chkumapping();
+
+-- DROP USER MAPPING IF EXISTS
+DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER sv1;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "current_user" SERVER sv2;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR USER SERVER sv3;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "user" SERVER sv4;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR SESSION_USER SERVER sv5;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER sv6;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "Public" SERVER sv7;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR testrolx SERVER sv8;
+SELECT * FROM chkumapping();
+
+DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9; --error
+DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
+
+-- GRANT/REVOKE
+UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2) FROM PUBLIC;
+
+GRANT ALL PRIVILEGES ON FUNCTION testagg1(int2) TO PUBLIC;
+GRANT ALL PRIVILEGES ON FUNCTION testagg2(int2) TO CURRENT_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg3(int2) TO "current_user";
+GRANT ALL PRIVILEGES ON FUNCTION testagg4(int2) TO SESSION_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg5(int2) TO "Public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg6(int2) TO testrolx;
+GRANT ALL PRIVILEGES ON FUNCTION testagg7(int2) TO "public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ TO current_user, public, testrolx;
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO CURRENT_ROLE; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO USER; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO NONE; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO "none"; --error
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM CURRENT_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM "current_user";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM SESSION_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM "Public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM testrolx;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM "public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ FROM current_user, public, testrolx;
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM CURRENT_ROLE; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM USER; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM NONE; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM "none"; --error
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+-- clean up
+\c
+
+DROP OWNED BY testrol0, "Public", "current_user", testrol1, testrol2, testrolx CASCADE;
+DROP ROLE testrol0, testrol1, testrol2, testrolx;
+DROP ROLE "Public", "None", "current_user", "session_user", "user";
Actually this is better -- I added token location tracking, and changed
RoleId to use RoleSpec which means it can throw errors with locations
when "public" or "none" are specified. I think the checks for
public/none in CreateRole and AlterRole are dead code now.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-ALTER-USER-CURRENT_USER-v7.patchtext/x-diff; charset=us-asciiDownload
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1e3888e..e88c8c3 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -421,22 +421,25 @@ ExecuteGrantStmt(GrantStmt *stmt)
istmt.behavior = stmt->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, stmt->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -904,22 +907,25 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
iacls.behavior = action->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, action->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 78b54b4..1d8799b 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -679,7 +679,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
Oid
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 3b95552..2a8b2a0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 537e31c..adf4c79 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1148,10 +1130,14 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
ObjectAddress referenced;
ForeignServer *srv;
ForeignDataWrapper *fdw;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1243,10 +1229,15 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
Oid useId;
Oid umId;
ForeignServer *srv;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1327,20 +1318,27 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid useId;
Oid umId;
ForeignServer *srv;
+ RoleSpec *role = (RoleSpec *) stmt->user;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
-
- if (stmt->username && !OidIsValid(useId))
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ role->rolename);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index d98da0d..103dd44 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -129,13 +129,7 @@ parse_policy_command(const char *cmd_name)
/*
* policy_role_list_to_array
- * helper function to convert a list of role names in to an array of
- * role ids.
- *
- * Note: If PUBLIC is provided as a role name, then ACL_ID_PUBLIC is
- * used as the role id.
- *
- * roles - the list of role names to convert.
+ * helper function to convert a list of RoleSpecs to an array of role ids.
*/
static ArrayType *
policy_role_list_to_array(List *roles)
@@ -162,25 +156,25 @@ policy_role_list_to_array(List *roles)
foreach(cell, roles)
{
- Oid roleid = get_role_oid_or_public(strVal(lfirst(cell)));
+ RoleSpec *spec = lfirst(cell);
/*
* PUBLIC covers all roles, so it only makes sense alone.
*/
- if (roleid == ACL_ID_PUBLIC)
+ if (spec->roletype == ROLESPEC_PUBLIC)
{
if (num_roles != 1)
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ignoring roles specified other than public"),
errhint("All roles are members of the public role.")));
-
- temp_array[0] = ObjectIdGetDatum(roleid);
+ temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
num_roles = 1;
break;
}
else
- temp_array[i++] = ObjectIdGetDatum(roleid);
+ temp_array[i++] =
+ ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
}
role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index a44dbf4..f6da883 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +58,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (stmt->authrole)
+ owner_uid = get_rolespec_oid(stmt->authrole, false);
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for role %u", owner_uid);
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
+
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 07ab4b4..6bde084 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3486,7 +3486,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9367,7 +9367,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 03cc8fe..70cc035 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2210eed..d4be7b8 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -445,10 +445,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -480,7 +480,9 @@ AlterRole(AlterRoleStmt *stmt)
TupleDesc pg_authid_dsc;
HeapTuple tuple,
new_tuple;
+ Form_pg_authid authform;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,33 +651,30 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ tuple = get_rolespec_tuple(stmt->role);
+ authform = (Form_pg_authid) GETSTRUCT(tuple);
+ rolename = pstrdup(NameStr(authform->rolname));
roleid = HeapTupleGetOid(tuple);
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
- if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
+ if (authform->rolsuper || issuper >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter superusers")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
+ else if (authform->rolreplication || isreplication >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter replication users")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
+ else if (authform->rolbypassrls || bypassrls >= 0)
{
if (!superuser())
ereport(ERROR,
@@ -720,11 +719,11 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
/*
* Build an updated tuple, perusing the information just obtained
@@ -794,7 +793,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +840,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,13 +869,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ roletuple = get_rolespec_tuple(stmt->role);
roleid = HeapTupleGetOid(roletuple);
/*
@@ -965,7 +958,8 @@ DropRole(DropRoleStmt *stmt)
foreach(item, stmt->roles)
{
- const char *role = strVal(lfirst(item));
+ RoleSpec *rolspec = lfirst(item);
+ char *role;
HeapTuple tuple,
tmp_tuple;
ScanKeyData scankey;
@@ -974,6 +968,12 @@ DropRole(DropRoleStmt *stmt)
SysScanDesc sscan;
Oid roleid;
+ if (rolspec->roletype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot use special role specifier in \"%s\"", "DROP ROLE")));
+ role = rolspec->rolename;
+
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
{
@@ -1240,11 +1240,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1293,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1319,7 +1319,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1335,7 +1335,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1347,22 +1347,24 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/*
- * roleNamesToIds
+ * roleSpecsToIds
+ *
+ * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
*
- * Given a list of role names (as String nodes), generate a list of role OIDs
- * in the same order.
+ * ROLESPEC_PUBLIC is not allowed.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ Node *rolespec = (Node *) lfirst(l);
+ Oid roleid;
+ roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
return result;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 9fe8008..ebb6f3a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2504,6 +2504,18 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roletype);
+ COPY_STRING_FIELD(rolename);
+ COPY_LOCATION_FIELD(location);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2650,6 +2662,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2689,16 +2702,6 @@ _copyGrantStmt(const GrantStmt *from)
return newnode;
}
-static PrivGrantee *
-_copyPrivGrantee(const PrivGrantee *from)
-{
- PrivGrantee *newnode = makeNode(PrivGrantee);
-
- COPY_STRING_FIELD(rolname);
-
- return newnode;
-}
-
static FuncWithArgs *
_copyFuncWithArgs(const FuncWithArgs *from)
{
@@ -2730,7 +2733,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3038,7 +3041,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3424,7 +3427,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3561,7 +3564,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3573,7 +3576,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3585,7 +3588,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3698,7 +3701,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3710,7 +3713,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3769,7 +3772,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3854,7 +3857,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4728,9 +4731,6 @@ copyObject(const void *from)
case T_CommonTableExpr:
retval = _copyCommonTableExpr(from);
break;
- case T_PrivGrantee:
- retval = _copyPrivGrantee(from);
- break;
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
@@ -4740,6 +4740,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fe509b0..8186e84 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -973,6 +973,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,14 +1010,6 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
}
static bool
-_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
-{
- COMPARE_STRING_FIELD(rolname);
-
- return true;
-}
-
-static bool
_equalFuncWithArgs(const FuncWithArgs *a, const FuncWithArgs *b)
{
COMPARE_NODE_FIELD(funcname);
@@ -1041,7 +1034,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1295,7 +1288,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1618,7 +1611,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1735,7 +1728,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1745,7 +1738,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1755,7 +1748,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1853,7 +1846,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1863,7 +1856,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1912,7 +1905,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1983,7 +1976,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2455,6 +2448,16 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roletype);
+ COMPARE_STRING_FIELD(rolename);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3153,9 +3156,6 @@ equal(const void *a, const void *b)
case T_CommonTableExpr:
retval = _equalCommonTableExpr(a, b);
break;
- case T_PrivGrantee:
- retval = _equalPrivGrantee(a, b);
- break;
case T_FuncWithArgs:
retval = _equalFuncWithArgs(a, b);
break;
@@ -3165,6 +3165,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 581f7a1..b668a90 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -143,6 +143,7 @@ static Node *makeBitStringConst(char *str, int location);
static Node *makeNullAConst(int location);
static Node *makeAConst(Value *v, int location);
static Node *makeBoolAConst(bool state, int location);
+static Node *makeRoleSpec(RoleSpecType type, int location);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
static List *check_func_name(List *names, core_yyscan_t yyscanner);
static List *check_indirection(List *indirection, core_yyscan_t yyscanner);
@@ -291,7 +292,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,12 +474,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
%type <str> createdb_opt_name
%type <node> var_value zone_value
+%type <node> auth_ident RoleSpec opt_granted_by
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
@@ -494,7 +495,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <node> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -871,7 +873,6 @@ CreateRoleStmt:
}
;
-
opt_with: WITH {}
| WITH_LA {}
| /*EMPTY*/ {}
@@ -1037,7 +1038,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1053,7 +1054,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleSpec opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1079,7 +1080,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1091,7 +1092,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleSpec SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1180,7 +1181,7 @@ CreateGroupStmt:
*****************************************************************************/
AlterGroupStmt:
- ALTER GROUP_P RoleId add_drop USER role_list
+ ALTER GROUP_P RoleSpec add_drop USER role_list
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1228,15 +1229,12 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1246,20 +1244,17 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ /* schema name can be omitted here, too */
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1272,9 +1267,9 @@ CreateSchemaStmt:
| CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* ...but not both */
+ /* ...but not here */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2259,12 +2254,12 @@ alter_table_cmd:
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
- /* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3756,7 +3751,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4478,7 +4473,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4486,10 +4481,8 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
;
/* User mapping authorization identifier */
-auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+auth_ident: RoleSpec { $$ = $1; }
+ | USER { $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1); }
;
/*****************************************************************************
@@ -4502,7 +4495,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4510,7 +4503,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4527,7 +4520,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4612,7 +4605,7 @@ RowSecurityOptionalWithCheck:
RowSecurityDefaultToRole:
TO role_list { $$ = $2; }
- | /* EMPTY */ { $$ = list_make1(makeString("public")); }
+ | /* EMPTY */ { $$ = list_make1(makeRoleSpec(ROLESPEC_PUBLIC, -1)); }
;
RowSecurityOptionalToRole:
@@ -5432,7 +5425,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleSpec
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6348,26 +6341,9 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
- $$ = (Node *)n;
- }
- | GROUP_P RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
- $$ = (Node *)n;
- }
+grantee:
+ RoleSpec { $$ = $1; }
+ | GROUP_P RoleSpec { $$ = $2; }
;
@@ -6438,7 +6414,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -8104,7 +8080,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -8113,7 +8089,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -8121,7 +8097,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -8129,7 +8105,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -8137,7 +8113,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -8145,7 +8121,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -8154,7 +8130,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -8162,7 +8138,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8170,7 +8146,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8179,7 +8155,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8188,7 +8164,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8197,7 +8173,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8205,7 +8181,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8213,7 +8189,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8221,7 +8197,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8229,7 +8205,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8237,7 +8213,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8245,7 +8221,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8253,7 +8229,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -13113,19 +13089,86 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
-
-role_list: RoleId
- { $$ = list_make1(makeString($1)); }
- | role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
- ;
SignedIconst: Iconst { $$ = $1; }
| '+' Iconst { $$ = + $2; }
| '-' Iconst { $$ = - $2; }
;
+/* Role specifications */
+RoleId: RoleSpec
+ {
+ RoleSpec *spc = (RoleSpec *) $1;
+ switch (spc->roletype)
+ {
+ case ROLESPEC_CSTRING:
+ $$ = spc->rolename;
+ break;
+ case ROLESPEC_PUBLIC:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "public"),
+ errposition(@1)));
+ case ROLESPEC_SESSION_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name",
+ "SESSION_USER"),
+ errposition(@1)));
+ case ROLESPEC_CURRENT_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name",
+ "CURRENT_USER"),
+ errposition(@1)));
+ }
+ }
+ ;
+
+RoleSpec: NonReservedWord
+ {
+ /*
+ * "public" and "none" are not keywords, but they must
+ * be treated specially here.
+ */
+ RoleSpec *n;
+ if (strcmp($1, "public") == 0)
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_PUBLIC, @1);
+ n->roletype = ROLESPEC_PUBLIC;
+ }
+ else if (strcmp($1, "none") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "none"),
+ parser_errposition(@1)));
+ }
+ else
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_CSTRING, @1);
+ n->rolename = pstrdup($1);
+ }
+ $$ = (Node *) n;
+ }
+ | CURRENT_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1);
+ }
+ | SESSION_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_SESSION_USER, @1);
+ }
+ ;
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
+ ;
+
/*
* Name classification hierarchy.
*
@@ -13812,6 +13855,20 @@ makeBoolAConst(bool state, int location)
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
+/* makeRoleSpec
+ * Create a RoleSpec with the given type
+ */
+static Node *
+makeRoleSpec(RoleSpecType type, int location)
+{
+ RoleSpec *spec = makeNode(RoleSpec);
+
+ spec->roletype = type;
+ spec->location = location;
+
+ return (Node *) spec;
+}
+
/* check_qualified_name --- check the result of qualified_name production
*
* It's easiest to let the grammar production for qualified_name allow
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c29f106..1e6da9c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2723,7 +2723,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = (RoleSpec *) stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 411d779..d4b5364 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,99 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+/*
+ * Given a RoleSpec node, return the OID it points 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 cached HeapTuple it points 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;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern Oid RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 97ef0fc..38469ef 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ac13302..497559d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -285,6 +285,25 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - a role name or one of a few special values.
+ */
+typedef enum RoleSpecType
+{
+ ROLESPEC_CSTRING, /* role name is stored as a C string */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC /* role name is "public" */
+} RoleSpecType;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecType roletype; /* Type of this rolespec */
+ char *rolename; /* filled only for ROLESPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1263,7 +1282,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ Node *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1362,7 +1381,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ Node *newowner; /* RoleSpec */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1434,17 +1454,11 @@ typedef struct GrantStmt
* or plain names (as Value strings) */
List *privileges; /* list of AccessPriv nodes */
/* privileges == NIL denotes ALL PRIVILEGES */
- List *grantees; /* list of PrivGrantee nodes */
+ List *grantees; /* list of RoleSpec nodes */
bool grant_option; /* grant or revoke grant option */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantStmt;
-typedef struct PrivGrantee
-{
- NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
-} PrivGrantee;
-
/*
* Note: FuncWithArgs carries only the types of the input parameters of the
* function. So it is sufficient to identify an existing function, but it
@@ -1487,7 +1501,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ Node *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1699,7 +1713,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ Node *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1825,7 +1839,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1833,7 +1847,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1841,7 +1855,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1991,7 +2005,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1999,7 +2013,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2375,7 +2389,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ Node *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2831,7 +2845,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ Node *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ab0df6c..35f8853 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -24,6 +24,7 @@
#ifndef ACL_H
#define ACL_H
+#include "access/htup.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/snapshot.h"
@@ -227,8 +228,10 @@ extern bool is_member_of_role(Oid member, Oid role);
extern bool is_member_of_role_nosuper(Oid member, Oid role);
extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
-extern Oid get_role_oid(const char *rolname, bool missing_ok);
-extern Oid get_role_oid_or_public(const char *rolname);
+extern Oid get_role_oid(const char *rolename, bool missing_ok);
+extern Oid get_role_oid_or_public(const char *rolename);
+extern Oid get_rolespec_oid(const Node *node, bool missing_ok);
+extern HeapTuple get_rolespec_tuple(const Node *node);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
diff --git a/src/test/regress/expected/rolenames.out b/src/test/regress/expected/rolenames.out
new file mode 100644
index 0000000..7c06d6e
--- /dev/null
+++ b/src/test/regress/expected/rolenames.out
@@ -0,0 +1,959 @@
+CREATE OR REPLACE FUNCTION chkrolattr()
+ RETURNS TABLE ("role" name, rolekeyword text, canlogin bool, replication bool)
+ AS $$
+SELECT r.rolname, v.keyword, r.rolcanlogin, r.rolreplication
+ FROM pg_roles r
+ JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'),
+ ('current_user', '-'),
+ ('session_user', '-'),
+ ('Public', '-'),
+ ('None', '-'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ ORDER BY 1;
+$$ LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION chksetconfig()
+ RETURNS TABLE (db name, "role" name, rolkeyword text, setconfig text[])
+ AS $$
+SELECT COALESCE(d.datname, 'ALL'), COALESCE(r.rolname, 'ALL'),
+ COALESCE(v.keyword, '-'), s.setconfig
+ FROM pg_db_role_setting s
+ LEFT JOIN pg_roles r ON (r.oid = s.setrole)
+ LEFT JOIN pg_database d ON (d.oid = s.setdatabase)
+ LEFT JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ORDER BY 1, 2;
+$$ LANGUAGE SQL;
+CREATE OR REPLACE FUNCTION chkumapping()
+ RETURNS TABLE (umname name, umserver name, umoptions text[])
+ AS $$
+SELECT r.rolname, s.srvname, m.umoptions
+ FROM pg_user_mapping m
+ LEFT JOIN pg_roles r ON (r.oid = m.umuser)
+ JOIN pg_foreign_server s ON (s.oid = m.umserver)
+ ORDER BY 2;
+$$ LANGUAGE SQL;
+CREATE ROLE "Public";
+CREATE ROLE "None";
+CREATE ROLE "current_user";
+CREATE ROLE "session_user";
+CREATE ROLE "user";
+CREATE ROLE current_user; -- error
+ERROR: CURRENT_USER cannot be used as a role name
+LINE 1: CREATE ROLE current_user;
+ ^
+CREATE ROLE current_role; -- error
+ERROR: syntax error at or near "current_role"
+LINE 1: CREATE ROLE current_role;
+ ^
+CREATE ROLE session_user; -- error
+ERROR: SESSION_USER cannot be used as a role name
+LINE 1: CREATE ROLE session_user;
+ ^
+CREATE ROLE user; -- error
+ERROR: syntax error at or near "user"
+LINE 1: CREATE ROLE user;
+ ^
+CREATE ROLE all; -- error
+ERROR: syntax error at or near "all"
+LINE 1: CREATE ROLE all;
+ ^
+CREATE ROLE public; -- error
+ERROR: role name "public" is reserved
+LINE 1: CREATE ROLE public;
+ ^
+CREATE ROLE "public"; -- error
+ERROR: role name "public" is reserved
+LINE 1: CREATE ROLE "public";
+ ^
+CREATE ROLE none; -- error
+ERROR: role name "none" is reserved
+LINE 1: CREATE ROLE none;
+ ^
+CREATE ROLE "none"; -- error
+ERROR: role name "none" is reserved
+LINE 1: CREATE ROLE "none";
+ ^
+CREATE ROLE testrol0 SUPERUSER LOGIN;
+CREATE ROLE testrolx SUPERUSER LOGIN;
+CREATE ROLE testrol2 SUPERUSER;
+CREATE ROLE testrol1 SUPERUSER LOGIN IN ROLE testrol2;
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+-- ALTER ROLE
+BEGIN;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | f
+ session_user | - | f | f
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | f
+(6 rows)
+
+ALTER ROLE CURRENT_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | f
+ session_user | - | f | f
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | t
+(6 rows)
+
+ALTER ROLE "current_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | t
+ session_user | - | f | f
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | t
+(6 rows)
+
+ALTER ROLE SESSION_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | t
+ session_user | - | f | f
+ testrol1 | session_user | t | t
+ testrol2 | current_user | f | t
+(6 rows)
+
+ALTER ROLE "session_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | t
+ session_user | - | f | t
+ testrol1 | session_user | t | t
+ testrol2 | current_user | f | t
+(6 rows)
+
+ALTER USER "Public" WITH REPLICATION;
+ALTER USER "None" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | t
+ Public | - | f | t
+ current_user | - | f | t
+ session_user | - | f | t
+ testrol1 | session_user | t | t
+ testrol2 | current_user | f | t
+(6 rows)
+
+ALTER USER testrol1 WITH NOREPLICATION;
+ALTER USER testrol2 WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | t
+ Public | - | f | t
+ current_user | - | f | t
+ session_user | - | f | t
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | f
+(6 rows)
+
+ROLLBACK;
+ALTER ROLE USER WITH LOGIN; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER ROLE USER WITH LOGIN;
+ ^
+ALTER ROLE CURRENT_ROLE WITH LOGIN; --error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER ROLE CURRENT_ROLE WITH LOGIN;
+ ^
+ALTER ROLE ALL WITH REPLICATION; -- error
+ERROR: syntax error at or near "WITH"
+LINE 1: ALTER ROLE ALL WITH REPLICATION;
+ ^
+ALTER ROLE SESSION_ROLE WITH NOREPLICATION; -- error
+ERROR: role "session_role" does not exist
+ALTER ROLE PUBLIC WITH NOREPLICATION; -- error
+ERROR: role "public" does not exist
+ALTER ROLE "public" WITH NOREPLICATION; -- error
+ERROR: role "public" does not exist
+ALTER ROLE NONE WITH NOREPLICATION; -- error
+ERROR: role name "none" is reserved
+LINE 1: ALTER ROLE NONE WITH NOREPLICATION;
+ ^
+ALTER ROLE "none" WITH NOREPLICATION; -- error
+ERROR: role name "none" is reserved
+LINE 1: ALTER ROLE "none" WITH NOREPLICATION;
+ ^
+ALTER ROLE nonexistent WITH NOREPLICATION; -- error
+ERROR: role "nonexistent" does not exist
+-- ALTER USER
+BEGIN;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | f
+ session_user | - | f | f
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | f
+(6 rows)
+
+ALTER USER CURRENT_USER WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ role | rolekeyword | canlogin | replication
+--------------+--------------+----------+-------------
+ None | - | f | f
+ Public | - | f | f
+ current_user | - | f | f
+ session_user | - | f | f
+ testrol1 | session_user | t | f
+ testrol2 | current_user | f | f
+(6 rows)
+
+ALTER USER 'current_user' WITH NOREPLICATION;
+ERROR: syntax error at or near "'current_user'"
+LINE 1: ALTER USER 'current_user' WITH NOREPLICATION;
+ ^
+SELECT * FROM chkrolattr();
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ALTER USER SESSION_USER WITH REPLICATION;
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+SELECT * FROM chkrolattr();
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ALTER USER 'session_user' WITH REPLICATION;
+ERROR: syntax error at or near "'session_user'"
+LINE 1: ALTER USER 'session_user' WITH REPLICATION;
+ ^
+SELECT * FROM chkrolattr();
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ALTER USER 'Public' WITH REPLICATION;
+ERROR: syntax error at or near "'Public'"
+LINE 1: ALTER USER 'Public' WITH REPLICATION;
+ ^
+ALTER USER 'None' WITH REPLICATION;
+ERROR: syntax error at or near "'None'"
+LINE 1: ALTER USER 'None' WITH REPLICATION;
+ ^
+SELECT * FROM chkrolattr();
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ALTER USER testrol1 WITH NOREPLICATION;
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ALTER USER testrol2 WITH NOREPLICATION;
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+SELECT * FROM chkrolattr();
+ERROR: current transaction is aborted, commands ignored until end of transaction block
+ROLLBACK;
+ALTER USER USER WITH LOGIN; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER USER USER WITH LOGIN;
+ ^
+ALTER USER CURRENT_ROLE WITH LOGIN; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER USER CURRENT_ROLE WITH LOGIN;
+ ^
+ALTER USER ALL WITH REPLICATION; -- error
+ERROR: syntax error at or near "ALL"
+LINE 1: ALTER USER ALL WITH REPLICATION;
+ ^
+ALTER USER SESSION_ROLE WITH NOREPLICATION; -- error
+ERROR: role "session_role" does not exist
+ALTER USER PUBLIC WITH NOREPLICATION; -- error
+ERROR: role "public" does not exist
+ALTER USER "public" WITH NOREPLICATION; -- error
+ERROR: role "public" does not exist
+ALTER USER NONE WITH NOREPLICATION; -- error
+ERROR: role name "none" is reserved
+LINE 1: ALTER USER NONE WITH NOREPLICATION;
+ ^
+ALTER USER "none" WITH NOREPLICATION; -- error
+ERROR: role name "none" is reserved
+LINE 1: ALTER USER "none" WITH NOREPLICATION;
+ ^
+ALTER USER nonexistent WITH NOREPLICATION; -- error
+ERROR: role "nonexistent" does not exist
+-- ALTER ROLE SET/RESET
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+------+------------+-------------------------------------------------------------------------------------
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(1 row)
+
+ALTER ROLE CURRENT_USER SET application_name to 'FOO';
+ALTER ROLE SESSION_USER SET application_name to 'BAR';
+ALTER ROLE "current_user" SET application_name to 'FOOFOO';
+ALTER ROLE "Public" SET application_name to 'BARBAR';
+ALTER ROLE ALL SET application_name to 'SLAP';
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+--------------+--------------+-------------------------------------------------------------------------------------
+ ALL | ALL | - | {application_name=SLAP}
+ ALL | Public | - | {application_name=BARBAR}
+ ALL | current_user | - | {application_name=FOOFOO}
+ ALL | testrol1 | session_user | {application_name=BAR}
+ ALL | testrol2 | current_user | {application_name=FOO}
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(6 rows)
+
+ALTER ROLE testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+--------------+--------------+-------------------------------------------------------------------------------------
+ ALL | ALL | - | {application_name=SLAP}
+ ALL | Public | - | {application_name=BARBAR}
+ ALL | current_user | - | {application_name=FOOFOO}
+ ALL | testrol1 | session_user | {application_name=SLAM}
+ ALL | testrol2 | current_user | {application_name=FOO}
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(6 rows)
+
+ALTER ROLE CURRENT_USER RESET application_name;
+ALTER ROLE SESSION_USER RESET application_name;
+ALTER ROLE "current_user" RESET application_name;
+ALTER ROLE "Public" RESET application_name;
+ALTER ROLE ALL RESET application_name;
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+------+------------+-------------------------------------------------------------------------------------
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(1 row)
+
+ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ';
+ ^
+ALTER ROLE USER SET application_name to 'BOOM'; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER ROLE USER SET application_name to 'BOOM';
+ ^
+ALTER ROLE PUBLIC SET application_name to 'BOMB'; -- error
+ERROR: role "public" does not exist
+ALTER ROLE nonexistent SET application_name to 'BOMB'; -- error
+ERROR: role "nonexistent" does not exist
+-- ALTER USER SET/RESET
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+------+------------+-------------------------------------------------------------------------------------
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(1 row)
+
+ALTER USER CURRENT_USER SET application_name to 'FOO';
+ALTER USER SESSION_USER SET application_name to 'BAR';
+ALTER USER "current_user" SET application_name to 'FOOFOO';
+ALTER USER "Public" SET application_name to 'BARBAR';
+ALTER USER ALL SET application_name to 'SLAP';
+ERROR: syntax error at or near "ALL"
+LINE 1: ALTER USER ALL SET application_name to 'SLAP';
+ ^
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+--------------+--------------+-------------------------------------------------------------------------------------
+ ALL | Public | - | {application_name=BARBAR}
+ ALL | current_user | - | {application_name=FOOFOO}
+ ALL | testrol1 | session_user | {application_name=BAR}
+ ALL | testrol2 | current_user | {application_name=FOO}
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(5 rows)
+
+ALTER USER testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+--------------+--------------+-------------------------------------------------------------------------------------
+ ALL | Public | - | {application_name=BARBAR}
+ ALL | current_user | - | {application_name=FOOFOO}
+ ALL | testrol1 | session_user | {application_name=SLAM}
+ ALL | testrol2 | current_user | {application_name=FOO}
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(5 rows)
+
+ALTER USER CURRENT_USER RESET application_name;
+ALTER USER SESSION_USER RESET application_name;
+ALTER USER "current_user" RESET application_name;
+ALTER USER "Public" RESET application_name;
+ALTER USER ALL RESET application_name;
+ERROR: syntax error at or near "ALL"
+LINE 1: ALTER USER ALL RESET application_name;
+ ^
+SELECT * FROM chksetconfig();
+ db | role | rolkeyword | setconfig
+------------+------+------------+-------------------------------------------------------------------------------------
+ regression | ALL | - | {lc_messages=C,lc_monetary=C,lc_numeric=C,lc_time=C,timezone_abbreviations=Default}
+(1 row)
+
+ALTER USER CURRENT_USER SET application_name to 'BAZ'; -- error
+ALTER USER USER SET application_name to 'BOOM'; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER USER USER SET application_name to 'BOOM';
+ ^
+ALTER USER PUBLIC SET application_name to 'BOMB'; -- error
+ERROR: role "public" does not exist
+ALTER USER NONE SET application_name to 'BOMB'; -- error
+ERROR: role name "none" is reserved
+LINE 1: ALTER USER NONE SET application_name to 'BOMB';
+ ^
+ALTER USER nonexistent SET application_name to 'BOMB'; -- error
+ERROR: role "nonexistent" does not exist
+-- CREAETE SCHEMA
+set client_min_messages to error;
+CREATE SCHEMA newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA newschema5 AUTHORIZATION "Public";
+CREATE SCHEMA newschema6 AUTHORIZATION USER; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: CREATE SCHEMA newschema6 AUTHORIZATION USER;
+ ^
+CREATE SCHEMA newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: CREATE SCHEMA newschema6 AUTHORIZATION CURRENT_ROLE;
+ ^
+CREATE SCHEMA newschema6 AUTHORIZATION PUBLIC; -- error
+ERROR: role "public" does not exist
+CREATE SCHEMA newschema6 AUTHORIZATION "public"; -- error
+ERROR: role "public" does not exist
+CREATE SCHEMA newschema6 AUTHORIZATION NONE; -- error
+ERROR: role name "none" is reserved
+LINE 1: CREATE SCHEMA newschema6 AUTHORIZATION NONE;
+ ^
+CREATE SCHEMA newschema6 AUTHORIZATION nonexistent; -- error
+ERROR: role "nonexistent" does not exist
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+ nspname | rolname
+------------+--------------
+ newschema1 | testrol2
+ newschema2 | current_user
+ newschema3 | testrol1
+ newschema4 | testrolx
+ newschema5 | Public
+(5 rows)
+
+DROP SCHEMA IF EXISTS newschema1;
+DROP SCHEMA IF EXISTS newschema2;
+DROP SCHEMA IF EXISTS newschema3;
+DROP SCHEMA IF EXISTS newschema4;
+DROP SCHEMA IF EXISTS newschema5;
+DROP SCHEMA IF EXISTS newschema6;
+CREATE SCHEMA IF NOT EXISTS newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA IF NOT EXISTS newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA IF NOT EXISTS newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA IF NOT EXISTS newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA IF NOT EXISTS newschema5 AUTHORIZATION "Public";
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION USER; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION USER;
+ ^
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ...ATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION CURRENT_RO...
+ ^
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION PUBLIC; -- error
+ERROR: role "public" does not exist
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION "public"; -- error
+ERROR: role "public" does not exist
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION NONE; -- error
+ERROR: role name "none" is reserved
+LINE 1: CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION NONE;
+ ^
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION nonexistent; -- error
+ERROR: role "nonexistent" does not exist
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+ nspname | rolname
+------------+--------------
+ newschema1 | testrol2
+ newschema2 | current_user
+ newschema3 | testrol1
+ newschema4 | testrolx
+ newschema5 | Public
+(5 rows)
+
+-- ALTER TABLE OWNER TO
+\c -
+SET SESSION AUTHORIZATION testrol0;
+set client_min_messages to error;
+CREATE TABLE testtab1 (a int);
+CREATE TABLE testtab2 (a int);
+CREATE TABLE testtab3 (a int);
+CREATE TABLE testtab4 (a int);
+CREATE TABLE testtab5 (a int);
+CREATE TABLE testtab6 (a int);
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+ALTER TABLE testtab1 OWNER TO CURRENT_USER;
+ALTER TABLE testtab2 OWNER TO "current_user";
+ALTER TABLE testtab3 OWNER TO SESSION_USER;
+ALTER TABLE testtab4 OWNER TO testrolx;
+ALTER TABLE testtab5 OWNER TO "Public";
+ALTER TABLE testtab6 OWNER TO CURRENT_ROLE; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER TABLE testtab6 OWNER TO CURRENT_ROLE;
+ ^
+ALTER TABLE testtab6 OWNER TO USER; --error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER TABLE testtab6 OWNER TO USER;
+ ^
+ALTER TABLE testtab6 OWNER TO PUBLIC; -- error
+ERROR: role "public" does not exist
+ALTER TABLE testtab6 OWNER TO "public"; -- error
+ERROR: role "public" does not exist
+ALTER TABLE testtab6 OWNER TO nonexistent; -- error
+ERROR: role "nonexistent" does not exist
+SELECT c.relname, r.rolname
+ FROM pg_class c JOIN pg_roles r ON (r.oid = c.relowner)
+ WHERE relname LIKE 'testtab_'
+ ORDER BY 1;
+ relname | rolname
+----------+--------------
+ testtab1 | testrol2
+ testtab2 | current_user
+ testtab3 | testrol1
+ testtab4 | testrolx
+ testtab5 | Public
+ testtab6 | testrol0
+(6 rows)
+
+-- ALTER TABLE, VIEW, MATERIALIZED VIEW, FOREIGN TABLE, SEQUENCE are
+-- changed their owner in the same way.
+-- ALTER AGGREGATE
+\c -
+SET SESSION AUTHORIZATION testrol0;
+DROP AGGREGATE IF EXISTS testagg1(int2);
+NOTICE: aggregate testagg1(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg2(int2);
+NOTICE: aggregate testagg2(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg3(int2);
+NOTICE: aggregate testagg3(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg4(int2);
+NOTICE: aggregate testagg4(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg5(int2);
+NOTICE: aggregate testagg5(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg6(int2);
+NOTICE: aggregate testagg6(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg7(int2);
+NOTICE: aggregate testagg7(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg8(int2);
+NOTICE: aggregate testagg8(int2) does not exist, skipping
+DROP AGGREGATE IF EXISTS testagg9(int2);
+NOTICE: aggregate testagg9(int2) does not exist, skipping
+CREATE AGGREGATE testagg1(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg2(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg3(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg4(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg5(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg6(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg7(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg8(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg9(int2) (SFUNC = int2_sum, STYPE = int8);
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+ALTER AGGREGATE testagg1(int2) OWNER TO CURRENT_USER;
+ALTER AGGREGATE testagg2(int2) OWNER TO "current_user";
+ALTER AGGREGATE testagg3(int2) OWNER TO SESSION_USER;
+ALTER AGGREGATE testagg4(int2) OWNER TO testrolx;
+ALTER AGGREGATE testagg5(int2) OWNER TO "Public";
+ALTER AGGREGATE testagg6(int2) OWNER TO CURRENT_ROLE; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER AGGREGATE testagg6(int2) OWNER TO CURRENT_ROLE;
+ ^
+ALTER AGGREGATE testagg6(int2) OWNER TO USER; -- error
+ERROR: syntax error at or near "USER"
+LINE 1: ALTER AGGREGATE testagg6(int2) OWNER TO USER;
+ ^
+ALTER AGGREGATE testagg6(int2) OWNER TO PUBLIC; -- error
+ERROR: role "public" does not exist
+ALTER AGGREGATE testagg6(int2) OWNER TO "public"; -- error
+ERROR: role "public" does not exist
+ALTER AGGREGATE testagg6(int2) OWNER TO nonexistent; -- error
+ERROR: role "nonexistent" does not exist
+SELECT p.proname, r.rolname
+ FROM pg_proc p JOIN pg_roles r ON (r.oid = p.proowner)
+ WHERE proname LIKE 'testagg_'
+ ORDER BY 1;
+ proname | rolname
+----------+--------------
+ testagg1 | testrol2
+ testagg2 | current_user
+ testagg3 | testrol1
+ testagg4 | testrolx
+ testagg5 | Public
+ testagg6 | testrol0
+ testagg7 | testrol0
+ testagg8 | testrol0
+ testagg9 | testrol0
+(9 rows)
+
+ALTER AGGREGATE testagg1(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg2(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg3(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg4(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg5(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg6(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg7(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg8(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+ALTER AGGREGATE testagg9(int2) OWNER TO regress_role_superuser;
+ERROR: role "regress_role_superuser" does not exist
+-- CREATE USER MAPPING
+CREATE FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv1 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv2 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv3 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv4 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv5 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv6 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv7 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv8 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv9 FOREIGN DATA WRAPPER test_wrapper;
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+CREATE USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (user 'CURRENT_ROLE'); -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: CREATE USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ ^
+CREATE USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (user 'nonexistent'); -- error;
+ERROR: role "nonexistent" does not exist
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------------+----------+---------------------------
+ testrol2 | sv1 | {user=CURRENT_USER}
+ current_user | sv2 | {"user=\"current_user\""}
+ testrol2 | sv3 | {user=USER}
+ user | sv4 | {"user=\"USER\""}
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(8 rows)
+
+-- ALTER USER MAPPING
+ALTER USER MAPPING FOR CURRENT_USER SERVER sv1
+ OPTIONS (SET user 'CURRENT_USER_alt');
+ALTER USER MAPPING FOR "current_user" SERVER sv2
+ OPTIONS (SET user '"current_user"_alt');
+ALTER USER MAPPING FOR USER SERVER sv3
+ OPTIONS (SET user 'USER_alt');
+ALTER USER MAPPING FOR "user" SERVER sv4
+ OPTIONS (SET user '"user"_alt');
+ALTER USER MAPPING FOR SESSION_USER SERVER sv5
+ OPTIONS (SET user 'SESSION_USER_alt');
+ALTER USER MAPPING FOR PUBLIC SERVER sv6
+ OPTIONS (SET user 'public_alt');
+ALTER USER MAPPING FOR "Public" SERVER sv7
+ OPTIONS (SET user '"Public"_alt');
+ALTER USER MAPPING FOR testrolx SERVER sv8
+ OPTIONS (SET user 'testrolx_alt');
+ALTER USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (SET user 'CURRENT_ROLE_alt');
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ALTER USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ ^
+ALTER USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (SET user 'nonexistent_alt'); -- error
+ERROR: role "nonexistent" does not exist
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------------+----------+-------------------------------
+ testrol2 | sv1 | {user=CURRENT_USER_alt}
+ current_user | sv2 | {"user=\"current_user\"_alt"}
+ testrol2 | sv3 | {user=USER_alt}
+ user | sv4 | {"user=\"user\"_alt"}
+ testrol1 | sv5 | {user=SESSION_USER_alt}
+ | sv6 | {user=public_alt}
+ Public | sv7 | {"user=\"Public\"_alt"}
+ testrolx | sv8 | {user=testrolx_alt}
+(8 rows)
+
+-- DROP USER MAPPING
+DROP USER MAPPING FOR CURRENT_USER SERVER sv1;
+DROP USER MAPPING FOR "current_user" SERVER sv2;
+DROP USER MAPPING FOR USER SERVER sv3;
+DROP USER MAPPING FOR "user" SERVER sv4;
+DROP USER MAPPING FOR SESSION_USER SERVER sv5;
+DROP USER MAPPING FOR PUBLIC SERVER sv6;
+DROP USER MAPPING FOR "Public" SERVER sv7;
+DROP USER MAPPING FOR testrolx SERVER sv8;
+DROP USER MAPPING FOR CURRENT_ROLE SERVER sv9; -- error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: DROP USER MAPPING FOR CURRENT_ROLE SERVER sv9;
+ ^
+DROP USER MAPPING FOR nonexistent SERVER sv; -- error
+ERROR: role "nonexistent" does not exist
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------+----------+-----------
+(0 rows)
+
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------------+----------+---------------------------
+ testrol2 | sv1 | {user=CURRENT_USER}
+ current_user | sv2 | {"user=\"current_user\""}
+ testrol2 | sv3 | {user=USER}
+ user | sv4 | {"user=\"USER\""}
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(8 rows)
+
+-- DROP USER MAPPING IF EXISTS
+DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER sv1;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------------+----------+---------------------------
+ current_user | sv2 | {"user=\"current_user\""}
+ testrol2 | sv3 | {user=USER}
+ user | sv4 | {"user=\"USER\""}
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(7 rows)
+
+DROP USER MAPPING IF EXISTS FOR "current_user" SERVER sv2;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+---------------------
+ testrol2 | sv3 | {user=USER}
+ user | sv4 | {"user=\"USER\""}
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(6 rows)
+
+DROP USER MAPPING IF EXISTS FOR USER SERVER sv3;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+---------------------
+ user | sv4 | {"user=\"USER\""}
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(5 rows)
+
+DROP USER MAPPING IF EXISTS FOR "user" SERVER sv4;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+---------------------
+ testrol1 | sv5 | {user=SESSION_USER}
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(4 rows)
+
+DROP USER MAPPING IF EXISTS FOR SESSION_USER SERVER sv5;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+---------------------
+ | sv6 | {user=PUBLIC}
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(3 rows)
+
+DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER sv6;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+---------------------
+ Public | sv7 | {"user=\"Public\""}
+ testrolx | sv8 | {user=testrolx}
+(2 rows)
+
+DROP USER MAPPING IF EXISTS FOR "Public" SERVER sv7;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+----------+----------+-----------------
+ testrolx | sv8 | {user=testrolx}
+(1 row)
+
+DROP USER MAPPING IF EXISTS FOR testrolx SERVER sv8;
+SELECT * FROM chkumapping();
+ umname | umserver | umoptions
+--------+----------+-----------
+(0 rows)
+
+DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9; --error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9;
+ ^
+DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
+NOTICE: role "nonexistent" does not exist, skipping
+-- GRANT/REVOKE
+UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+ proname | proacl
+----------+--------
+ testagg1 |
+ testagg2 |
+ testagg3 |
+ testagg4 |
+ testagg5 |
+ testagg6 |
+ testagg7 |
+ testagg8 |
+ testagg9 |
+(9 rows)
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2) FROM PUBLIC;
+GRANT ALL PRIVILEGES ON FUNCTION testagg1(int2) TO PUBLIC;
+GRANT ALL PRIVILEGES ON FUNCTION testagg2(int2) TO CURRENT_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg3(int2) TO "current_user";
+GRANT ALL PRIVILEGES ON FUNCTION testagg4(int2) TO SESSION_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg5(int2) TO "Public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg6(int2) TO testrolx;
+GRANT ALL PRIVILEGES ON FUNCTION testagg7(int2) TO "public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ TO current_user, public, testrolx;
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+ proname | proacl
+----------+---------------------------------------------------------------------------
+ testagg1 | {testrol2=X/testrol2,=X/testrol2}
+ testagg2 | {current_user=X/current_user,testrol2=X/current_user}
+ testagg3 | {testrol1=X/testrol1,current_user=X/testrol1}
+ testagg4 | {testrolx=X/testrolx,testrol1=X/testrolx}
+ testagg5 | {Public=X/Public}
+ testagg6 | {testrol0=X/testrol0,testrolx=X/testrol0}
+ testagg7 | {testrol0=X/testrol0,=X/testrol0}
+ testagg8 | {testrol0=X/testrol0,testrol2=X/testrol0,=X/testrol0,testrolx=X/testrol0}
+ testagg9 |
+(9 rows)
+
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO CURRENT_ROLE; --error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ...RANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO CURRENT_RO...
+ ^
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO USER; --error
+ERROR: syntax error at or near "USER"
+LINE 1: GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO USER;
+ ^
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO NONE; --error
+ERROR: role name "none" is reserved
+LINE 1: GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO NONE;
+ ^
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO "none"; --error
+ERROR: role name "none" is reserved
+LINE 1: GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO "none";
+ ^
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+ proname | proacl
+----------+---------------------------------------------------------------------------
+ testagg1 | {testrol2=X/testrol2,=X/testrol2}
+ testagg2 | {current_user=X/current_user,testrol2=X/current_user}
+ testagg3 | {testrol1=X/testrol1,current_user=X/testrol1}
+ testagg4 | {testrolx=X/testrolx,testrol1=X/testrolx}
+ testagg5 | {Public=X/Public}
+ testagg6 | {testrol0=X/testrol0,testrolx=X/testrol0}
+ testagg7 | {testrol0=X/testrol0,=X/testrol0}
+ testagg8 | {testrol0=X/testrol0,testrol2=X/testrol0,=X/testrol0,testrolx=X/testrol0}
+ testagg9 |
+(9 rows)
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM CURRENT_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM "current_user";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM SESSION_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM "Public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM testrolx;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM "public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ FROM current_user, public, testrolx;
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+ proname | proacl
+----------+-------------------------------
+ testagg1 | {testrol2=X/testrol2}
+ testagg2 | {current_user=X/current_user}
+ testagg3 | {testrol1=X/testrol1}
+ testagg4 | {testrolx=X/testrolx}
+ testagg5 | {}
+ testagg6 | {testrol0=X/testrol0}
+ testagg7 | {testrol0=X/testrol0}
+ testagg8 | {testrol0=X/testrol0}
+ testagg9 |
+(9 rows)
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM CURRENT_ROLE; --error
+ERROR: syntax error at or near "CURRENT_ROLE"
+LINE 1: ...KE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM CURRENT_RO...
+ ^
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM USER; --error
+ERROR: syntax error at or near "USER"
+LINE 1: REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM USER;
+ ^
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM NONE; --error
+ERROR: role name "none" is reserved
+LINE 1: REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM NONE;
+ ^
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM "none"; --error
+ERROR: role name "none" is reserved
+LINE 1: ...EVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM "none";
+ ^
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+ proname | proacl
+----------+-------------------------------
+ testagg1 | {testrol2=X/testrol2}
+ testagg2 | {current_user=X/current_user}
+ testagg3 | {testrol1=X/testrol1}
+ testagg4 | {testrolx=X/testrolx}
+ testagg5 | {}
+ testagg6 | {testrol0=X/testrol0}
+ testagg7 | {testrol0=X/testrol0}
+ testagg8 | {testrol0=X/testrol0}
+ testagg9 |
+(9 rows)
+
+-- clean up
+\c
+DROP OWNED BY testrol0, "Public", "current_user", testrol1, testrol2, testrolx CASCADE;
+DROP ROLE testrol0, testrol1, testrol2, testrolx;
+DROP ROLE "Public", "None", "current_user", "session_user", "user";
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e0ae2f2..6d3b865 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -59,7 +59,7 @@ test: create_index create_view
# ----------
# Another group of parallel tests
# ----------
-test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views
+test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views rolenames
# ----------
# sanity_check does a vacuum, affecting the sort order of SELECT *
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7f762bd..8326894 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -71,6 +71,7 @@ test: typed_table
test: vacuum
test: drop_if_exists
test: updatable_views
+test: rolenames
test: sanity_check
test: errors
test: select
diff --git a/src/test/regress/sql/rolenames.sql b/src/test/regress/sql/rolenames.sql
new file mode 100644
index 0000000..2bc6a30
--- /dev/null
+++ b/src/test/regress/sql/rolenames.sql
@@ -0,0 +1,459 @@
+CREATE OR REPLACE FUNCTION chkrolattr()
+ RETURNS TABLE ("role" name, rolekeyword text, canlogin bool, replication bool)
+ AS $$
+SELECT r.rolname, v.keyword, r.rolcanlogin, r.rolreplication
+ FROM pg_roles r
+ JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'),
+ ('current_user', '-'),
+ ('session_user', '-'),
+ ('Public', '-'),
+ ('None', '-'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ ORDER BY 1;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION chksetconfig()
+ RETURNS TABLE (db name, "role" name, rolkeyword text, setconfig text[])
+ AS $$
+SELECT COALESCE(d.datname, 'ALL'), COALESCE(r.rolname, 'ALL'),
+ COALESCE(v.keyword, '-'), s.setconfig
+ FROM pg_db_role_setting s
+ LEFT JOIN pg_roles r ON (r.oid = s.setrole)
+ LEFT JOIN pg_database d ON (d.oid = s.setdatabase)
+ LEFT JOIN (VALUES(CURRENT_USER, 'current_user'),
+ (SESSION_USER, 'session_user'))
+ AS v(uname, keyword)
+ ON (r.rolname = v.uname)
+ORDER BY 1, 2;
+$$ LANGUAGE SQL;
+
+CREATE OR REPLACE FUNCTION chkumapping()
+ RETURNS TABLE (umname name, umserver name, umoptions text[])
+ AS $$
+SELECT r.rolname, s.srvname, m.umoptions
+ FROM pg_user_mapping m
+ LEFT JOIN pg_roles r ON (r.oid = m.umuser)
+ JOIN pg_foreign_server s ON (s.oid = m.umserver)
+ ORDER BY 2;
+$$ LANGUAGE SQL;
+
+CREATE ROLE "Public";
+CREATE ROLE "None";
+CREATE ROLE "current_user";
+CREATE ROLE "session_user";
+CREATE ROLE "user";
+
+CREATE ROLE current_user; -- error
+CREATE ROLE current_role; -- error
+CREATE ROLE session_user; -- error
+CREATE ROLE user; -- error
+CREATE ROLE all; -- error
+
+CREATE ROLE public; -- error
+CREATE ROLE "public"; -- error
+CREATE ROLE none; -- error
+CREATE ROLE "none"; -- error
+
+CREATE ROLE testrol0 SUPERUSER LOGIN;
+CREATE ROLE testrolx SUPERUSER LOGIN;
+CREATE ROLE testrol2 SUPERUSER;
+CREATE ROLE testrol1 SUPERUSER LOGIN IN ROLE testrol2;
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+-- ALTER ROLE
+BEGIN;
+SELECT * FROM chkrolattr();
+ALTER ROLE CURRENT_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE "current_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE SESSION_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER ROLE "session_user" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER "Public" WITH REPLICATION;
+ALTER USER "None" WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER testrol1 WITH NOREPLICATION;
+ALTER USER testrol2 WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ROLLBACK;
+
+ALTER ROLE USER WITH LOGIN; -- error
+ALTER ROLE CURRENT_ROLE WITH LOGIN; --error
+ALTER ROLE ALL WITH REPLICATION; -- error
+ALTER ROLE SESSION_ROLE WITH NOREPLICATION; -- error
+ALTER ROLE PUBLIC WITH NOREPLICATION; -- error
+ALTER ROLE "public" WITH NOREPLICATION; -- error
+ALTER ROLE NONE WITH NOREPLICATION; -- error
+ALTER ROLE "none" WITH NOREPLICATION; -- error
+ALTER ROLE nonexistent WITH NOREPLICATION; -- error
+
+-- ALTER USER
+BEGIN;
+SELECT * FROM chkrolattr();
+ALTER USER CURRENT_USER WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'current_user' WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER SESSION_USER WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'session_user' WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER 'Public' WITH REPLICATION;
+ALTER USER 'None' WITH REPLICATION;
+SELECT * FROM chkrolattr();
+ALTER USER testrol1 WITH NOREPLICATION;
+ALTER USER testrol2 WITH NOREPLICATION;
+SELECT * FROM chkrolattr();
+ROLLBACK;
+
+ALTER USER USER WITH LOGIN; -- error
+ALTER USER CURRENT_ROLE WITH LOGIN; -- error
+ALTER USER ALL WITH REPLICATION; -- error
+ALTER USER SESSION_ROLE WITH NOREPLICATION; -- error
+ALTER USER PUBLIC WITH NOREPLICATION; -- error
+ALTER USER "public" WITH NOREPLICATION; -- error
+ALTER USER NONE WITH NOREPLICATION; -- error
+ALTER USER "none" WITH NOREPLICATION; -- error
+ALTER USER nonexistent WITH NOREPLICATION; -- error
+
+-- ALTER ROLE SET/RESET
+SELECT * FROM chksetconfig();
+ALTER ROLE CURRENT_USER SET application_name to 'FOO';
+ALTER ROLE SESSION_USER SET application_name to 'BAR';
+ALTER ROLE "current_user" SET application_name to 'FOOFOO';
+ALTER ROLE "Public" SET application_name to 'BARBAR';
+ALTER ROLE ALL SET application_name to 'SLAP';
+SELECT * FROM chksetconfig();
+ALTER ROLE testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ALTER ROLE CURRENT_USER RESET application_name;
+ALTER ROLE SESSION_USER RESET application_name;
+ALTER ROLE "current_user" RESET application_name;
+ALTER ROLE "Public" RESET application_name;
+ALTER ROLE ALL RESET application_name;
+SELECT * FROM chksetconfig();
+
+
+ALTER ROLE CURRENT_ROLE SET application_name to 'BAZ'; -- error
+ALTER ROLE USER SET application_name to 'BOOM'; -- error
+ALTER ROLE PUBLIC SET application_name to 'BOMB'; -- error
+ALTER ROLE nonexistent SET application_name to 'BOMB'; -- error
+
+-- ALTER USER SET/RESET
+SELECT * FROM chksetconfig();
+ALTER USER CURRENT_USER SET application_name to 'FOO';
+ALTER USER SESSION_USER SET application_name to 'BAR';
+ALTER USER "current_user" SET application_name to 'FOOFOO';
+ALTER USER "Public" SET application_name to 'BARBAR';
+ALTER USER ALL SET application_name to 'SLAP';
+SELECT * FROM chksetconfig();
+ALTER USER testrol1 SET application_name to 'SLAM';
+SELECT * FROM chksetconfig();
+ALTER USER CURRENT_USER RESET application_name;
+ALTER USER SESSION_USER RESET application_name;
+ALTER USER "current_user" RESET application_name;
+ALTER USER "Public" RESET application_name;
+ALTER USER ALL RESET application_name;
+SELECT * FROM chksetconfig();
+
+
+ALTER USER CURRENT_USER SET application_name to 'BAZ'; -- error
+ALTER USER USER SET application_name to 'BOOM'; -- error
+ALTER USER PUBLIC SET application_name to 'BOMB'; -- error
+ALTER USER NONE SET application_name to 'BOMB'; -- error
+ALTER USER nonexistent SET application_name to 'BOMB'; -- error
+
+-- CREAETE SCHEMA
+set client_min_messages to error;
+CREATE SCHEMA newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA newschema5 AUTHORIZATION "Public";
+
+CREATE SCHEMA newschema6 AUTHORIZATION USER; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION PUBLIC; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION "public"; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION NONE; -- error
+CREATE SCHEMA newschema6 AUTHORIZATION nonexistent; -- error
+
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+
+DROP SCHEMA IF EXISTS newschema1;
+DROP SCHEMA IF EXISTS newschema2;
+DROP SCHEMA IF EXISTS newschema3;
+DROP SCHEMA IF EXISTS newschema4;
+DROP SCHEMA IF EXISTS newschema5;
+DROP SCHEMA IF EXISTS newschema6;
+
+CREATE SCHEMA IF NOT EXISTS newschema1 AUTHORIZATION CURRENT_USER;
+CREATE SCHEMA IF NOT EXISTS newschema2 AUTHORIZATION "current_user";
+CREATE SCHEMA IF NOT EXISTS newschema3 AUTHORIZATION SESSION_USER;
+CREATE SCHEMA IF NOT EXISTS newschema4 AUTHORIZATION testrolx;
+CREATE SCHEMA IF NOT EXISTS newschema5 AUTHORIZATION "Public";
+
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION USER; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION CURRENT_ROLE; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION PUBLIC; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION "public"; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION NONE; -- error
+CREATE SCHEMA IF NOT EXISTS newschema6 AUTHORIZATION nonexistent; -- error
+
+SELECT n.nspname, r.rolname FROM pg_namespace n
+ JOIN pg_roles r ON (r.oid = n.nspowner)
+ WHERE n.nspname LIKE 'newschema_' ORDER BY 1;
+
+-- ALTER TABLE OWNER TO
+\c -
+SET SESSION AUTHORIZATION testrol0;
+set client_min_messages to error;
+CREATE TABLE testtab1 (a int);
+CREATE TABLE testtab2 (a int);
+CREATE TABLE testtab3 (a int);
+CREATE TABLE testtab4 (a int);
+CREATE TABLE testtab5 (a int);
+CREATE TABLE testtab6 (a int);
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+ALTER TABLE testtab1 OWNER TO CURRENT_USER;
+ALTER TABLE testtab2 OWNER TO "current_user";
+ALTER TABLE testtab3 OWNER TO SESSION_USER;
+ALTER TABLE testtab4 OWNER TO testrolx;
+ALTER TABLE testtab5 OWNER TO "Public";
+
+ALTER TABLE testtab6 OWNER TO CURRENT_ROLE; -- error
+ALTER TABLE testtab6 OWNER TO USER; --error
+ALTER TABLE testtab6 OWNER TO PUBLIC; -- error
+ALTER TABLE testtab6 OWNER TO "public"; -- error
+ALTER TABLE testtab6 OWNER TO nonexistent; -- error
+
+SELECT c.relname, r.rolname
+ FROM pg_class c JOIN pg_roles r ON (r.oid = c.relowner)
+ WHERE relname LIKE 'testtab_'
+ ORDER BY 1;
+
+-- ALTER TABLE, VIEW, MATERIALIZED VIEW, FOREIGN TABLE, SEQUENCE are
+-- changed their owner in the same way.
+
+-- ALTER AGGREGATE
+\c -
+SET SESSION AUTHORIZATION testrol0;
+DROP AGGREGATE IF EXISTS testagg1(int2);
+DROP AGGREGATE IF EXISTS testagg2(int2);
+DROP AGGREGATE IF EXISTS testagg3(int2);
+DROP AGGREGATE IF EXISTS testagg4(int2);
+DROP AGGREGATE IF EXISTS testagg5(int2);
+DROP AGGREGATE IF EXISTS testagg6(int2);
+DROP AGGREGATE IF EXISTS testagg7(int2);
+DROP AGGREGATE IF EXISTS testagg8(int2);
+DROP AGGREGATE IF EXISTS testagg9(int2);
+CREATE AGGREGATE testagg1(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg2(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg3(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg4(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg5(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg6(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg7(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg8(int2) (SFUNC = int2_sum, STYPE = int8);
+CREATE AGGREGATE testagg9(int2) (SFUNC = int2_sum, STYPE = int8);
+
+\c -
+SET SESSION AUTHORIZATION testrol1;
+SET ROLE testrol2;
+
+ALTER AGGREGATE testagg1(int2) OWNER TO CURRENT_USER;
+ALTER AGGREGATE testagg2(int2) OWNER TO "current_user";
+ALTER AGGREGATE testagg3(int2) OWNER TO SESSION_USER;
+ALTER AGGREGATE testagg4(int2) OWNER TO testrolx;
+ALTER AGGREGATE testagg5(int2) OWNER TO "Public";
+
+ALTER AGGREGATE testagg6(int2) OWNER TO CURRENT_ROLE; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO USER; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO PUBLIC; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO "public"; -- error
+ALTER AGGREGATE testagg6(int2) OWNER TO nonexistent; -- error
+
+SELECT p.proname, r.rolname
+ FROM pg_proc p JOIN pg_roles r ON (r.oid = p.proowner)
+ WHERE proname LIKE 'testagg_'
+ ORDER BY 1;
+
+ALTER AGGREGATE testagg1(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg2(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg3(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg4(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg5(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg6(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg7(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg8(int2) OWNER TO regress_role_superuser;
+ALTER AGGREGATE testagg9(int2) OWNER TO regress_role_superuser;
+
+
+-- CREATE USER MAPPING
+CREATE FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv1 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv2 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv3 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv4 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv5 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv6 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv7 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv8 FOREIGN DATA WRAPPER test_wrapper;
+CREATE SERVER sv9 FOREIGN DATA WRAPPER test_wrapper;
+
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+
+CREATE USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (user 'CURRENT_ROLE'); -- error
+CREATE USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (user 'nonexistent'); -- error;
+
+SELECT * FROM chkumapping();
+
+-- ALTER USER MAPPING
+ALTER USER MAPPING FOR CURRENT_USER SERVER sv1
+ OPTIONS (SET user 'CURRENT_USER_alt');
+ALTER USER MAPPING FOR "current_user" SERVER sv2
+ OPTIONS (SET user '"current_user"_alt');
+ALTER USER MAPPING FOR USER SERVER sv3
+ OPTIONS (SET user 'USER_alt');
+ALTER USER MAPPING FOR "user" SERVER sv4
+ OPTIONS (SET user '"user"_alt');
+ALTER USER MAPPING FOR SESSION_USER SERVER sv5
+ OPTIONS (SET user 'SESSION_USER_alt');
+ALTER USER MAPPING FOR PUBLIC SERVER sv6
+ OPTIONS (SET user 'public_alt');
+ALTER USER MAPPING FOR "Public" SERVER sv7
+ OPTIONS (SET user '"Public"_alt');
+ALTER USER MAPPING FOR testrolx SERVER sv8
+ OPTIONS (SET user 'testrolx_alt');
+
+ALTER USER MAPPING FOR CURRENT_ROLE SERVER sv9
+ OPTIONS (SET user 'CURRENT_ROLE_alt');
+ALTER USER MAPPING FOR nonexistent SERVER sv9
+ OPTIONS (SET user 'nonexistent_alt'); -- error
+
+SELECT * FROM chkumapping();
+
+-- DROP USER MAPPING
+DROP USER MAPPING FOR CURRENT_USER SERVER sv1;
+DROP USER MAPPING FOR "current_user" SERVER sv2;
+DROP USER MAPPING FOR USER SERVER sv3;
+DROP USER MAPPING FOR "user" SERVER sv4;
+DROP USER MAPPING FOR SESSION_USER SERVER sv5;
+DROP USER MAPPING FOR PUBLIC SERVER sv6;
+DROP USER MAPPING FOR "Public" SERVER sv7;
+DROP USER MAPPING FOR testrolx SERVER sv8;
+
+DROP USER MAPPING FOR CURRENT_ROLE SERVER sv9; -- error
+DROP USER MAPPING FOR nonexistent SERVER sv; -- error
+SELECT * FROM chkumapping();
+
+CREATE USER MAPPING FOR CURRENT_USER SERVER sv1 OPTIONS (user 'CURRENT_USER');
+CREATE USER MAPPING FOR "current_user" SERVER sv2 OPTIONS (user '"current_user"');
+CREATE USER MAPPING FOR USER SERVER sv3 OPTIONS (user 'USER');
+CREATE USER MAPPING FOR "user" SERVER sv4 OPTIONS (user '"USER"');
+CREATE USER MAPPING FOR SESSION_USER SERVER sv5 OPTIONS (user 'SESSION_USER');
+CREATE USER MAPPING FOR PUBLIC SERVER sv6 OPTIONS (user 'PUBLIC');
+CREATE USER MAPPING FOR "Public" SERVER sv7 OPTIONS (user '"Public"');
+CREATE USER MAPPING FOR testrolx SERVER sv8 OPTIONS (user 'testrolx');
+SELECT * FROM chkumapping();
+
+-- DROP USER MAPPING IF EXISTS
+DROP USER MAPPING IF EXISTS FOR CURRENT_USER SERVER sv1;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "current_user" SERVER sv2;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR USER SERVER sv3;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "user" SERVER sv4;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR SESSION_USER SERVER sv5;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR PUBLIC SERVER sv6;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR "Public" SERVER sv7;
+SELECT * FROM chkumapping();
+DROP USER MAPPING IF EXISTS FOR testrolx SERVER sv8;
+SELECT * FROM chkumapping();
+
+DROP USER MAPPING IF EXISTS FOR CURRENT_ROLE SERVER sv9; --error
+DROP USER MAPPING IF EXISTS FOR nonexistent SERVER sv9; -- error
+
+-- GRANT/REVOKE
+UPDATE pg_proc SET proacl = null WHERE proname LIKE 'testagg_';
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2) FROM PUBLIC;
+
+GRANT ALL PRIVILEGES ON FUNCTION testagg1(int2) TO PUBLIC;
+GRANT ALL PRIVILEGES ON FUNCTION testagg2(int2) TO CURRENT_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg3(int2) TO "current_user";
+GRANT ALL PRIVILEGES ON FUNCTION testagg4(int2) TO SESSION_USER;
+GRANT ALL PRIVILEGES ON FUNCTION testagg5(int2) TO "Public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg6(int2) TO testrolx;
+GRANT ALL PRIVILEGES ON FUNCTION testagg7(int2) TO "public";
+GRANT ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ TO current_user, public, testrolx;
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO CURRENT_ROLE; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO USER; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO NONE; --error
+GRANT ALL PRIVILEGES ON FUNCTION testagg9(int2) TO "none"; --error
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg1(int2) FROM PUBLIC;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg2(int2) FROM CURRENT_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg3(int2) FROM "current_user";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg4(int2) FROM SESSION_USER;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg5(int2) FROM "Public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg6(int2) FROM testrolx;
+REVOKE ALL PRIVILEGES ON FUNCTION testagg7(int2) FROM "public";
+REVOKE ALL PRIVILEGES ON FUNCTION testagg8(int2)
+ FROM current_user, public, testrolx;
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM CURRENT_ROLE; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM USER; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM NONE; --error
+REVOKE ALL PRIVILEGES ON FUNCTION testagg9(int2) FROM "none"; --error
+
+SELECT proname, proacl FROM pg_proc WHERE proname LIKE 'testagg_';
+
+-- clean up
+\c
+
+DROP OWNED BY testrol0, "Public", "current_user", testrol1, testrol2, testrolx CASCADE;
+DROP ROLE testrol0, testrol1, testrol2, testrolx;
+DROP ROLE "Public", "None", "current_user", "session_user", "user";
There is something odd here going on:
alvherre=# alter group test add user current_user;
ERROR: role "test" is a member of role "(null)"
Surely (null) is not the right name to be reporting there ...
Attached is a rebased patch, which also has some incomplete doc changes.
With this patch applied, doing
\h ALTER ROLE
in psql looks quite odd: note how wide it has become. Maybe we should
be doing this differently? (Hmm, why don't we accept ALL in the first SET
line? Maybe that's just a mistake and the four lines should be all
identical in the first half ...)
alvherre=# \h alter role
Command: ALTER ROLE
Description: change a database role
Syntax:
ALTER ROLE { name | CURRENT_USER | SESSION_USER } [ WITH ] option [ ... ]
where option can be:
SUPERUSER | NOSUPERUSER
| CREATEDB | NOCREATEDB
| CREATEROLE | NOCREATEROLE
| CREATEUSER | NOCREATEUSER
| INHERIT | NOINHERIT
| LOGIN | NOLOGIN
| REPLICATION | NOREPLICATION
| BYPASSRLS | NOBYPASSRLS
| CONNECTION LIMIT connlimit
| [ ENCRYPTED | UNENCRYPTED ] PASSWORD 'password'
| VALID UNTIL 'timestamp'
ALTER ROLE name RENAME TO new_name
ALTER ROLE { name | CURRENT_USER | SESSION_USER } [ IN DATABASE database_name ] SET configuration_parameter { TO | = } { value | DEFAULT }
ALTER ROLE { name | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE database_name ] SET configuration_parameter FROM CURRENT
ALTER ROLE { name | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE database_name ] RESET configuration_parameter
ALTER ROLE { name | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE database_name ] RESET ALL
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
Attachments:
0001-ALTER-USER-CURRENT_USER-v8.patchtext/x-diff; charset=us-asciiDownload
diff --git a/doc/src/sgml/ref/alter_group.sgml b/doc/src/sgml/ref/alter_group.sgml
index 1432242..5f0d8b4 100644
--- a/doc/src/sgml/ref/alter_group.sgml
+++ b/doc/src/sgml/ref/alter_group.sgml
@@ -21,10 +21,10 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-ALTER GROUP <replaceable class="PARAMETER">group_name</replaceable> ADD USER <replaceable class="PARAMETER">user_name</replaceable> [, ... ]
-ALTER GROUP <replaceable class="PARAMETER">group_name</replaceable> DROP USER <replaceable class="PARAMETER">user_name</replaceable> [, ... ]
+ALTER GROUP { <replaceable class="PARAMETER">group_name</replaceable> | CURRENT_USER | SESSION_USER } ADD USER <replaceable class="PARAMETER">user_name</replaceable> [, ... ]
+ALTER GROUP { <replaceable class="PARAMETER">group_name</replaceable> | CURRENT_USER | SESSION_USER } DROP USER <replaceable class="PARAMETER">user_name</replaceable> [, ... ]
-ALTER GROUP <replaceable class="PARAMETER">group_name</replaceable> RENAME TO <replaceable>new_name</replaceable>
+ALTER GROUP { <replaceable class="PARAMETER">group_name</replaceable> | CURRENT_USER | SESSION_USER } RENAME TO <replaceable>new_name</replaceable>
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/alter_role.sgml b/doc/src/sgml/ref/alter_role.sgml
index 0471daa..59f6499 100644
--- a/doc/src/sgml/ref/alter_role.sgml
+++ b/doc/src/sgml/ref/alter_role.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ]
<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase>
@@ -39,10 +39,10 @@ ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replace
ALTER ROLE <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER ROLE <replaceable class="PARAMETER">name</replaceable> [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
-ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET <replaceable>configuration_parameter</replaceable>
+ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER | ALL } [ IN DATABASE <replaceable class="PARAMETER">database_name</replaceable> ] RESET ALL
</synopsis>
</refsynopsisdiv>
@@ -129,6 +129,25 @@ ALTER ROLE { <replaceable class="PARAMETER">name</replaceable> | ALL } [ IN DATA
</varlistentry>
<varlistentry>
+ <term>CURRENT_USER</term>
+ <listitem>
+ <para>
+ Indicates to
+ Alter the current user instead of a specifically named role.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>SESSION_USER</term>
+ <listitem>
+ <para>
+ Alter the current session role instead of a specifically named role.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>SUPERUSER</literal></term>
<term><literal>NOSUPERUSER</literal></term>
<term><literal>CREATEDB</></term>
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 58ae1da..628729d 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
+ALTER USER { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ]
<phrase>where <replaceable class="PARAMETER">option</replaceable> can be:</phrase>
@@ -38,10 +38,10 @@ ALTER USER <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replace
ALTER USER <replaceable class="PARAMETER">name</replaceable> RENAME TO <replaceable>new_name</replaceable>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
-ALTER USER <replaceable class="PARAMETER">name</replaceable> SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
-ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET <replaceable>configuration_parameter</replaceable>
-ALTER USER <replaceable class="PARAMETER">name</replaceable> RESET ALL
+ALTER USER { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } SET <replaceable>configuration_parameter</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
+ALTER USER { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } SET <replaceable>configuration_parameter</replaceable> FROM CURRENT
+ALTER USER { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } RESET <replaceable>configuration_parameter</replaceable>
+ALTER USER { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } RESET ALL
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1e3888e..e88c8c3 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -421,22 +421,25 @@ ExecuteGrantStmt(GrantStmt *stmt)
istmt.behavior = stmt->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, stmt->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
- else
- istmt.grantees =
- lappend_oid(istmt.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
}
/*
@@ -904,22 +907,25 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
iacls.behavior = action->behavior;
/*
- * Convert the PrivGrantee list into an Oid list. Note that at this point
- * we insert an ACL_ID_PUBLIC into the list if an empty role name is
- * detected (which is what the grammar uses if PUBLIC is found), so
- * downstream there shouldn't be any additional work needed to support
- * this case.
+ * Convert the RoleSpec list into an Oid list. Note that at this point
+ * we insert an ACL_ID_PUBLIC into the list if appropriate, so downstream
+ * there shouldn't be any additional work needed to support this case.
*/
foreach(cell, action->grantees)
{
- PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+ RoleSpec *grantee = (RoleSpec *) lfirst(cell);
+ Oid grantee_uid;
- if (grantee->rolname == NULL)
- iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
- else
- iacls.grantees =
- lappend_oid(iacls.grantees,
- get_role_oid(grantee->rolname, false));
+ switch (grantee->roletype)
+ {
+ case ROLESPEC_PUBLIC:
+ grantee_uid = ACL_ID_PUBLIC;
+ break;
+ default:
+ grantee_uid = get_rolespec_oid((Node *) grantee, false);
+ break;
+ }
+ iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
}
/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 59aacef..af726ca 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -699,7 +699,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
ObjectAddress
ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
{
- Oid newowner = get_role_oid(stmt->newowner, false);
+ Oid newowner = get_rolespec_oid(stmt->newowner, false);
switch (stmt->objectType)
{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index aa73357..5cc74d0 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1371,7 +1371,7 @@ CreateExtension(CreateExtensionStmt *stmt)
CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
csstmt->schemaname = schemaName;
- csstmt->authid = NULL; /* will be created by current user */
+ csstmt->authrole = NULL; /* will be created by current user */
csstmt->schemaElts = NIL;
csstmt->if_not_exists = false;
CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index bd48391..3b85c2c 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
/*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
- if (!username)
- /* PUBLIC user mapping */
- return InvalidOid;
-
- if (strcmp(username, "current_user") == 0)
- /* map to the owner */
- return GetUserId();
-
- /* map to provided user */
- return get_role_oid(username, missing_ok);
-}
-
-/*
* Internal workhorse for changing a data wrapper's owner.
*
* Allow this only for superusers; also the new owner must be a
@@ -1156,10 +1138,14 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
ObjectAddress referenced;
ForeignServer *srv;
ForeignDataWrapper *fdw;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
/* Check that the server exists. */
srv = GetForeignServerByName(stmt->servername, false);
@@ -1252,10 +1238,15 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
Oid umId;
ForeignServer *srv;
ObjectAddress address;
+ RoleSpec *role = (RoleSpec *) stmt->user;
rel = heap_open(UserMappingRelationId, RowExclusiveLock);
- useId = GetUserOidFromMapping(stmt->username, false);
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
+ useId = get_rolespec_oid(stmt->user, false);
+
srv = GetForeignServerByName(stmt->servername, false);
umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1338,20 +1329,27 @@ RemoveUserMapping(DropUserMappingStmt *stmt)
Oid useId;
Oid umId;
ForeignServer *srv;
+ RoleSpec *role = (RoleSpec *) stmt->user;
- useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
- srv = GetForeignServerByName(stmt->servername, true);
-
- if (stmt->username && !OidIsValid(useId))
+ if (role->roletype == ROLESPEC_PUBLIC)
+ useId = ACL_ID_PUBLIC;
+ else
{
- /*
- * IF EXISTS specified, role not found and not public. Notice this and
- * leave.
- */
- elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
- return InvalidOid;
+ useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+ if (!OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public. Notice this
+ * and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping",
+ role->rolename);
+ return InvalidOid;
+ }
}
+ srv = GetForeignServerByName(stmt->servername, true);
+
if (!srv)
{
if (!stmt->missing_ok)
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index e862997..a3d840d 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -129,13 +129,7 @@ parse_policy_command(const char *cmd_name)
/*
* policy_role_list_to_array
- * helper function to convert a list of role names in to an array of
- * role ids.
- *
- * Note: If PUBLIC is provided as a role name, then ACL_ID_PUBLIC is
- * used as the role id.
- *
- * roles - the list of role names to convert.
+ * helper function to convert a list of RoleSpecs to an array of role ids.
*/
static ArrayType *
policy_role_list_to_array(List *roles)
@@ -162,25 +156,25 @@ policy_role_list_to_array(List *roles)
foreach(cell, roles)
{
- Oid roleid = get_role_oid_or_public(strVal(lfirst(cell)));
+ RoleSpec *spec = lfirst(cell);
/*
* PUBLIC covers all roles, so it only makes sense alone.
*/
- if (roleid == ACL_ID_PUBLIC)
+ if (spec->roletype == ROLESPEC_PUBLIC)
{
if (num_roles != 1)
ereport(WARNING,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ignoring roles specified other than public"),
errhint("All roles are members of the public role.")));
-
- temp_array[0] = ObjectIdGetDatum(roleid);
+ temp_array[0] = ObjectIdGetDatum(ACL_ID_PUBLIC);
num_roles = 1;
break;
}
else
- temp_array[i++] = ObjectIdGetDatum(roleid);
+ temp_array[i++] =
+ ObjectIdGetDatum(get_rolespec_oid((Node *) spec, false));
}
role_ids = construct_array(temp_array, num_roles, OIDOID, sizeof(Oid), true,
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 722142e..c090ed2 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_namespace.h"
#include "commands/dbcommands.h"
@@ -42,8 +43,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
Oid
CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
{
- const char *schemaName = stmt->schemaname;
- const char *authId = stmt->authid;
+ const char *schemaName = stmt->schemaname;
Oid namespaceId;
OverrideSearchPath *overridePath;
List *parsetree_list;
@@ -58,11 +58,24 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
/*
* Who is supposed to own the new schema?
*/
- if (authId)
- owner_uid = get_role_oid(authId, false);
+ if (stmt->authrole)
+ owner_uid = get_rolespec_oid(stmt->authrole, false);
else
owner_uid = saved_uid;
+ /* fill schema name with the user name if not specified */
+ if (!schemaName)
+ {
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for role %u", owner_uid);
+ schemaName =
+ pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+ ReleaseSysCache(tuple);
+ }
+
/*
* To create a schema, must have schema-create privilege on the current
* database and must be able to become the target role (this does not
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6536778..623e6bf 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3507,7 +3507,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
break;
case AT_ChangeOwner: /* ALTER OWNER */
ATExecChangeOwner(RelationGetRelid(rel),
- get_role_oid(cmd->name, false),
+ get_rolespec_oid(cmd->newowner, false),
false, lockmode);
break;
case AT_ClusterOn: /* CLUSTER ON */
@@ -9388,7 +9388,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
HeapTuple tuple;
Oid orig_tablespaceoid;
Oid new_tablespaceoid;
- List *role_oids = roleNamesToIds(stmt->roles);
+ List *role_oids = roleSpecsToIds(stmt->roles);
/* Ensure we were not asked to move something we can't */
if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 68b6917..fd22612 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
- ownerId = get_role_oid(stmt->owner, false);
+ ownerId = get_rolespec_oid(stmt->owner, false);
else
ownerId = GetUserId();
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 0d30838..0123abc 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -445,10 +445,10 @@ CreateRole(CreateRoleStmt *stmt)
* option, rolemembers don't.
*/
AddRoleMems(stmt->role, roleid,
- adminmembers, roleNamesToIds(adminmembers),
+ adminmembers, roleSpecsToIds(adminmembers),
GetUserId(), true);
AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
/* Post creation hook for new role */
@@ -480,7 +480,9 @@ AlterRole(AlterRoleStmt *stmt)
TupleDesc pg_authid_dsc;
HeapTuple tuple,
new_tuple;
+ Form_pg_authid authform;
ListCell *option;
+ char *rolename = NULL;
char *password = NULL; /* user password */
bool encrypt_password = Password_encryption; /* encrypt password? */
char encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,33 +651,30 @@ AlterRole(AlterRoleStmt *stmt)
pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
pg_authid_dsc = RelationGetDescr(pg_authid_rel);
- tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
- if (!HeapTupleIsValid(tuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ tuple = get_rolespec_tuple(stmt->role);
+ authform = (Form_pg_authid) GETSTRUCT(tuple);
+ rolename = pstrdup(NameStr(authform->rolname));
roleid = HeapTupleGetOid(tuple);
/*
* To mess with a superuser you gotta be superuser; else you need
* createrole, or just want to change your own password
*/
- if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
+ if (authform->rolsuper || issuper >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter superusers")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
+ else if (authform->rolreplication || isreplication >= 0)
{
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to alter replication users")));
}
- else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
+ else if (authform->rolbypassrls || bypassrls >= 0)
{
if (!superuser())
ereport(ERROR,
@@ -720,11 +719,11 @@ AlterRole(AlterRoleStmt *stmt)
* Call the password checking hook if there is one defined
*/
if (check_password_hook && password)
- (*check_password_hook) (stmt->role,
- password,
- isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
- validUntil_datum,
- validUntil_null);
+ (*check_password_hook)(rolename ,
+ password,
+ isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+ validUntil_datum,
+ validUntil_null);
/*
* Build an updated tuple, perusing the information just obtained
@@ -794,7 +793,7 @@ AlterRole(AlterRoleStmt *stmt)
CStringGetTextDatum(password);
else
{
- if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+ if (!pg_md5_encrypt(password, rolename, strlen(rolename),
encrypted_password))
elog(ERROR, "password encryption failed");
new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +840,12 @@ AlterRole(AlterRoleStmt *stmt)
CommandCounterIncrement();
if (stmt->action == +1) /* add members to role */
- AddRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ AddRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
GetUserId(), false);
else if (stmt->action == -1) /* drop members from role */
- DelRoleMems(stmt->role, roleid,
- rolemembers, roleNamesToIds(rolemembers),
+ DelRoleMems(rolename, roleid,
+ rolemembers, roleSpecsToIds(rolemembers),
false);
/*
@@ -870,13 +869,7 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
if (stmt->role)
{
- roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-
- if (!HeapTupleIsValid(roletuple))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("role \"%s\" does not exist", stmt->role)));
-
+ roletuple = get_rolespec_tuple(stmt->role);
roleid = HeapTupleGetOid(roletuple);
/*
@@ -965,7 +958,8 @@ DropRole(DropRoleStmt *stmt)
foreach(item, stmt->roles)
{
- const char *role = strVal(lfirst(item));
+ RoleSpec *rolspec = lfirst(item);
+ char *role;
HeapTuple tuple,
tmp_tuple;
ScanKeyData scankey;
@@ -974,6 +968,12 @@ DropRole(DropRoleStmt *stmt)
SysScanDesc sscan;
Oid roleid;
+ if (rolspec->roletype != ROLESPEC_CSTRING)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("cannot use special role specifier in \"%s\"", "DROP ROLE")));
+ role = rolspec->rolename;
+
tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
if (!HeapTupleIsValid(tuple))
{
@@ -1243,11 +1243,11 @@ GrantRole(GrantRoleStmt *stmt)
ListCell *item;
if (stmt->grantor)
- grantor = get_role_oid(stmt->grantor, false);
+ grantor = get_rolespec_oid(stmt->grantor, false);
else
grantor = GetUserId();
- grantee_ids = roleNamesToIds(stmt->grantee_roles);
+ grantee_ids = roleSpecsToIds(stmt->grantee_roles);
/* AccessShareLock is enough since we aren't modifying pg_authid */
pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1296,7 +1296,7 @@ GrantRole(GrantRoleStmt *stmt)
void
DropOwnedObjects(DropOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
/* Check privileges */
@@ -1322,7 +1322,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
void
ReassignOwnedObjects(ReassignOwnedStmt *stmt)
{
- List *role_ids = roleNamesToIds(stmt->roles);
+ List *role_ids = roleSpecsToIds(stmt->roles);
ListCell *cell;
Oid newrole;
@@ -1338,7 +1338,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/* Must have privileges on the receiving side too */
- newrole = get_role_oid(stmt->newrole, false);
+ newrole = get_rolespec_oid(stmt->newrole, false);
if (!has_privs_of_role(GetUserId(), newrole))
ereport(ERROR,
@@ -1350,22 +1350,24 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
}
/*
- * roleNamesToIds
+ * roleSpecsToIds
*
- * Given a list of role names (as String nodes), generate a list of role OIDs
- * in the same order.
+ * Given a list of RoleSpecs, generate a list of role OIDs in the same order.
+ *
+ * ROLESPEC_PUBLIC is not allowed.
*/
List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
{
List *result = NIL;
ListCell *l;
foreach(l, memberNames)
{
- char *rolename = strVal(lfirst(l));
- Oid roleid = get_role_oid(rolename, false);
+ Node *rolespec = (Node *) lfirst(l);
+ Oid roleid;
+ roleid = get_rolespec_oid(rolespec, false);
result = lappend_oid(result, roleid);
}
return result;
@@ -1440,7 +1442,7 @@ AddRoleMems(const char *rolename, Oid roleid,
forboth(nameitem, memberNames, iditem, memberIds)
{
- const char *membername = strVal(lfirst(nameitem));
+ RoleSpec *member = lfirst(nameitem);
Oid memberid = lfirst_oid(iditem);
HeapTuple authmem_tuple;
HeapTuple tuple;
@@ -1448,6 +1450,8 @@ AddRoleMems(const char *rolename, Oid roleid,
bool new_record_nulls[Natts_pg_auth_members];
bool new_record_repl[Natts_pg_auth_members];
+
+
/*
* Refuse creation of membership loops, including the trivial case
* where a role is made a member of itself. We do this by checking to
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 9fe8008..ebb6f3a 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2504,6 +2504,18 @@ _copyXmlSerialize(const XmlSerialize *from)
return newnode;
}
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+ RoleSpec *newnode = makeNode(RoleSpec);
+
+ COPY_SCALAR_FIELD(roletype);
+ COPY_STRING_FIELD(rolename);
+ COPY_LOCATION_FIELD(location);
+
+ return newnode;
+}
+
static Query *
_copyQuery(const Query *from)
{
@@ -2650,6 +2662,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
COPY_SCALAR_FIELD(subtype);
COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(newowner);
COPY_NODE_FIELD(def);
COPY_SCALAR_FIELD(behavior);
COPY_SCALAR_FIELD(missing_ok);
@@ -2689,16 +2702,6 @@ _copyGrantStmt(const GrantStmt *from)
return newnode;
}
-static PrivGrantee *
-_copyPrivGrantee(const PrivGrantee *from)
-{
- PrivGrantee *newnode = makeNode(PrivGrantee);
-
- COPY_STRING_FIELD(rolname);
-
- return newnode;
-}
-
static FuncWithArgs *
_copyFuncWithArgs(const FuncWithArgs *from)
{
@@ -2730,7 +2733,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
COPY_NODE_FIELD(grantee_roles);
COPY_SCALAR_FIELD(is_grant);
COPY_SCALAR_FIELD(admin_opt);
- COPY_STRING_FIELD(grantor);
+ COPY_NODE_FIELD(grantor);
COPY_SCALAR_FIELD(behavior);
return newnode;
@@ -3038,7 +3041,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
COPY_NODE_FIELD(relation);
COPY_NODE_FIELD(object);
COPY_NODE_FIELD(objarg);
- COPY_STRING_FIELD(newowner);
+ COPY_NODE_FIELD(newowner);
return newnode;
}
@@ -3424,7 +3427,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
- COPY_STRING_FIELD(owner);
+ COPY_NODE_FIELD(owner);
COPY_STRING_FIELD(location);
COPY_NODE_FIELD(options);
@@ -3561,7 +3564,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
{
CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3573,7 +3576,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
{
AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_NODE_FIELD(options);
@@ -3585,7 +3588,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
{
DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
- COPY_STRING_FIELD(username);
+ COPY_NODE_FIELD(user);
COPY_STRING_FIELD(servername);
COPY_SCALAR_FIELD(missing_ok);
@@ -3698,7 +3701,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
{
AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_NODE_FIELD(options);
COPY_SCALAR_FIELD(action);
@@ -3710,7 +3713,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
{
AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
- COPY_STRING_FIELD(role);
+ COPY_NODE_FIELD(role);
COPY_STRING_FIELD(database);
COPY_NODE_FIELD(setstmt);
@@ -3769,7 +3772,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
COPY_STRING_FIELD(schemaname);
- COPY_STRING_FIELD(authid);
+ COPY_NODE_FIELD(authrole);
COPY_NODE_FIELD(schemaElts);
COPY_SCALAR_FIELD(if_not_exists);
@@ -3854,7 +3857,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
COPY_NODE_FIELD(roles);
- COPY_STRING_FIELD(newrole);
+ COPY_NODE_FIELD(newrole);
return newnode;
}
@@ -4728,9 +4731,6 @@ copyObject(const void *from)
case T_CommonTableExpr:
retval = _copyCommonTableExpr(from);
break;
- case T_PrivGrantee:
- retval = _copyPrivGrantee(from);
- break;
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
@@ -4740,6 +4740,9 @@ copyObject(const void *from)
case T_XmlSerialize:
retval = _copyXmlSerialize(from);
break;
+ case T_RoleSpec:
+ retval = _copyRoleSpec(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fe509b0..8186e84 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -973,6 +973,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
{
COMPARE_SCALAR_FIELD(subtype);
COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(newowner);
COMPARE_NODE_FIELD(def);
COMPARE_SCALAR_FIELD(behavior);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,14 +1010,6 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
}
static bool
-_equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
-{
- COMPARE_STRING_FIELD(rolname);
-
- return true;
-}
-
-static bool
_equalFuncWithArgs(const FuncWithArgs *a, const FuncWithArgs *b)
{
COMPARE_NODE_FIELD(funcname);
@@ -1041,7 +1034,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
COMPARE_NODE_FIELD(grantee_roles);
COMPARE_SCALAR_FIELD(is_grant);
COMPARE_SCALAR_FIELD(admin_opt);
- COMPARE_STRING_FIELD(grantor);
+ COMPARE_NODE_FIELD(grantor);
COMPARE_SCALAR_FIELD(behavior);
return true;
@@ -1295,7 +1288,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
COMPARE_NODE_FIELD(relation);
COMPARE_NODE_FIELD(object);
COMPARE_NODE_FIELD(objarg);
- COMPARE_STRING_FIELD(newowner);
+ COMPARE_NODE_FIELD(newowner);
return true;
}
@@ -1618,7 +1611,7 @@ static bool
_equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
- COMPARE_STRING_FIELD(owner);
+ COMPARE_NODE_FIELD(owner);
COMPARE_STRING_FIELD(location);
COMPARE_NODE_FIELD(options);
@@ -1735,7 +1728,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
static bool
_equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1745,7 +1738,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
static bool
_equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_NODE_FIELD(options);
@@ -1755,7 +1748,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
static bool
_equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
{
- COMPARE_STRING_FIELD(username);
+ COMPARE_NODE_FIELD(user);
COMPARE_STRING_FIELD(servername);
COMPARE_SCALAR_FIELD(missing_ok);
@@ -1853,7 +1846,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
static bool
_equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_NODE_FIELD(options);
COMPARE_SCALAR_FIELD(action);
@@ -1863,7 +1856,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
static bool
_equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
{
- COMPARE_STRING_FIELD(role);
+ COMPARE_NODE_FIELD(role);
COMPARE_STRING_FIELD(database);
COMPARE_NODE_FIELD(setstmt);
@@ -1912,7 +1905,7 @@ static bool
_equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
{
COMPARE_STRING_FIELD(schemaname);
- COMPARE_STRING_FIELD(authid);
+ COMPARE_NODE_FIELD(authrole);
COMPARE_NODE_FIELD(schemaElts);
COMPARE_SCALAR_FIELD(if_not_exists);
@@ -1983,7 +1976,7 @@ static bool
_equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
{
COMPARE_NODE_FIELD(roles);
- COMPARE_STRING_FIELD(newrole);
+ COMPARE_NODE_FIELD(newrole);
return true;
}
@@ -2455,6 +2448,16 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
return true;
}
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+ COMPARE_SCALAR_FIELD(roletype);
+ COMPARE_STRING_FIELD(rolename);
+ COMPARE_LOCATION_FIELD(location);
+
+ return true;
+}
+
/*
* Stuff from pg_list.h
*/
@@ -3153,9 +3156,6 @@ equal(const void *a, const void *b)
case T_CommonTableExpr:
retval = _equalCommonTableExpr(a, b);
break;
- case T_PrivGrantee:
- retval = _equalPrivGrantee(a, b);
- break;
case T_FuncWithArgs:
retval = _equalFuncWithArgs(a, b);
break;
@@ -3165,6 +3165,9 @@ equal(const void *a, const void *b)
case T_XmlSerialize:
retval = _equalXmlSerialize(a, b);
break;
+ case T_RoleSpec:
+ retval = _equalRoleSpec(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 581f7a1..b668a90 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -143,6 +143,7 @@ static Node *makeBitStringConst(char *str, int location);
static Node *makeNullAConst(int location);
static Node *makeAConst(Value *v, int location);
static Node *makeBoolAConst(bool state, int location);
+static Node *makeRoleSpec(RoleSpecType type, int location);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
static List *check_func_name(List *names, core_yyscan_t yyscanner);
static List *check_indirection(List *indirection, core_yyscan_t yyscanner);
@@ -291,7 +292,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <str> opt_type
%type <str> foreign_server_version opt_foreign_server_version
-%type <str> auth_ident
%type <str> opt_in_database
%type <str> OptSchemaName
@@ -474,12 +474,13 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <ival> Iconst SignedIconst
%type <str> Sconst comment_text notify_payload
-%type <str> RoleId opt_granted_by opt_boolean_or_string
+%type <str> RoleId opt_boolean_or_string
%type <list> var_list
%type <str> ColId ColLabel var_name type_function_name param_name
%type <str> NonReservedWord NonReservedWord_or_Sconst
%type <str> createdb_opt_name
%type <node> var_value zone_value
+%type <node> auth_ident RoleSpec opt_granted_by
%type <keyword> unreserved_keyword type_func_name_keyword
%type <keyword> col_name_keyword reserved_keyword
@@ -494,7 +495,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> constraints_set_list
%type <boolean> constraints_set_mode
-%type <str> OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str> OptTableSpace OptConsTableSpace
+%type <node> OptTableSpaceOwner
%type <ival> opt_check_option
%type <str> opt_provider security_label
@@ -871,7 +873,6 @@ CreateRoleStmt:
}
;
-
opt_with: WITH {}
| WITH_LA {}
| /*EMPTY*/ {}
@@ -1037,7 +1038,7 @@ CreateUserStmt:
*****************************************************************************/
AlterRoleStmt:
- ALTER ROLE RoleId opt_with AlterOptRoleList
+ ALTER ROLE RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1053,7 +1054,7 @@ opt_in_database:
;
AlterRoleSetStmt:
- ALTER ROLE RoleId opt_in_database SetResetClause
+ ALTER ROLE RoleSpec opt_in_database SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1079,7 +1080,7 @@ AlterRoleSetStmt:
*****************************************************************************/
AlterUserStmt:
- ALTER USER RoleId opt_with AlterOptRoleList
+ ALTER USER RoleSpec opt_with AlterOptRoleList
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1091,7 +1092,7 @@ AlterUserStmt:
AlterUserSetStmt:
- ALTER USER RoleId SetResetClause
+ ALTER USER RoleSpec SetResetClause
{
AlterRoleSetStmt *n = makeNode(AlterRoleSetStmt);
n->role = $3;
@@ -1180,7 +1181,7 @@ CreateGroupStmt:
*****************************************************************************/
AlterGroupStmt:
- ALTER GROUP_P RoleId add_drop USER role_list
+ ALTER GROUP_P RoleSpec add_drop USER role_list
{
AlterRoleStmt *n = makeNode(AlterRoleStmt);
n->role = $3;
@@ -1228,15 +1229,12 @@ DropGroupStmt:
*****************************************************************************/
CreateSchemaStmt:
- CREATE SCHEMA OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ CREATE SCHEMA OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */
- if ($3 != NULL)
- n->schemaname = $3;
- else
- n->schemaname = $5;
- n->authid = $5;
+ n->schemaname = $3;
+ n->authrole = $5;
n->schemaElts = $6;
n->if_not_exists = false;
$$ = (Node *)n;
@@ -1246,20 +1244,17 @@ CreateSchemaStmt:
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */
n->schemaname = $3;
- n->authid = NULL;
+ n->authrole = NULL;
n->schemaElts = $4;
n->if_not_exists = false;
$$ = (Node *)n;
}
- | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleId OptSchemaEltList
+ | CREATE SCHEMA IF_P NOT EXISTS OptSchemaName AUTHORIZATION RoleSpec OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* One can omit the schema name or the authorization id. */
- if ($6 != NULL)
- n->schemaname = $6;
- else
- n->schemaname = $8;
- n->authid = $8;
+ /* schema name can be omitted here, too */
+ n->schemaname = $6;
+ n->authrole = $8;
if ($9 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1272,9 +1267,9 @@ CreateSchemaStmt:
| CREATE SCHEMA IF_P NOT EXISTS ColId OptSchemaEltList
{
CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
- /* ...but not both */
+ /* ...but not here */
n->schemaname = $6;
- n->authid = NULL;
+ n->authrole = NULL;
if ($7 != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2259,12 +2254,12 @@ alter_table_cmd:
n->subtype = AT_DropOf;
$$ = (Node *)n;
}
- /* ALTER TABLE <name> OWNER TO RoleId */
- | OWNER TO RoleId
+ /* ALTER TABLE <name> OWNER TO RoleSpec */
+ | OWNER TO RoleSpec
{
AlterTableCmd *n = makeNode(AlterTableCmd);
n->subtype = AT_ChangeOwner;
- n->name = $3;
+ n->newowner = $3;
$$ = (Node *)n;
}
/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3756,7 +3751,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
}
;
-OptTableSpaceOwner: OWNER name { $$ = $2; }
+OptTableSpaceOwner: OWNER RoleSpec { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
@@ -4478,7 +4473,7 @@ import_qualification:
CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
{
CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4486,10 +4481,8 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
;
/* User mapping authorization identifier */
-auth_ident:
- CURRENT_USER { $$ = "current_user"; }
- | USER { $$ = "current_user"; }
- | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+auth_ident: RoleSpec { $$ = $1; }
+ | USER { $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1); }
;
/*****************************************************************************
@@ -4502,7 +4495,7 @@ auth_ident:
DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->missing_ok = false;
$$ = (Node *) n;
@@ -4510,7 +4503,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
| DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
{
DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
- n->username = $7;
+ n->user = $7;
n->servername = $9;
n->missing_ok = true;
$$ = (Node *) n;
@@ -4527,7 +4520,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
{
AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
- n->username = $5;
+ n->user = $5;
n->servername = $7;
n->options = $8;
$$ = (Node *) n;
@@ -4612,7 +4605,7 @@ RowSecurityOptionalWithCheck:
RowSecurityDefaultToRole:
TO role_list { $$ = $2; }
- | /* EMPTY */ { $$ = list_make1(makeString("public")); }
+ | /* EMPTY */ { $$ = list_make1(makeRoleSpec(ROLESPEC_PUBLIC, -1)); }
;
RowSecurityOptionalToRole:
@@ -5432,7 +5425,7 @@ DropOwnedStmt:
;
ReassignOwnedStmt:
- REASSIGN OWNED BY role_list TO name
+ REASSIGN OWNED BY role_list TO RoleSpec
{
ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
n->roles = $4;
@@ -6348,26 +6341,9 @@ grantee_list:
| grantee_list ',' grantee { $$ = lappend($1, $3); }
;
-grantee: RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* This hack lets us avoid reserving PUBLIC as a keyword*/
- if (strcmp($1, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $1;
- $$ = (Node *)n;
- }
- | GROUP_P RoleId
- {
- PrivGrantee *n = makeNode(PrivGrantee);
- /* Treat GROUP PUBLIC as a synonym for PUBLIC */
- if (strcmp($2, "public") == 0)
- n->rolname = NULL;
- else
- n->rolname = $2;
- $$ = (Node *)n;
- }
+grantee:
+ RoleSpec { $$ = $1; }
+ | GROUP_P RoleSpec { $$ = $2; }
;
@@ -6438,7 +6414,7 @@ opt_grant_admin_option: WITH ADMIN OPTION { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_granted_by: GRANTED BY RoleId { $$ = $3; }
+opt_granted_by: GRANTED BY RoleSpec { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -8104,7 +8080,7 @@ AlterObjectSchemaStmt:
*
*****************************************************************************/
-AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
+AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_AGGREGATE;
@@ -8113,7 +8089,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER COLLATION any_name OWNER TO RoleId
+ | ALTER COLLATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_COLLATION;
@@ -8121,7 +8097,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER CONVERSION_P any_name OWNER TO RoleId
+ | ALTER CONVERSION_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_CONVERSION;
@@ -8129,7 +8105,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DATABASE database_name OWNER TO RoleId
+ | ALTER DATABASE database_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DATABASE;
@@ -8137,7 +8113,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER DOMAIN_P any_name OWNER TO RoleId
+ | ALTER DOMAIN_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_DOMAIN;
@@ -8145,7 +8121,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER FUNCTION function_with_argtypes OWNER TO RoleId
+ | ALTER FUNCTION function_with_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FUNCTION;
@@ -8154,7 +8130,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+ | ALTER opt_procedural LANGUAGE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LANGUAGE;
@@ -8162,7 +8138,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleId
+ | ALTER LARGE_P OBJECT_P NumericOnly OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_LARGEOBJECT;
@@ -8170,7 +8146,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
+ | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPERATOR;
@@ -8179,7 +8155,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $7;
$$ = (Node *)n;
}
- | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPCLASS;
@@ -8188,7 +8164,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleId
+ | ALTER OPERATOR FAMILY any_name USING access_method OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_OPFAMILY;
@@ -8197,7 +8173,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $9;
$$ = (Node *)n;
}
- | ALTER SCHEMA name OWNER TO RoleId
+ | ALTER SCHEMA name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_SCHEMA;
@@ -8205,7 +8181,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TYPE_P any_name OWNER TO RoleId
+ | ALTER TYPE_P any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TYPE;
@@ -8213,7 +8189,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TABLESPACE name OWNER TO RoleId
+ | ALTER TABLESPACE name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TABLESPACE;
@@ -8221,7 +8197,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH DICTIONARY any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSDICTIONARY;
@@ -8229,7 +8205,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleId
+ | ALTER TEXT_P SEARCH CONFIGURATION any_name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_TSCONFIGURATION;
@@ -8237,7 +8213,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FDW;
@@ -8245,7 +8221,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $8;
$$ = (Node *)n;
}
- | ALTER SERVER name OWNER TO RoleId
+ | ALTER SERVER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_FOREIGN_SERVER;
@@ -8253,7 +8229,7 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
n->newowner = $6;
$$ = (Node *)n;
}
- | ALTER EVENT TRIGGER name OWNER TO RoleId
+ | ALTER EVENT TRIGGER name OWNER TO RoleSpec
{
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
n->objectType = OBJECT_EVENT_TRIGGER;
@@ -13113,19 +13089,86 @@ AexprConst: Iconst
Iconst: ICONST { $$ = $1; };
Sconst: SCONST { $$ = $1; };
-RoleId: NonReservedWord { $$ = $1; };
-
-role_list: RoleId
- { $$ = list_make1(makeString($1)); }
- | role_list ',' RoleId
- { $$ = lappend($1, makeString($3)); }
- ;
SignedIconst: Iconst { $$ = $1; }
| '+' Iconst { $$ = + $2; }
| '-' Iconst { $$ = - $2; }
;
+/* Role specifications */
+RoleId: RoleSpec
+ {
+ RoleSpec *spc = (RoleSpec *) $1;
+ switch (spc->roletype)
+ {
+ case ROLESPEC_CSTRING:
+ $$ = spc->rolename;
+ break;
+ case ROLESPEC_PUBLIC:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "public"),
+ errposition(@1)));
+ case ROLESPEC_SESSION_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name",
+ "SESSION_USER"),
+ errposition(@1)));
+ case ROLESPEC_CURRENT_USER:
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("%s cannot be used as a role name",
+ "CURRENT_USER"),
+ errposition(@1)));
+ }
+ }
+ ;
+
+RoleSpec: NonReservedWord
+ {
+ /*
+ * "public" and "none" are not keywords, but they must
+ * be treated specially here.
+ */
+ RoleSpec *n;
+ if (strcmp($1, "public") == 0)
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_PUBLIC, @1);
+ n->roletype = ROLESPEC_PUBLIC;
+ }
+ else if (strcmp($1, "none") == 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_RESERVED_NAME),
+ errmsg("role name \"%s\" is reserved",
+ "none"),
+ parser_errposition(@1)));
+ }
+ else
+ {
+ n = (RoleSpec *) makeRoleSpec(ROLESPEC_CSTRING, @1);
+ n->rolename = pstrdup($1);
+ }
+ $$ = (Node *) n;
+ }
+ | CURRENT_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_CURRENT_USER, @1);
+ }
+ | SESSION_USER
+ {
+ $$ = makeRoleSpec(ROLESPEC_SESSION_USER, @1);
+ }
+ ;
+
+role_list: RoleSpec
+ { $$ = list_make1($1); }
+ | role_list ',' RoleSpec
+ { $$ = lappend($1, $3); }
+ ;
+
/*
* Name classification hierarchy.
*
@@ -13812,6 +13855,20 @@ makeBoolAConst(bool state, int location)
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
+/* makeRoleSpec
+ * Create a RoleSpec with the given type
+ */
+static Node *
+makeRoleSpec(RoleSpecType type, int location)
+{
+ RoleSpec *spec = makeNode(RoleSpec);
+
+ spec->roletype = type;
+ spec->location = location;
+
+ return (Node *) spec;
+}
+
/* check_qualified_name --- check the result of qualified_name production
*
* It's easiest to let the grammar production for qualified_name allow
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index c29f106..1e6da9c 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
{
const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
char *schemaname; /* name of schema */
- char *authid; /* owner of schema */
+ RoleSpec *authrole; /* owner of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -2723,7 +2723,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
- cxt.authid = stmt->authid;
+ cxt.authrole = (RoleSpec *) stmt->authrole;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 411d779..d4b5364 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,99 @@ get_role_oid_or_public(const char *rolname)
return get_role_oid(rolname, false);
}
+
+/*
+ * Given a RoleSpec node, return the OID it points 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 cached HeapTuple it points 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;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index ccadb04..d35cb0c 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -31,6 +31,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
extern ObjectAddress RenameRole(const char *oldname, const char *newname);
extern void DropOwnedObjects(DropOwnedStmt *stmt);
extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
#endif /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 97ef0fc..38469ef 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
T_XmlSerialize,
T_WithClause,
T_CommonTableExpr,
+ T_RoleSpec,
/*
* TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index ac13302..497559d 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -285,6 +285,25 @@ typedef struct CollateClause
} CollateClause;
/*
+ * RoleSpec - a role name or one of a few special values.
+ */
+typedef enum RoleSpecType
+{
+ ROLESPEC_CSTRING, /* role name is stored as a C string */
+ ROLESPEC_CURRENT_USER, /* role spec is CURRENT_USER */
+ ROLESPEC_SESSION_USER, /* role spec is SESSION_USER */
+ ROLESPEC_PUBLIC /* role name is "public" */
+} RoleSpecType;
+
+typedef struct RoleSpec
+{
+ NodeTag type;
+ RoleSpecType roletype; /* Type of this rolespec */
+ char *rolename; /* filled only for ROLESPEC_CSTRING */
+ int location; /* token location, or -1 if unknown */
+} RoleSpec;
+
+/*
* FuncCall - a function or aggregate invocation
*
* agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1263,7 +1282,7 @@ typedef struct CreateSchemaStmt
{
NodeTag type;
char *schemaname; /* the name of the schema to create */
- char *authid; /* the owner of the created schema */
+ Node *authrole; /* the owner of the created schema */
List *schemaElts; /* schema components (list of parsenodes) */
bool if_not_exists; /* just do nothing if schema already exists? */
} CreateSchemaStmt;
@@ -1362,7 +1381,8 @@ typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */
NodeTag type;
AlterTableType subtype; /* Type of table alteration to apply */
char *name; /* column, constraint, or trigger to act on,
- * or new owner or tablespace */
+ * or tablespace */
+ Node *newowner; /* RoleSpec */
Node *def; /* definition of new column, index,
* constraint, or parent table */
DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */
@@ -1434,17 +1454,11 @@ typedef struct GrantStmt
* or plain names (as Value strings) */
List *privileges; /* list of AccessPriv nodes */
/* privileges == NIL denotes ALL PRIVILEGES */
- List *grantees; /* list of PrivGrantee nodes */
+ List *grantees; /* list of RoleSpec nodes */
bool grant_option; /* grant or revoke grant option */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantStmt;
-typedef struct PrivGrantee
-{
- NodeTag type;
- char *rolname; /* if NULL then PUBLIC */
-} PrivGrantee;
-
/*
* Note: FuncWithArgs carries only the types of the input parameters of the
* function. So it is sufficient to identify an existing function, but it
@@ -1487,7 +1501,7 @@ typedef struct GrantRoleStmt
List *grantee_roles; /* list of member roles to add/delete */
bool is_grant; /* true = GRANT, false = REVOKE */
bool admin_opt; /* with admin option */
- char *grantor; /* set grantor to other than current role */
+ Node *grantor; /* set grantor to other than current role */
DropBehavior behavior; /* drop behavior (for REVOKE) */
} GrantRoleStmt;
@@ -1699,7 +1713,7 @@ typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
- char *owner;
+ Node *owner;
char *location;
List *options;
} CreateTableSpaceStmt;
@@ -1825,7 +1839,7 @@ typedef struct CreateForeignTableStmt
typedef struct CreateUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} CreateUserMappingStmt;
@@ -1833,7 +1847,7 @@ typedef struct CreateUserMappingStmt
typedef struct AlterUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
List *options; /* generic options to server */
} AlterUserMappingStmt;
@@ -1841,7 +1855,7 @@ typedef struct AlterUserMappingStmt
typedef struct DropUserMappingStmt
{
NodeTag type;
- char *username; /* username or PUBLIC/CURRENT_USER */
+ Node *user; /* user role */
char *servername; /* server name */
bool missing_ok; /* ignore missing mappings */
} DropUserMappingStmt;
@@ -1991,7 +2005,7 @@ typedef struct CreateRoleStmt
typedef struct AlterRoleStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
List *options; /* List of DefElem nodes */
int action; /* +1 = add members, -1 = drop members */
} AlterRoleStmt;
@@ -1999,7 +2013,7 @@ typedef struct AlterRoleStmt
typedef struct AlterRoleSetStmt
{
NodeTag type;
- char *role; /* role name */
+ Node *role; /* role */
char *database; /* database name, or NULL */
VariableSetStmt *setstmt; /* SET or RESET subcommand */
} AlterRoleSetStmt;
@@ -2375,7 +2389,7 @@ typedef struct AlterOwnerStmt
RangeVar *relation; /* in case it's a table */
List *object; /* in case it's some other object */
List *objarg; /* argument types, if applicable */
- char *newowner; /* the new owner */
+ Node *newowner; /* the new owner */
} AlterOwnerStmt;
@@ -2831,7 +2845,7 @@ typedef struct ReassignOwnedStmt
{
NodeTag type;
List *roles;
- char *newrole;
+ Node *newrole;
} ReassignOwnedStmt;
/*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index ab0df6c..35f8853 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -24,6 +24,7 @@
#ifndef ACL_H
#define ACL_H
+#include "access/htup.h"
#include "nodes/parsenodes.h"
#include "utils/array.h"
#include "utils/snapshot.h"
@@ -227,8 +228,10 @@ extern bool is_member_of_role(Oid member, Oid role);
extern bool is_member_of_role_nosuper(Oid member, Oid role);
extern bool is_admin_of_role(Oid member, Oid role);
extern void check_is_member_of_role(Oid member, Oid role);
-extern Oid get_role_oid(const char *rolname, bool missing_ok);
-extern Oid get_role_oid_or_public(const char *rolname);
+extern Oid get_role_oid(const char *rolename, bool missing_ok);
+extern Oid get_role_oid_or_public(const char *rolename);
+extern Oid get_rolespec_oid(const Node *node, bool missing_ok);
+extern HeapTuple get_rolespec_tuple(const Node *node);
extern void select_best_grantor(Oid roleId, AclMode privileges,
const Acl *acl, Oid ownerId,
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index e0ae2f2..6d3b865 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -59,7 +59,7 @@ test: create_index create_view
# ----------
# Another group of parallel tests
# ----------
-test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views
+test: create_aggregate create_function_3 create_cast constraints triggers inherit create_table_like typed_table vacuum drop_if_exists updatable_views rolenames
# ----------
# sanity_check does a vacuum, affecting the sort order of SELECT *
diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule
index 7f762bd..8326894 100644
--- a/src/test/regress/serial_schedule
+++ b/src/test/regress/serial_schedule
@@ -71,6 +71,7 @@ test: typed_table
test: vacuum
test: drop_if_exists
test: updatable_views
+test: rolenames
test: sanity_check
test: errors
test: select
Alvaro Herrera wrote:
With this patch applied, doing
\h ALTER ROLE
in psql looks quite odd: note how wide it has become. Maybe we should
be doing this differently? (Hmm, why don't we accept ALL in the first SET
line? Maybe that's just a mistake and the four lines should be all
identical in the first half ...)
I have fixed the remaining issues, completed the doc changes, and
pushed. Given the lack of feedback I had to follow my gut on the best
way to change the docs. I added the regression test you submitted with
some additional changes, mainly to make sure they don't fail immediately
when other databases exist; maybe some more concurrency or platform
issues will show up there, but let's see what the buildfarm says.
Thanks Horiguchi-san for the patch and everyone for the reviews. (It's
probably worthwhile giving things an extra look.)
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Thank you for completing this and very sorry not to respond these
days.
I understood that it is committed after I noticed that rebasing
my code failed..
Although after committed, I found some issues as I looked on
it. Please forgive me to comment it now after all this time.
Several changes in docs according to the changed syntax and one
change in code itself to allow CURRENT_USER in GRANT <roleid> TO
<roleid> syntax.
At Mon, 9 Mar 2015 15:50:32 -0300, Alvaro Herrera <alvherre@2ndquadrant.com> wrote in <20150309185032.GQ3291@alvh.no-ip.org>
Alvaro Herrera wrote:
With this patch applied, doing
\h ALTER ROLE
in psql looks quite odd: note how wide it has become. Maybe we should
be doing this differently? (Hmm, why don't we accept ALL in the first SET
line? Maybe that's just a mistake and the four lines should be all
identical in the first half ...)I have fixed the remaining issues, completed the doc changes, and
pushed. Given the lack of feedback I had to follow my gut on the best
way to change the docs. I added the regression test you submitted with
some additional changes, mainly to make sure they don't fail immediately
when other databases exist; maybe some more concurrency or platform
issues will show up there, but let's see what the buildfarm says.Thanks Horiguchi-san for the patch and everyone for the reviews. (It's
probably worthwhile giving things an extra look.)
====
| =# alter role current_user rename to "PubLic";
| ERROR: CURRENT_USER cannot be used as a role name
| LINE 1: alter role current_user rename to "PubLic";
| ^
The error message sounds somewhat different from the intention. I
think the following message would be clearer.
| ERROR: CURRENT_USER cannot be used as a role name here
====
The document sql-altergroup.html says
| ALTER GROUP role_specification ADD USER user_name [, ... ]
But current_user is also usable in user_name list. So the doc
should be as following, but it would not be necessary to be fixed
because it is an obsolete commnand..
| ALTER GROUP role_specification ADD USER role_specification [, ... ]
"ALTER GROUP role_spec ADD/DROP USER role_spec" is naturally
denied so I think no additional description is needed.
====
sql-alterpolicy.html
"ALTER POLICY name ON table_name TO" also accepts current_user
and so as the role to which the policy applies.
# As a different topic, the syntax "ALTER POLICY <pname> ON
# <tname> TO <user>" looks a bit wired, it might be better be to
# be "ON <tname> APPLY TO <user>" but I shouldn't try to fix it
# since it is a long standing syntax..
====
sql-createtablespace.html
"OWNER username" should be "OWNER user_name | (CURRENT|SESSION)_USER"
====
sql-drop-owned.html, sql-reassign-owned.html
"name" should be " {name | (CURRENT|SESSION)_USER}"
For REASSIGN OWNED, TO clause also needs the same fix.
======
sql-grant.html, sql-revoke.html,
"GRANT <roles> TO <roles>" and "REVOKE <roles> FROM <roles>" are
the modern equivalents of the deprecated syntaxes "ALTER <roles>
ADD USER <roles>" and "ALTER <roles> DROP USER <roles>"
respectively. But the current parser infrastructure doesn't allow
coexistence of the two following syntaxes but I couldn't find the
way to their coexistence.
# more precisely, I guess the GRANT followed by both
# privelege_list and role_list will steps out of the realm of
# LALR(1), which I don't know well of..
"GRANT <privs> ON ..."
"GRANT <roles> TO ..."
After some struggle, I decided to add special rules
(CURRENT|SESSION)_USER to the non-terminal "privilege" and make a
room to store RoleSpec in AccessPriv. This is quite ugly but
there seems no way other than that to accomplish it.. (AccessPriv
already conveys other than the information different from what
its name represents:p)
After this fix, the commands like following are processed
properly. public and none are simply handled as nonexistent
names.
GRANT test1 TO CURRENT_USER;
GRANT <priv> ON <table> TO <role> properly rejects CURRENT_USER
as <priv>.
But the change in gram.y cuases changes in preproc.y as following,
privilege:
SELECT opt_column_list
{
...
| ColId opt_column_list
{
$$ = cat_str(2,$1,$2);
}
+ | CURRENT_USER
+ {
+ $$ = mm_strdup("current_user");
+ }
+ | SESSION_USER
+ {
+ $$ = mm_strdup("session_user");
+ }
;
I don't understand what this change causes...
=====
I haven't looked on the docs for syntaxes related to
AlterOwnerStatement. But perhaps they don't be wrong.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
Attachments:
0001-Some-additional-changes-for-ALTER-ROLE-USER-CURRENT_.patchtext/x-patch; charset=us-asciiDownload
>From 26afc656576c8778921ff44519e3de86866ab138 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Thu, 12 Mar 2015 20:56:14 +0900
Subject: [PATCH] Some additional changes for ALTER ROLE/USER CURRENT_USER.
Some documents are not edit according to new specs. Addition to it,
"GRANT <roles> TO <roles>" and "REVOKE <roles> FROM <roles>" syntaxes,
which are the modern replacement of "ALTER GROUP ADD/DROP USER"
syntax, are not accepted by the previous patch.
This patch fixes some docs and changes the syntax of GRANT command to
accept CURRENT_ROLE and SESSION_ROLE as other similar command does.
---
doc/src/sgml/ref/alter_policy.sgml | 2 +-
doc/src/sgml/ref/create_policy.sgml | 2 +-
doc/src/sgml/ref/create_tablespace.sgml | 2 +-
doc/src/sgml/ref/drop_owned.sgml | 2 +-
doc/src/sgml/ref/grant.sgml | 3 ++-
doc/src/sgml/ref/reassign_owned.sgml | 3 ++-
doc/src/sgml/ref/revoke.sgml | 36 ++++++++++++++++++++-------------
src/backend/catalog/aclchk.c | 4 ++++
src/backend/commands/user.c | 10 +++++++--
src/backend/nodes/equalfuncs.c | 1 +
src/backend/parser/Makefile | 2 +-
src/backend/parser/gram.y | 22 +++++++++++++++++---
src/include/nodes/parsenodes.h | 4 ++++
src/test/regress/expected/rolenames.out | 4 ++--
14 files changed, 69 insertions(+), 28 deletions(-)
diff --git a/doc/src/sgml/ref/alter_policy.sgml b/doc/src/sgml/ref/alter_policy.sgml
index 6d03db5..2e63206 100644
--- a/doc/src/sgml/ref/alter_policy.sgml
+++ b/doc/src/sgml/ref/alter_policy.sgml
@@ -23,7 +23,7 @@ PostgreSQL documentation
<synopsis>
ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable>
[ RENAME TO <replaceable class="PARAMETER">new_name</replaceable> ]
- [ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] ]
+ [ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( <replaceable class="parameter">using_expression</replaceable> ) ]
[ WITH CHECK ( <replaceable class="parameter">check_expression</replaceable> ) ]
</synopsis>
diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml
index 868a6c1..7efb45e 100644
--- a/doc/src/sgml/ref/create_policy.sgml
+++ b/doc/src/sgml/ref/create_policy.sgml
@@ -23,7 +23,7 @@ PostgreSQL documentation
<synopsis>
CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table_name</replaceable>
[ FOR { ALL | SELECT | INSERT | UPDATE | DELETE } ]
- [ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] ]
+ [ TO { <replaceable class="parameter">role_name</replaceable> | PUBLIC | CURRENT_USER | SESSION_USER } [, ...] ]
[ USING ( <replaceable class="parameter">using_expression</replaceable> ) ]
[ WITH CHECK ( <replaceable class="parameter">check_expression</replaceable> ) ]
</synopsis>
diff --git a/doc/src/sgml/ref/create_tablespace.sgml b/doc/src/sgml/ref/create_tablespace.sgml
index 9072d07..5756c3e 100644
--- a/doc/src/sgml/ref/create_tablespace.sgml
+++ b/doc/src/sgml/ref/create_tablespace.sgml
@@ -22,7 +22,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
CREATE TABLESPACE <replaceable class="parameter">tablespace_name</replaceable>
- [ OWNER <replaceable class="parameter">user_name</replaceable> ]
+ [ OWNER { <replaceable>new_owner</replaceable> | CURRENT_USER | SESSION_USER } ]
LOCATION '<replaceable class="parameter">directory</replaceable>'
[ WITH ( <replaceable class="PARAMETER">tablespace_option</replaceable> = <replaceable class="PARAMETER">value</replaceable> [, ... ] ) ]
</synopsis>
diff --git a/doc/src/sgml/ref/drop_owned.sgml b/doc/src/sgml/ref/drop_owned.sgml
index 1cd8e60..64906ef 100644
--- a/doc/src/sgml/ref/drop_owned.sgml
+++ b/doc/src/sgml/ref/drop_owned.sgml
@@ -21,7 +21,7 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-DROP OWNED BY <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ]
+DROP OWNED BY { <replaceable class="PARAMETER">name</replaceable> | CURRENT_USER | SESSION_USER } [, ...] [ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index d9ac8d2..a984a74 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -79,6 +79,8 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
ON TYPE <replaceable>type_name</replaceable> [, ...]
TO <replaceable class="PARAMETER">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
+GRANT <replaceable class="PARAMETER">role_specification</replaceable> [, ...] TO <replaceable class="PARAMETER">role_specification</replaceable> [, ...] [ WITH ADMIN OPTION ]
+
<phrase>where <replaceable class="PARAMETER">role_specification</replaceable> can be:</phrase>
[ GROUP ] <replaceable class="PARAMETER">role_name</replaceable>
@@ -86,7 +88,6 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
| CURRENT_USER
| SESSION_USER
-GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replaceable class="PARAMETER">role_name</replaceable> [, ...] [ WITH ADMIN OPTION ]
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/reassign_owned.sgml b/doc/src/sgml/ref/reassign_owned.sgml
index d7d6abb..382cba3 100644
--- a/doc/src/sgml/ref/reassign_owned.sgml
+++ b/doc/src/sgml/ref/reassign_owned.sgml
@@ -21,7 +21,8 @@ PostgreSQL documentation
<refsynopsisdiv>
<synopsis>
-REASSIGN OWNED BY <replaceable class="PARAMETER">old_role</replaceable> [, ...] TO <replaceable class="PARAMETER">new_role</replaceable>
+REASSIGN OWNED BY { <replaceable class="PARAMETER">old_role</replaceable> | CURRENT_USER | SESSION_USER } [, ...]
+ TO { <replaceable class="PARAMETER">new_role</replaceable> | CURRENT_USER | SESSION_USER }
</synopsis>
</refsynopsisdiv>
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 36c286b..24910f6 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -26,14 +26,14 @@ REVOKE [ GRANT OPTION FOR ]
[, ...] | ALL [ PRIVILEGES ] }
ON { [ TABLE ] <replaceable class="PARAMETER">table_name</replaceable> [, ...]
| ALL TABLES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | REFERENCES } ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] )
[, ...] | ALL [ PRIVILEGES ] ( <replaceable class="PARAMETER">column_name</replaceable> [, ...] ) }
ON [ TABLE ] <replaceable class="PARAMETER">table_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
@@ -41,73 +41,81 @@ REVOKE [ GRANT OPTION FOR ]
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE <replaceable class="PARAMETER">sequence_name</replaceable> [, ...]
| ALL SEQUENCES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>database_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON FOREIGN SERVER <replaceable>server_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ EXECUTE | ALL [ PRIVILEGES ] }
ON { FUNCTION <replaceable>function_name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_type</replaceable> [, ...] ] ) [, ...]
| ALL FUNCTIONS IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE <replaceable>lang_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
ON LARGE OBJECT <replaceable class="PARAMETER">loid</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ USAGE | ALL [ PRIVILEGES ] }
ON TYPE <replaceable>type_name</replaceable> [, ...]
- FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">role_specification</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ ADMIN OPTION FOR ]
- <replaceable class="PARAMETER">role_name</replaceable> [, ...] FROM <replaceable class="PARAMETER">role_name</replaceable> [, ...]
+ <replaceable class="PARAMETER">role_specification</replaceable> [, ...] FROM <replaceable class="PARAMETER">role_specification</replaceable> [, ...]
[ CASCADE | RESTRICT ]
+
+<phrase>where <replaceable class="PARAMETER">role_specification</replaceable> can be:</phrase>
+
+ [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable>
+ | PUBLIC
+ | CURRENT_USER
+ | SESSION_USER
+
</synopsis>
</refsynopsisdiv>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 8e75c27..2c35645 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -533,6 +533,7 @@ ExecuteGrantStmt(GrantStmt *stmt)
* If it's a column-level specification, we just set it aside in
* col_privs for the moment; but insist it's for a relation.
*/
+
if (privnode->cols)
{
if (stmt->objtype != ACL_OBJECT_RELATION)
@@ -543,6 +544,9 @@ ExecuteGrantStmt(GrantStmt *stmt)
continue;
}
+ if (privnode->rolespec) /* syntax error */
+ elog(ERROR, "\"%s\" cannot be specified as privilege",
+ privnode->rolespec->rolename);
if (privnode->priv_name == NULL) /* parser mistake? */
elog(ERROR, "AccessPriv node must specify privilege or columns");
priv = string_to_privilege(privnode->priv_name);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 75f1b3c..66e7257 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1256,11 +1256,17 @@ GrantRole(GrantRoleStmt *stmt)
foreach(item, stmt->granted_roles)
{
AccessPriv *priv = (AccessPriv *) lfirst(item);
+ RoleSpec *rolespec = priv->rolespec;
char *rolename = priv->priv_name;
Oid roleid;
- /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
- if (rolename == NULL || priv->cols != NIL)
+ /*
+ * Must reject priv(columns) and ALL PRIVILEGES(columns) if priv is
+ * not a rolespec
+ */
+ if (rolespec)
+ rolename = get_rolespec_name(rolespec);
+ else if (rolename == NULL || priv->cols != NIL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("column names cannot be included in GRANT/REVOKE ROLE")));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index fcd58ad..eef3b95 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1026,6 +1026,7 @@ _equalAccessPriv(const AccessPriv *a, const AccessPriv *b)
{
COMPARE_STRING_FIELD(priv_name);
COMPARE_NODE_FIELD(cols);
+ COMPARE_NODE_FIELD(rolespec);
return true;
}
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index 0395bd5..3c002a2 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -38,7 +38,7 @@ endif
gram.h: gram.c ;
-gram.c: BISONFLAGS += -d
+gram.c: BISONFLAGS += -vd
gram.c: BISON_CHECK_CMD = $(PERL) $(srcdir)/check_keywords.pl $< $(top_srcdir)/src/include/parser/kwlist.h
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index cf0d317..9d75a63 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6201,9 +6201,25 @@ privilege: SELECT opt_column_list
n->cols = $2;
$$ = n;
}
+ | CURRENT_USER
+ {
+ RoleSpec *rs =
+ (RoleSpec *)makeRoleSpec(ROLESPEC_CURRENT_USER, @1);
+ AccessPriv *n = makeNode(AccessPriv);
+ n->rolespec = (Node*)rs;
+ rs->rolename = pstrdup($1);
+ $$ = n;
+ }
+ | SESSION_USER
+ {
+ RoleSpec *rs =
+ (RoleSpec *)makeRoleSpec(ROLESPEC_SESSION_USER, @1);
+ AccessPriv *n = makeNode(AccessPriv);
+ n->rolespec = (Node*)rs;
+ rs->rolename = pstrdup($1);
+ }
;
-
/* Don't bother trying to fold the first two rules into one using
* opt_table. You're going to get conflicts.
*/
@@ -13166,13 +13182,13 @@ RoleId: RoleSpec
case ROLESPEC_SESSION_USER:
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
- errmsg("%s cannot be used as a role name",
+ errmsg("%s cannot be used as a role name here",
"SESSION_USER"),
parser_errposition(@1)));
case ROLESPEC_CURRENT_USER:
ereport(ERROR,
(errcode(ERRCODE_RESERVED_NAME),
- errmsg("%s cannot be used as a role name",
+ errmsg("%s cannot be used as a role name here",
"CURRENT_USER"),
parser_errposition(@1)));
}
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 38ed661..4bdffef 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1480,12 +1480,16 @@ typedef struct FuncWithArgs
* cols == NIL denotes "all columns"
* Note that simple "ALL PRIVILEGES" is represented as a NIL list, not
* an AccessPriv with both fields null.
+ *
+ * In some cases, AccessPriv conveys RoleSpec to allow special roles such as
+ * CURRENT_USER or SESSION_USER. rolespec is filled for the cases.
*/
typedef struct AccessPriv
{
NodeTag type;
char *priv_name; /* string name of privilege */
List *cols; /* list of Value strings */
+ Node *rolespec; /* filled if any rolespec specific info exists */
} AccessPriv;
/* ----------------------
diff --git a/src/test/regress/expected/rolenames.out b/src/test/regress/expected/rolenames.out
index 1879337..8f88c02 100644
--- a/src/test/regress/expected/rolenames.out
+++ b/src/test/regress/expected/rolenames.out
@@ -43,7 +43,7 @@ CREATE ROLE "current_user";
CREATE ROLE "session_user";
CREATE ROLE "user";
CREATE ROLE current_user; -- error
-ERROR: CURRENT_USER cannot be used as a role name
+ERROR: CURRENT_USER cannot be used as a role name here
LINE 1: CREATE ROLE current_user;
^
CREATE ROLE current_role; -- error
@@ -51,7 +51,7 @@ ERROR: syntax error at or near "current_role"
LINE 1: CREATE ROLE current_role;
^
CREATE ROLE session_user; -- error
-ERROR: SESSION_USER cannot be used as a role name
+ERROR: SESSION_USER cannot be used as a role name here
LINE 1: CREATE ROLE session_user;
^
CREATE ROLE user; -- error
--
2.1.0.GIT
Kyotaro HORIGUCHI wrote:
Thank you for completing this and very sorry not to respond these
days.I understood that it is committed after I noticed that rebasing
my code failed..
You'd do well to check your email, I guess :-)
Although after committed, I found some issues as I looked on
it. Please forgive me to comment it now after all this time.
====
| =# alter role current_user rename to "PubLic";
| ERROR: CURRENT_USER cannot be used as a role name
| LINE 1: alter role current_user rename to "PubLic";
| ^The error message sounds somewhat different from the intention. I
think the following message would be clearer.| ERROR: CURRENT_USER cannot be used as a role name here
Okay, changed.
====
The document sql-altergroup.html says| ALTER GROUP role_specification ADD USER user_name [, ... ]
But current_user is also usable in user_name list. So the doc
should be as following, but it would not be necessary to be fixed
because it is an obsolete commnand..| ALTER GROUP role_specification ADD USER role_specification [, ... ]
Yeah, EDONTCARE.
"ALTER GROUP role_spec ADD/DROP USER role_spec" is naturally
denied so I think no additional description is needed.
+1
====
sql-alterpolicy.html"ALTER POLICY name ON table_name TO" also accepts current_user
and so as the role to which the policy applies.
Changed.
# As a different topic, the syntax "ALTER POLICY <pname> ON
# <tname> TO <user>" looks a bit wired, it might be better be to
# be "ON <tname> APPLY TO <user>" but I shouldn't try to fix it
# since it is a long standing syntax..
Yeah, it's a bit strange. Not a strong opinion. Maybe you should raise
it as a separate thread.
====
sql-createtablespace.html
sql-drop-owned.html, sql-reassign-owned.html
Changed.
======
sql-grant.html, sql-revoke.html,"GRANT <roles> TO <roles>" and "REVOKE <roles> FROM <roles>" are
the modern equivalents of the deprecated syntaxes "ALTER <roles>
ADD USER <roles>" and "ALTER <roles> DROP USER <roles>"
respectively. But the current parser infrastructure doesn't allow
coexistence of the two following syntaxes but I couldn't find the
way to their coexistence.
I decided to leave this out. I think we should consider it as a new
patch for 9.6; these changes aren't as clear-cut as the rest of your
patch. I didn't want to have to research the ecpg changes.
--
�lvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers
Hello,
At Thu, 30 Apr 2015 17:12:25 -0300, Alvaro Herrera <alvherre@2ndquadrant.com> wrote in <20150430201225.GV4369@alvh.no-ip.org>
Kyotaro HORIGUCHI wrote:
Thank you for completing this and very sorry not to respond these
days.I understood that it is committed after I noticed that rebasing
my code failed..You'd do well to check your email, I guess :-)
Yeah, I agree with you since I noticed that before I read the
mail mentioning that. I should be more carefull:( Sorry to bother
you and thank you for your kindness.
| =# alter role current_user rename to "PubLic";
| ERROR: CURRENT_USER cannot be used as a role name
| LINE 1: alter role current_user rename to "PubLic";
| ^The error message sounds somewhat different from the intention. I
think the following message would be clearer.| ERROR: CURRENT_USER cannot be used as a role name here
Okay, changed.
====
The document sql-altergroup.html says| ALTER GROUP role_specification ADD USER user_name [, ... ]
But current_user is also usable in user_name list. So the doc
should be as following, but it would not be necessary to be fixed
because it is an obsolete commnand..| ALTER GROUP role_specification ADD USER role_specification [, ... ]
Yeah, EDONTCARE.
"ALTER GROUP role_spec ADD/DROP USER role_spec" is naturally
denied so I think no additional description is needed.+1
====
sql-alterpolicy.html"ALTER POLICY name ON table_name TO" also accepts current_user
and so as the role to which the policy applies.Changed.
# As a different topic, the syntax "ALTER POLICY <pname> ON
# <tname> TO <user>" looks a bit wired, it might be better be to
# be "ON <tname> APPLY TO <user>" but I shouldn't try to fix it
# since it is a long standing syntax..Yeah, it's a bit strange. Not a strong opinion. Maybe you should raise
it as a separate thread.====
sql-createtablespace.html
sql-drop-owned.html, sql-reassign-owned.htmlChanged.
Thank you applying the changes above.
======
sql-grant.html, sql-revoke.html,"GRANT <roles> TO <roles>" and "REVOKE <roles> FROM <roles>" are
the modern equivalents of the deprecated syntaxes "ALTER <roles>
ADD USER <roles>" and "ALTER <roles> DROP USER <roles>"
respectively. But the current parser infrastructure doesn't allow
coexistence of the two following syntaxes but I couldn't find the
way to their coexistence.I decided to leave this out. I think we should consider it as a new
patch for 9.6; these changes aren't as clear-cut as the rest of your
patch. I didn't want to have to research the ecpg changes.
Ok, it sounds fair enough.
regards,
--
Kyotaro Horiguchi
NTT Open Source Software Center
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers