Skip to content

Fix dropped SELECT clauses and lost FROM-list comma#40

Merged
gmr merged 2 commits into
mainfrom
fix/select-dropped-clauses
Jul 6, 2026
Merged

Fix dropped SELECT clauses and lost FROM-list comma#40
gmr merged 2 commits into
mainfrom
fix/select-dropped-clauses

Conversation

@gmr

@gmr gmr commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes four bugs in the SELECT formatter (src/formatter/select.rs) where whole clauses were silently dropped or a comma was lost, producing invalid SQL. A small reusable helper was extracted in src/formatter/expr.rs.

Problem

Solution

Tests

Added regression fixtures (auto-discovered by tests/all_fixtures.rs):

All 72 fixtures pass; just check (fmt + clippy -D warnings + test) is green.

Fixes #18
Fixes #19
Fixes #20
Fixes #21

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Enhanced SQL formatting for window functions, including OVER with inline window specifications and named window references.
    • Added/improved rendering of WINDOW definitions and row-level locking clauses (FOR UPDATE / FOR SHARE), plus correct FETCH FIRST ... ROWS ONLY output.
    • Improved SELECT formatting consistency for FROM clauses when mixing comma-separated items with explicit JOIN ... ON.
  • Tests

    • Added and updated fixtures covering named window usage, locking clauses, FETCH FIRST, and comma/join combinations.

The SELECT formatter silently discarded several clauses and dropped a
comma between mixed FROM items. All four are addressed in
src/formatter/select.rs (with a small reusable helper extracted in
src/formatter/expr.rs).

- #18: FOR UPDATE / FOR SHARE locking clauses were dropped. Added a
  `for_locking` field to SelectClauses, collect `for_locking_clause`,
  and render each locking item (including OF list, NOWAIT, SKIP LOCKED,
  NO KEY UPDATE, KEY SHARE) in both river and left-aligned renderers.
- #19: WINDOW clause was dropped, leaving dangling OVER references.
  Added a `window_clause` field, collect it, and render the named
  window definitions. Extracted `format_window_spec_body` from
  `format_over_clause` so the spec body is formatted consistently.
- #20: FETCH FIRST n ROWS ONLY was dropped (extract_limit_value could
  not read select_fetch_first_value). The FETCH FIRST form is now
  preserved verbatim rather than normalized to LIMIT, since that is
  what the user wrote and there is no existing LIMIT normalization.
- #21: Comma was dropped between a plain table and a JOIN group in
  mixed FROM lists (both orders). `has_multiple_non_join` only counted
  non-join refs; replaced with logic that appends a comma after every
  FROM item except the last, in both river and left-aligned styles.

Added regression fixtures: river/{for_locking_clause, window_named_clause,
fetch_first_rows_only, from_comma_join_mix} and aweber/from_comma_join_mix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f6afc55c-728d-46a8-8cc6-767131e3686c

📥 Commits

Reviewing files that changed from the base of the PR and between b7c1115 and 82aca22.

📒 Files selected for processing (2)
  • src/formatter/expr.rs
  • tests/fixtures/river/window_named_clause.expected
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/fixtures/river/window_named_clause.expected
  • src/formatter/expr.rs

📝 Walkthrough

Walkthrough

This PR preserves WINDOW, FOR UPDATE/FOR SHARE, and FETCH FIRST clauses during SELECT formatting, and fixes comma placement for mixed comma-and-JOIN FROM lists in both river and left-aligned styles. It also adds fixtures covering the updated output.

Changes

Missing SELECT clause preservation fixes

Layer / File(s) Summary
Window spec body formatting refactor
src/formatter/expr.rs, tests/fixtures/river/window_named_clause.*
format_over_clause now distinguishes inline window specs, named window references, and fallback window bodies, and format_window_spec_body returns only the inner contents used by the named-window fixture.
Clause collection and river formatting
src/formatter/select.rs, tests/fixtures/river/fetch_first_rows_only.*, tests/fixtures/river/for_locking_clause.*, tests/fixtures/river/from_comma_join_mix.*, tests/fixtures/river/window_named_clause.*
SelectClauses collects WINDOW and locking clauses, river formatting emits them, preserves FETCH FIRST, updates river width keyword tracking, and formats mixed FROM items by position.
Left-aligned formatting and comma placement
src/formatter/select.rs, tests/fixtures/aweber/from_comma_join_mix.*
Left-aligned formatting emits WINDOW and locking blocks, preserves FETCH FIRST, and formats mixed FROM lists with position-based commas.
Test fixtures
tests/fixtures/river/*, tests/fixtures/aweber/*
New SQL and expected fixtures cover named windows, locking clauses, FETCH FIRST, and mixed comma-plus-JOIN FROM syntax.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

  • gmr/libpgfmt#4: Both PRs modify src/formatter/expr.rs window clause formatting and OVER rendering.

Poem

I hop through SQL, ears held high,
Where lost clauses now can’t slip by.
WINDOW, FOR, and FETCH first too,
Commas stay put in joins I chew. 🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main fix: preserving dropped SELECT clauses and mixed FROM-list commas.
Linked Issues check ✅ Passed The changes address #18-#21 by preserving locking clauses, WINDOW clauses, FETCH FIRST, and mixed FROM-list commas.
Out of Scope Changes check ✅ Passed All code and fixture changes are directly tied to the SELECT formatter fixes described in the linked issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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

@gmr

gmr commented Jul 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/fixtures/river/window_named_clause.expected`:
- Around line 1-4: The expected SQL output is rewriting a bare named-window
reference into an inline window specification; update the formatter/fixture for
the ROW_NUMBER() OVER form so the named window reference stays as OVER w instead
of being rendered as OVER (w). Focus on the window-clause handling in the SQL
formatting path that produces this expected file and preserve the bare
named-window syntax when a WINDOW alias like w is referenced.

In `@tests/fixtures/river/window_named_clause.sql`:
- Line 1: The window formatting in format_over_clause is rewriting named window
references like OVER w into OVER (...), which changes the emitted SQL form.
Update the formatter to preserve a bare named window reference when the OVER
clause points directly to a named window, and only parenthesize inline
specifications; use the existing format_over_clause logic to distinguish these
cases so this fixture stays as OVER w, or add a separate frame-clause case if
needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a5d42cda-c290-4a94-857f-bffe9c896966

📥 Commits

Reviewing files that changed from the base of the PR and between c949e2b and b7c1115.

📒 Files selected for processing (12)
  • src/formatter/expr.rs
  • src/formatter/select.rs
  • tests/fixtures/aweber/from_comma_join_mix.expected
  • tests/fixtures/aweber/from_comma_join_mix.sql
  • tests/fixtures/river/fetch_first_rows_only.expected
  • tests/fixtures/river/fetch_first_rows_only.sql
  • tests/fixtures/river/for_locking_clause.expected
  • tests/fixtures/river/for_locking_clause.sql
  • tests/fixtures/river/from_comma_join_mix.expected
  • tests/fixtures/river/from_comma_join_mix.sql
  • tests/fixtures/river/window_named_clause.expected
  • tests/fixtures/river/window_named_clause.sql

Comment thread tests/fixtures/river/window_named_clause.expected
Comment thread tests/fixtures/river/window_named_clause.sql
format_over_clause unconditionally wrapped the window reference in
parentheses, rewriting `OVER w` into `OVER (w)`. In PostgreSQL these are
distinct forms: `OVER w` references a named window from the WINDOW clause,
while `OVER (w ...)` copies and extends that definition and is rejected when
the named window already carries a frame clause.

Only parenthesize when the over_clause has an inline window_specification;
render a bare named-window reference (a ColId child) as `OVER name`. Updates
the river/window_named_clause fixture to expect the bare form.

Addresses CodeRabbit review feedback on PR #40.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@gmr gmr merged commit e455476 into main Jul 6, 2026
3 checks passed
@gmr gmr deleted the fix/select-dropped-clauses branch July 6, 2026 20:59
gmr added a commit that referenced this pull request Jul 8, 2026
* Fix inline comments mangling CREATE FOREIGN TABLE formatting (#41)

CREATE FOREIGN TABLE mishandled inline `-- ...` comments the same way
CREATE TABLE did before #40: comments between columns were treated as
bogus columns (alignment padding plus a trailing comma that mangled the
comment text), and a comment after the last element was dropped.

Factor the comment-association logic added for CREATE TABLE into a shared
`collect_table_elements` helper and use it from both statement formatters.
`format_create_foreign_table_stmt` now renders trailing comments at the
end of the element they follow (aligned to a common column in river
style, single-space in left-aligned styles), keeping the original element
order.

Also registers the previously unwired CREATE FOREIGN TABLE fixtures in the
test harness alongside the new inline-comment fixtures.

Closes #41

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Extract shared left-aligned table-element renderer

The non-river rendering loop in format_create_foreign_table_stmt was
byte-identical to the one in format_create_table_stmt. Extract it into a
render_grouped_elements_left_aligned helper that both callers use,
mirroring the earlier collect_table_elements extraction.

Addresses CodeRabbit nitpick on PR #43. Behavior is unchanged; all
fixtures and unit tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant