Skip to content

Commit 0d03612

Browse files
committed
Properly handle CAST functions on HQL.
See #3024
1 parent 3132f49 commit 0d03612

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,9 +492,18 @@ frameEnd
492492

493493
// https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-functions
494494
castFunction
495-
: CAST '(' expression AS identifier ')'
495+
: CAST '(' expression AS castTarget ')'
496496
;
497497

498+
castTarget
499+
: castTargetType ('(' INTEGER_LITERAL (',' INTEGER_LITERAL)? ')')?
500+
;
501+
502+
castTargetType
503+
returns [String fullTargetName]
504+
: (i=identifier { $fullTargetName = _localctx.i.getText(); }) ('.' c=identifier { $fullTargetName += ("." + _localctx.c.getText() ); })*
505+
;
506+
498507
extractFunction
499508
: EXTRACT '(' expression FROM expression ')'
500509
| dateTimeFunction '(' expression ')'

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/HqlQueryRenderer.java

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public List<JpaQueryParsingToken> visitCte(HqlParser.CteContext ctx) {
106106
if (ctx.MATERIALIZED() != null) {
107107
tokens.add(TOKEN_MATERIALIZED);
108108
}
109-
109+
110110
tokens.add(TOKEN_OPEN_PAREN);
111111
tokens.addAll(visit(ctx.queryExpression()));
112112
tokens.add(TOKEN_CLOSE_PAREN);
@@ -1790,16 +1790,47 @@ public List<JpaQueryParsingToken> visitCastFunction(HqlParser.CastFunctionContex
17901790

17911791
List<JpaQueryParsingToken> tokens = new ArrayList<>();
17921792

1793-
tokens.add(new JpaQueryParsingToken(ctx.CAST()));
1793+
tokens.add(new JpaQueryParsingToken(ctx.CAST(), false));
17941794
tokens.add(TOKEN_OPEN_PAREN);
17951795
tokens.addAll(visit(ctx.expression()));
17961796
tokens.add(new JpaQueryParsingToken(ctx.AS()));
1797-
tokens.addAll(visit(ctx.identifier()));
1797+
tokens.addAll(visit(ctx.castTarget()));
1798+
NOSPACE(tokens);
17981799
tokens.add(TOKEN_CLOSE_PAREN);
17991800

18001801
return tokens;
18011802
}
18021803

1804+
@Override
1805+
public List<JpaQueryParsingToken> visitCastTarget(HqlParser.CastTargetContext ctx) {
1806+
1807+
List<JpaQueryParsingToken> tokens = new ArrayList<>();
1808+
1809+
tokens.addAll(visit(ctx.castTargetType()));
1810+
1811+
if (ctx.INTEGER_LITERAL() != null && !ctx.INTEGER_LITERAL().isEmpty()) {
1812+
1813+
tokens.add(TOKEN_OPEN_PAREN);
1814+
1815+
ctx.INTEGER_LITERAL().forEach(terminalNode -> {
1816+
1817+
tokens.add(new JpaQueryParsingToken(terminalNode));
1818+
tokens.add(TOKEN_COMMA);
1819+
});
1820+
CLIP(tokens);
1821+
NOSPACE(tokens);
1822+
1823+
tokens.add(TOKEN_CLOSE_PAREN);
1824+
}
1825+
1826+
return tokens;
1827+
}
1828+
1829+
@Override
1830+
public List<JpaQueryParsingToken> visitCastTargetType(HqlParser.CastTargetTypeContext ctx) {
1831+
return List.of(new JpaQueryParsingToken(ctx.fullTargetName));
1832+
}
1833+
18031834
@Override
18041835
public List<JpaQueryParsingToken> visitExtractFunction(HqlParser.ExtractFunctionContext ctx) {
18051836

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,4 +1521,9 @@ void floorShouldBeValidEntityName() {
15211521
void queryWithSignShouldWork() {
15221522
assertQuery("select t.sign from TestEntity t");
15231523
}
1524+
1525+
@Test // GH-3024
1526+
void castFunctionWithFqdnShouldWork() {
1527+
assertQuery("SELECT o FROM Order o WHERE CAST(:userId AS java.util.UUID) IS NULL OR o.user.id = :userId");
1528+
}
15241529
}

0 commit comments

Comments
 (0)