Skip to content

Commit af4c601

Browse files
committed
Use COALESCE for LIKE with wildcards.
To handle potential NULL values when LIKE is combined with wildcards, insert a COALESCE function. See #3041
1 parent 684ed61 commit af4c601

File tree

3 files changed

+11
-8
lines changed

3 files changed

+11
-8
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ private static String potentiallyWrapWithWildcards(String replacement, String su
362362
concatWrapper.append("'%',");
363363
}
364364

365-
concatWrapper.append(replacement);
365+
concatWrapper.append("COALESCE(" + replacement + ",'')");
366366

367367
if (substring.endsWith("%")) {
368368
concatWrapper.append(",'%'");

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ void customQueryWithNullMatch() {
9999

100100
List<EmployeeWithName> Employees = repository.customQueryWithNullableParam(null);
101101

102-
assertThat(Employees).extracting(EmployeeWithName::getName).isEmpty();
102+
assertThat(Employees).extracting(EmployeeWithName::getName).containsExactlyInAnyOrder("Frodo Baggins",
103+
"Bilbo Baggins");
103104
}
104105

105106
@Test // GH-2939
@@ -133,7 +134,8 @@ void customQueryWithNullMatchInNative() {
133134

134135
List<EmployeeWithName> Employees = repository.customQueryWithNullableParamInNative(null);
135136

136-
assertThat(Employees).extracting(EmployeeWithName::getName).isEmpty();
137+
assertThat(Employees).extracting(EmployeeWithName::getName).containsExactlyInAnyOrder("Frodo Baggins",
138+
"Bilbo Baggins");
137139
}
138140

139141
@Test

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ void detectsPositionalLikeBindings() {
6464
true);
6565

6666
assertThat(query.hasParameterBindings()).isTrue();
67-
assertThat(query.getQueryString())
68-
.isEqualTo("select u from User u where u.firstname like CONCAT('%',?1,'%') or u.lastname like CONCAT('%',?2)");
67+
assertThat(query.getQueryString()).isEqualTo(
68+
"select u from User u where u.firstname like CONCAT('%',COALESCE(?1,''),'%') or u.lastname like CONCAT('%',COALESCE(?2,''))");
6969

7070
List<ParameterBinding> bindings = query.getParameterBindings();
7171
assertThat(bindings).hasSize(2);
@@ -87,7 +87,8 @@ void detectsNamedLikeBindings() {
8787
StringQuery query = new StringQuery("select u from User u where u.firstname like %:firstname", true);
8888

8989
assertThat(query.hasParameterBindings()).isTrue();
90-
assertThat(query.getQueryString()).isEqualTo("select u from User u where u.firstname like CONCAT('%',:firstname)");
90+
assertThat(query.getQueryString())
91+
.isEqualTo("select u from User u where u.firstname like CONCAT('%',COALESCE(:firstname,''))");
9192

9293
List<ParameterBinding> bindings = query.getParameterBindings();
9394
assertThat(bindings).hasSize(1);
@@ -200,8 +201,8 @@ void removesLikeBindingsFromQueryIfQueryContainsSimpleBinding() {
200201
assertNamedBinding(ParameterBinding.class, "word", bindings.get(1));
201202

202203
assertThat(query.getQueryString())
203-
.isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE CONCAT('%',:escapedWord,'%') ESCAPE '~'"
204-
+ " OR a.content LIKE CONCAT('%',:escapedWord,'%') ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC");
204+
.isEqualTo("SELECT a FROM Article a WHERE a.overview LIKE CONCAT('%',COALESCE(:escapedWord,''),'%') ESCAPE '~'"
205+
+ " OR a.content LIKE CONCAT('%',COALESCE(:escapedWord,''),'%') ESCAPE '~' OR a.title = :word ORDER BY a.articleId DESC");
205206
}
206207

207208
@Test // DATAJPA-483

0 commit comments

Comments
 (0)