From 48667c560fcc1d8c37b118f684a129db01f0d346 Mon Sep 17 00:00:00 2001 From: Nikita Malakhov Date: Mon, 16 Jan 2023 17:14:07 +0300 Subject: [PATCH] The following test case found by PostgresPro team: In the following example, partitioned tables and regular tables behave differently: CREATE TABLE vacuum_tab (a int) PARTITION BY HASH (a); CREATE TABLE vacuum_tab_1 PARTITION OF vacuum_tab FOR VALUES WITH (MODULUS 2, REMAINDER 0); CREATE TABLE vacuum_tab_2 PARTITION OF vacuum_tab FOR VALUES WITH (MODULUS 2, REMAINDER 1); CREATE ROLE regress_vacuum_conflict; In the first session: begin; LOCK vacuum_tab IN SHARE UPDATE EXCLUSIVE MODE; In the second: SET ROLE regress_vacuum_conflict; VACUUM vacuum_tab; WARNING: permission denied to vacuum "vacuum_tab", skipping it <---- hangs here, trying to lock vacuum_tab_1 In non-partitioned case second session exits after emitting warning. In partitioned case, it hangs, trying to get locks. This is due to the fact that in expand_vacuum_rel() we skip parent table if vacuum_is_permitted_for_relation(), but don't perform such check for its child. The fix adds vacuum_is_permitted_for_relation() check before adding partition relation to the vacuum list, and while performing vacuum this emits warning that permission for vacuum is denied, and goes on without trying to acquire the lock. --- src/backend/commands/vacuum.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index c4ed7efce3..99f6e334ee 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -849,7 +849,9 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) foreach(part_lc, part_oids) { - Oid part_oid = lfirst_oid(part_lc); + Oid part_oid = lfirst_oid(part_lc); + HeapTuple part_tuple; + Form_pg_class part_classForm; if (part_oid == relid) continue; /* ignore original table */ @@ -859,11 +861,26 @@ expand_vacuum_rel(VacuumRelation *vrel, int options) * complain about failure to open one of these relations * later. */ - oldcontext = MemoryContextSwitchTo(vac_context); - vacrels = lappend(vacrels, makeVacuumRelation(NULL, - part_oid, - vrel->va_cols)); - MemoryContextSwitchTo(oldcontext); + + /* + * Check partition relations for vacuum permit. Do not add + * them to the list if vacuum is not permitted. + */ + part_tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(part_oid)); + if (HeapTupleIsValid(part_tuple)) + { + part_classForm = (Form_pg_class) GETSTRUCT(part_tuple); + + if (vacuum_is_permitted_for_relation(part_oid, part_classForm, options)) + { + oldcontext = MemoryContextSwitchTo(vac_context); + vacrels = lappend(vacrels, makeVacuumRelation(NULL, + part_oid, + vrel->va_cols)); + MemoryContextSwitchTo(oldcontext); + } + } + ReleaseSysCache(part_tuple); } } -- 2.25.1