From 89a7f00d67a2fe7dde3b8f12c5700e5340862c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Villemain?= Date: Tue, 25 Mar 2025 20:46:58 +0100 Subject: [PATCH] Add an alternative output for GRANT testing PostgreSQL introduces MAINTAIN privilege, this change the default output of some test queries. I added a new alternative "grant_on_table_propagation_0.out" which is used for PostgreSQL versions < 17 (so we just have to drop it when 17 will be the oldest supported version). --- .../expected/grant_on_table_propagation.out | 36 +- .../expected/grant_on_table_propagation_0.out | 464 ++++++++++++++++++ 2 files changed, 482 insertions(+), 18 deletions(-) create mode 100644 src/test/regress/expected/grant_on_table_propagation_0.out diff --git a/src/test/regress/expected/grant_on_table_propagation.out b/src/test/regress/expected/grant_on_table_propagation.out index dafc5d2e7..d1ccadc71 100644 --- a/src/test/regress/expected/grant_on_table_propagation.out +++ b/src/test/regress/expected/grant_on_table_propagation.out @@ -177,11 +177,11 @@ RESET ROLE; -- check on coordinator and workers SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -209,11 +209,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -238,11 +238,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -283,11 +283,11 @@ RESET ROLE; -- check on coordinator and workers SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -309,11 +309,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -334,11 +334,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -366,11 +366,11 @@ HINT: Connect to the coordinator and run it again. SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -392,11 +392,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute @@ -417,11 +417,11 @@ ORDER BY 1, 2; SET search_path TO grant_on_table; SELECT relname, relacl FROM pg_class WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; - relname | relacl + relname | relacl --------------------------------------------------------------------- dist_table | local_table | - ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} + ref_table | {postgres=arwdDxtm/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} (3 rows) SELECT attrelid::regclass, attname, attacl FROM pg_attribute diff --git a/src/test/regress/expected/grant_on_table_propagation_0.out b/src/test/regress/expected/grant_on_table_propagation_0.out new file mode 100644 index 000000000..392b08105 --- /dev/null +++ b/src/test/regress/expected/grant_on_table_propagation_0.out @@ -0,0 +1,464 @@ +-- +-- GRANT_ON_TABLE_PROPAGATION +-- +SET citus.shard_replication_factor TO 1; +CREATE SCHEMA grant_on_table; +SET search_path TO grant_on_table; +-- create some simple tables: 1 local and 2 managed by citus +-- d ACL must not be updated in anyway. +CREATE TABLE dist_table (id bigint GENERATED BY DEFAULT AS IDENTITY primary key, a int, b text, c int, d text); +SELECT create_distributed_table('grant_on_table.dist_table', 'id'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE ref_table (id bigint GENERATED BY DEFAULT AS IDENTITY primary key, a int, b text, c int, d text); +SELECT create_reference_table('grant_on_table.ref_table'); + create_reference_table +--------------------------------------------------------------------- + +(1 row) + +CREATE TABLE local_table (id int GENERATED BY DEFAULT AS IDENTITY primary key, a int, b text, c int, d text); +\c - - - :worker_1_port +SET search_path TO grant_on_table; +CREATE TABLE local_table (id int GENERATED BY DEFAULT AS IDENTITY primary key, a int, b text, c int, d text); +\c - - - :worker_2_port +SET search_path TO grant_on_table; +CREATE TABLE local_table (id int GENERATED BY DEFAULT AS IDENTITY primary key, a int, b text, c int, d text); +\c - - - :master_port +SET search_path TO grant_on_table; +-- create some users +CREATE USER grant_user_0; +GRANT USAGE ON SCHEMA grant_on_table TO grant_user_0; +CREATE USER grant_user_1; +GRANT USAGE ON SCHEMA grant_on_table TO grant_user_1; +-- this one should not be granted anything: +CREATE USER nogrant_user; +GRANT USAGE ON SCHEMA grant_on_table TO nogrant_user; +-- +-- tests related to columns ACL +-- +-- test single table, single priv, single col, single user +GRANT SELECT (a) ON ref_table TO grant_user_0; +-- simple check +SET ROLE grant_user_0; +-- ok: +SELECT a FROM grant_on_table.ref_table; + a +--------------------------------------------------------------------- +(0 rows) + +-- not ok: +SELECT b FROM grant_on_table.ref_table; +ERROR: permission denied for table ref_table +RESET ROLE; +-- test several tables, several distinct priv, several cols, several users +GRANT SELECT (c, b), INSERT (id, a) ON ref_table, dist_table TO grant_user_0, grant_user_1; +-- simple check +SET ROLE grant_user_0; +-- ok: +INSERT INTO grant_on_table.ref_table (a) VALUES (1); +-- not ok: +INSERT INTO grant_on_table.ref_table (b) VALUES (1); +ERROR: permission denied for table ref_table +-- ok: +SELECT a, b, c FROM grant_on_table.ref_table; + a | b | c +--------------------------------------------------------------------- + 1 | | +(1 row) + +SET ROLE grant_user_1; +-- ok: +INSERT INTO grant_on_table.ref_table (a) VALUES (1); +-- not ok: +INSERT INTO grant_on_table.ref_table (b) VALUES (1); +ERROR: permission denied for table ref_table +-- not ok: +SELECT a, b, c FROM grant_on_table.ref_table; +ERROR: permission denied for table ref_table +-- ok: +SELECT b, c FROM grant_on_table.ref_table; + b | c +--------------------------------------------------------------------- + | + | +(2 rows) + +RESET ROLE; +-- test several tables, several distinct priv, several cols and non cols, several users +GRANT UPDATE (c, b), DELETE ON ref_table TO grant_user_0, grant_user_1; +-- test special case: with system columns (it's ok) +GRANT INSERT (ctid, xmin, b) ON ref_table TO grant_user_0; +-- simple check +SET ROLE grant_user_0; +-- ok: +INSERT INTO grant_on_table.ref_table (b) VALUES (1); +-- ok: +UPDATE grant_on_table.ref_table SET b = 3; +-- not ok: +UPDATE grant_on_table.ref_table SET d = 3; +ERROR: permission denied for table ref_table +DELETE FROM grant_on_table.ref_table; +RESET ROLE; +-- test special case: ALL +GRANT ALL (id) ON ref_table TO grant_user_0; +GRANT ALL (id, c) ON ref_table TO grant_user_1; +-- simple check +SET ROLE grant_user_1; +-- we've just granted INSERT ON c with ALL +-- ok: +INSERT INTO grant_on_table.ref_table (c) VALUES (3); +-- still not ok: +INSERT INTO grant_on_table.ref_table (d) VALUES (3); +ERROR: permission denied for table ref_table +-- ok: +SELECT id,c FROM grant_on_table.ref_table; + id | c +--------------------------------------------------------------------- + 4 | 3 +(1 row) + +DELETE FROM grant_on_table.ref_table; +RESET ROLE; +-- ALL cannot be mixed with other privs +GRANT SELECT (d), ALL (d) ON ref_table TO nogrant_user; +ERROR: syntax error at or near "ALL" +GRANT ALL (d), SELECT (d) ON ref_table TO nogrant_user; +ERROR: syntax error at or near "," +-- simple check before the next test +SET ROLE grant_user_1; +-- we've just granted SELECT id on ALL TABLES +-- not ok: +SELECT id +FROM grant_on_table.ref_table +UNION ALL +SELECT id +FROM grant_on_table.dist_table +UNION ALL +SELECT id +FROM grant_on_table.local_table; +ERROR: permission denied for table dist_table +RESET ROLE; +-- test special case: ALL TABLES IN SCHEMA is not supposed to be correct +-- but is accepted by PostgreSQL - non documented feature +GRANT SELECT (id) ON ALL TABLES IN SCHEMA grant_on_table TO grant_user_1; +-- simple check +SET ROLE grant_user_1; +-- we've just granted SELECT id on ALL TABLES +-- ok: +SELECT id +FROM grant_on_table.ref_table +UNION ALL +SELECT id +FROM grant_on_table.dist_table +UNION ALL +SELECT id +FROM grant_on_table.local_table; + id +--------------------------------------------------------------------- +(0 rows) + +RESET ROLE; +-- test special case: TRUNCATE and some others are not correct, here mixed with correct +GRANT TRUNCATE (b, a), SELECT (d) ON ref_table TO nogrant_user; +ERROR: invalid privilege type TRUNCATE for column +-- check non propagation for local table +GRANT UPDATE (id) ON local_table TO grant_user_0; +-- special case: mixed with distributed table: +GRANT INSERT (b, c) ON local_table, dist_table TO grant_user_1; +-- simple check +SET ROLE grant_user_1; +-- ok: +INSERT INTO grant_on_table.dist_table (b, c) VALUES ('ok', 1); +RESET ROLE; +-- check on coordinator and workers +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | b | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | id | {grant_user_0=a/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=ar/postgres,grant_user_1=a/postgres} + ref_table | b | {grant_user_0=arw/postgres,grant_user_1=rw/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | id | {grant_user_0=arwx/postgres,grant_user_1=arwx/postgres} + ref_table | xmin | {grant_user_0=a/postgres} + local_table | b | {grant_user_1=a/postgres} + local_table | c | {grant_user_1=a/postgres} + local_table | id | {grant_user_1=r/postgres,grant_user_0=w/postgres} +(13 rows) + +\c - - - :worker_1_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | b | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | id | {grant_user_0=a/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=ar/postgres,grant_user_1=a/postgres} + ref_table | b | {grant_user_0=arw/postgres,grant_user_1=rw/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | id | {grant_user_0=arwx/postgres,grant_user_1=arwx/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(10 rows) + +\c - - - :worker_2_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | b | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + dist_table | id | {grant_user_0=a/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=ar/postgres,grant_user_1=a/postgres} + ref_table | b | {grant_user_0=arw/postgres,grant_user_1=rw/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | id | {grant_user_0=arwx/postgres,grant_user_1=arwx/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(10 rows) + +\c - - - :master_port +SET search_path TO grant_on_table; +-- revoke, for columns it's the same logic so we don't bother testing combinations +REVOKE SELECT(id, a) ON ref_table, dist_table, local_table FROM grant_user_0, grant_user_1; +-- simple check +SET ROLE grant_user_0; +-- not ok: +SELECT a FROM grant_on_table.ref_table; +ERROR: permission denied for table ref_table +RESET ROLE; +REVOKE ALL(id, b) ON ref_table, dist_table, local_table from grant_user_0, grant_user_1; +-- simple check +SET ROLE grant_user_0; +-- not ok: +SELECT b FROM grant_on_table.ref_table; +ERROR: permission denied for table ref_table +RESET ROLE; +-- check on coordinator and workers +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} + local_table | c | {grant_user_1=a/postgres} +(7 rows) + +\c - - - :worker_1_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(6 rows) + +\c - - - :worker_2_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(6 rows) + +-- and test from a worker +\c - - - :worker_1_port +SET search_path TO grant_on_table; +GRANT SELECT (a, b) ON ref_table TO grant_user_0; +ERROR: operation is not allowed on this node +HINT: Connect to the coordinator and run it again. +-- check on coordinator and workers +\c - - - :master_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} + local_table | c | {grant_user_1=a/postgres} +(7 rows) + +\c - - - :worker_1_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(6 rows) + +\c - - - :worker_2_port +SET search_path TO grant_on_table; +SELECT relname, relacl FROM pg_class +WHERE relname IN ('dist_table', 'ref_table', 'local_table') ORDER BY 1; + relname | relacl +--------------------------------------------------------------------- + dist_table | + local_table | + ref_table | {postgres=arwdDxt/postgres,grant_user_0=d/postgres,grant_user_1=d/postgres} +(3 rows) + +SELECT attrelid::regclass, attname, attacl FROM pg_attribute +WHERE attrelid IN ('dist_table'::regclass, 'ref_table'::regclass, 'local_table'::regclass) + AND attacl IS NOT NULL +ORDER BY 1, 2; + attrelid | attname | attacl +--------------------------------------------------------------------- + dist_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + dist_table | c | {grant_user_0=r/postgres,grant_user_1=ar/postgres} + ref_table | a | {grant_user_0=a/postgres,grant_user_1=a/postgres} + ref_table | c | {grant_user_0=rw/postgres,grant_user_1=arwx/postgres} + ref_table | ctid | {grant_user_0=a/postgres} + ref_table | xmin | {grant_user_0=a/postgres} +(6 rows) + +\c - - - :master_port +SET search_path TO grant_on_table; +-- cleanup +REVOKE ALL ON ref_table, dist_table, local_table from grant_user_0, grant_user_1; +-- and try some WITH GRANT OPTION +GRANT ALL(id, b) ON ref_table TO grant_user_0 WITH GRANT OPTION; +SET ROLE grant_user_0; +GRANT ALL(id, b) ON grant_on_table.ref_table TO grant_user_1; +SET ROLE grant_user_1; +INSERT INTO grant_on_table.ref_table (b) VALUES ('OK'); +SELECT id, b FROM grant_on_table.ref_table; + id | b +--------------------------------------------------------------------- + 5 | OK +(1 row) + +RESET ROLE; +-- cleanup +-- prevent useless messages on DROP objects. +SET client_min_messages TO ERROR; +DROP SCHEMA grant_on_table CASCADE; +DROP ROLE grant_user_0, grant_user_1, nogrant_user; +RESET client_min_messages; +RESET search_path;