Use primary table alias for SQL count query derivation with DISTINCT queries.

We now use render COUNT(DISTINCT a.*) where 'a' is the primary table alias instead of COUNT(DISTINCT *).

Closes #3707
This commit is contained in:
Mark Paluch
2024-12-10 15:17:37 +01:00
parent 3cc84e85f0
commit 9f7c591963
2 changed files with 28 additions and 6 deletions

View File

@@ -58,6 +58,7 @@ import org.springframework.util.StringUtils;
* @author Geoffrey Deremetz
* @author Yanming Zhou
* @author Christoph Strobl
* @author Mark Paluch
* @since 2.7.0
*/
public class JSqlParserQueryEnhancer implements QueryEnhancer {
@@ -119,7 +120,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
Select selectStatement = parseSelectStatement(queryString);
if (selectStatement instanceof SetOperationList setOperationList) {
if (selectStatement instanceof SetOperationList setOperationList) {
return applySortingToSetOperationList(setOperationList, sort);
}
@@ -217,7 +218,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
}
Select selectStatement = (Select) statement;
if (selectStatement instanceof PlainSelect selectBody) {
if (selectStatement instanceof PlainSelect selectBody) {
return getJoinAliases(selectBody);
}
@@ -315,7 +316,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
* ValuesStatement has no alias
* SetOperation can have multiple alias for each operation item
*/
if (!(selectStatement instanceof PlainSelect selectBody)) {
if (!(selectStatement instanceof PlainSelect selectBody)) {
return null;
}
@@ -370,7 +371,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
/*
We only support count queries for {@link PlainSelect}.
*/
if (!(selectStatement instanceof PlainSelect selectBody)) {
if (!(selectStatement instanceof PlainSelect selectBody)) {
return this.query.getQueryString();
}
@@ -413,7 +414,7 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
Select selectBody = selectStatement;
if (selectStatement instanceof SetOperationList setOperationList) {
if (selectStatement instanceof SetOperationList setOperationList) {
// using the first one since for setoperations the projection has to be the same
selectBody = setOperationList.getSelects().get(0);
@@ -491,7 +492,12 @@ public class JSqlParserQueryEnhancer implements QueryEnhancer {
return column.getFullyQualifiedName();
}
return query.isNativeQuery() ? (distinct ? "*" : "1") : tableAlias == null ? "*" : tableAlias;
// TODO: We should not handle JPQL here...
if (!query.isNativeQuery()) {
return tableAlias == null ? "*" : tableAlias;
}
return distinct ? ((tableAlias != null ? tableAlias + "." : "") + "*") : "1";
}
@Override

View File

@@ -51,6 +51,22 @@ public class JSqlParserQueryEnhancerUnitTests extends QueryEnhancerTckTests {
assertThat(sql).isEqualTo("SELECT e FROM Employee e ORDER BY e.foo ASC, e.bar ASC");
}
@Test // GH-3707
void countQueriesShouldConsiderPrimaryTableAlias() {
QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("""
SELECT DISTINCT a.*, b.b1
FROM TableA a
JOIN TableB b ON a.b = b.b
LEFT JOIN TableC c ON b.c = c.c
ORDER BY b.b1, a.a1, a.a2
""", true));
String sql = enhancer.createCountQueryFor();
assertThat(sql).startsWith("SELECT count(DISTINCT a.*) FROM TableA a");
}
@Override
@ParameterizedTest // GH-2773
@MethodSource("jpqlCountQueries")