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);
}