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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user