Summary
Proposal for a new editor rule that flags application code overriding the Postgres query planner via connection-scoped SET commands.
Motivation
A production incident class that static review keeps missing: a view toggled enable_hashjoin and enable_mergejoin off on the connection before running a query whose filtered row set grows over time. Postgres then had no choice but to satisfy the query with nested-loop joins — progressively slower as the data grew — and neither code review nor an AI reviewer flagged the diff, because the diff looks innocent in isolation.
Two reasons this fits the rule engine well:
- It's pure string shape — the GUC name is in the SQL text even when the value is a bind parameter (
%s), so the line-oriented regex engine can catch it with no AST and no Python process.
- It is invisible to the CLI analyzers too:
nplusone, suggest-indexes, and migration-risk don't look at raw SQL session commands.
Proposed rule
- Code:
DOL041, category performance, default severity warning, applicability unsafe (no QuickFix — the fix is a design decision).
- Detects:
SET / SET LOCAL / SET SESSION of planner-toggling GUCs — enable_* (hashjoin, mergejoin, nestloop, seqscan, indexscan, …), plan_cache_mode, jit* — inside any line, including inside cursor.execute(...) strings.
- Does not flag: non-planner session settings (
statement_timeout, search_path, work_mem, …) — those have legitimate per-request uses and would make the rule noisy.
- Non-goal for this PR: the CLI counterpart — the roadmap already tracks porting the DOL engine into the Python CLI (one catalogue, three surfaces), so this lands editor-side first and rides that work later.
Test plan
Regex + fixtures in test/rules/rawsql.test.js, mirroring test/rules/queryset.test.js: parameterized and literal values, SET LOCAL/SET SESSION variants, TO form, and negative cases.
Happy to send the PR if this is in scope.
Summary
Proposal for a new editor rule that flags application code overriding the Postgres query planner via connection-scoped
SETcommands.Motivation
A production incident class that static review keeps missing: a view toggled
enable_hashjoinandenable_mergejoinoff on the connection before running a query whose filtered row set grows over time. Postgres then had no choice but to satisfy the query with nested-loop joins — progressively slower as the data grew — and neither code review nor an AI reviewer flagged the diff, because the diff looks innocent in isolation.Two reasons this fits the rule engine well:
%s), so the line-oriented regex engine can catch it with no AST and no Python process.nplusone,suggest-indexes, andmigration-riskdon't look at raw SQL session commands.Proposed rule
DOL041, categoryperformance, default severitywarning, applicabilityunsafe(no QuickFix — the fix is a design decision).SET/SET LOCAL/SET SESSIONof planner-toggling GUCs —enable_*(hashjoin, mergejoin, nestloop, seqscan, indexscan, …),plan_cache_mode,jit*— inside any line, including insidecursor.execute(...)strings.statement_timeout,search_path,work_mem, …) — those have legitimate per-request uses and would make the rule noisy.Test plan
Regex + fixtures in
test/rules/rawsql.test.js, mirroringtest/rules/queryset.test.js: parameterized and literal values,SET LOCAL/SET SESSIONvariants,TOform, and negative cases.Happy to send the PR if this is in scope.