Skip to content

Fix JPQL, EQL, and HQL query rendering round-trips#4273

Closed
jewoodev wants to merge 4 commits into
spring-projects:mainfrom
jewoodev:jpql-eql-renderer-spec-fixes
Closed

Fix JPQL, EQL, and HQL query rendering round-trips#4273
jewoodev wants to merge 4 commits into
spring-projects:mainfrom
jewoodev:jpql-eql-renderer-spec-fixes

Conversation

@jewoodev

@jewoodev jewoodev commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

These four focused commits fix renderer-only defects where the JPQL, EQL, and HQL renderers fail to preserve parsed query constructs during rendering. The first three affect JpqlQueryRenderer and EqlQueryRenderer (HQL already round-trips these correctly); the fourth fixes the HQL-only column(...) function in HqlQueryRenderer. All four are confined to visitor methods, add round-trip tests, and leave the grammars untouched.

Fix Root cause Change
TREAT(…) downcast TREAT branch guarded by a condition duplicated from the preceding branch → unreachable, cast silently dropped check TREAT() first
Two-argument LOCATE(…) third-argument guard used != null on a never-null list accessor → visit(null), throwing NullPointerException check the list is non-empty
Subquery FROM collection member visitSubquery_from_clause rendered only the identification variable, dropping a trailing collection_member_declaration and leaving its alias undefined iterate child nodes in source order
HQL column(…) cast target visitColumnFunction appended the function name as an expression after the . (stray space) and, for the optional cast, visited jpaNonstandardFunctionName() instead of castTarget()column(tbl.foo as int) rendered as column(tbl. foo as foo) append without expression spacing and render castTarget(), matching visitJpaNonstandardFunction
  • You have read the Spring Data contribution guidelines.
  • You use the code formatters provided here and have them applied to your changes. Don’t submit any formatting related changes.
  • You submit test cases (unit or integration tests) that back your changes.
  • You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).

Closes #4272

jewoodev added 3 commits June 4, 2026 22:34
The `TREAT(qualified_identification_variable AS subtype)` alternative of `single_valued_path_expression` was guarded by a condition duplicated from the preceding `qualified_identification_variable` branch, so the branch rendering the downcast was unreachable. `SELECT TREAT(VALUE(m) AS Employee) …` rendered as `SELECT VALUE(m) …`, silently dropping the cast.

Check `TREAT()` first so the downcast expression is rendered.

Closes spring-projects#4272
Signed-off-by: jewoodev <jewoos15@naver.com>
The optional third argument of `LOCATE` was guarded by `ctx.arithmetic_expression() != null`. As `arithmetic_expression` is a list accessor that never returns `null`, the guard was always true, so `LOCATE('a', e.name)` reached `visit(ctx.arithmetic_expression(0))` with no element and threw a `NullPointerException`.

Check whether the list is empty before rendering the third argument.

Closes spring-projects#4272
Signed-off-by: jewoodev <jewoos15@naver.com>
The subquery `FROM` clause grammar allows a `collection_member_declaration` after the comma (`FROM subselect_identification_variable_declaration (',' (subselect_identification_variable_declaration | collection_member_declaration))*`), but `visitSubquery_from_clause` rendered only `subselect_identification_variable_declaration`. `SELECT l FROM Order o2, IN(o2.lineItems) l …` dropped the `, IN(o2.lineItems) l` term, leaving the alias `l` undefined in the rendered subquery.

Render both declaration types in their source order by iterating over the child nodes.

Closes spring-projects#4272
Signed-off-by: jewoodev <jewoos15@naver.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 4, 2026
@mp911de mp911de added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 4, 2026
`visitColumnFunction` renders the `columnFunction` rule
`column(path '.' jpaNonstandardFunctionName (AS castTarget)?)`, but appended
the function name as an expression after the `.` token, and for the optional
cast it visited `jpaNonstandardFunctionName()` again instead of `castTarget()`.

`column(tbl.foo as int)` rendered as `column(tbl. foo as foo)`, inserting a
stray space after the dot and dropping the cast target while repeating the
function name.

Append the function name without expression spacing and render `castTarget()`
after `AS`, as the equivalent `visitJpaNonstandardFunction` already does.

Closes spring-projects#4272

Signed-off-by: jewoodev <jewoos15@naver.com>
@jewoodev jewoodev changed the title Fix JPQL and EQL renderer round-trip for TREAT, LOCATE, and subquery FROM Fix JPQL, EQL, and HQL query rendering round-trips Jun 5, 2026
@mp911de mp911de self-assigned this Jun 5, 2026
mp911de pushed a commit that referenced this pull request Jun 5, 2026
…subqueries.

We now render `TREAT(…)` downcasts in qualified identification variables`LOCATE(…)` calls without an offset argument, and collection member declarations in subquery `FROM` clauses correctly.
HQL `column(…)` rendering now uses the actual cast target for `column(path as type)`.

Closes #4272
Original pull request: #4273
Signed-off-by: jewoodev <jewoos15@naver.com>
mp911de added a commit that referenced this pull request Jun 5, 2026
Remove unused code, add missing annotation.

See #4272
Original pull request: #4273
mp911de pushed a commit that referenced this pull request Jun 5, 2026
…subqueries.

We now render `TREAT(…)` downcasts in qualified identification variables`LOCATE(…)` calls without an offset argument, and collection member declarations in subquery `FROM` clauses correctly.
HQL `column(…)` rendering now uses the actual cast target for `column(path as type)`.

Closes #4272
Original pull request: #4273
Signed-off-by: jewoodev <jewoos15@naver.com>
mp911de added a commit that referenced this pull request Jun 5, 2026
Properly support DISTINCT queries without a primary alias.
Remove unused code, add missing annotation.

See #4272
Original pull request: #4273
mp911de pushed a commit that referenced this pull request Jun 5, 2026
…subqueries.

We now render `TREAT(…)` downcasts in qualified identification variables`LOCATE(…)` calls without an offset argument, and collection member declarations in subquery `FROM` clauses correctly.
HQL `column(…)` rendering now uses the actual cast target for `column(path as type)`.

Closes #4272
Original pull request: #4273
Signed-off-by: jewoodev <jewoos15@naver.com>
mp911de added a commit that referenced this pull request Jun 5, 2026
Properly support DISTINCT queries without a primary alias.
Remove unused code, add missing annotation.

See #4272
Original pull request: #4273
@mp911de

mp911de commented Jun 5, 2026

Copy link
Copy Markdown
Member

Thank you for your contribution. That's merged, polished, and backported now.

@mp911de mp911de closed this Jun 5, 2026
@mp911de mp911de added this to the 3.5.12 (2025.0.12) milestone Jun 5, 2026
@jewoodev jewoodev deleted the jpql-eql-renderer-spec-fixes branch June 5, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug A general bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JPQL and EQL renderers fail using TREAT, LOCATE, and subqueries from collection members

3 participants