Skip to content

Commit 3f19e17

Browse files
committed
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
1 parent 275e719 commit 3f19e17

File tree

3 files changed

+56
-7
lines changed

3 files changed

+56
-7
lines changed

src/backend/commands/cluster.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,10 +1647,8 @@ get_tables_to_cluster(MemoryContext cluster_context)
16471647
* Given an index on a partitioned table, return a list of RelToCluster for
16481648
* all the children leaves tables/indexes.
16491649
*
1650-
* Caller must hold lock on the table containing the index.
1651-
*
16521650
* Like expand_vacuum_rel, but here caller must hold AccessExclusiveLock
1653-
* on the table already.
1651+
* on the table containing the index.
16541652
*/
16551653
static List *
16561654
get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
@@ -1663,9 +1661,6 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
16631661
/* Do not lock the children until they're processed */
16641662
inhoids = find_all_inheritors(indexOid, NoLock, NULL);
16651663

1666-
/* Use a permanent memory context for the result list */
1667-
old_context = MemoryContextSwitchTo(cluster_context);
1668-
16691664
foreach(lc, inhoids)
16701665
{
16711666
Oid indexrelid = lfirst_oid(lc);
@@ -1676,12 +1671,22 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
16761671
if (get_rel_relkind(indexrelid) != RELKIND_INDEX)
16771672
continue;
16781673

1674+
/* Silently skip partitions which the user has no access to. */
1675+
if (!pg_class_ownercheck(relid, GetUserId()) &&
1676+
(!pg_database_ownercheck(MyDatabaseId, GetUserId()) ||
1677+
IsSharedRelation(relid)))
1678+
continue;
1679+
1680+
/* Use a permanent memory context for the result list */
1681+
old_context = MemoryContextSwitchTo(cluster_context);
1682+
16791683
rtc = (RelToCluster *) palloc(sizeof(RelToCluster));
16801684
rtc->tableOid = relid;
16811685
rtc->indexOid = indexrelid;
16821686
rtcs = lappend(rtcs, rtc);
1687+
1688+
MemoryContextSwitchTo(old_context);
16831689
}
16841690

1685-
MemoryContextSwitchTo(old_context);
16861691
return rtcs;
16871692
}

src/test/regress/expected/cluster.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,31 @@ ERROR: cannot mark index clustered in partitioned table
493493
ALTER TABLE clstrpart CLUSTER ON clstrpart_idx;
494494
ERROR: cannot mark index clustered in partitioned table
495495
DROP TABLE clstrpart;
496+
-- Ownership of partitions is checked
497+
CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i);
498+
CREATE INDEX ptnowner_i_idx ON ptnowner(i);
499+
CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
500+
CREATE ROLE regress_ptnowner;
501+
CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
502+
ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
503+
ALTER TABLE ptnowner OWNER TO regress_ptnowner;
504+
CREATE TEMP TABLE ptnowner_oldnodes AS
505+
SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree
506+
JOIN pg_class AS c ON c.oid=tree.relid;
507+
SET SESSION AUTHORIZATION regress_ptnowner;
508+
CLUSTER ptnowner USING ptnowner_i_idx;
509+
RESET SESSION AUTHORIZATION;
510+
SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
511+
JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
512+
relname | ?column?
513+
-----------+----------
514+
ptnowner | t
515+
ptnowner1 | f
516+
ptnowner2 | t
517+
(3 rows)
518+
519+
DROP TABLE ptnowner;
520+
DROP ROLE regress_ptnowner;
496521
-- Test CLUSTER with external tuplesorting
497522
create table clstr_4 as select * from tenk1;
498523
create index cluster_sort on clstr_4 (hundred, thousand, tenthous);

src/test/regress/sql/cluster.sql

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,25 @@ ALTER TABLE clstrpart SET WITHOUT CLUSTER;
229229
ALTER TABLE clstrpart CLUSTER ON clstrpart_idx;
230230
DROP TABLE clstrpart;
231231

232+
-- Ownership of partitions is checked
233+
CREATE TABLE ptnowner(i int unique) PARTITION BY LIST (i);
234+
CREATE INDEX ptnowner_i_idx ON ptnowner(i);
235+
CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
236+
CREATE ROLE regress_ptnowner;
237+
CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
238+
ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
239+
ALTER TABLE ptnowner OWNER TO regress_ptnowner;
240+
CREATE TEMP TABLE ptnowner_oldnodes AS
241+
SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree
242+
JOIN pg_class AS c ON c.oid=tree.relid;
243+
SET SESSION AUTHORIZATION regress_ptnowner;
244+
CLUSTER ptnowner USING ptnowner_i_idx;
245+
RESET SESSION AUTHORIZATION;
246+
SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
247+
JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
248+
DROP TABLE ptnowner;
249+
DROP ROLE regress_ptnowner;
250+
232251
-- Test CLUSTER with external tuplesorting
233252

234253
create table clstr_4 as select * from tenk1;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy