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 b66c96d363
commit e6a008cf08
7 changed files with 21 additions and 36 deletions

View File

@@ -314,7 +314,6 @@ scalar_expression
| datetime_expression
| boolean_expression
| case_expression
| cast_function
| entity_type_expression
;
@@ -954,7 +953,6 @@ FETCH : F E T C H;
FIRST : F I R S T;
FLOAT : F L O A 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;
@@ -965,7 +963,6 @@ INNER : I N N E R;
INTEGER : I N T E G 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;
@@ -1006,7 +1003,6 @@ SOME : S O M E;
SQRT : S Q R T;
STRING : S T R I N G;
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

@@ -307,7 +307,6 @@ scalar_expression
| datetime_expression
| boolean_expression
| case_expression
| cast_function
| entity_type_expression
;
@@ -454,7 +453,6 @@ string_expression
| aggregate_expression
| case_expression
| function_invocation
| string_expression op='||' string_expression
| string_cast_function
| type_cast_function
| '(' subquery ')'
@@ -950,7 +948,6 @@ FETCH : F E T C H;
FIRST : F I R S T;
FLOAT : F L O A 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;
@@ -961,7 +958,6 @@ INNER : I N N E R;
INTEGER : I N T E G 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;
@@ -1002,7 +998,6 @@ SOME : S O M E;
SQRT : S Q R T;
STRING : S T R I N G;
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

@@ -1010,8 +1010,6 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
return visit(ctx.case_expression());
} else if (ctx.entity_type_expression() != null) {
return visit(ctx.entity_type_expression());
} else if (ctx.cast_function() != null) {
return (visit(ctx.cast_function()));
}
return QueryTokenStream.empty();
@@ -1363,8 +1361,8 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendExpression(visit(ctx.string_expression(0)));
builder.appendExpression(visit(ctx.comparison_operator()));
builder.appendInline(visit(ctx.string_expression(0)));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.string_expression(1) != null) {
builder.appendExpression(visit(ctx.string_expression(1)));
@@ -1420,7 +1418,7 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.datetime_expression(0)));
builder.append(QueryTokens.ventilated(ctx.comparison_operator().op));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.datetime_expression(1) != null) {
builder.appendExpression(visit(ctx.datetime_expression(1)));
@@ -1453,8 +1451,8 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendExpression(visit(ctx.arithmetic_expression(0)));
builder.appendExpression(visit(ctx.comparison_operator()));
builder.appendInline(visit(ctx.arithmetic_expression(0)));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.arithmetic_expression(1) != null) {
builder.appendExpression(visit(ctx.arithmetic_expression(1)));
@@ -1491,7 +1489,7 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
@Override
public QueryTokenStream visitComparison_operator(EqlParser.Comparison_operatorContext ctx) {
return QueryTokenStream.ofToken(ctx.op);
return QueryTokenStream.from(QueryTokens.ventilated(ctx.op));
}
@Override
@@ -2005,7 +2003,7 @@ class EqlQueryRenderer extends EqlBaseVisitor<QueryTokenStream> {
if (ctx.AS() != null) {
builder.append(QueryTokens.expression(ctx.AS()));
}
builder.appendInline(QueryTokenStream.concat(ctx.identification_variable(), this::visit, TOKEN_SPACE));
builder.appendInline(visit(ctx.identification_variable()));
if (!CollectionUtils.isEmpty(ctx.numeric_literal())) {

View File

@@ -985,8 +985,6 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
return visit(ctx.case_expression());
} else if (ctx.entity_type_expression() != null) {
return visit(ctx.entity_type_expression());
} else if (ctx.cast_function() != null) {
return (visit(ctx.cast_function()));
}
return QueryTokenStream.empty();
@@ -1336,7 +1334,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.string_expression(0)));
builder.append(visit(ctx.comparison_operator()));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.string_expression(1) != null) {
builder.append(visit(ctx.string_expression(1)));
@@ -1392,7 +1390,7 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.appendInline(visit(ctx.datetime_expression(0)));
builder.append(QueryTokens.ventilated(ctx.comparison_operator().op));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.datetime_expression(1) != null) {
builder.append(visit(ctx.datetime_expression(1)));
@@ -1425,8 +1423,8 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
QueryRendererBuilder builder = QueryRenderer.builder();
builder.append(visit(ctx.arithmetic_expression(0)));
builder.append(visit(ctx.comparison_operator()));
builder.appendInline(visit(ctx.arithmetic_expression(0)));
builder.appendInline(visit(ctx.comparison_operator()));
if (ctx.arithmetic_expression(1) != null) {
builder.append(visit(ctx.arithmetic_expression(1)));
@@ -1469,19 +1467,17 @@ class JpqlQueryRenderer extends JpqlBaseVisitor<QueryTokenStream> {
@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.expression(ctx.op));
builder.append(QueryTokens.ventilated(ctx.op));
builder.append(visit(ctx.arithmetic_term()));
return builder;
} else {
builder.append(visit(ctx.arithmetic_term()));
return visit(ctx.arithmetic_term());
}
return builder;
}
@Override

View File

@@ -25,12 +25,12 @@ import org.junit.jupiter.params.provider.MethodSource;
*
* @author Greg Turnquist
*/
public class EqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
class EqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNative()).isFalse();
assumeThat(query.isNative()).describedAs("EQL (non-native) only").isFalse();
return JpaQueryEnhancer.forEql(query.getQueryString());
}

View File

@@ -25,12 +25,12 @@ import org.junit.jupiter.params.provider.MethodSource;
*
* @author Greg Turnquist
*/
public class HqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
class HqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNative()).isFalse();
assumeThat(query.isNative()).describedAs("HQL (non-native) only").isFalse();
return JpaQueryEnhancer.forHql(query.getQueryString());
}

View File

@@ -25,12 +25,12 @@ import org.junit.jupiter.params.provider.MethodSource;
*
* @author Greg Turnquist
*/
public class JpqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
class JpqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
@Override
QueryEnhancer createQueryEnhancer(DeclaredQuery query) {
assumeThat(query.isNative()).isFalse();
assumeThat(query.isNative()).describedAs("JPQL (non-native) only").isFalse();
return JpaQueryEnhancer.forJpql(query.getQueryString());
}