From 17c0267136a835f9aad783718efdc08a0bacb0d5 Mon Sep 17 00:00:00 2001 From: Raphael Fakhri <153192858+RaphaelFakhri@users.noreply.github.com> Date: Sat, 24 Oct 2026 18:55:11 +0000 Subject: [PATCH] fix(0030): detect autovacuum_enabled set to off, 0 or no --- lints/0030_autovacuum_disabled.sql | 10 +++++++++- splinter.sql | 10 +++++++++- test/expected/0030_autovacuum_disabled.out | 21 +++++++++++++++++++++ test/sql/0030_autovacuum_disabled.sql | 14 ++++++++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/lints/0030_autovacuum_disabled.sql b/lints/0030_autovacuum_disabled.sql index aaaf07f..9bb0014 100644 --- a/lints/0030_autovacuum_disabled.sql +++ b/lints/0030_autovacuum_disabled.sql @@ -22,7 +22,15 @@ from pg_catalog.pg_class cls join pg_catalog.pg_namespace nsp on cls.relnamespace = nsp.oid where cls.relkind = 'r' - and 'autovacuum_enabled=false' = any(cls.reloptions) + -- Postgres stores the value as written (false, off, 0, no, ...), so + -- parse it as a boolean instead of matching one spelling + and exists ( + select 1 + from pg_catalog.unnest(cls.reloptions) as opt + where + opt like 'autovacuum_enabled=%' + and not pg_catalog.substr(opt, 20)::boolean + ) and nsp.nspname not in ( '_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', diff --git a/splinter.sql b/splinter.sql index 46bb331..8f7ebc1 100644 --- a/splinter.sql +++ b/splinter.sql @@ -1863,7 +1863,15 @@ from pg_catalog.pg_class cls join pg_catalog.pg_namespace nsp on cls.relnamespace = nsp.oid where cls.relkind = 'r' - and 'autovacuum_enabled=false' = any(cls.reloptions) + -- Postgres stores the value as written (false, off, 0, no, ...), so + -- parse it as a boolean instead of matching one spelling + and exists ( + select 1 + from pg_catalog.unnest(cls.reloptions) as opt + where + opt like 'autovacuum_enabled=%' + and not pg_catalog.substr(opt, 20)::boolean + ) and nsp.nspname not in ( '_timescaledb_cache', '_timescaledb_catalog', '_timescaledb_config', '_timescaledb_internal', 'auth', 'cron', 'extensions', 'graphql', diff --git a/test/expected/0030_autovacuum_disabled.out b/test/expected/0030_autovacuum_disabled.out index 7dc6e26..716bddb 100644 --- a/test/expected/0030_autovacuum_disabled.out +++ b/test/expected/0030_autovacuum_disabled.out @@ -34,4 +34,25 @@ begin; (0 rows) rollback to savepoint b; + savepoint c; + -- NEGATIVE: autovacuum_enabled=on (another spelling of true) — must not fire + create table public.active_on (id int) with (autovacuum_enabled = on); + select * from lint."0030_autovacuum_disabled"; + name | title | level | facing | categories | description | detail | remediation | metadata | cache_key +------+-------+-------+--------+------------+-------------+--------+-------------+----------+----------- +(0 rows) + + -- POSITIVE: other spellings of false that Postgres stores verbatim — must fire + create table public.events (id int) with (autovacuum_enabled = off); + create table public.logs (id int) with (autovacuum_enabled = 0); + create table public.metrics (id int) with (autovacuum_enabled = 'no'); + select name, detail, cache_key from lint."0030_autovacuum_disabled"; + name | detail | cache_key +---------------------+-----------------------------------------------------------------------------------+------------------------------------ + autovacuum_disabled | Table `public`.`events` has autovacuum_enabled=false set as a storage parameter. | autovacuum_disabled_public_events + autovacuum_disabled | Table `public`.`logs` has autovacuum_enabled=false set as a storage parameter. | autovacuum_disabled_public_logs + autovacuum_disabled | Table `public`.`metrics` has autovacuum_enabled=false set as a storage parameter. | autovacuum_disabled_public_metrics +(3 rows) + + rollback to savepoint c; rollback; diff --git a/test/sql/0030_autovacuum_disabled.sql b/test/sql/0030_autovacuum_disabled.sql index 8a6cc6e..85d8cc2 100644 --- a/test/sql/0030_autovacuum_disabled.sql +++ b/test/sql/0030_autovacuum_disabled.sql @@ -26,4 +26,18 @@ begin; rollback to savepoint b; + savepoint c; + + -- NEGATIVE: autovacuum_enabled=on (another spelling of true) — must not fire + create table public.active_on (id int) with (autovacuum_enabled = on); + select * from lint."0030_autovacuum_disabled"; + + -- POSITIVE: other spellings of false that Postgres stores verbatim — must fire + create table public.events (id int) with (autovacuum_enabled = off); + create table public.logs (id int) with (autovacuum_enabled = 0); + create table public.metrics (id int) with (autovacuum_enabled = 'no'); + select name, detail, cache_key from lint."0030_autovacuum_disabled"; + + rollback to savepoint c; + rollback;