Emit EXCLUDE frame-exclusion for single-bound window frames#201
Merged
lelit merged 1 commit intoJul 22, 2026
Merged
Conversation
`window_def()` printed the `EXCLUDE CURRENT ROW`/`EXCLUDE GROUP`/`EXCLUDE TIES` clause only inside the `if fo & FRAMEOPTION_BETWEEN:` branch, so a frame using a single bound (e.g. `ROWS 5 PRECEDING EXCLUDE CURRENT ROW`) had the exclusion bit set in the AST but silently dropped on reprint, changing the window's semantics. Per the PostgreSQL grammar `frame_exclusion` follows `frame_extent` for both the single `frame_bound` and the `BETWEEN frame_bound AND frame_bound` forms, so dedent the EXCLUDE block one level to run for every non-default frame.
Owner
|
Thank you for the report, and I appreciate the disclosure! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
RawStream/IndentedStreamsilently drop theEXCLUDE CURRENT ROW/EXCLUDE GROUP/EXCLUDE TIESframe-exclusion clause when a window frame uses a single bound (noBETWEEN), which changes the query's semantics:BETWEENframes are unaffected (ROWS BETWEEN 5 PRECEDING AND CURRENT ROW EXCLUDE CURRENT ROWround-trips fine), which is the tell: the exclusion bit is in the AST, it just isn't emitted for single-bound frames.Root cause (
pglast/printers/dml.py,window_def()): theEXCLUDEprinting block was nested inside theif fo & FRAMEOPTION_BETWEEN:branch. But in the PostgreSQL grammarframe_exclusionfollowsframe_extentand applies to both the singleframe_boundand theBETWEEN frame_bound AND frame_boundforms. So for single-bound frames the exclusion was never printed.Fix: dedent the
EXCLUDEblock one level out of theif BETWEENbranch so it runs for every non-default frame.EXCLUDE NO OTHERS(the grammar default, no bit set) still prints nothing.Verification (re-runnable from the diff): added four statements to
tests/test_printers_roundtrip/dml/select.sql— single-boundROWS/RANGE/GROUPSeach with a differentEXCLUDE, plus aBETWEEN ... EXCLUDE CURRENT ROWguard. The round-trip harness re-parses and asserts AST equality (and also checksIndentedStream). The three single-bound cases fail on the current tree and pass with the fix; the full suite is green (2120 passedin the round-trip module).Disclosure: This PR was authored by an AI coding agent (Claude Code) running on this account: the AI found the bug, ran the repro, wrote the tests, and wrote this description. The human account holder reviews every change and is accountable for it. The verification above is real and re-runnable from the diff. If this isn't the kind of contribution you want, say so and I'll close it.