diff --git a/pom.xml b/pom.xml index c77686453f..00dcb23f86 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.springframework.data spring-data-jpa-parent - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT pom Spring Data JPA Parent diff --git a/spring-data-envers/pom.xml b/spring-data-envers/pom.xml index db915d7c3b..ea3bdb0629 100755 --- a/spring-data-envers/pom.xml +++ b/spring-data-envers/pom.xml @@ -5,12 +5,12 @@ org.springframework.data spring-data-envers - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT org.springframework.data spring-data-jpa-parent - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa-distribution/pom.xml b/spring-data-jpa-distribution/pom.xml index a5cb2f09b5..46f8ea3d24 100644 --- a/spring-data-jpa-distribution/pom.xml +++ b/spring-data-jpa-distribution/pom.xml @@ -14,7 +14,7 @@ org.springframework.data spring-data-jpa-parent - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/pom.xml b/spring-data-jpa/pom.xml index 27313e9e3c..e5a4e12ddc 100644 --- a/spring-data-jpa/pom.xml +++ b/spring-data-jpa/pom.xml @@ -6,7 +6,7 @@ org.springframework.data spring-data-jpa - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT Spring Data JPA Spring Data module for JPA repositories. @@ -15,7 +15,7 @@ org.springframework.data spring-data-jpa-parent - 3.1.0-SNAPSHOT + 3.1.0-gh-2864-SNAPSHOT ../pom.xml diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 index 253caafc11..b07504c316 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Hql.g4 @@ -700,7 +700,7 @@ reservedWord | FOR | FORMAT | FROM -// | FULL + | FULL | FUNCTION | GROUP | GROUPS @@ -712,7 +712,7 @@ reservedWord | IN | INDEX | INDICES -// | INNER + | INNER | INSERT | INSTANT | INTERSECT @@ -722,7 +722,7 @@ reservedWord | KEY | LAST | LEADING -// | LEFT + | LEFT | LIKE | LIMIT | LIST @@ -760,7 +760,7 @@ reservedWord | OR | ORDER | OTHERS -// | OUTER + | OUTER | OVER | OVERFLOW | OVERLAY @@ -773,7 +773,7 @@ reservedWord | QUARTER | RANGE | RESPECT -// | RIGHT + | RIGHT | ROLLUP | ROW | ROWS diff --git a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 index dc96a6ea46..fb12b38efa 100644 --- a/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 +++ b/spring-data-jpa/src/main/antlr4/org/springframework/data/jpa/repository/query/Jpql.g4 @@ -596,9 +596,12 @@ trim_character identification_variable : IDENTIFICATION_VARIABLE - | ORDER // Gap in the spec requires supporting 'Order' as an entity name - | COUNT // Gap in the spec requires supporting 'count' as a possible name - | KEY // Gap in the sepc requires supported 'key' as a possible name + | ORDER + | COUNT + | KEY + | LEFT + | INNER + | OUTER | spel_expression // we use various SpEL expressions in our queries ; diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java index cae0d71d31..defb5aafd2 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HqlQueryTransformerTests.java @@ -18,9 +18,13 @@ import static org.assertj.core.api.Assertions.*; import java.util.regex.Pattern; +import java.util.stream.Stream; import org.assertj.core.api.SoftAssertions; 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.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.JpaSort; @@ -808,6 +812,40 @@ void countQueryShouldWorkEvenWithoutExplicitAlias() { "select count(b) FROM BookError b WHERE portal = :portal"); } + @ParameterizedTest + @MethodSource("queriesWithReservedWordsAsIdentifiers") // GH-2864 + void usingReservedWordAsRelationshipNameShouldWork(String relationshipName, String joinAlias) { + + HqlQueryParser.parseQuery(String.format(""" + select u + from UserAccountEntity u + join fetch u.lossInspectorLimitConfiguration lil + join fetch u.companyTeam ct + where exists ( + select iu + from UserAccountEntity iu + join iu.roles u2r + join u2r.role r + join r.rights r2r + join r2r.%s %s + where + %s.code = :rightCode + and iu = u + ) + and ct.id = :teamId + """, relationshipName, joinAlias, joinAlias)); + } + + static Stream queriesWithReservedWordsAsIdentifiers() { + + return Stream.of( // + Arguments.of("right", "rt"), // + Arguments.of("left", "lt"), // + Arguments.of("outer", "ou"), // + Arguments.of("full", "full"), // + Arguments.of("inner", "inr")); + } + private void assertCountQuery(String originalQuery, String countQuery) { assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery); } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java index d63cbd26d8..8ebcfa83e0 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpqlQueryTransformerTests.java @@ -18,9 +18,13 @@ import static org.assertj.core.api.Assertions.*; import java.util.regex.Pattern; +import java.util.stream.Stream; import org.assertj.core.api.SoftAssertions; 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.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.JpaSort; @@ -679,6 +683,40 @@ void queryParserPicksCorrectAliasAmidstMultipleAlises() { assertThat(alias("select u from User as u left join u.roles as r")).isEqualTo("u"); } + @ParameterizedTest + @MethodSource("queriesWithReservedWordsAsIdentifiers") // GH-2864 + void usingReservedWordAsRelationshipNameShouldWork(String relationshipName, String joinAlias) { + + JpqlQueryParser.parseQuery(String.format(""" + select u + from UserAccountEntity u + join u.lossInspectorLimitConfiguration lil + join u.companyTeam ct + where exists ( + select iu + from UserAccountEntity iu + join iu.roles u2r + join u2r.role r + join r.rights r2r + join r2r.inner inr + where + inr.code = :rightCode + and iu = u + ) + and ct.id = :teamId + """, relationshipName, joinAlias, joinAlias)); + } + + static Stream queriesWithReservedWordsAsIdentifiers() { + + return Stream.of( // + Arguments.of("right", "rt"), // + Arguments.of("left", "lt"), // + Arguments.of("outer", "ou"), // + Arguments.of("full", "full"), // + Arguments.of("inner", "inr")); + } + private void assertCountQuery(String originalQuery, String countQuery) { assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery); }