Skip to content

Commit 9f7c591

Browse files
committed
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
1 parent 3cc84e8 commit 9f7c591

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancer.java

+12-6
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
* @author Geoffrey Deremetz
5959
* @author Yanming Zhou
6060
* @author Christoph Strobl
61+
* @author Mark Paluch
6162
* @since 2.7.0
6263
*/
6364
public class JSqlParserQueryEnhancer implements QueryEnhancer {
@@ -119,7 +120,7 @@ public String applySorting(Sort sort, @Nullable String alias) {
119120

120121
Select selectStatement = parseSelectStatement(queryString);
121122

122-
if (selectStatement instanceof SetOperationList setOperationList) {
123+
if (selectStatement instanceof SetOperationList setOperationList) {
123124
return applySortingToSetOperationList(setOperationList, sort);
124125
}
125126

@@ -217,7 +218,7 @@ private Set<String> getJoinAliases(String query) {
217218
}
218219

219220
Select selectStatement = (Select) statement;
220-
if (selectStatement instanceof PlainSelect selectBody) {
221+
if (selectStatement instanceof PlainSelect selectBody) {
221222
return getJoinAliases(selectBody);
222223
}
223224

@@ -315,7 +316,7 @@ private String detectAlias(String query) {
315316
* ValuesStatement has no alias
316317
* SetOperation can have multiple alias for each operation item
317318
*/
318-
if (!(selectStatement instanceof PlainSelect selectBody)) {
319+
if (!(selectStatement instanceof PlainSelect selectBody)) {
319320
return null;
320321
}
321322

@@ -370,7 +371,7 @@ public String createCountQueryFor(@Nullable String countProjection) {
370371
/*
371372
We only support count queries for {@link PlainSelect}.
372373
*/
373-
if (!(selectStatement instanceof PlainSelect selectBody)) {
374+
if (!(selectStatement instanceof PlainSelect selectBody)) {
374375
return this.query.getQueryString();
375376
}
376377

@@ -413,7 +414,7 @@ public String getProjection() {
413414

414415
Select selectBody = selectStatement;
415416

416-
if (selectStatement instanceof SetOperationList setOperationList) {
417+
if (selectStatement instanceof SetOperationList setOperationList) {
417418

418419
// using the first one since for setoperations the projection has to be the same
419420
selectBody = setOperationList.getSelects().get(0);
@@ -491,7 +492,12 @@ private String countPropertyNameForSelection(List<SelectItem<?>> selectItems, bo
491492
return column.getFullyQualifiedName();
492493
}
493494

494-
return query.isNativeQuery() ? (distinct ? "*" : "1") : tableAlias == null ? "*" : tableAlias;
495+
// TODO: We should not handle JPQL here...
496+
if (!query.isNativeQuery()) {
497+
return tableAlias == null ? "*" : tableAlias;
498+
}
499+
500+
return distinct ? ((tableAlias != null ? tableAlias + "." : "") + "*") : "1";
495501
}
496502

497503
@Override

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JSqlParserQueryEnhancerUnitTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,22 @@ void shouldApplySorting() {
5151
assertThat(sql).isEqualTo("SELECT e FROM Employee e ORDER BY e.foo ASC, e.bar ASC");
5252
}
5353

54+
@Test // GH-3707
55+
void countQueriesShouldConsiderPrimaryTableAlias() {
56+
57+
QueryEnhancer enhancer = createQueryEnhancer(DeclaredQuery.of("""
58+
SELECT DISTINCT a.*, b.b1
59+
FROM TableA a
60+
JOIN TableB b ON a.b = b.b
61+
LEFT JOIN TableC c ON b.c = c.c
62+
ORDER BY b.b1, a.a1, a.a2
63+
""", true));
64+
65+
String sql = enhancer.createCountQueryFor();
66+
67+
assertThat(sql).startsWith("SELECT count(DISTINCT a.*) FROM TableA a");
68+
}
69+
5470
@Override
5571
@ParameterizedTest // GH-2773
5672
@MethodSource("jpqlCountQueries")

0 commit comments

Comments
 (0)