Skip to content

Commit 8f49df7

Browse files
committed
spring-projectsGH-2341 - Fix missing DISTINCT in count query bug.
The `COUNT_MATCH` did not consider line breaks after the `from` clause or the `where` clause. This lead 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. Closes spring-projects#2341 Related tickets spring-projects#2177
1 parent bca2adc commit 8f49df7

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
@@ -146,7 +146,7 @@ public abstract class QueryUtils {
146146
builder.append(IDENTIFIER_GROUP);
147147
builder.append("(.*)");
148148

149-
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
149+
COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE | DOTALL);
150150

151151
Map<PersistentAttributeType, Class<? extends Annotation>> persistentAttributeTypes = new HashMap<>();
152152
persistentAttributeTypes.put(ONE_TO_ONE, OneToOne.class);
@@ -482,7 +482,8 @@ public static String createCountQueryFor(String originalQuery, @Nullable String
482482
boolean useVariable = StringUtils.hasText(variable) //
483483
&& !variable.startsWith(" new") //
484484
&& !variable.startsWith("count(") //
485-
&& !variable.contains(","); //
485+
&& !variable.contains(",") //
486+
&& !variable.contains("*");
486487

487488
String complexCountValue = matcher.matches() && StringUtils.hasText(matcher.group(COMPLEX_COUNT_FIRST_INDEX))
488489
? COMPLEX_COUNT_VALUE

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

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

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

@@ -511,6 +516,28 @@ void findProjectionClauseWithIncludedFrom() {
511516
assertThat(QueryUtils.getProjection("select x, frommage, y from t")).isEqualTo("x, frommage, y");
512517
}
513518

519+
@Test // GH-2341
520+
void countProjectionDistrinctQueryIncludesNewLineAfterFromAndBeforeJoin() {
521+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1\nLEFT JOIN Entity2 entity2 ON entity1.key = entity2.key";
522+
523+
assertCountQuery(originalQuery,
524+
"select count(DISTINCT entity1) FROM Entity1 entity1\nLEFT JOIN Entity2 entity2 ON entity1.key = entity2.key");
525+
}
526+
527+
@Test
528+
void countProjectionDistinctQueryIncludesNewLineAfterEntity() {
529+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key";
530+
assertCountQuery(originalQuery,
531+
"select count(DISTINCT entity1) FROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key");
532+
}
533+
534+
@Test
535+
void countProjectionDistinctQueryIncludesNewLineAfterEntityAndBeforeWhere() {
536+
String originalQuery = "SELECT DISTINCT entity1\nFROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key\nwhere entity1.id = 1799";
537+
assertCountQuery(originalQuery,
538+
"select count(DISTINCT entity1) FROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key\nwhere entity1.id = 1799");
539+
}
540+
514541
private static void assertCountQuery(String originalQuery, String countQuery) {
515542
assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery);
516543
}

0 commit comments

Comments
 (0)