diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2022-04-14 22:11:06 +0200 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2022-04-14 22:11:06 +0200 |
commit | 3f19e176ae0f55a653d62e1504dbe5ad8c1006a0 (patch) | |
tree | 2d8cd38e77dc359d0ce5d6df25afeb85c141c94f /src | |
parent | 275e719d910459db747346a51d56185e2440763b (diff) | |
download | postgresql-3f19e176ae0f55a653d62e1504dbe5ad8c1006a0.tar.gz postgresql-3f19e176ae0f55a653d62e1504dbe5ad8c1006a0.zip |
Have CLUSTER ignore partitions not owned by caller
If a partitioned table has partitions owned by roles other than the
owner of the partitioned table, don't include them in the to-be-
clustered list. This is similar to what VACUUM FULL does (except we do
it sooner, because there is no reason to postpone it). Add a simple
test to verify that only owned partitions are clustered.
While at it, change memory context switch-and-back to occur once per
partition instead of outside of the loop.
Author: Justin Pryzby <pryzby@telsasoft.com>
Reviewed-by: Zhihong Yu <zyu@yugabyte.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/20220411140609.GF26620@telsasoft.com
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/cluster.c | 19 | ||||
-rw-r--r-- | src/test/regress/expected/cluster.out | 25 | ||||
-rw-r--r-- | src/test/regress/sql/cluster.sql | 19 |
3 files changed, 56 insertions, 7 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 0f0a6e9f018..d8a6d43d959 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1647,10 +1647,8 @@ get_tables_to_cluster(MemoryContext cluster_context) * Given an index on a partitioned table, return a list of RelToCluster for * all the children leaves tables/indexes. * - * Caller must hold lock on the table containing the index. - * * Like expand_vacuum_rel, but here caller must hold AccessExclusiveLock - * on the table already. + * on the table containing the index. */ static List * get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid) @@ -1663,9 +1661,6 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid) /* Do not lock the children until they're processed */ inhoids = find_all_inheritors(indexOid, NoLock, NULL); - /* Use a permanent memory context for the result list */ - old_context = MemoryContextSwitchTo(cluster_context); - foreach(lc, inhoids) { Oid indexrelid = lfirst_oid(lc); @@ -1676,12 +1671,22 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid) if (get_rel_relkind(indexrelid) != RELKIND_INDEX) continue; + /* Silently skip partitions which the user has no access to. */ + if (!pg_class_ownercheck(relid, GetUserId()) && + (!pg_database_ownercheck(MyDatabaseId, GetUserId()) || + IsSharedRelation(relid))) + continue; + + /* Use a permanent memory context for the result list */ + old_context = MemoryContextSwitchTo(cluster_context); + rtc = (RelToCluster *) palloc(sizeof(RelToCluster)); rtc->tableOid = relid; rtc->indexOid = indexrelid; rtcs = lappend(rtcs, rtc); + + MemoryContextSwitchTo(old_context); } - MemoryContextSwitchTo(old_context); return rtcs; } diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index 953818c74e1..6c8c4c929ab 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -493,6 +493,31 @@ ERROR: cannot mark index clustered in partitioned table ALTER TABLE clstrpart CLUSTER ON clstrpart_idx; ERROR: cannot mark index clustered in partitioned table DROP TABLE clstrpart; +-- Ownership of partitions is checked +CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i); +CREATE INDEX ptnowner_i_idx ON ptnowner(i); +CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1); +CREATE ROLE regress_ptnowner; +CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2); +ALTER TABLE ptnowner1 OWNER TO regress_ptnowner; +ALTER TABLE ptnowner OWNER TO regress_ptnowner; +CREATE TEMP TABLE ptnowner_oldnodes AS + SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree + JOIN pg_class AS c ON c.oid=tree.relid; +SET SESSION AUTHORIZATION regress_ptnowner; +CLUSTER ptnowner USING ptnowner_i_idx; +RESET SESSION AUTHORIZATION; +SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a + JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C"; + relname | ?column? +-----------+---------- + ptnowner | t + ptnowner1 | f + ptnowner2 | t +(3 rows) + +DROP TABLE ptnowner; +DROP ROLE regress_ptnowner; -- Test CLUSTER with external tuplesorting create table clstr_4 as select * from tenk1; create index cluster_sort on clstr_4 (hundred, thousand, tenthous); diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql index 5601684ee3f..e758088ef6a 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -229,6 +229,25 @@ ALTER TABLE clstrpart SET WITHOUT CLUSTER; ALTER TABLE clstrpart CLUSTER ON clstrpart_idx; DROP TABLE clstrpart; +-- Ownership of partitions is checked +CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i); +CREATE INDEX ptnowner_i_idx ON ptnowner(i); +CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1); +CREATE ROLE regress_ptnowner; +CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2); +ALTER TABLE ptnowner1 OWNER TO regress_ptnowner; +ALTER TABLE ptnowner OWNER TO regress_ptnowner; +CREATE TEMP TABLE ptnowner_oldnodes AS + SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree + JOIN pg_class AS c ON c.oid=tree.relid; +SET SESSION AUTHORIZATION regress_ptnowner; +CLUSTER ptnowner USING ptnowner_i_idx; +RESET SESSION AUTHORIZATION; +SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a + JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C"; +DROP TABLE ptnowner; +DROP ROLE regress_ptnowner; + -- Test CLUSTER with external tuplesorting create table clstr_4 as select * from tenk1; |