Skip to content

Commit fa9b681

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 a9813a7 commit fa9b681

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
@@ -145,11 +145,10 @@ public DeclaredQuery deriveCountQuery(@Nullable String countQueryProjection) {
145145
for (ParameterBinding binding : bindings) {
146146

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

150-
// replace incompatible bindings
151-
if ( derivedBindings.removeIf(
152-
it -> identifier.test(it) && notCompatible.test(it))) {
150+
// replace incompatible bindings
151+
if (derivedBindings.removeIf(it -> identifier.test(it) && notCompatible.test(it))) {
153152
derivedBindings.add(binding);
154153
}
155154
}
@@ -282,7 +281,7 @@ enum ParameterBindingParser {
282281
INSTANCE;
283282

284283
private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
285-
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
284+
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![\\&\\|#\\w]))";
286285
// .....................................................................^ not followed by a hash or a letter.
287286
// .................................................................^ zero or more digits.
288287
// .............................................................^ start with a question mark.
@@ -366,7 +365,9 @@ String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(String que
366365
Integer parameterIndex = getParameterIndex(parameterIndexString);
367366

368367
String match = matcher.group(0);
369-
if (JDBC_STYLE_PARAM.matcher(match).find()) {
368+
Matcher jdbcStyleMatcher = JDBC_STYLE_PARAM.matcher(match);
369+
370+
if (jdbcStyleMatcher.find()) {
370371
queryMeta.usesJdbcStyleParameters = true;
371372
}
372373

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

@@ -538,7 +553,6 @@ void treatsGreaterThanBindingAsSimpleBinding() {
538553

539554
assertThat(bindings).hasSize(1);
540555
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
541-
542556
}
543557

544558
@Test // DATAJPA-473
@@ -634,6 +648,19 @@ void shouldReplaceExpressionWithLikeParameters() {
634648
.isEqualTo("select a from A a where a.b LIKE :__$synthetic$__1 and a.c LIKE :__$synthetic$__2");
635649
}
636650

651+
@Test // GH-3907
652+
void considersOnlyDedicatedPositionalBindMarkersAsSuch() {
653+
654+
StringQuery query = new StringQuery(
655+
"select '[\"x\", \"c\"]'::jsonb ?| array[?1]::text[] FROM foo WHERE foo BETWEEN ?1 and ?2", true);
656+
657+
assertThat(query.getParameterBindings()).hasSize(2);
658+
659+
query = new StringQuery("select '[\"x\", \"c\"]'::jsonb ?& array[:foo]::text[] FROM foo WHERE foo = :bar", true);
660+
661+
assertThat(query.getParameterBindings()).hasSize(2);
662+
}
663+
637664
@Test // DATAJPA-712, GH-3619
638665
void shouldReplaceAllPositionExpressionParametersWithInClause() {
639666

0 commit comments

Comments
 (0)