Fix parsing entity names in JPQL query with package names that contain reserved words.
Resolves: #3451 Original pull request: #3457
This commit is contained in:
@@ -638,7 +638,7 @@ identification_variable
|
||||
;
|
||||
|
||||
constructor_name
|
||||
: state_field_path_expression
|
||||
: entity_name
|
||||
;
|
||||
|
||||
literal
|
||||
@@ -720,7 +720,7 @@ collection_value_field
|
||||
;
|
||||
|
||||
entity_name
|
||||
: identification_variable ('.' identification_variable)* // Hibernate sometimes expands the entity name to FQDN when using named queries
|
||||
: reserved_word ('.' reserved_word)* // Hibernate sometimes expands the entity name to FQDN when using named queries
|
||||
;
|
||||
|
||||
result_variable
|
||||
@@ -748,6 +748,90 @@ character_valued_input_parameter
|
||||
| input_parameter
|
||||
;
|
||||
|
||||
reserved_word
|
||||
: IDENTIFICATION_VARIABLE
|
||||
| f=(ABS
|
||||
|ALL
|
||||
|AND
|
||||
|ANY
|
||||
|AS
|
||||
|ASC
|
||||
|AVG
|
||||
|BETWEEN
|
||||
|BOTH
|
||||
|BY
|
||||
|CASE
|
||||
|CEILING
|
||||
|COALESCE
|
||||
|CONCAT
|
||||
|COUNT
|
||||
|CURRENT_DATE
|
||||
|CURRENT_TIME
|
||||
|CURRENT_TIMESTAMP
|
||||
|DATE
|
||||
|DATETIME
|
||||
|DELETE
|
||||
|DESC
|
||||
|DISTINCT
|
||||
|END
|
||||
|ELSE
|
||||
|EMPTY
|
||||
|ENTRY
|
||||
|ESCAPE
|
||||
|EXISTS
|
||||
|EXP
|
||||
|EXTRACT
|
||||
|FALSE
|
||||
|FETCH
|
||||
|FLOOR
|
||||
|FUNCTION
|
||||
|IN
|
||||
|INDEX
|
||||
|INNER
|
||||
|IS
|
||||
|KEY
|
||||
|LEFT
|
||||
|LENGTH
|
||||
|LIKE
|
||||
|LN
|
||||
|LOCAL
|
||||
|LOCATE
|
||||
|LOWER
|
||||
|MAX
|
||||
|MEMBER
|
||||
|MIN
|
||||
|MOD
|
||||
|NEW
|
||||
|NOT
|
||||
|NULL
|
||||
|NULLIF
|
||||
|OBJECT
|
||||
|OF
|
||||
|ON
|
||||
|OR
|
||||
|ORDER
|
||||
|OUTER
|
||||
|POWER
|
||||
|ROUND
|
||||
|SELECT
|
||||
|SET
|
||||
|SIGN
|
||||
|SIZE
|
||||
|SOME
|
||||
|SQRT
|
||||
|SUBSTRING
|
||||
|SUM
|
||||
|THEN
|
||||
|TIME
|
||||
|TRAILING
|
||||
|TREAT
|
||||
|TRIM
|
||||
|TRUE
|
||||
|TYPE
|
||||
|UPDATE
|
||||
|UPPER
|
||||
|VALUE)
|
||||
;
|
||||
/*
|
||||
Lexer rules
|
||||
*/
|
||||
|
||||
@@ -2331,7 +2331,7 @@ class EqlQueryRenderer extends EqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = new ArrayList<>();
|
||||
|
||||
tokens.addAll(visit(ctx.state_field_path_expression()));
|
||||
tokens.addAll(visit(ctx.entity_name()));
|
||||
NOSPACE(tokens);
|
||||
|
||||
return tokens;
|
||||
@@ -2492,8 +2492,8 @@ class EqlQueryRenderer extends EqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
|
||||
List<JpaQueryParsingToken> tokens = new ArrayList<>();
|
||||
|
||||
ctx.identification_variable().forEach(identificationVariableContext -> {
|
||||
tokens.addAll(visit(identificationVariableContext));
|
||||
ctx.reserved_word().forEach(identificationVariableContext -> {
|
||||
tokens.addAll(visitReserved_word(identificationVariableContext));
|
||||
NOSPACE(tokens);
|
||||
tokens.add(TOKEN_DOT);
|
||||
});
|
||||
@@ -2543,4 +2543,15 @@ class EqlQueryRenderer extends EqlBaseVisitor<List<JpaQueryParsingToken>> {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JpaQueryParsingToken> visitReserved_word(EqlParser.Reserved_wordContext ctx) {
|
||||
if (ctx.IDENTIFICATION_VARIABLE() != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.IDENTIFICATION_VARIABLE()));
|
||||
} else if (ctx.f != null) {
|
||||
return List.of(new JpaQueryParsingToken(ctx.f));
|
||||
} else {
|
||||
return List.of();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,15 @@ package org.springframework.data.jpa.repository.query;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.jpa.repository.query.JpaQueryParsingToken.*;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
/**
|
||||
@@ -55,6 +59,10 @@ class EqlQueryRendererTests {
|
||||
return render(new EqlQueryRenderer().visit(parsedQuery));
|
||||
}
|
||||
|
||||
static Stream<Arguments> reservedWords() {
|
||||
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
|
||||
}
|
||||
|
||||
private void assertQuery(String query) {
|
||||
|
||||
String slimmedDownQuery = reduceWhitespace(query);
|
||||
@@ -997,25 +1005,25 @@ class EqlQueryRendererTests {
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select 1 from User u",
|
||||
"select -1 from User u",
|
||||
"select +1 from User u",
|
||||
"select +1*-100 from User u",
|
||||
"select count(u)*-0.7f from User u",
|
||||
@ValueSource(strings = { "select 1 from User u", "select -1 from User u", "select +1 from User u",
|
||||
"select +1*-100 from User u", "select count(u)*-0.7f from User u",
|
||||
"select count(oi) + (-100) as perc from StockOrderItem oi",
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20"
|
||||
})
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
|
||||
void signedLiteralShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select -count(u) from User u",
|
||||
"select +1*(-count(u)) from User u"
|
||||
})
|
||||
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
|
||||
void signedExpressionsShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3451
|
||||
@MethodSource("reservedWords")
|
||||
void entityNameWithPackageContainingReservedWord(String reservedWord) {
|
||||
|
||||
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
|
||||
assertQuery(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class HqlQueryRendererTests {
|
||||
return render(new HqlQueryRenderer().visit(parsedQuery));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> reservedWords() {
|
||||
static Stream<Arguments> reservedWords() {
|
||||
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
|
||||
}
|
||||
|
||||
@@ -1648,30 +1648,22 @@ class HqlQueryRendererTests {
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select 1 from User",
|
||||
"select -1 from User",
|
||||
"select +1 from User",
|
||||
"select +1*-100 from User",
|
||||
"select count(u)*-0.7f from User u",
|
||||
"select count(oi) + (-100) as perc from StockOrderItem oi",
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20"
|
||||
})
|
||||
@ValueSource(
|
||||
strings = { "select 1 from User", "select -1 from User", "select +1 from User", "select +1*-100 from User",
|
||||
"select count(u)*-0.7f from User u", "select count(oi) + (-100) as perc from StockOrderItem oi",
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
|
||||
void signedLiteralShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select -count(u) from User u",
|
||||
"select +1*(-count(u)) from User u"
|
||||
})
|
||||
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
|
||||
void signedExpressionsShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3451
|
||||
@MethodSource({"reservedWords"})
|
||||
@MethodSource("reservedWords")
|
||||
void entityNameWithPackageContainingReservedWord(String reservedWord) {
|
||||
|
||||
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
|
||||
|
||||
@@ -60,7 +60,7 @@ class JpqlQueryRendererTests {
|
||||
return render(new JpqlQueryRenderer().visit(parsedQuery));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> reservedWords() {
|
||||
static Stream<Arguments> reservedWords() {
|
||||
return Stream.of("abs", "exp", "any", "case", "else", "index", "time").map(Arguments::of);
|
||||
}
|
||||
|
||||
@@ -1006,35 +1006,26 @@ class JpqlQueryRendererTests {
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select 1 as value from User u",
|
||||
"select -1 as value from User u",
|
||||
"select +1 as value from User u",
|
||||
"select +1*-100 as value from User u",
|
||||
"select count(u)*-0.7f as value from User u",
|
||||
"select count(oi) + (-100) as perc from StockOrderItem oi",
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20"
|
||||
})
|
||||
@ValueSource(strings = { "select 1 as value from User u", "select -1 as value from User u",
|
||||
"select +1 as value from User u", "select +1*-100 as value from User u",
|
||||
"select count(u)*-0.7f as value from User u", "select count(oi) + (-100) as perc from StockOrderItem oi",
|
||||
"select p from Payment p where length(p.cardNumber) between +16 and -20" })
|
||||
void signedLiteralShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3342
|
||||
@ValueSource(strings = {
|
||||
"select -count(u) from User u",
|
||||
"select +1*(-count(u)) from User u"
|
||||
})
|
||||
@ValueSource(strings = { "select -count(u) from User u", "select +1*(-count(u)) from User u" })
|
||||
void signedExpressionsShouldWork(String query) {
|
||||
assertQuery(query);
|
||||
}
|
||||
|
||||
@ParameterizedTest // GH-3451
|
||||
@MethodSource({"reservedWords"})
|
||||
@MethodSource("reservedWords")
|
||||
void entityNameWithPackageContainingReservedWord(String reservedWord) {
|
||||
|
||||
String source = "select new com.company.%s.thing.stuff.ClassName(e.id) from Experience e".formatted(reservedWord);
|
||||
assertQuery(source);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user