Drop AS token when creating JPQL count query using DISTINCT.

Fixes: #3269
Original pull request: #3276
This commit is contained in:
Christoph Strobl
2023-12-18 13:04:46 +01:00
committed by Mark Paluch
parent 4162b76470
commit be9c0b5a46
3 changed files with 41 additions and 2 deletions

View File

@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
* An ANTLR {@link org.antlr.v4.runtime.tree.ParseTreeVisitor} that transforms a parsed HQL query.
*
* @author Greg Turnquist
* @author Christoph Strobl
* @since 3.1
*/
class HqlQueryTransformer extends HqlQueryRenderer {
@@ -357,12 +358,14 @@ class HqlQueryTransformer extends HqlQueryRenderer {
if (ctx.DISTINCT() != null) {
if (selectionListTokens.stream().anyMatch(hqlToken -> hqlToken.getToken().contains("new"))) {
List<JpaQueryParsingToken> countSelection = getCountSelection(selectionListTokens);
if (countSelection.stream().anyMatch(hqlToken -> hqlToken.getToken().contains("new"))) {
// constructor
tokens.add(new JpaQueryParsingToken(() -> primaryFromAlias));
} else {
// keep all the select items to distinct against
tokens.addAll(selectionListTokens);
tokens.addAll(countSelection);
}
} else {
tokens.add(new JpaQueryParsingToken(() -> primaryFromAlias));
@@ -394,4 +397,19 @@ class HqlQueryTransformer extends HqlQueryRenderer {
static <T> ArrayList<T> newArrayList() {
return new ArrayList<>();
}
private static List<JpaQueryParsingToken> getCountSelection(List<JpaQueryParsingToken> selectionListTokens) {
List<JpaQueryParsingToken> target = new ArrayList<>(selectionListTokens.size());
for (int i = 0; i < selectionListTokens.size(); i++) {
JpaQueryParsingToken token = selectionListTokens.get(i);
if (token.isA(TOKEN_AS)) {
i++;
continue;
}
target.add(token);
}
selectionListTokens = target;
return selectionListTokens;
}
}

View File

@@ -131,6 +131,15 @@ class JpaQueryParsingToken {
return this.space;
}
boolean isA(JpaQueryParsingToken token) {
return token.getToken().equalsIgnoreCase(this.getToken());
}
@Override
public String toString() {
return getToken();
}
/**
* Switch the last {@link JpaQueryParsingToken}'s spacing to {@literal true}.
*/

View File

@@ -34,6 +34,7 @@ import org.springframework.lang.Nullable;
* Verify that HQL queries are properly transformed through the {@link JpaQueryEnhancer} and the {@link HqlQueryParser}.
*
* @author Greg Turnquist
* @author Christoph Strobl
*/
class HqlQueryTransformerTests {
@@ -1031,6 +1032,17 @@ class HqlQueryTransformerTests {
"SELECT t3 FROM Test3 t3 JOIN t3.test2 x WHERE x.id = :test2Id order by t3.testDuplicateColumnName desc");
}
@Test // GH-3269
void createsCountQueryUsingAliasCorrectly() {
assertCountQuery("select distinct 1 as x from Employee","select count(distinct 1) from Employee AS __");
assertCountQuery("SELECT DISTINCT abc AS x FROM T","SELECT count(DISTINCT abc) FROM T AS __");
assertCountQuery("select distinct a as x, b as y from Employee","select count(distinct a , b) from Employee AS __");
assertCountQuery("select distinct sum(amount) as x from Employee GROUP BY n","select count(distinct sum(amount)) from Employee AS __ GROUP BY n");
assertCountQuery("select distinct a, b, sum(amount) as c, d from Employee GROUP BY n","select count(distinct a, b, sum(amount) , d) from Employee AS __ GROUP BY n");
assertCountQuery("select distinct a, count(b) as c from Employee GROUP BY n","select count(distinct a, count(b)) from Employee AS __ GROUP BY n");
}
private void assertCountQuery(String originalQuery, String countQuery) {
assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery);
}