Skip to content

fix: support PostgreSQL GROUPS window frames - #2460

Merged
manticore-projects merged 2 commits into
JSQLParser:masterfrom
jianjindream:fix/2431-postgresql-groups-window-frame
Aug 12, 2026
Merged

fix: support PostgreSQL GROUPS window frames#2460
manticore-projects merged 2 commits into
JSQLParser:masterfrom
jianjindream:fix/2431-postgresql-groups-window-frame

Conversation

@jianjindream

@jianjindream jianjindream commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Fixes #2431

What

Add support for PostgreSQL GROUPS window frames and all four window frame exclusions.

How

  • Add WindowElement.Type.GROUPS.
  • Treat GROUPS as a reserved structural keyword.
  • Add WindowElement.Exclusion for:
    • EXCLUDE CURRENT ROW
    • EXCLUDE GROUP
    • EXCLUDE TIES
    • EXCLUDE NO OTHERS
  • Keep TIES and OTHERS contextual so they remain usable as unquoted identifiers outside the frame-exclusion grammar.
  • Keep deparsing centralized in WindowElement.toString().

Tests

  • Assert the parsed analytic expression, non-null window element, frame type, and exclusion type.
  • Cover BETWEEN ... AND ..., a single-sided frame, a named WINDOW, and all four frame exclusions.
  • Verify ties and others remain usable as identifiers.
  • ./gradlew clean check
  • mvn clean verify

@jianjindream
jianjindream marked this pull request as ready for review August 11, 2026 16:26
Copilot AI lite review requested due to automatic review settings August 11, 2026 16:26

Copilot AI 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.

Pull request overview

Adds PostgreSQL-compatible support for GROUPS window frames, enabling parsing/deparsing of ... OVER ( ... GROUPS ... ) frame specifications (fixes #2431).

Changes:

  • Added GROUPS as a non-reserved keyword so it can still be used as an unquoted identifier outside window-frame contexts.
  • Extended WindowElement.Type with GROUPS and updated the window-frame grammar to accept GROUPS alongside ROWS/RANGE.
  • Added unit tests covering GROUPS BETWEEN ... AND ..., single-sided UNBOUNDED PRECEDING, and named WINDOW definitions.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
src/test/java/net/sf/jsqlparser/statement/select/WindowFunctionTest.java Adds regression/variant tests asserting AST typing and round-trip deparse for GROUPS frames.
src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt Adds GROUPS token to non-reserved keywords and accepts it in the WindowElement frame-mode grammar.
src/main/java/net/sf/jsqlparser/expression/WindowElement.java Extends WindowElement.Type enum to include GROUPS for AST representation and deparsing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/test/java/net/sf/jsqlparser/statement/select/WindowFunctionTest.java Outdated
@manticore-projects

Copy link
Copy Markdown
Contributor

Thank you for working on this.

PostgreSQL's (and SQL:2011's) frame clause has a third component that JSqlParser's WindowElement() doesn't model at all. It bites harder in GROUPS mode and so I do wonder if not adding full support while you are on it.

{ RANGE | ROWS | GROUPS } frame_start [ frame_exclusion ]
{ RANGE | ROWS | GROUPS } BETWEEN frame_start AND frame_end [ frame_exclusion ]

frame_exclusion ::= EXCLUDE CURRENT ROW
                  | EXCLUDE GROUP
                  | EXCLUDE TIES
                  | EXCLUDE NO OTHERS

With your PR this meaningful query still fails:

SELECT id, ts, value,
       SUM(value) OVER (ORDER BY ts
                        GROUPS BETWEEN 1 PRECEDING AND CURRENT ROW
                        EXCLUDE TIES) AS sum_excl_ties
FROM events
ORDER BY ts, id;

Furthermore, promoting a word to a token breaks every production taking a raw <S_IDENTIFIER>: CREATE SCHEMA (~10496), SET PATH (~10538), Oracle KEEP (~9121), interval type (~9092), COLLATE (7912), and the nested ColDataType() lookahead (10873). We either need to declare it a reserved keyword (which was reasonable) or make at least CREATE SCHEMA work with it.

@jianjindream

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed review. I’ve updated the PR in 43710af to model all four frame exclusions: EXCLUDE CURRENT ROW, EXCLUDE GROUP, EXCLUDE TIES, and EXCLUDE NO OTHERS.

I also moved GROUPS to the reserved token set instead of broadening productions that only accept raw identifiers. TIES and OTHERS remain contextual identifiers, so they are only recognized specially after EXCLUDE and remain usable as ordinary unquoted identifiers elsewhere.

The tests now cover all four exclusions, the GROUPS ... EXCLUDE TIES query, explicit AST type/non-null assertions, named windows, and identifier compatibility. The updated Gradle and Maven CI checks are green.

@manticore-projects

Copy link
Copy Markdown
Contributor

Very nice! Thank you much for your contribution!

@manticore-projects
manticore-projects merged commit d92f407 into JSQLParser:master Aug 12, 2026
7 checks passed
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.

[BUG] JSQLParser 5.4-SNAPSHOT : PostgreSQL : GROUPS not supported in window function frame clause

3 participants