Suppress selection item aliasing for the actual count query.

We now no longer apply count selection filtering but rather skip select field aliasing when rendering a count query to drop the field alias within a count query.

Previously, we removed field aliasing by filtering the token stream which also removed the AS keyword from cast operators.

Closes: #3536
Original Pull Request: #3553
This commit is contained in:
Mark Paluch
2024-08-01 09:50:01 +02:00
committed by Christoph Strobl
parent d7316f4b44
commit 78ea533292
2 changed files with 34 additions and 6 deletions

View File

@@ -23,6 +23,7 @@ import java.util.List;
import org.antlr.v4.runtime.ParserRuleContext;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.HqlParser.SelectionContext;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -331,6 +332,17 @@ class HqlQueryTransformer extends HqlQueryRenderer {
return tokens;
}
@Override
public List<JpaQueryParsingToken> visitSelection(SelectionContext ctx) {
if(!countQuery || isSubquery(ctx)) {
return super.visitSelection(ctx);
}
// do not append variables to skip AS field aliasing
return visit(ctx.selectExpression());
}
@Override
public List<JpaQueryParsingToken> visitSelectClause(HqlParser.SelectClauseContext ctx) {
@@ -339,6 +351,7 @@ class HqlQueryTransformer extends HqlQueryRenderer {
tokens.add(new JpaQueryParsingToken(ctx.SELECT()));
if (countQuery && !isSubquery(ctx)) {
tokens.add(TOKEN_COUNT_FUNC);
if (countProjection != null) {
@@ -358,14 +371,12 @@ class HqlQueryTransformer extends HqlQueryRenderer {
if (ctx.DISTINCT() != null) {
List<JpaQueryParsingToken> countSelection = QueryTransformers.filterCountSelection(selectionListTokens);
if (countSelection.stream().anyMatch(hqlToken -> hqlToken.getToken().contains("new"))) {
if (selectionListTokens.stream().anyMatch(hqlToken -> hqlToken.getToken().contains("new"))) {
// constructor
tokens.add(new JpaQueryParsingToken(() -> primaryFromAlias));
} else {
// keep all the select items to distinct against
tokens.addAll(countSelection);
tokens.addAll(selectionListTokens);
}
} else {
tokens.add(new JpaQueryParsingToken(() -> primaryFromAlias));

View File

@@ -85,6 +85,23 @@ class HqlQueryTransformerTests {
assertThat(results).isEqualTo("select count(e) FROM Employee e where e.name = :name");
}
@Test // GH-3536
void shouldCreateCountQueryForDistinctCount() {
// given
var original = """
select distinct cast(e.timestampField as date) as foo
from ExampleEntity e
order by cast(e.timestampField as date) desc
""";
// when
var results = createCountQueryFor(original);
// then
assertThat(results).isEqualTo("select count(distinct cast(e.timestampField as date)) from ExampleEntity e");
}
@Test
void applyCountToMoreComplexQuery() {
@@ -1037,9 +1054,9 @@ class HqlQueryTransformerTests {
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 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, 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");
}