Skip to content

Commit 2545e6d

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 36f559e commit 2545e6d

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

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

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

151-
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
151+
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE | DOTALL);
152152

153153
Map<PersistentAttributeType, Class<? extends Annotation>> persistentAttributeTypes = new HashMap<>();
154154
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

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

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

424+
@Test // GH-2341
425+
void createCountQueryStarCharacterConverted() {
426+
assertThat(createCountQueryFor("select * from User user")).isEqualTo("select count(user) from User user");
427+
}
428+
424429
@Test
425430
void createCountQuerySupportsLineBreaksInSelectClause() {
426431

@@ -522,6 +527,28 @@ void findProjectionClauseWithIncludedFrom() {
522527
assertThat(QueryUtils.getProjection("select x, frommage, y from t")).isEqualTo("x, frommage, y");
523528
}
524529

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

0 commit comments

Comments
 (0)