Skip to content

fix(analyser): check fixes of statements with placeholders with parameters - #1037

Merged
psteinroe merged 2 commits into
mainfrom
fix/fix-check-placeholders
Nov 2, 2026
Merged

psteinroe merged 2 commits into
mainfrom
fix/fix-check-placeholders

Conversation

@psteinroe

@psteinroe psteinroe commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Since #906, Analyser::analyse only keeps a fix if the fixed statement still parses. The check parsed the statement as written. The linter itself first converts placeholders to parameters (pgls_lexer::convert_to_positional_params, which the workspace runs before parsing each statement). So a statement with a psql variable never passed the check, and lost every fix:

create index users_tenant_idx on :"schema".users (email) where tenant = :'tenant';
-- before: requireConcurrentIndexCreation is reported, but has no fix
-- after:  create index concurrently users_tenant_idx on :"schema".users (email) where tenant = :'tenant';

keeps_statement_valid now parses the fixed statement with its placeholders converted, the same way the statement was parsed. The conversion keeps the text length, so the edits apply unchanged. The placeholders stay as written in the fixed file, because the fix is applied to the source, not to the converted text. pgls_lexer moves from a dev-dependency of pgls_analyser to a normal dependency. It depends only on the tokenizer and the text crates, so there's no cycle, and the WASM build already pulls it in through the workspace.

The spec harness (rules_tests.rs) now parses statements the way the workspace does: placeholders converted, with with_identifier_parameters set. Its "a fix must keep the input valid" assertion uses the same conversion, so specs can contain psql variables. No existing snapshot changes.

Tests

  • Unit fixes_of_statements_with_placeholders_are_checked_with_parameters: :name, :'name', $name and :"name". A valid fix is kept and a broken one is still dropped.
  • Specs requireConcurrentIndexCreation/fix_psql_variables (value placeholders in a WHERE) and constraintMissingNotValid/fix_psql_variables (an identifier placeholder as the schema). Both now show the fix.
  • Workspace test_fix_file_fixes_statements_with_psql_variables: fix_file adds CONCURRENTLY and keeps :"schema", :'tenant' and $plan as written.
  • All three fail with the old check (verified by reverting the one-line change).
  • cargo test -p pgls_analyser -p pgls_workspace (including the Postgres regression test), cargo clippy -p pgls_analyser -p pgls_workspace --all-targets -- -D warnings.

Not covered

Update: merged main after #1044, which replaced keeps_statement_valid with keeps_sql_valid. Both of its paths now parse with placeholders converted, through a small parses helper: the fix applied to the statement, and for a fix that edits after its statement, the file text with and without the fix. Before, a file with a placeholder never passed the "parses without the fix" guard, so such fixes were kept unchecked. New tests: unit fixes_after_statements_with_placeholders_are_checked_with_parameters, and spec banUncommittedTransaction/no_semicolon_at_the_end_psql_variables (the invalid commit; fix is dropped; without the conversion in the guard, the harness fails with "produces invalid SQL"). This also covers the L1 point under "Not covered".

…eters

The guard from #906 parsed the fixed statement as written, so a statement
with a psql variable (:name, :'name', :"name", $name) never parsed and
lost all of its fixes. It now converts the placeholders to parameters
first, like the statement itself is parsed. The spec harness parses the
same way.
@psteinroe psteinroe added the ready label Nov 2, 2026
@psteinroe
psteinroe merged commit 72f9976 into main Nov 2, 2026
12 checks passed
@psteinroe
psteinroe deleted the fix/fix-check-placeholders branch November 2, 2026 12:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant