diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 index 46748477a..3ed025efb 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Eql.g4 @@ -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 */ diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java index 22a10faee..f3ecafe01 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/EqlQueryRenderer.java @@ -2331,7 +2331,7 @@ class EqlQueryRenderer extends EqlBaseVisitor> { List 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 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> { return List.of(); } } + + @Override + public List 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(); + } + } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java index 326b53f6c..055940e9e 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/EqlQueryRendererTests.java @@ -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 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); + } } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java index a4451f84c..2bcf467e1 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryRendererTests.java @@ -61,7 +61,7 @@ class HqlQueryRendererTests { return render(new HqlQueryRenderer().visit(parsedQuery)); } - public static Stream reservedWords() { + static Stream 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); diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java index 6085e991f..2f20fe70f 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryRendererTests.java @@ -60,7 +60,7 @@ class JpqlQueryRendererTests { return render(new JpqlQueryRenderer().visit(parsedQuery)); } - public static Stream reservedWords() { + static Stream 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); } - }