Skip to content

Commit 4a51f68

Browse files
committed
Avoid capturing ?& and ?| as bind parameter markers.
We now exclude `?&` and `?|` from being matched as JDBC-style parameter bind marker. Closes #3907
1 parent 03daec8 commit 4a51f68

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,10 @@ public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {
143143
for (ParameterBinding binding : bindings) {
144144

145145
Predicate<ParameterBinding> identifier = binding::bindsTo;
146-
Predicate<ParameterBinding> notCompatible = Predicate.not(binding::isCompatibleWith);
146+
Predicate<ParameterBinding> notCompatible = Predicate.not(binding::isCompatibleWith);
147147

148-
// replace incompatible bindings
149-
if ( derivedBindings.removeIf(
150-
it -> identifier.test(it) && notCompatible.test(it))) {
148+
// replace incompatible bindings
149+
if (derivedBindings.removeIf(it -> identifier.test(it) && notCompatible.test(it))) {
151150
derivedBindings.add(binding);
152151
}
153152
}
@@ -206,7 +205,7 @@ enum ParameterBindingParser {
206205
INSTANCE;
207206

208207
private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
209-
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
208+
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![\\&\\|#\\w]))";
210209
// .....................................................................^ not followed by a hash or a letter.
211210
// .................................................................^ zero or more digits.
212211
// .............................................................^ start with a question mark.
@@ -295,7 +294,9 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
295294
Integer parameterIndex = getParameterIndex(parameterIndexString);
296295

297296
String match = matcher.group(0);
298-
if (JDBC_STYLE_PARAM.matcher(match).find()) {
297+
Matcher jdbcStyleMatcher = JDBC_STYLE_PARAM.matcher(match);
298+
299+
if (jdbcStyleMatcher.find()) {
299300
queryMeta.usesJdbcStyleParameters = true;
300301
}
301302

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

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,21 @@ void rewritesPositionalLikeToUniqueParametersIfNecessary() {
236236
assertThat(bindings).hasSize(3);
237237
}
238238

239+
@Test // GH-3907
240+
void rewritesPositionalLikeToUniqueParametersIfNecessaryUsingPostgresJsonbOperator() {
241+
242+
StringQuery query = new StringQuery(
243+
"select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like %?1 or u.firstname like ?1% or u.firstname = ?1",
244+
true);
245+
246+
assertThat(query.hasParameterBindings()).isTrue();
247+
assertThat(query.getQueryString()).isEqualTo(
248+
"select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like ?1 or u.firstname like ?2 or u.firstname = ?3");
249+
250+
List<ParameterBinding> bindings = query.getParameterBindings();
251+
assertThat(bindings).hasSize(3);
252+
}
253+
239254
@Test // GH-3041
240255
void reusesNamedLikeBindingsWherePossible() {
241256

@@ -494,7 +509,6 @@ void treatsGreaterThanBindingAsSimpleBinding() {
494509

495510
assertThat(bindings).hasSize(1);
496511
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
497-
498512
}
499513

500514
@Test // DATAJPA-473
@@ -590,6 +604,19 @@ void shouldReplaceExpressionWithLikeParameters() {
590604
.isEqualTo("select a from A a where a.b LIKE :__$synthetic$__1 and a.c LIKE :__$synthetic$__2");
591605
}
592606

607+
@Test // GH-3907
608+
void considersOnlyDedicatedPositionalBindMarkersAsSuch() {
609+
610+
StringQuery query = new StringQuery(
611+
"select '[\"x\", \"c\"]'::jsonb ?| array[?1]::text[] FROM foo WHERE foo BETWEEN ?1 and ?2", true);
612+
613+
assertThat(query.getParameterBindings()).hasSize(2);
614+
615+
query = new StringQuery("select '[\"x\", \"c\"]'::jsonb ?& array[:foo]::text[] FROM foo WHERE foo = :bar", true);
616+
617+
assertThat(query.getParameterBindings()).hasSize(2);
618+
}
619+
593620
@Test // DATAJPA-712, GH-3619
594621
void shouldReplaceAllPositionExpressionParametersWithInClause() {
595622

0 commit comments

Comments
 (0)