Skip to content

Keep FOR UPDATE after LIMIT, and check formatting is a fixed point - #68

Merged
gmr merged 1 commit into
mainfrom
fix/locking-after-limit
Sep 23, 2026
Merged

gmr merged 1 commit into
mainfrom
fix/locking-after-limit

Conversation

@gmr

@gmr gmr commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Closes #67.

FOR UPDATE after LIMIT

SELECT ctid FROM t ORDER BY a LIMIT 1 FOR UPDATE SKIP LOCKED;
-- every style, v1.4.0 and main:
SELECT ctid FROM t ORDER BY a LIMIT 1;

The locking clause is lost, so a formatted job-queue worker takes no lock. After LIMIT the grammar wraps it in opt_for_locking_clause, which the clause collector did not match. It is now collected like opt_select_limit.

Fixed-point guard

The corpus writes this as FOR UPDATE LIMIT n, which #59 fixed and renders as LIMIT n FOR UPDATE, so the lock only disappeared on a second pass, which the guard never ran. formatted_corpus_is_a_fixed_point in tests/token_loss_test.rs now formats every corpus statement twice in every style and requires the same result.

It found one more case: a string constant continued across lines ('foo' then 'bar' on the next line, which PostgreSQL joins) gained seven spaces on every pass. The value was unchanged, since the whitespace sits between the parts, but the output was not stable. The parts are now joined by a bare newline and layout supplies the indentation.

The guard now checks three things over the PostgreSQL 19 documentation corpus in all 8 styles: no token loss, output re-parses, and formatting is a fixed point.

🤖 Generated with Claude Code

https://claude.ai/code/session_01UFqHcQxRwX8CuJaECqiHUz

Summary by CodeRabbit

  • Bug Fixes
    • Preserved FOR UPDATE SKIP LOCKED clauses when they follow LIMIT.
    • Improved formatting of PostgreSQL string literals continued across lines.
  • Tests
    • Added checks for consistent formatting across styles and repeated formatting of PostgreSQL documentation examples.

    SELECT ctid FROM t ORDER BY a LIMIT 10 FOR UPDATE
    ->  SELECT ctid FROM t ORDER BY a LIMIT 10

When the locking clause follows LIMIT, the grammar wraps it in
opt_for_locking_clause, which the clause collector did not match. The
output runs and takes no row locks; `LIMIT 1 FOR UPDATE SKIP LOCKED` is
the usual job-queue pattern. Present in v1.4.0 (#67).

The guard missed it because the documentation writes `FOR UPDATE LIMIT
n`, which #59 fixed and renders as `LIMIT n FOR UPDATE`: the lock only
disappeared on a second pass. A new corpus test checks that formatting
every statement twice, in every style, gives the same result. It found
one more: a string constant continued across lines, `'foo'` then `'bar'`
on the next line, gained seven spaces of indentation on every pass. The
parts arrive as one token with the whitespace between them, and layout
indented it again. They are now joined by a bare newline, and layout
supplies the indentation.

Closes #67.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UFqHcQxRwX8CuJaECqiHUz
@coderabbitai

coderabbitai Bot commented Sep 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 6800e2de-6381-4169-ac19-6c827a5d590e

📥 Commits

Reviewing files that changed from the base of the PR and between 247d671 and 912136e.

📒 Files selected for processing (4)
  • src/formatter/expr.rs
  • src/formatter/select.rs
  • tests/smoke_test.rs
  • tests/token_loss_test.rs

Included review availability: 4 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 6 reviews per hour.


📝 Walkthrough

Walkthrough

The formatter now joins continued string literal tokens with newlines and collects locking clauses wrapped after LIMIT. Tests check both behaviors and verify fixed-point formatting across parseable corpus statements and styles.

Changes

Continued string literals

Layer / File(s) Summary
Join continued string literal tokens
src/formatter/expr.rs
format_string_const joins multiple whitespace-separated literal tokens with newlines. Single literals and inputs that do not consist only of literals remain unchanged.

Locking clauses after LIMIT

Layer / File(s) Summary
Collect wrapped locking clauses and test formatting
src/formatter/select.rs, tests/smoke_test.rs, tests/token_loss_test.rs
Clause collection now handles a locking clause nested in opt_for_locking_clause. Regression tests check FOR UPDATE SKIP LOCKED after LIMIT, string-continuation idempotence, and fixed-point formatting across corpus statements and styles.

Estimated code review effort: 2 (Simple) | ~12 minutes

Merge Risk: ⚪ Minimal · up to 91213

No concrete issue remains that would prevent merging after normal checks.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes both primary changes: preserving FOR UPDATE after LIMIT and checking fixed-point formatting.
Linked Issues check ✅ Passed The changes satisfy the coding requirements in issue #67. collect_clauses_recursive() now recognizes opt_for_locking_clause and collects its nested for_locking_clause, which preserves `FOR UPDAT…
Out of Scope Changes check ✅ Passed The changes stay within issue #67 scope. The string-constant handling prevents repeated formatting from changing corpus output, and its regression coverage supports the required fixed-point check. The…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

A rabbit checks the lines of SQL,
Then joins the strings with care.
It keeps the lock after LIMIT,
And tests each style’s second pass.
One happy hop, one tidy query!

Comment @coderabbitai help to get the list of available commands.

@gmr
gmr merged commit cdd1ab5 into main Sep 23, 2026
4 checks passed
@gmr
gmr deleted the fix/locking-after-limit branch September 23, 2026 20:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FOR UPDATE after LIMIT is dropped, so the formatted query takes no lock

1 participant