On 2020-06-24 20:21, Peter Eisentraut wrote:
On 2020-06-24 10:12, Vik Fearing wrote:
On 6/24/20 8:35 AM, Peter Eisentraut wrote:
I was checking some loose ends in SQL conformance, when I noticed: We
support GRANT role ... GRANTED BY CURRENT_USER, but we don't support
CURRENT_ROLE in that place, even though in PostgreSQL they are
equivalent.  Here is a trivial patch to add that.


The only thing that isn't dead-obvious about this patch is the commit
message says "[PATCH 1/2]".  What is in the other part?

Hehe.  The second patch is some in-progress work to add the GRANTED BY
clause to the regular GRANT command.  More on that perhaps at a later date.

Here is the highly anticipated and quite underwhelming second part of this patch set.

--
Peter Eisentraut
2ndQuadrant, an EDB company
https://www.2ndquadrant.com/
From 72b1e99337b6fc9e72bcca003eb2d18351079261 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 10 Dec 2020 19:38:21 +0100
Subject: [PATCH] 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 of SQL
feature T332.  In the future, perhaps more interesting things could be
done with this, too.
---
 doc/src/sgml/ref/grant.sgml          | 25 ++++++++++++++++++++++---
 doc/src/sgml/ref/revoke.sgml         | 13 +++++++++++++
 src/backend/catalog/aclchk.c         | 16 ++++++++++++++++
 src/backend/catalog/sql_features.txt |  2 +-
 src/backend/nodes/copyfuncs.c        |  1 +
 src/backend/nodes/equalfuncs.c       |  1 +
 src/backend/parser/gram.y            | 13 ++++++++-----
 src/include/nodes/parsenodes.h       |  1 +
 8 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index c3db393bde..a897712de2 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -26,58 +26,71 @@
     ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, 
...]
          | ALL TABLES IN SCHEMA <replaceable 
class="parameter">schema_name</replaceable> [, ...] }
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { { 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> [, 
...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { { USAGE | SELECT | UPDATE }
     [, ...] | ALL [ PRIVILEGES ] }
     ON { SEQUENCE <replaceable class="parameter">sequence_name</replaceable> 
[, ...]
          | ALL SEQUENCES IN SCHEMA <replaceable 
class="parameter">schema_name</replaceable> [, ...] }
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
     ON DATABASE <replaceable>database_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { USAGE | ALL [ PRIVILEGES ] }
     ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { USAGE | ALL [ PRIVILEGES ] }
     ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { USAGE | ALL [ PRIVILEGES ] }
     ON FOREIGN SERVER <replaceable>server_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { EXECUTE | ALL [ PRIVILEGES ] }
     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> [, ...] ] ) ] [, ...]
          | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA <replaceable 
class="parameter">schema_name</replaceable> [, ...] }
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { USAGE | ALL [ PRIVILEGES ] }
     ON LANGUAGE <replaceable>lang_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
     ON LARGE OBJECT <replaceable class="parameter">loid</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
     ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { CREATE | ALL [ PRIVILEGES ] }
     ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT { USAGE | ALL [ PRIVILEGES ] }
     ON TYPE <replaceable>type_name</replaceable> [, ...]
     TO <replaceable class="parameter">role_specification</replaceable> [, ...] 
[ WITH GRANT OPTION ]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
 
 GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO 
<replaceable class="parameter">role_specification</replaceable> [, ...]
     [ WITH ADMIN OPTION ]
@@ -133,6 +146,12 @@ <title>GRANT on Database Objects</title>
    to <literal>PUBLIC</literal>.
   </para>
 
+  <para>
+   If <literal>GRANTED BY</literal> is specified, the specified grantor must
+   be the current user.  This clause is currently present in this form only
+   for SQL compatibility.
+  </para>
+
   <para>
    There is no need to grant privileges to the owner of an object
    (usually the user that created it),
@@ -410,9 +429,9 @@ <title>Compatibility</title>
 
    <para>
     The SQL standard allows the <literal>GRANTED BY</literal> option to
-    be used in all forms of <command>GRANT</command>.  PostgreSQL only
-    supports it when granting role membership, and even then only superusers
-    may use it in nontrivial ways.
+    specify only <literal>CURRENT_USER</literal> or
+    <literal>CURRENT_ROLE</literal>.  The other variants are PostgreSQL
+    extensions.
    </para>
 
    <para>
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 35ff87a4f5..3014c864ea 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -27,6 +27,7 @@
     ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, 
...]
          | ALL TABLES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] 
}
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
@@ -34,6 +35,7 @@
     [, ...] | ALL [ PRIVILEGES ] ( <replaceable 
class="parameter">column_name</replaceable> [, ...] ) }
     ON [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, 
...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
@@ -42,30 +44,35 @@
     ON { SEQUENCE <replaceable class="parameter">sequence_name</replaceable> 
[, ...]
          | ALL SEQUENCES IN SCHEMA <replaceable>schema_name</replaceable> [, 
...] }
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { { CREATE | CONNECT | TEMPORARY | TEMP } [, ...] | ALL [ PRIVILEGES ] }
     ON DATABASE <replaceable>database_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { USAGE | ALL [ PRIVILEGES ] }
     ON DOMAIN <replaceable>domain_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { USAGE | ALL [ PRIVILEGES ] }
     ON FOREIGN DATA WRAPPER <replaceable>fdw_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { USAGE | ALL [ PRIVILEGES ] }
     ON FOREIGN SERVER <replaceable>server_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
@@ -73,36 +80,42 @@
     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> [, ...] ] ) ] [, ...]
          | ALL { FUNCTIONS | PROCEDURES | ROUTINES } IN SCHEMA 
<replaceable>schema_name</replaceable> [, ...] }
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { USAGE | ALL [ PRIVILEGES ] }
     ON LANGUAGE <replaceable>lang_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { { SELECT | UPDATE } [, ...] | ALL [ PRIVILEGES ] }
     ON LARGE OBJECT <replaceable class="parameter">loid</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
     ON SCHEMA <replaceable>schema_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { CREATE | ALL [ PRIVILEGES ] }
     ON TABLESPACE <replaceable>tablespace_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ GRANT OPTION FOR ]
     { USAGE | ALL [ PRIVILEGES ] }
     ON TYPE <replaceable>type_name</replaceable> [, ...]
     FROM <replaceable class="parameter">role_specification</replaceable> [, 
...]
+    [ GRANTED BY <replaceable 
class="parameter">role_specification</replaceable> ]
     [ CASCADE | RESTRICT ]
 
 REVOKE [ ADMIN OPTION FOR ]
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index c4594b0b09..1fa8f4d575 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -363,6 +363,22 @@ ExecuteGrantStmt(GrantStmt *stmt)
        const char *errormsg;
        AclMode         all_privileges;
 
+       if (stmt->grantor)
+       {
+               Oid                     grantor;
+
+               grantor = get_rolespec_oid(stmt->grantor, false);
+
+               /*
+                * Currently, this clause is only for SQL compatibility, not 
very
+                * interesting otherwise.
+                */
+               if (grantor != GetUserId())
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("grantor must be current 
user")));
+       }
+
        /*
         * Turn the regular GrantStmt into the InternalGrant form.
         */
diff --git a/src/backend/catalog/sql_features.txt 
b/src/backend/catalog/sql_features.txt
index caa971c435..86519ad297 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -475,7 +475,7 @@ T324        Explicit security for SQL routines              
        NO
 T325   Qualified SQL parameter references                      YES     
 T326   Table functions                 NO      
 T331   Basic roles                     YES     
-T332   Extended roles                  NO      mostly supported
+T332   Extended roles                  YES     
 T341   Overloading of SQL-invoked functions and procedures                     
YES     
 T351   Bracketed SQL comments (/*...*/ comments)                       YES     
 T431   Extended grouping capabilities                  YES     
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 70f8b718e0..fe4082adbc 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -3256,6 +3256,7 @@ _copyGrantStmt(const GrantStmt *from)
        COPY_NODE_FIELD(privileges);
        COPY_NODE_FIELD(grantees);
        COPY_SCALAR_FIELD(grant_option);
+       COPY_NODE_FIELD(grantor);
        COPY_SCALAR_FIELD(behavior);
 
        return newnode;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 541e0e6b48..7f898e4b36 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -1133,6 +1133,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
        COMPARE_NODE_FIELD(privileges);
        COMPARE_NODE_FIELD(grantees);
        COMPARE_SCALAR_FIELD(grant_option);
+       COMPARE_NODE_FIELD(grantor);
        COMPARE_SCALAR_FIELD(behavior);
 
        return true;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 8f341ac006..95c397ecd2 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -6722,7 +6722,7 @@ opt_from_in:      from_in
  *****************************************************************************/
 
 GrantStmt:     GRANT privileges ON privilege_target TO grantee_list
-                       opt_grant_grant_option
+                       opt_grant_grant_option opt_granted_by
                                {
                                        GrantStmt *n = makeNode(GrantStmt);
                                        n->is_grant = true;
@@ -6732,13 +6732,14 @@ GrantStmt:      GRANT privileges ON privilege_target TO 
grantee_list
                                        n->objects = ($4)->objs;
                                        n->grantees = $6;
                                        n->grant_option = $7;
+                                       n->grantor = $8;
                                        $$ = (Node*)n;
                                }
                ;
 
 RevokeStmt:
                        REVOKE privileges ON privilege_target
-                       FROM grantee_list opt_drop_behavior
+                       FROM grantee_list opt_granted_by opt_drop_behavior
                                {
                                        GrantStmt *n = makeNode(GrantStmt);
                                        n->is_grant = false;
@@ -6748,11 +6749,12 @@ RevokeStmt:
                                        n->objtype = ($4)->objtype;
                                        n->objects = ($4)->objs;
                                        n->grantees = $6;
-                                       n->behavior = $7;
+                                       n->grantor = $7;
+                                       n->behavior = $8;
                                        $$ = (Node *)n;
                                }
                        | REVOKE GRANT OPTION FOR privileges ON privilege_target
-                       FROM grantee_list opt_drop_behavior
+                       FROM grantee_list opt_granted_by opt_drop_behavior
                                {
                                        GrantStmt *n = makeNode(GrantStmt);
                                        n->is_grant = false;
@@ -6762,7 +6764,8 @@ RevokeStmt:
                                        n->objtype = ($7)->objtype;
                                        n->objects = ($7)->objs;
                                        n->grantees = $9;
-                                       n->behavior = $10;
+                                       n->grantor = $10;
+                                       n->behavior = $11;
                                        $$ = (Node *)n;
                                }
                ;
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 48a79a7657..41d6f4f191 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -1930,6 +1930,7 @@ typedef struct GrantStmt
        /* privileges == NIL denotes ALL PRIVILEGES */
        List       *grantees;           /* list of RoleSpec nodes */
        bool            grant_option;   /* grant or revoke grant option */
+       RoleSpec   *grantor;
        DropBehavior behavior;          /* drop behavior (for REVOKE) */
 } GrantStmt;
 
-- 
2.29.2

Reply via email to