Skip to content

Commit 3e64d9a

Browse files
DiegoKrupitzagregturn
authored andcommitted
Fix missing DISTINCT in count queries.
The `COUNT_MATCH` does not consider line breaks after the `from` clause or the `where` clause. This leads to a no match scenario in the construction of the count query. With the fix we now consider line breaks/whitespaces after the `from` and `where` clause. See #2341 Related tickets: #2177
1 parent 32f0f54 commit 3e64d9a

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public abstract class QueryUtils {
147147
builder.append(IDENTIFIER_GROUP);
148148
builder.append("(.*)");
149149

150-
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
150+
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE | DOTALL);
151151

152152
Map<PersistentAttributeType, Class<? extends Annotation>> persistentAttributeTypes = new HashMap<>();
153153
persistentAttributeTypes.put(ONE_TO_ONE, OneToOne.class);
@@ -490,7 +490,8 @@ public static String createCountQueryFor(String originalQuery, @Nullable String
490490
boolean useVariable = StringUtils.hasText(variable) //
491491
&& !variable.startsWith(" new") //
492492
&& !variable.startsWith("count(") //
493-
&& !variable.contains(","); //
493+
&& !variable.contains(",") //
494+
&& !variable.contains("*");
494495

495496
String complexCountValue = matcher.matches() && StringUtils.hasText(matcher.group(COMPLEX_COUNT_FIRST_INDEX))
496497
? COMPLEX_COUNT_VALUE

src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java

+27
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,11 @@ void createCountQuerySupportsWhitespaceCharacters() {
423423
" where user.age = 18\n ");
424424
}
425425

426+
@Test // GH-2341
427+
void createCountQueryStarCharacterConverted() {
428+
assertThat(createCountQueryFor("select * from User user")).isEqualTo("select count(user) from User user");
429+
}
430+
426431
@Test
427432
void createCountQuerySupportsLineBreaksInSelectClause() {
428433

@@ -524,6 +529,28 @@ void findProjectionClauseWithIncludedFrom() {
524529
assertThat(QueryUtils.getProjection("select x, frommage, y from t")).isEqualTo("x, frommage, y");
525530
}
526531

532+
@Test // GH-2341
533+
void countProjectionDistrinctQueryIncludesNewLineAfterFromAndBeforeJoin() {
534+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1\nLEFT JOIN Entity2 entity2 ON entity1.key = entity2.key";
535+
536+
assertCountQuery(originalQuery,
537+
"select count(DISTINCT entity1) FROM Entity1 entity1\nLEFT JOIN Entity2 entity2 ON entity1.key = entity2.key");
538+
}
539+
540+
@Test // GH-2341
541+
void countProjectionDistinctQueryIncludesNewLineAfterEntity() {
542+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key";
543+
assertCountQuery(originalQuery,
544+
"select count(DISTINCT entity1) FROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key");
545+
}
546+
547+
@Test // GH-2341
548+
void countProjectionDistinctQueryIncludesNewLineAfterEntityAndBeforeWhere() {
549+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key\nwhere entity1.id = 1799";
550+
assertCountQuery(originalQuery,
551+
"select count(DISTINCT entity1) FROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key\nwhere entity1.id = 1799");
552+
}
553+
527554
private static void assertCountQuery(String originalQuery, String countQuery) {
528555
assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery);
529556
}

0 commit comments

Comments
 (0)