Recognize RIGHT, LEFT, OUTER, INNER and FULL as JPQL/HQL reserved words.

RIGHT, LEFT, OUTER, INNER, and FULL are HQL tokens. This means they also need to be recognized as potential reserved words and thus possibly identifiers. This can show up if someone, for example, uses "right" as the name of a relationship in a JPA entity.

Resolves #2864.
Original pull request: #2874.
This commit is contained in:
Greg L. Turnquist
2023-03-20 16:14:56 -05:00
committed by Mark Paluch
parent 0ac0ee4b7d
commit 9c4273cf34
4 changed files with 84 additions and 5 deletions

View File

@@ -692,7 +692,7 @@ reservedWord
| FOR
| FORMAT
| FROM
// | FULL
| FULL
| FUNCTION
| GROUP
| GROUPS
@@ -704,7 +704,7 @@ reservedWord
| IN
| INDEX
| INDICES
// | INNER
| INNER
| INSERT
| INSTANT
| INTERSECT
@@ -714,7 +714,7 @@ reservedWord
| KEY
| LAST
| LEADING
// | LEFT
| LEFT
| LIKE
| LIMIT
| LIST
@@ -752,7 +752,7 @@ reservedWord
| OR
| ORDER
| OTHERS
// | OUTER
| OUTER
| OVER
| OVERFLOW
| OVERLAY
@@ -765,7 +765,7 @@ reservedWord
| QUARTER
| RANGE
| RESPECT
// | RIGHT
| RIGHT
| ROLLUP
| ROW
| ROWS

View File

@@ -599,6 +599,9 @@ 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
| LEFT
| INNER
| OUTER
;
constructor_name

View File

@@ -18,9 +18,13 @@ package org.springframework.data.jpa.repository.query;
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,30 @@ class HqlQueryTransformerTests {
"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));
}
@Test // GH-2508
void detectAliasWithCastCorrectly() {
@@ -819,6 +847,16 @@ class HqlQueryTransformerTests {
.isEqualTo("u");
}
static Stream<Arguments> 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);
}

View File

@@ -18,9 +18,13 @@ package org.springframework.data.jpa.repository.query;
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 @@ class JpqlQueryTransformerTests {
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<Arguments> 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);
}