From 1a84c4a5d89ecc8e13e7c499f1624ed1ea7df8e6 Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Thu, 5 Nov 2026 21:28:40 +0530 Subject: [PATCH] Add isolation test for lock-skip statistics and privileges. A role that has no privileges to VACUUM or ANALYZE a table must not be able to change that table's statistics. Skips caused by a lock held by someone else are currently reported before vacuum_is_permitted_for_relation() is reached, so such a role can increase lock_skipped_vacuum_count and lock_skipped_analyze_count, and the corresponding last_lock_skipped_* times, of a table it cannot touch. The test locks a table in ACCESS EXCLUSIVE mode in one session, runs VACUUM (SKIP_LOCKED) and ANALYZE (SKIP_LOCKED) on it from a role without privileges in another one, and expects both counters to stay at zero. A control permutation runs the same statements as the table owner and expects both counters to be one. The first permutation fails until the skip is reported only for a caller that is permitted to process the table. --- .../expected/vacuum-skip-locked-perms.out | 41 +++++++++++++++++ src/test/isolation/isolation_schedule | 1 + .../specs/vacuum-skip-locked-perms.spec | 45 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/test/isolation/expected/vacuum-skip-locked-perms.out create mode 100644 src/test/isolation/specs/vacuum-skip-locked-perms.spec diff --git a/src/test/isolation/expected/vacuum-skip-locked-perms.out b/src/test/isolation/expected/vacuum-skip-locked-perms.out new file mode 100644 index 00000000000..a5f88b65da2 --- /dev/null +++ b/src/test/isolation/expected/vacuum-skip-locked-perms.out @@ -0,0 +1,41 @@ +Parsed test spec with 2 sessions + +starting permutation: lock s2_unpriv s2_vacuum s2_analyze s2_reset commit check_stat +step lock: + BEGIN; + LOCK TABLE vsl_tab IN ACCESS EXCLUSIVE MODE; + +step s2_unpriv: SET ROLE regress_vsl_unpriv; +s2: WARNING: skipping vacuum of "vsl_tab" --- lock not available +step s2_vacuum: VACUUM (SKIP_LOCKED) vsl_tab; +s2: WARNING: skipping analyze of "vsl_tab" --- lock not available +step s2_analyze: ANALYZE (SKIP_LOCKED) vsl_tab; +step s2_reset: RESET ROLE; +step commit: + COMMIT; + +step check_stat: SELECT pg_stat_get_lock_skipped_vacuum_count('vsl_tab'::regclass) AS vac_skips, pg_stat_get_lock_skipped_analyze_count('vsl_tab'::regclass) AS anl_skips; +vac_skips|anl_skips +---------+--------- + 0| 0 +(1 row) + + +starting permutation: lock s2_vacuum s2_analyze commit check_stat +step lock: + BEGIN; + LOCK TABLE vsl_tab IN ACCESS EXCLUSIVE MODE; + +s2: WARNING: skipping vacuum of "vsl_tab" --- lock not available +step s2_vacuum: VACUUM (SKIP_LOCKED) vsl_tab; +s2: WARNING: skipping analyze of "vsl_tab" --- lock not available +step s2_analyze: ANALYZE (SKIP_LOCKED) vsl_tab; +step commit: + COMMIT; + +step check_stat: SELECT pg_stat_get_lock_skipped_vacuum_count('vsl_tab'::regclass) AS vac_skips, pg_stat_get_lock_skipped_analyze_count('vsl_tab'::regclass) AS anl_skips; +vac_skips|anl_skips +---------+--------- + 1| 1 +(1 row) + diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule index bf9a2037c70..7c6f4099b28 100644 --- a/src/test/isolation/isolation_schedule +++ b/src/test/isolation/isolation_schedule @@ -107,6 +107,7 @@ test: timeouts test: vacuum-concurrent-drop test: vacuum-conflict test: vacuum-skip-locked +test: vacuum-skip-locked-perms test: stats test: horizons test: predicate-hash diff --git a/src/test/isolation/specs/vacuum-skip-locked-perms.spec b/src/test/isolation/specs/vacuum-skip-locked-perms.spec new file mode 100644 index 00000000000..366b43c4b89 --- /dev/null +++ b/src/test/isolation/specs/vacuum-skip-locked-perms.spec @@ -0,0 +1,45 @@ +# Test that lock-skip statistics are not recorded for a role that lacks the +# privileges to VACUUM or ANALYZE the table. +# +# A role that cannot vacuum or analyze a table must not be able to change that +# table's statistics, so a skip caused by a lock held by someone else must not +# be counted when the caller would not have been permitted to process the table +# anyway. The second permutation is the control: the same skips are counted +# for a role that is allowed to process the table. + +setup +{ + CREATE ROLE regress_vsl_unpriv; + CREATE TABLE vsl_tab (a int); + ALTER TABLE vsl_tab SET (autovacuum_enabled = false); +} + +teardown +{ + DROP TABLE vsl_tab; + DROP ROLE regress_vsl_unpriv; +} + +session s1 +step lock +{ + BEGIN; + LOCK TABLE vsl_tab IN ACCESS EXCLUSIVE MODE; +} +step commit +{ + COMMIT; +} +step check_stat { SELECT pg_stat_get_lock_skipped_vacuum_count('vsl_tab'::regclass) AS vac_skips, pg_stat_get_lock_skipped_analyze_count('vsl_tab'::regclass) AS anl_skips; } + +session s2 +step s2_unpriv { SET ROLE regress_vsl_unpriv; } +step s2_reset { RESET ROLE; } +step s2_vacuum { VACUUM (SKIP_LOCKED) vsl_tab; } +step s2_analyze { ANALYZE (SKIP_LOCKED) vsl_tab; } + +# The role has no privileges on the table: nothing is counted. +permutation lock s2_unpriv s2_vacuum s2_analyze s2_reset commit check_stat + +# Control: the owner (the superuser running the test) is counted. +permutation lock s2_vacuum s2_analyze commit check_stat -- 2.55.0