Skip to content

Commit 6aaaa76

Browse files
committed
Allow GRANTED BY clause in normal GRANT and REVOKE statements
The SQL standard allows a GRANTED BY clause on GRANT and REVOKE (privilege) statements that can specify CURRENT_USER or CURRENT_ROLE. In PostgreSQL, both of these are the default behavior. Since we already have all the parsing support for this for the GRANT (role) statement, we might as well add basic support for this for the privilege variant as well. This allows us to check off SQL feature T332. In the future, perhaps more interesting things could be done with this, too. Reviewed-by: Simon Riggs <simon@2ndquadrant.com> Discussion: https://www.postgresql.org/message-id/flat/f2feac44-b4c5-f38f-3699-2851d6a76dc9@2ndquadrant.com
1 parent 7da8341 commit 6aaaa76

File tree

10 files changed

+71
-13
lines changed

10 files changed

+71
-13
lines changed

doc/src/sgml/ref/grant.sgml

+22-3
Original file line numberDiff line numberDiff line change
@@ -26,58 +26,71 @@ GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
2626
ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
2727
| ALL TABLES IN SCHEMA <replaceable class="parameter">schema_name</replaceable> [, ...] }
2828
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
29+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
2930

3031
GRANT { { SELECT | INSERT | UPDATE | REFERENCES } ( <replaceable class="parameter">column_name</replaceable> [, ...] )
3132
[, ...] | ALL [ PRIVILEGES ] ( <replaceable class="parameter">column_name</replaceable> [, ...] ) }
3233
ON [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
3334
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
35+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
3436

3537
GRANT { { USAGE | SELECT | UPDATE }
3638
[, ...] | ALL [ PRIVILEGES ] }
3739
ON { SEQUENCE <replaceable class="parameter">sequence_name</replaceable> [, ...]
3840
| ALL SEQUENCES IN SCHEMA <replaceable class="parameter">schema_name</replaceable> [, ...] }
3941
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
42+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
4043

4144
GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
4245
ON DATABASE <replaceable>database_name</replaceable> [, ...]
4346
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
47+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
4448

4549
GRANT { USAGE | ALL [ PRIVILEGES ] }
4650
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
4751
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
52+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
4853

4954
GRANT { USAGE | ALL [ PRIVILEGES ] }
5055
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
5156
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
57+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
5258

5359
GRANT { USAGE | ALL [ PRIVILEGES ] }
5460
ON FOREIGN SERVER <replaceable>server_name</replaceable> [, ...]
5561
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
62+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
5663

5764
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
5865
ON { { FUNCTION | PROCEDURE | ROUTINE } <replaceable>routine_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_type</replaceable> [, ...] ] ) ] [, ...]
5966
| ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA <replaceable class="parameter">schema_name</replaceable> [, ...] }
6067
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
68+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
6169

6270
GRANT { USAGE | ALL [ PRIVILEGES ] }
6371
ON LANGUAGE <replaceable>lang_name</replaceable> [, ...]
6472
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
73+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
6574

6675
GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
6776
ON LARGE OBJECT <replaceable class="parameter">loid</replaceable> [, ...]
6877
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
78+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
6979

7080
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
7181
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
7282
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
83+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
7384

7485
GRANT { CREATE | ALL [ PRIVILEGES ] }
7586
ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
7687
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
88+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
7789

7890
GRANT { USAGE | ALL [ PRIVILEGES ] }
7991
ON TYPE <replaceable>type_name</replaceable> [, ...]
8092
TO <replaceable class="parameter">role_specification</replaceable> [, ...] [ WITH GRANT OPTION ]
93+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
8194

8295
GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replaceable class="parameter">role_specification</replaceable> [, ...]
8396
[ WITH ADMIN OPTION ]
@@ -133,6 +146,12 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
133146
to <literal>PUBLIC</literal>.
134147
</para>
135148

149+
<para>
150+
If <literal>GRANTED BY</literal> is specified, the specified grantor must
151+
be the current user. This clause is currently present in this form only
152+
for SQL compatibility.
153+
</para>
154+
136155
<para>
137156
There is no need to grant privileges to the owner of an object
138157
(usually the user that created it),
@@ -410,9 +429,9 @@ GRANT admins TO joe;
410429

411430
<para>
412431
The SQL standard allows the <literal>GRANTED BY</literal> option to
413-
be used in all forms of <command>GRANT</command>. PostgreSQL only
414-
supports it when granting role membership, and even then only superusers
415-
may use it in nontrivial ways.
432+
specify only <literal>CURRENT_USER</literal> or
433+
<literal>CURRENT_ROLE</literal>. The other variants are PostgreSQL
434+
extensions.
416435
</para>
417436

418437
<para>

doc/src/sgml/ref/revoke.sgml

+13
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@ REVOKE [ GRANT OPTION FOR ]
2727
ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
2828
| ALL TABLES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
2929
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
30+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
3031
[ CASCADE | RESTRICT ]
3132

3233
REVOKE [ GRANT OPTION FOR ]
3334
{ { SELECT | INSERT | UPDATE | REFERENCES } ( <replaceable class="parameter">column_name</replaceable> [, ...] )
3435
[, ...] | ALL [ PRIVILEGES ] ( <replaceable class="parameter">column_name</replaceable> [, ...] ) }
3536
ON [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
3637
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
38+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
3739
[ CASCADE | RESTRICT ]
3840

3941
REVOKE [ GRANT OPTION FOR ]
@@ -42,67 +44,78 @@ REVOKE [ GRANT OPTION FOR ]
4244
ON { SEQUENCE <replaceable class="parameter">sequence_name</replaceable> [, ...]
4345
| ALL SEQUENCES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
4446
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
47+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
4548
[ CASCADE | RESTRICT ]
4649

4750
REVOKE [ GRANT OPTION FOR ]
4851
{ { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
4952
ON DATABASE <replaceable>database_name</replaceable> [, ...]
5053
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
54+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
5155
[ CASCADE | RESTRICT ]
5256

5357
REVOKE [ GRANT OPTION FOR ]
5458
{ USAGE | ALL [ PRIVILEGES ] }
5559
ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
5660
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
61+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
5762
[ CASCADE | RESTRICT ]
5863

5964
REVOKE [ GRANT OPTION FOR ]
6065
{ USAGE | ALL [ PRIVILEGES ] }
6166
ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
6267
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
68+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
6369
[ CASCADE | RESTRICT ]
6470

6571
REVOKE [ GRANT OPTION FOR ]
6672
{ USAGE | ALL [ PRIVILEGES ] }
6773
ON FOREIGN SERVER <replaceable>server_name</replaceable> [, ...]
6874
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
75+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
6976
[ CASCADE | RESTRICT ]
7077

7178
REVOKE [ GRANT OPTION FOR ]
7279
{ EXECUTE | ALL [ PRIVILEGES ] }
7380
ON { { FUNCTION | PROCEDURE | ROUTINE } <replaceable>function_name</replaceable> [ ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">arg_name</replaceable> ] <replaceable class="parameter">arg_type</replaceable> [, ...] ] ) ] [, ...]
7481
| ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }
7582
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
83+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
7684
[ CASCADE | RESTRICT ]
7785

7886
REVOKE [ GRANT OPTION FOR ]
7987
{ USAGE | ALL [ PRIVILEGES ] }
8088
ON LANGUAGE <replaceable>lang_name</replaceable> [, ...]
8189
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
90+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
8291
[ CASCADE | RESTRICT ]
8392

8493
REVOKE [ GRANT OPTION FOR ]
8594
{ { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
8695
ON LARGE OBJECT <replaceable class="parameter">loid</replaceable> [, ...]
8796
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
97+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
8898
[ CASCADE | RESTRICT ]
8999

90100
REVOKE [ GRANT OPTION FOR ]
91101
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
92102
ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
93103
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
104+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
94105
[ CASCADE | RESTRICT ]
95106

96107
REVOKE [ GRANT OPTION FOR ]
97108
{ CREATE | ALL [ PRIVILEGES ] }
98109
ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
99110
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
111+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
100112
[ CASCADE | RESTRICT ]
101113

102114
REVOKE [ GRANT OPTION FOR ]
103115
{ USAGE | ALL [ PRIVILEGES ] }
104116
ON TYPE <replaceable>type_name</replaceable> [, ...]
105117
FROM <replaceable class="parameter">role_specification</replaceable> [, ...]
118+
[ GRANTED BY <replaceable class="parameter">role_specification</replaceable> ]
106119
[ CASCADE | RESTRICT ]
107120

108121
REVOKE [ ADMIN OPTION FOR ]

src/backend/catalog/aclchk.c

+16
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,22 @@ ExecuteGrantStmt(GrantStmt *stmt)
363363
const char *errormsg;
364364
AclMode all_privileges;
365365

366+
if (stmt->grantor)
367+
{
368+
Oid grantor;
369+
370+
grantor = get_rolespec_oid(stmt->grantor, false);
371+
372+
/*
373+
* Currently, this clause is only for SQL compatibility, not very
374+
* interesting otherwise.
375+
*/
376+
if (grantor != GetUserId())
377+
ereport(ERROR,
378+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
379+
errmsg("grantor must be current user")));
380+
}
381+
366382
/*
367383
* Turn the regular GrantStmt into the InternalGrant form.
368384
*/

src/backend/catalog/sql_features.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ T324 Explicit security for SQL routines NO
475475
T325 Qualified SQL parameter references YES
476476
T326 Table functions NO
477477
T331 Basic roles YES
478-
T332 Extended roles NO mostly supported
478+
T332 Extended roles YES
479479
T341 Overloading of SQL-invoked functions and procedures YES
480480
T351 Bracketed SQL comments (/*...*/ comments) YES
481481
T431 Extended grouping capabilities YES

src/backend/nodes/copyfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -3270,6 +3270,7 @@ _copyGrantStmt(const GrantStmt *from)
32703270
COPY_NODE_FIELD(privileges);
32713271
COPY_NODE_FIELD(grantees);
32723272
COPY_SCALAR_FIELD(grant_option);
3273+
COPY_NODE_FIELD(grantor);
32733274
COPY_SCALAR_FIELD(behavior);
32743275

32753276
return newnode;

src/backend/nodes/equalfuncs.c

+1
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
11451145
COMPARE_NODE_FIELD(privileges);
11461146
COMPARE_NODE_FIELD(grantees);
11471147
COMPARE_SCALAR_FIELD(grant_option);
1148+
COMPARE_NODE_FIELD(grantor);
11481149
COMPARE_SCALAR_FIELD(behavior);
11491150

11501151
return true;

src/backend/parser/gram.y

+8-5
Original file line numberDiff line numberDiff line change
@@ -6772,7 +6772,7 @@ opt_from_in: from_in
67726772
*****************************************************************************/
67736773

67746774
GrantStmt: GRANT privileges ON privilege_target TO grantee_list
6775-
opt_grant_grant_option
6775+
opt_grant_grant_option opt_granted_by
67766776
{
67776777
GrantStmt *n = makeNode(GrantStmt);
67786778
n->is_grant = true;
@@ -6782,13 +6782,14 @@ GrantStmt: GRANT privileges ON privilege_target TO grantee_list
67826782
n->objects = ($4)->objs;
67836783
n->grantees = $6;
67846784
n->grant_option = $7;
6785+
n->grantor = $8;
67856786
$$ = (Node*)n;
67866787
}
67876788
;
67886789

67896790
RevokeStmt:
67906791
REVOKE privileges ON privilege_target
6791-
FROM grantee_list opt_drop_behavior
6792+
FROM grantee_list opt_granted_by opt_drop_behavior
67926793
{
67936794
GrantStmt *n = makeNode(GrantStmt);
67946795
n->is_grant = false;
@@ -6798,11 +6799,12 @@ RevokeStmt:
67986799
n->objtype = ($4)->objtype;
67996800
n->objects = ($4)->objs;
68006801
n->grantees = $6;
6801-
n->behavior = $7;
6802+
n->grantor = $7;
6803+
n->behavior = $8;
68026804
$$ = (Node *)n;
68036805
}
68046806
| REVOKE GRANT OPTION FOR privileges ON privilege_target
6805-
FROM grantee_list opt_drop_behavior
6807+
FROM grantee_list opt_granted_by opt_drop_behavior
68066808
{
68076809
GrantStmt *n = makeNode(GrantStmt);
68086810
n->is_grant = false;
@@ -6812,7 +6814,8 @@ RevokeStmt:
68126814
n->objtype = ($7)->objtype;
68136815
n->objects = ($7)->objs;
68146816
n->grantees = $9;
6815-
n->behavior = $10;
6817+
n->grantor = $10;
6818+
n->behavior = $11;
68166819
$$ = (Node *)n;
68176820
}
68186821
;

src/include/nodes/parsenodes.h

+1
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,7 @@ typedef struct GrantStmt
19491949
/* privileges == NIL denotes ALL PRIVILEGES */
19501950
List *grantees; /* list of RoleSpec nodes */
19511951
bool grant_option; /* grant or revoke grant option */
1952+
RoleSpec *grantor;
19521953
DropBehavior behavior; /* drop behavior (for REVOKE) */
19531954
} GrantStmt;
19541955

src/test/regress/expected/privileges.out

+4-2
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ SELECT * FROM atest1;
7070
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
7171
GRANT SELECT ON atest2 TO regress_priv_user2;
7272
GRANT UPDATE ON atest2 TO regress_priv_user3;
73-
GRANT INSERT ON atest2 TO regress_priv_user4;
74-
GRANT TRUNCATE ON atest2 TO regress_priv_user5;
73+
GRANT INSERT ON atest2 TO regress_priv_user4 GRANTED BY CURRENT_USER;
74+
GRANT TRUNCATE ON atest2 TO regress_priv_user5 GRANTED BY CURRENT_ROLE;
75+
GRANT TRUNCATE ON atest2 TO regress_priv_user4 GRANTED BY regress_priv_user5; -- error
76+
ERROR: grantor must be current user
7577
SET SESSION AUTHORIZATION regress_priv_user2;
7678
SELECT session_user, current_user;
7779
session_user | current_user

src/test/regress/sql/privileges.sql

+4-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ SELECT * FROM atest1;
6464
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
6565
GRANT SELECT ON atest2 TO regress_priv_user2;
6666
GRANT UPDATE ON atest2 TO regress_priv_user3;
67-
GRANT INSERT ON atest2 TO regress_priv_user4;
68-
GRANT TRUNCATE ON atest2 TO regress_priv_user5;
67+
GRANT INSERT ON atest2 TO regress_priv_user4 GRANTED BY CURRENT_USER;
68+
GRANT TRUNCATE ON atest2 TO regress_priv_user5 GRANTED BY CURRENT_ROLE;
69+
70+
GRANT TRUNCATE ON atest2 TO regress_priv_user4 GRANTED BY regress_priv_user5; -- error
6971

7072

7173
SET SESSION AUTHORIZATION regress_priv_user2;

0 commit comments

Comments
 (0)