Fix JPQL and EQL CAST(…) function parsing.

We now define arithmetic, string, and typed cast functions to support all potential variants of casting supported by JPQL and EQL.

Closes #3863
This commit is contained in:
Mark Paluch
2025-05-09 15:51:17 +02:00
parent 59383b3014
commit b98e3705d5
6 changed files with 333 additions and 107 deletions

View File

@@ -441,7 +441,8 @@ arithmetic_primary
| functions_returning_numerics
| aggregate_expression
| case_expression
| cast_function
| arithmetic_cast_function
| type_cast_function
| function_invocation
| '(' subquery ')'
;
@@ -454,6 +455,8 @@ string_expression
| aggregate_expression
| case_expression
| function_invocation
| string_cast_function
| type_cast_function
| '(' subquery ')'
;
@@ -547,8 +550,16 @@ trim_specification
| BOTH
;
cast_function
: CAST '(' single_valued_path_expression identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
arithmetic_cast_function
: CAST '(' string_expression (AS)? f=(INTEGER|LONG|FLOAT|DOUBLE) ')'
;
type_cast_function
: CAST '(' scalar_expression (AS)? identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
;
string_cast_function
: CAST '(' scalar_expression (AS)? STRING ')'
;
function_invocation
@@ -903,6 +914,7 @@ DATETIME : D A T E T I M E ;
DELETE : D E L E T E;
DESC : D E S C;
DISTINCT : D I S T I N C T;
DOUBLE : D O U B L E;
END : E N D;
ELSE : E L S E;
EMPTY : E M P T Y;
@@ -916,6 +928,7 @@ FALSE : F A L S E;
FETCH : F E T C H;
FIRST : F I R S T;
FLOOR : F L O O R;
FLOAT : F L O A T;
FROM : F R O M;
FUNCTION : F U N C T I O N;
GROUP : G R O U P;
@@ -925,6 +938,7 @@ INDEX : I N D E X;
INNER : I N N E R;
INTERSECT : I N T E R S E C T;
IS : I S;
INTEGER : I N T E G E R;
JOIN : J O I N;
KEY : K E Y;
LAST : L A S T;
@@ -935,6 +949,7 @@ LIKE : L I K E;
LN : L N;
LOCAL : L O C A L;
LOCATE : L O C A T E;
LONG : L O N G;
LOWER : L O W E R;
MAX : M A X;
MEMBER : M E M B E R;
@@ -961,6 +976,7 @@ SIZE : S I Z E;
SOME : S O M E;
SQRT : S Q R T;
SUBSTRING : S U B S T R I N G;
STRING : S T R I N G;
SUM : S U M;
THEN : T H E N;
TIME : T I M E;

View File

@@ -387,13 +387,15 @@ all_or_any_expression
;
comparison_expression
: string_expression comparison_operator (string_expression | all_or_any_expression)
| boolean_expression op=(EQUAL | NOT_EQUAL) (boolean_expression | all_or_any_expression)
| enum_expression op=(EQUAL | NOT_EQUAL) (enum_expression | all_or_any_expression)
| datetime_expression comparison_operator (datetime_expression | all_or_any_expression)
| entity_expression op=(EQUAL | NOT_EQUAL) (entity_expression | all_or_any_expression)
| arithmetic_expression comparison_operator (arithmetic_expression | all_or_any_expression)
| entity_type_expression op=(EQUAL | NOT_EQUAL) entity_type_expression
: string_expression comparison_operator (string_expression | all_or_any_expression) #StringComparison
| boolean_expression op=(EQUAL | NOT_EQUAL) (boolean_expression | all_or_any_expression) #BooleanComparison
| boolean_expression #DirectBooleanCheck
| enum_expression op=(EQUAL | NOT_EQUAL) (enum_expression | all_or_any_expression) #EnumComparison
| datetime_expression comparison_operator (datetime_expression | all_or_any_expression) #DatetimeComparison
| entity_expression op=(EQUAL | NOT_EQUAL) (entity_expression | all_or_any_expression) #EntityComparison
| arithmetic_expression comparison_operator (arithmetic_expression | all_or_any_expression) #ArithmeticComparison
| entity_type_expression op=(EQUAL | NOT_EQUAL) entity_type_expression #EntityTypeComparison
| string_expression REGEXP string_literal #RegexpComparison
;
comparison_operator
@@ -427,6 +429,8 @@ arithmetic_primary
| functions_returning_numerics
| aggregate_expression
| case_expression
| arithmetic_cast_function
| type_cast_function
| function_invocation
| '(' subquery ')'
;
@@ -439,6 +443,8 @@ string_expression
| aggregate_expression
| case_expression
| function_invocation
| string_cast_function
| type_cast_function
| '(' subquery ')'
;
@@ -532,6 +538,17 @@ trim_specification
| BOTH
;
arithmetic_cast_function
: CAST '(' string_expression (AS)? f=(INTEGER|LONG|FLOAT|DOUBLE) ')'
;
type_cast_function
: CAST '(' scalar_expression (AS)? identification_variable ('(' numeric_literal (',' numeric_literal)* ')')? ')'
;
string_cast_function
: CAST '(' scalar_expression (AS)? STRING ')'
;
function_invocation
: FUNCTION '(' function_name (',' function_arg)* ')'
@@ -750,6 +767,7 @@ reserved_word
|BOTH
|BY
|CASE
|CAST
|CEILING
|COALESCE
|CONCAT
@@ -870,6 +888,7 @@ BETWEEN : B E T W E E N;
BOTH : B O T H;
BY : B Y;
CASE : C A S E;
CAST : C A S T;
CEILING : C E I L I N G;
COALESCE : C O A L E S C E;
CONCAT : C O N C A T;
@@ -882,6 +901,7 @@ DATETIME : D A T E T I M E ;
DELETE : D E L E T E;
DESC : D E S C;
DISTINCT : D I S T I N C T;
DOUBLE : D O U B L E;
END : E N D;
ELSE : E L S E;
EMPTY : E M P T Y;
@@ -894,6 +914,7 @@ FALSE : F A L S E;
FETCH : F E T C H;
FIRST : F I R S T;
FLOOR : F L O O R;
FLOAT : F L O A T;
FROM : F R O M;
FUNCTION : F U N C T I O N;
GROUP : G R O U P;
@@ -901,7 +922,9 @@ HAVING : H A V I N G;
IN : I N;
INDEX : I N D E X;
INNER : I N N E R;
INTERSECT : I N T E R S E C T;
IS : I S;
INTEGER : I N T E G E R;
JOIN : J O I N;
KEY : K E Y;
LAST : L A S T;
@@ -912,6 +935,7 @@ LIKE : L I K E;
LN : L N;
LOCAL : L O C A L;
LOCATE : L O C A T E;
LONG : L O N G;
LOWER : L O W E R;
MAX : M A X;
MEMBER : M E M B E R;
@@ -929,6 +953,7 @@ OR : O R;
ORDER : O R D E R;
OUTER : O U T E R;
POWER : P O W E R;
REGEXP : R E G E X P;
ROUND : R O U N D;
SELECT : S E L E C T;
SET : S E T;
@@ -937,6 +962,7 @@ SIZE : S I Z E;
SOME : S O M E;
SQRT : S Q R T;
SUBSTRING : S U B S T R I N G;
STRING : S T R I N G;
SUM : S U M;
THEN : T H E N;
TIME : T I M E;

View File

@@ -23,6 +23,7 @@ import java.util.List;
import org.antlr.v4.runtime.tree.ParseTree;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.util.CollectionUtils;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders an EQL query without making any changes.
@@ -49,7 +50,7 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
} else if (ctx.delete_statement() != null) {
return visit(ctx.delete_statement());
} else {
return QueryRenderer.builder();
return QueryTokenStream.empty();
}
}
@@ -1312,14 +1313,14 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
if (ctx.identification_variable() != null) {
builder.append(visit(ctx.identification_variable()));
return visit(ctx.identification_variable());
} else if (ctx.input_parameter() != null) {
builder.append(visit(ctx.input_parameter()));
return visit(ctx.input_parameter());
} else if (ctx.literal() != null) {
builder.append(visit(ctx.literal()));
return visit(ctx.literal());
}
return builder;
return QueryTokenStream.empty();
}
@Override
@@ -1565,8 +1566,10 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
} else if (ctx.cast_function() != null) {
builder.append(visit(ctx.cast_function()));
} else if (ctx.arithmetic_cast_function() != null) {
builder.append(visit(ctx.arithmetic_cast_function()));
} else if (ctx.type_cast_function() != null) {
builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1596,6 +1599,10 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
} else if (ctx.string_cast_function() != null) {
builder.append(visit(ctx.string_cast_function()));
} else if (ctx.type_cast_function() != null) {
builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1952,17 +1959,36 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
}
@Override
public QueryTokenStream visitCast_function(EqlParser.Cast_functionContext ctx) {
public QueryTokenStream visitArithmetic_cast_function(EqlParser.Arithmetic_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendInline(visit(ctx.single_valued_path_expression()));
builder.append(TOKEN_SPACE);
builder.appendExpression(visit(ctx.string_expression()));
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.append(QueryTokens.token(ctx.f));
builder.append(TOKEN_CLOSE_PAREN);
return builder;
}
@Override
public QueryTokenStream visitType_cast_function(EqlParser.Type_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendExpression(visit(ctx.scalar_expression()));
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.appendInline(visit(ctx.identification_variable()));
if (ctx.numeric_literal() != null) {
if (!CollectionUtils.isEmpty(ctx.numeric_literal())) {
builder.append(TOKEN_OPEN_PAREN);
builder.appendInline(QueryTokenStream.concat(ctx.numeric_literal(), this::visit, TOKEN_COMMA));
@@ -1973,6 +1999,23 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
return builder;
}
@Override
public QueryTokenStream visitString_cast_function(EqlParser.String_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendExpression(visit(ctx.scalar_expression()));
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.append(QueryTokens.token(ctx.STRING()));
builder.append(TOKEN_CLOSE_PAREN);
return builder;
}
@Override
public QueryTokenStream visitFunction_invocation(EqlParser.Function_invocationContext ctx) {

View File

@@ -25,6 +25,7 @@ import org.antlr.v4.runtime.tree.ParseTree;
import org.springframework.data.jpa.repository.query.JpqlParser.NullsPrecedenceContext;
import org.springframework.data.jpa.repository.query.JpqlParser.Reserved_wordContext;
import org.springframework.data.jpa.repository.query.QueryRenderer.QueryRendererBuilder;
import org.springframework.util.CollectionUtils;
/**
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that renders a JPQL query without making any changes.
@@ -1273,115 +1274,174 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
}
@Override
public QueryTokenStream visitComparison_expression(JpqlParser.Comparison_expressionContext ctx) {
public QueryTokenStream visitStringComparison(JpqlParser.StringComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
if (!ctx.string_expression().isEmpty()) {
builder.appendInline(visit(ctx.string_expression(0)));
builder.append(visit(ctx.comparison_operator()));
builder.appendExpression(visit(ctx.string_expression(0)));
builder.appendExpression(visit(ctx.comparison_operator()));
if (ctx.string_expression(1) != null) {
builder.appendExpression(visit(ctx.string_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.boolean_expression().isEmpty()) {
builder.appendInline(visit(ctx.boolean_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
if (ctx.boolean_expression(1) != null) {
builder.appendExpression(visit(ctx.boolean_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.enum_expression().isEmpty()) {
builder.appendInline(visit(ctx.enum_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
if (ctx.enum_expression(1) != null) {
builder.appendExpression(visit(ctx.enum_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.datetime_expression().isEmpty()) {
builder.appendExpression(visit(ctx.datetime_expression(0)));
builder.appendExpression(visit(ctx.comparison_operator()));
if (ctx.datetime_expression(1) != null) {
builder.appendExpression(visit(ctx.datetime_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.entity_expression().isEmpty()) {
builder.appendInline(visit(ctx.entity_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
if (ctx.entity_expression(1) != null) {
builder.appendExpression(visit(ctx.entity_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.arithmetic_expression().isEmpty()) {
builder.appendExpression(visit(ctx.arithmetic_expression(0)));
builder.appendExpression(visit(ctx.comparison_operator()));
if (ctx.arithmetic_expression(1) != null) {
builder.appendExpression(visit(ctx.arithmetic_expression(1)));
} else {
builder.appendExpression(visit(ctx.all_or_any_expression()));
}
} else if (!ctx.entity_type_expression().isEmpty()) {
builder.appendInline(visit(ctx.entity_type_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
builder.appendExpression(visit(ctx.entity_type_expression(1)));
if (ctx.string_expression(1) != null) {
builder.append(visit(ctx.string_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitBooleanComparison(JpqlParser.BooleanComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.boolean_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
if (ctx.boolean_expression(1) != null) {
builder.append(visit(ctx.boolean_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitDirectBooleanCheck(JpqlParser.DirectBooleanCheckContext ctx) {
return visit(ctx.boolean_expression());
}
@Override
public QueryTokenStream visitEnumComparison(JpqlParser.EnumComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.enum_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
if (ctx.enum_expression(1) != null) {
builder.append(visit(ctx.enum_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitDatetimeComparison(JpqlParser.DatetimeComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.datetime_expression(0)));
builder.append(QueryTokens.ventilated(ctx.comparison_operator().op));
if (ctx.datetime_expression(1) != null) {
builder.append(visit(ctx.datetime_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitEntityComparison(JpqlParser.EntityComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendExpression(visit(ctx.entity_expression(0)));
builder.append(QueryTokens.expression(ctx.op));
if (ctx.entity_expression(1) != null) {
builder.append(visit(ctx.entity_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitArithmeticComparison(JpqlParser.ArithmeticComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(visit(ctx.arithmetic_expression(0)));
builder.append(visit(ctx.comparison_operator()));
if (ctx.arithmetic_expression(1) != null) {
builder.append(visit(ctx.arithmetic_expression(1)));
} else {
builder.append(visit(ctx.all_or_any_expression()));
}
return builder;
}
@Override
public QueryTokenStream visitEntityTypeComparison(JpqlParser.EntityTypeComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.entity_type_expression(0)));
builder.append(QueryTokens.ventilated(ctx.op));
builder.append(visit(ctx.entity_type_expression(1)));
return builder;
}
@Override
public QueryTokenStream visitRegexpComparison(JpqlParser.RegexpComparisonContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendExpression(visit(ctx.string_expression()));
builder.append(QueryTokens.expression(ctx.REGEXP()));
builder.appendExpression(visit(ctx.string_literal()));
return builder;
}
@Override
public QueryTokenStream visitComparison_operator(JpqlParser.Comparison_operatorContext ctx) {
return QueryRenderer.from(QueryTokens.token(ctx.op));
return QueryRendererBuilder.from(QueryTokens.ventilated(ctx.op));
}
@Override
public QueryTokenStream visitArithmetic_expression(JpqlParser.Arithmetic_expressionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
if (ctx.arithmetic_expression() != null) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(visit(ctx.arithmetic_expression()));
builder.append(QueryTokens.ventilated(ctx.op));
builder.append(QueryTokens.expression(ctx.op));
builder.append(visit(ctx.arithmetic_term()));
return builder;
} else {
return visit(ctx.arithmetic_term());
builder.append(visit(ctx.arithmetic_term()));
}
return builder;
}
@Override
public QueryTokenStream visitArithmetic_term(JpqlParser.Arithmetic_termContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
if (ctx.arithmetic_term() != null) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.arithmetic_term()));
builder.append(QueryTokens.ventilated(ctx.op));
builder.append(visit(ctx.arithmetic_factor()));
return builder;
} else {
return visit(ctx.arithmetic_factor());
builder.append(visit(ctx.arithmetic_factor()));
}
return builder;
}
@Override
@@ -1392,8 +1452,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
if (ctx.op != null) {
builder.append(QueryTokens.token(ctx.op));
}
builder.append(visit(ctx.arithmetic_primary()));
builder.appendInline(visit(ctx.arithmetic_primary()));
return builder;
}
@@ -1420,6 +1479,10 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
} else if (ctx.arithmetic_cast_function() != null) {
builder.append(visit(ctx.arithmetic_cast_function()));
} else if (ctx.type_cast_function() != null) {
builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1449,6 +1512,10 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
builder.append(visit(ctx.aggregate_expression()));
} else if (ctx.case_expression() != null) {
builder.append(visit(ctx.case_expression()));
} else if (ctx.string_cast_function() != null) {
builder.append(visit(ctx.string_cast_function()));
} else if (ctx.type_cast_function() != null) {
builder.append(visit(ctx.type_cast_function()));
} else if (ctx.function_invocation() != null) {
builder.append(visit(ctx.function_invocation()));
} else if (ctx.subquery() != null) {
@@ -1793,6 +1860,62 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
}
}
@Override
public QueryTokenStream visitArithmetic_cast_function(JpqlParser.Arithmetic_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendExpression(visit(ctx.string_expression()));
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.append(QueryTokens.token(ctx.f));
builder.append(TOKEN_CLOSE_PAREN);
return builder;
}
@Override
public QueryTokenStream visitType_cast_function(JpqlParser.Type_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendExpression(visit(ctx.scalar_expression()));
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.appendInline(visit(ctx.identification_variable()));
if (!CollectionUtils.isEmpty(ctx.numeric_literal())) {
builder.append(TOKEN_OPEN_PAREN);
builder.appendInline(QueryTokenStream.concat(ctx.numeric_literal(), this::visit, TOKEN_COMMA));
builder.append(TOKEN_CLOSE_PAREN);
}
builder.append(TOKEN_CLOSE_PAREN);
return builder;
}
@Override
public QueryTokenStream visitString_cast_function(JpqlParser.String_cast_functionContext ctx) {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(QueryTokens.token(ctx.CAST()));
builder.append(TOKEN_OPEN_PAREN);
builder.appendExpression(visit(ctx.scalar_expression()));
builder.append(QueryTokens.expression(ctx.AS()));
builder.append(QueryTokens.token(ctx.STRING()));
builder.append(TOKEN_CLOSE_PAREN);
return builder;
}
@Override
public QueryTokenStream visitFunction_invocation(JpqlParser.Function_invocationContext ctx) {

View File

@@ -338,6 +338,15 @@ class EqlQueryRendererTests {
""");
}
@Test // GH-3024, GH-3863
void casting() {
assertQuery("""
select cast(i as string) from Item i where cast(i.date as date) <= cast(:currentDateTime as date)
""");
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
}
@Test
void pathExpressionsNamedParametersExample() {

View File

@@ -291,7 +291,7 @@ class JpqlQueryRendererTests {
assertQuery("""
SELECT b.name, b.ISBN
FROM Order o JOIN TREAT(o.product AS Book) b
""");
""");
}
@Test
@@ -300,7 +300,7 @@ class JpqlQueryRendererTests {
assertQuery("""
SELECT e FROM Employee e JOIN TREAT(e.projects AS LargeProject) lp
WHERE lp.budget > 1000
""");
""");
}
/**
@@ -315,7 +315,7 @@ class JpqlQueryRendererTests {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE "cost overrun"
""");
""");
}
@Test
@@ -326,7 +326,7 @@ class JpqlQueryRendererTests {
WHERE TREAT(p AS LargeProject).budget > 1000
OR TREAT(p AS SmallProject).name LIKE 'Persist%'
OR p.description LIKE 'cost overrun'
""");
""");
}
@Test
@@ -336,7 +336,16 @@ class JpqlQueryRendererTests {
SELECT e FROM Employee e
WHERE TREAT(e AS Exempt).vacationDays > 10
OR TREAT(e AS Contractor).hours > 100
""");
""");
}
@Test // GH-3024, GH-3863
void casting() {
assertQuery("""
select cast(i as string) from Item i where cast(i.date as date) <= cast(:currentDateTime as date)
""");
assertQuery("SELECT e FROM Employee e WHERE CAST(e.salary NUMERIC(10, 2)) > 0.0");
}
@Test
@@ -400,7 +409,7 @@ class JpqlQueryRendererTests {
WHERE emp.salary > ALL (SELECT m.salary
FROM Manager m
WHERE m.department = emp.department)
""");
""");
}
@Test
@@ -412,7 +421,7 @@ class JpqlQueryRendererTests {
WHERE EXISTS (SELECT spouseEmp
FROM Employee spouseEmp
WHERE spouseEmp = emp.spouse)
""");
""");
}
@Test
@@ -480,7 +489,7 @@ class JpqlQueryRendererTests {
WHEN e.rating = 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
""");
""");
}
@Test
@@ -493,7 +502,7 @@ class JpqlQueryRendererTests {
WHEN 2 THEN e.salary * 1.05
ELSE e.salary * 1.01
END
""");
""");
}
@Test
@@ -533,7 +542,7 @@ class JpqlQueryRendererTests {
SELECT e
FROM Employee e
WHERE TYPE(e) IN (Exempt, Contractor)
""");
""");
}
@Test