From 94e84cc8c498aa25bce249087fadb99cfc5d0dbd Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Thu, 14 Apr 2022 09:03:12 -0500 Subject: [PATCH] Allow count queries to start with whitespace. See #2393. --- .../data/jpa/repository/query/QueryUtils.java | 14 ++++++++++---- .../jpa/repository/query/QueryUtilsUnitTests.java | 10 ++++++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java index eba4466bb..da041122d 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java @@ -110,7 +110,8 @@ public abstract class QueryUtils { private static final String EQUALS_CONDITION_STRING = "%s.%s = :%s"; private static final Pattern ORDER_BY = Pattern.compile("(order\\s+by\\s+)", CASE_INSENSITIVE); - private static final Pattern ORDER_BY_IN_WINDOW_OR_SUBSELECT = Pattern.compile("(\\(\\s*[a-z0-9 ,.*]*order\\s+by\\s+[a-z0-9 ,.]*\\s*\\))", CASE_INSENSITIVE); + private static final Pattern ORDER_BY_IN_WINDOW_OR_SUBSELECT = Pattern + .compile("(\\(\\s*[a-z0-9 ,.*]*order\\s+by\\s+[a-z0-9 ,.]*\\s*\\))", CASE_INSENSITIVE); private static final Pattern NAMED_PARAMETER = Pattern.compile(COLON_NO_DOUBLE_COLON + IDENTIFIER + "|#" + IDENTIFIER, CASE_INSENSITIVE); @@ -144,6 +145,7 @@ public abstract class QueryUtils { ALIAS_MATCH = compile(builder.toString(), CASE_INSENSITIVE); builder = new StringBuilder(); + builder.append("\\s*"); builder.append("(select\\s+((distinct)?((?s).+?)?)\\s+)?(from\\s+"); builder.append(IDENTIFIER); builder.append("(?:\\s+as)?\\s+)"); @@ -279,8 +281,8 @@ public abstract class QueryUtils { } /** - * Returns {@code true} if the query has {@code order by} clause. - * The query has {@code order by} clause if there is an {@code order by} which is not part of window clause. + * Returns {@code true} if the query has {@code order by} clause. The query has {@code order by} clause if there is an + * {@code order by} which is not part of window clause. * * @param query the analysed query string * @return {@code true} if the query has {@code order by} clause, {@code false} otherwise @@ -297,9 +299,13 @@ public abstract class QueryUtils { * @return the number of occurences of the pattern in the string */ private static int countOccurences(Pattern pattern, String string) { + Matcher matcher = pattern.matcher(string); + int occurences = 0; - while (matcher.find()) occurences++; + while (matcher.find()) { + occurences++; + } return occurences; } diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java index f9b48335b..9a3e86965 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/QueryUtilsUnitTests.java @@ -550,6 +550,16 @@ class QueryUtilsUnitTests { "select count(DISTINCT entity1) FROM Entity1 entity1 LEFT JOIN Entity2 entity2 ON entity1.key = entity2.key\nwhere entity1.id = 1799"); } + @Test // GH-2393 + void createCountQueryStartsWithWhitespace() { + + assertThat(createCountQueryFor(" \nselect * from User u where u.age > :age")) + .isEqualTo("select count(u) from User u where u.age > :age"); + + assertThat(createCountQueryFor(" \nselect u from User u where u.age > :age")) + .isEqualTo("select count(u) from User u where u.age > :age"); + } + private static void assertCountQuery(String originalQuery, String countQuery) { assertThat(createCountQueryFor(originalQuery)).isEqualTo(countQuery); }