Skip to content

fix: keep all clauses when deparsing SELECT without FROM (#2483) - #2484

Merged
manticore-projects merged 1 commit into
JSQLParser:masterfrom
fudianchn:fix/select-without-from-clauses
Aug 18, 2026
Merged

fix: keep all clauses when deparsing SELECT without FROM (#2483)#2484
manticore-projects merged 1 commit into
JSQLParser:masterfrom
fudianchn:fix/select-without-from-clauses

Conversation

@fudianchn

@fudianchn fudianchn commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

What

PlainSelect.toString() silently dropped every clause except WHERE / PREWHERE for a SELECT without FROM: GROUP BY, HAVING, WINDOW, QUALIFY, START WITH / CONNECT BY and PREFERRING parsed fine and were stored on the AST, but disappeared from the rendered SQL.

Why

FROM-less SELECT is supported Standard SQL (#1514). A parse -> toString -> reparse round trip silently rewrites the statement, the worst failure mode for audit / rewriting tools. The StatementDeParser path already renders all these clauses unconditionally, so the two render paths disagreed.

How

PlainSelect.appendSelectBodyTo: keep only the FROM-adjacent parts (FROM, lateral views, joins, FINAL, ksql WINDOW) inside the fromItem != null branch, move the shared clause chain out, and delete the truncated else // without from branch. This mirrors SelectDeParser, which already prints the whole chain outside its FROM block. Output for SELECTs with FROM is byte-identical (same checks in the same order).

Root cause

The else // without from branch of PlainSelect.appendSelectBodyTo rendered preWhere / where only, while the whole clause chain sat inside the fromItem != null branch.

Testing

Verification of the original issue

On master ad69ecc (jshell, CCJSqlParserUtil.parse(...).toString()):

IN : SELECT 1 GROUP BY 1 HAVING 1=1
OUT: SELECT 1

IN : SELECT 1 WINDOW w AS (ORDER BY 1)
OUT: SELECT 1

IN : SELECT 1 START WITH 1 = 1 CONNECT BY LEVEL <= 1
OUT: SELECT 1

With the fix, all statements from the issue round-trip through both toString() and StatementDeParser (both are asserted by the new tests).

Fixes #2483

…2483)

PlainSelect.appendSelectBodyTo printed the post-FROM clause chain
(oracle hierarchical, PREFERRING, GROUP BY, HAVING, QUALIFY, WINDOW,
EMIT CHANGES) only when a FROM item was present; the "without from"
branch rendered WHERE and PREWHERE alone. Move the shared clause
chain out of the fromItem branch, mirroring SelectDeParser, so a
FROM-less SELECT renders every clause stored on the AST. Output
for SELECTs with FROM is unchanged (same checks in the same order).

Signed-off-by: 付典 <fudianchn@gmail.com>
@fudianchn
fudianchn force-pushed the fix/select-without-from-clauses branch from c05bd1d to cc450a9 Compare August 18, 2026 02:08
@manticore-projects

Copy link
Copy Markdown
Contributor

Thank you, all of this came from a time where SELECT * FROM DUAL was the standard and nothing else.

@manticore-projects
manticore-projects merged commit 7013909 into JSQLParser:master Aug 18, 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 : RDBMS : SELECT without FROM silently drops GROUP BY / HAVING / WINDOW / QUALIFY / CONNECT BY / PREFERRING in toString()

2 participants