diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 72ecc45..3ad9fab 100644
*** a/doc/src/sgml/ref/grant.sgml
--- b/doc/src/sgml/ref/grant.sgml
*************** GRANT { { SELECT | INSERT | UPDATE | REF
*** 32,37 ****
--- 32,46 ----
ON [ TABLE ] table_name [, ...]
TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+ GRANT { SELECT | ALL [ PRIVILEGES ] }
+ ON { FOREIGN TABLE foreign_table_name [, ...]
+ | ALL FOREIGN TABLES IN SCHEMA schema_name [, ...] }
+ TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
+ GRANT { SELECT | ALL [ PRIVILEGES ] } ( column [, ...] )
+ ON FOREIGN TABLE foreign_table_name [, ...]
+ TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
GRANT { { USAGE | SELECT | UPDATE }
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE sequence_name [, ...]
*************** GRANT rol
*** 81,87 ****
The GRANT command has two basic variants: one
that grants privileges on a database object (table, column, view, sequence,
! database, foreign-data wrapper, foreign server, function,
procedural language, schema, or tablespace), and one that grants
membership in a role. These variants are similar in many ways, but
they are different enough to be described separately.
--- 90,96 ----
The GRANT command has two basic variants: one
that grants privileges on a database object (table, column, view, sequence,
! foreign table, database, foreign-data wrapper, foreign server, function,
procedural language, schema, or tablespace), and one that grants
membership in a role. These variants are similar in many ways, but
they are different enough to be described separately.
*************** GRANT rol
*** 100,107 ****
There is also an option to grant privileges on all objects of the same
type within one or more schemas. This functionality is currently supported
! only for tables, sequences, and functions (but note that ALL
! TABLES> is considered to include views).
--- 109,116 ----
There is also an option to grant privileges on all objects of the same
type within one or more schemas. This functionality is currently supported
! only for tables, sequences, functions and foreign tables (but note that
! ALL TABLES> is considered to include views).
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index 204c986..70702bd 100644
*** a/doc/src/sgml/ref/revoke.sgml
--- b/doc/src/sgml/ref/revoke.sgml
*************** REVOKE [ GRANT OPTION FOR ]
*** 37,42 ****
--- 37,56 ----
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
+ { SELECT | ALL [ PRIVILEGES ] }
+ ON { FOREIGN TABLE foreign_table_name [, ...]
+ | ALL FOREIGN TABLES IN SCHEMA schema_name [, ...] }
+ FROM { [ GROUP ] role_name | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
+ { SELECT ( column [, ...] )
+ | ALL [ PRIVILEGES ] ( column [, ...] ) }
+ ON FOREIGN TABLE foreign_table_name [, ...]
+ FROM { [ GROUP ] role_name | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
{ { USAGE | SELECT | UPDATE }
[, ...] | ALL [ PRIVILEGES ] }
ON { SEQUENCE sequence_name [, ...]
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 693b634..5aa9977 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** ExecuteGrantStmt(GrantStmt *stmt)
*** 518,524 ****
*/
if (privnode->cols)
{
! if (stmt->objtype != ACL_OBJECT_RELATION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("column privileges are only valid for relations")));
--- 518,525 ----
*/
if (privnode->cols)
{
! if (stmt->objtype != ACL_OBJECT_RELATION &&
! stmt->objtype != ACL_OBJECT_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("column privileges are only valid for relations")));
*************** objectsInSchemaToOids(GrantObjectType ob
*** 729,746 ****
switch (objtype)
{
case ACL_OBJECT_RELATION:
! /* Process regular tables, views and foreign tables */
objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
objects = list_concat(objects, objs);
objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
objects = list_concat(objects, objs);
- objs = getRelationsInNamespace(namespaceId, RELKIND_FOREIGN_TABLE);
- objects = list_concat(objects, objs);
break;
case ACL_OBJECT_SEQUENCE:
objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
objects = list_concat(objects, objs);
break;
case ACL_OBJECT_FUNCTION:
{
ScanKeyData key[1];
--- 730,750 ----
switch (objtype)
{
case ACL_OBJECT_RELATION:
! /* Process regular tables and views */
objs = getRelationsInNamespace(namespaceId, RELKIND_RELATION);
objects = list_concat(objects, objs);
objs = getRelationsInNamespace(namespaceId, RELKIND_VIEW);
objects = list_concat(objects, objs);
break;
case ACL_OBJECT_SEQUENCE:
objs = getRelationsInNamespace(namespaceId, RELKIND_SEQUENCE);
objects = list_concat(objects, objs);
break;
+ case ACL_OBJECT_FOREIGN_TABLE:
+ objs = getRelationsInNamespace(namespaceId,
+ RELKIND_FOREIGN_TABLE);
+ objects = list_concat(objects, objs);
+ break;
case ACL_OBJECT_FUNCTION:
{
ScanKeyData key[1];
*************** ExecGrant_Relation(InternalGrant *istmt)
*** 1938,1944 ****
AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
if (col_privs->priv_name == NULL)
! this_privileges = ACL_ALL_RIGHTS_COLUMN;
else
this_privileges = string_to_privilege(col_privs->priv_name);
--- 1942,1957 ----
AccessPriv *col_privs = (AccessPriv *) lfirst(cell_colprivs);
if (col_privs->priv_name == NULL)
! {
! /*
! * Columns of a foreign table accept same privilege as foreign
! * table itself.
! */
! if (pg_class_tuple->relkind == RELKIND_FOREIGN_TABLE)
! this_privileges = ACL_ALL_RIGHTS_FOREIGN_TABLE;
! else
! this_privileges = ACL_ALL_RIGHTS_COLUMN;
! }
else
this_privileges = string_to_privilege(col_privs->priv_name);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index a22ab66..5ad69e0 100644
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** privilege_target:
*** 5463,5468 ****
--- 5463,5476 ----
n->objs = $5;
$$ = n;
}
+ | ALL FOREIGN TABLES IN_P SCHEMA name_list
+ {
+ PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
+ n->targtype = ACL_TARGET_ALL_IN_SCHEMA;
+ n->objtype = ACL_OBJECT_FOREIGN_TABLE;
+ n->objs = $6;
+ $$ = n;
+ }
| ALL FUNCTIONS IN_P SCHEMA name_list
{
PrivTarget *n = (PrivTarget *) palloc(sizeof(PrivTarget));
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index c05bcab..4e284a5 100644
*** a/src/test/regress/expected/foreign_data.out
--- b/src/test/regress/expected/foreign_data.out
*************** SELECT * FROM ft1;
*** 675,680 ****
--- 675,811 ----
ERROR: foreign-data wrapper "dummy" has no handler
EXPLAIN SELECT * FROM ft1; -- ERROR
ERROR: foreign-data wrapper "dummy" has no handler
+ -- GRANT FOREIGN TABLE
+ GRANT SELECT ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT SELECT (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT INSERT ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type INSERT for foreign table
+ GRANT INSERT (c1) ON FOREIGN TABLE ft1 TO foreign_data_user; -- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT UPDATE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type UPDATE for foreign table
+ GRANT UPDATE (c1) ON FOREIGN TABLE ft1 TO foreign_data_user; -- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT DELETE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type DELETE for foreign table
+ GRANT TRUNCATE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type TRUNCATE for foreign table
+ GRANT REFERENCES ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type REFERENCES for foreign table
+ GRANT REFERENCES (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;-- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT TRIGGER ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type TRIGGER for foreign table
+ GRANT USAGE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type USAGE for foreign table
+ GRANT EXECUTE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type EXECUTE for foreign table
+ -- omitting FOREIGN TABLE
+ GRANT SELECT ON ft1 TO foreign_data_user;
+ GRANT SELECT (c1) ON ft1 TO foreign_data_user;
+ GRANT INSERT ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT INSERT (c1) ON ft1 TO foreign_data_user; -- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT UPDATE ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT UPDATE (c1) ON ft1 TO foreign_data_user; -- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT DELETE ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT TRUNCATE ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT REFERENCES ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT REFERENCES (c1) ON ft1 TO foreign_data_user ;-- WARNING
+ WARNING: foreign table "ft1" only supports SELECT column privileges
+ GRANT TRIGGER ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT USAGE ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: foreign table "ft1" only supports SELECT privileges
+ GRANT EXECUTE ON ft1 TO foreign_data_user; -- ERROR
+ ERROR: invalid privilege type EXECUTE for relation
+ \dp ft1
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ --------+------+---------------+---------------------------------------+-----------------------------------------
+ public | ft1 | foreign table | foreign_data_user=r/foreign_data_user | c1: +
+ | | | | foreign_data_user=r/foreign_data_user
+ (1 row)
+
+ REVOKE SELECT ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE SELECT (c1) ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE INSERT ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type INSERT for foreign table
+ REVOKE UPDATE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type UPDATE for foreign table
+ REVOKE DELETE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type DELETE for foreign table
+ REVOKE TRUNCATE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type TRUNCATE for foreign table
+ REVOKE REFERENCES ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type REFERENCES for foreign table
+ REVOKE TRIGGER ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type TRIGGER for foreign table
+ REVOKE USAGE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type USAGE for foreign table
+ REVOKE EXECUTE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ ERROR: invalid privilege type EXECUTE for foreign table
+ \dp ft1
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ --------+------+---------------+-------------------+--------------------------
+ public | ft1 | foreign table | |
+ (1 row)
+
+ -- GRANT/REVOKE ALL
+ GRANT ALL ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT ALL (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;
+ \dp ft1
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ --------+------+---------------+---------------------------------------+-----------------------------------------
+ public | ft1 | foreign table | foreign_data_user=r/foreign_data_user | c1: +
+ | | | | foreign_data_user=r/foreign_data_user
+ (1 row)
+
+ REVOKE ALL ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE ALL (c1) ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ \dp ft1
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ --------+------+---------------+-------------------+--------------------------
+ public | ft1 | foreign table | |
+ (1 row)
+
+ -- GRANT ALL FOREIGN TABLES IN SCHEMA
+ ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema;
+ CREATE FOREIGN TABLE foreign_schema.ft2 (c1 int) SERVER sc;
+ GRANT SELECT ON ALL FOREIGN TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ GRANT SELECT (c1) ON ALL FOREIGN TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ GRANT UPDATE ON ALL TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ \dp foreign_schema.ft*
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ ----------------+------+---------------+---------------------------------------+-----------------------------------------
+ foreign_schema | ft1 | foreign table | foreign_data_user=r/foreign_data_user | c1: +
+ | | | | foreign_data_user=r/foreign_data_user
+ foreign_schema | ft2 | foreign table | foreign_data_user=r/foreign_data_user | c1: +
+ | | | | foreign_data_user=r/foreign_data_user
+ (2 rows)
+
+ REVOKE SELECT ON ALL FOREIGN TABLES IN SCHEMA foreign_schema FROM foreign_data_user;
+ REVOKE SELECT (c1) ON ALL FOREIGN TABLES IN SCHEMA foreign_schema FROM foreign_data_user;
+ \dp foreign_schema.ft*
+ Access privileges
+ Schema | Name | Type | Access privileges | Column access privileges
+ ----------------+------+---------------+-------------------+--------------------------
+ foreign_schema | ft1 | foreign table | |
+ foreign_schema | ft2 | foreign table | |
+ (2 rows)
+
+ ALTER FOREIGN TABLE foreign_schema.ft1 SET SCHEMA public;
+ DROP FOREIGN TABLE foreign_schema.ft2;
-- ALTER FOREIGN TABLE
COMMENT ON FOREIGN TABLE ft1 IS 'foreign table';
COMMENT ON FOREIGN TABLE ft1 IS NULL;
diff --git a/src/test/regress/sql/foreign_data.sql b/src/test/regress/sql/foreign_data.sql
index 0d12b98..ddd1cf0 100644
*** a/src/test/regress/sql/foreign_data.sql
--- b/src/test/regress/sql/foreign_data.sql
*************** CREATE INDEX id_ft1_c2 ON ft1 (c2);
*** 276,281 ****
--- 276,341 ----
SELECT * FROM ft1; -- ERROR
EXPLAIN SELECT * FROM ft1; -- ERROR
+ -- GRANT FOREIGN TABLE
+ GRANT SELECT ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT SELECT (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT INSERT ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT INSERT (c1) ON FOREIGN TABLE ft1 TO foreign_data_user; -- WARNING
+ GRANT UPDATE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT UPDATE (c1) ON FOREIGN TABLE ft1 TO foreign_data_user; -- WARNING
+ GRANT DELETE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT TRUNCATE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT REFERENCES ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT REFERENCES (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;-- WARNING
+ GRANT TRIGGER ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT USAGE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ GRANT EXECUTE ON FOREIGN TABLE ft1 TO foreign_data_user; -- ERROR
+ -- omitting FOREIGN TABLE
+ GRANT SELECT ON ft1 TO foreign_data_user;
+ GRANT SELECT (c1) ON ft1 TO foreign_data_user;
+ GRANT INSERT ON ft1 TO foreign_data_user; -- ERROR
+ GRANT INSERT (c1) ON ft1 TO foreign_data_user; -- WARNING
+ GRANT UPDATE ON ft1 TO foreign_data_user; -- ERROR
+ GRANT UPDATE (c1) ON ft1 TO foreign_data_user; -- WARNING
+ GRANT DELETE ON ft1 TO foreign_data_user; -- ERROR
+ GRANT TRUNCATE ON ft1 TO foreign_data_user; -- ERROR
+ GRANT REFERENCES ON ft1 TO foreign_data_user; -- ERROR
+ GRANT REFERENCES (c1) ON ft1 TO foreign_data_user ;-- WARNING
+ GRANT TRIGGER ON ft1 TO foreign_data_user; -- ERROR
+ GRANT USAGE ON ft1 TO foreign_data_user; -- ERROR
+ GRANT EXECUTE ON ft1 TO foreign_data_user; -- ERROR
+ \dp ft1
+ REVOKE SELECT ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE SELECT (c1) ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE INSERT ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE UPDATE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE DELETE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE TRUNCATE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE REFERENCES ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE TRIGGER ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE USAGE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ REVOKE EXECUTE ON FOREIGN TABLE ft1 FROM foreign_data_user; -- ERROR
+ \dp ft1
+ -- GRANT/REVOKE ALL
+ GRANT ALL ON FOREIGN TABLE ft1 TO foreign_data_user;
+ GRANT ALL (c1) ON FOREIGN TABLE ft1 TO foreign_data_user;
+ \dp ft1
+ REVOKE ALL ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ REVOKE ALL (c1) ON FOREIGN TABLE ft1 FROM foreign_data_user;
+ \dp ft1
+ -- GRANT ALL FOREIGN TABLES IN SCHEMA
+ ALTER FOREIGN TABLE ft1 SET SCHEMA foreign_schema;
+ CREATE FOREIGN TABLE foreign_schema.ft2 (c1 int) SERVER sc;
+ GRANT SELECT ON ALL FOREIGN TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ GRANT SELECT (c1) ON ALL FOREIGN TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ GRANT UPDATE ON ALL TABLES IN SCHEMA foreign_schema TO foreign_data_user;
+ \dp foreign_schema.ft*
+ REVOKE SELECT ON ALL FOREIGN TABLES IN SCHEMA foreign_schema FROM foreign_data_user;
+ REVOKE SELECT (c1) ON ALL FOREIGN TABLES IN SCHEMA foreign_schema FROM foreign_data_user;
+ \dp foreign_schema.ft*
+ ALTER FOREIGN TABLE foreign_schema.ft1 SET SCHEMA public;
+ DROP FOREIGN TABLE foreign_schema.ft2;
+
-- ALTER FOREIGN TABLE
COMMENT ON FOREIGN TABLE ft1 IS 'foreign table';
COMMENT ON FOREIGN TABLE ft1 IS NULL;