Avoid capturing ?& and ?| as bind parameter markers.

We now exclude  `?&` and `?|` from being matched as JDBC-style parameter bind marker.

Closes #3907
This commit is contained in:
Mark Paluch
2025-06-03 16:53:04 +02:00
parent 03daec854b
commit 4a51f68876
2 changed files with 35 additions and 7 deletions

View File

@@ -143,11 +143,10 @@ class StringQuery implements DeclaredQuery {
for (ParameterBinding binding : bindings) {
Predicate<ParameterBinding> identifier = binding::bindsTo;
Predicate<ParameterBinding> notCompatible = Predicate.not(binding::isCompatibleWith);
Predicate<ParameterBinding> notCompatible = Predicate.not(binding::isCompatibleWith);
// replace incompatible bindings
if ( derivedBindings.removeIf(
it -> identifier.test(it) && notCompatible.test(it))) {
// replace incompatible bindings
if (derivedBindings.removeIf(it -> identifier.test(it) && notCompatible.test(it))) {
derivedBindings.add(binding);
}
}
@@ -206,7 +205,7 @@ class StringQuery implements DeclaredQuery {
INSTANCE;
private static final String EXPRESSION_PARAMETER_PREFIX = "__$synthetic$__";
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![#\\w]))";
public static final String POSITIONAL_OR_INDEXED_PARAMETER = "\\?(\\d*+(?![\\&\\|#\\w]))";
// .....................................................................^ not followed by a hash or a letter.
// .................................................................^ zero or more digits.
// .............................................................^ start with a question mark.
@@ -295,7 +294,9 @@ class StringQuery implements DeclaredQuery {
Integer parameterIndex = getParameterIndex(parameterIndexString);
String match = matcher.group(0);
if (JDBC_STYLE_PARAM.matcher(match).find()) {
Matcher jdbcStyleMatcher = JDBC_STYLE_PARAM.matcher(match);
if (jdbcStyleMatcher.find()) {
queryMeta.usesJdbcStyleParameters = true;
}

View File

@@ -236,6 +236,21 @@ class StringQueryUnitTests {
assertThat(bindings).hasSize(3);
}
@Test // GH-3907
void rewritesPositionalLikeToUniqueParametersIfNecessaryUsingPostgresJsonbOperator() {
StringQuery query = new StringQuery(
"select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like %?1 or u.firstname like ?1% or u.firstname = ?1",
true);
assertThat(query.hasParameterBindings()).isTrue();
assertThat(query.getQueryString()).isEqualTo(
"select '[\"x\", \"c\"]'::jsonb ?| '[\"x\", \"c\"]'::jsonb from User u where u.firstname like ?1 or u.firstname like ?2 or u.firstname = ?3");
List<ParameterBinding> bindings = query.getParameterBindings();
assertThat(bindings).hasSize(3);
}
@Test // GH-3041
void reusesNamedLikeBindingsWherePossible() {
@@ -494,7 +509,6 @@ class StringQueryUnitTests {
assertThat(bindings).hasSize(1);
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
}
@Test // DATAJPA-473
@@ -590,6 +604,19 @@ class StringQueryUnitTests {
.isEqualTo("select a from A a where a.b LIKE :__$synthetic$__1 and a.c LIKE :__$synthetic$__2");
}
@Test // GH-3907
void considersOnlyDedicatedPositionalBindMarkersAsSuch() {
StringQuery query = new StringQuery(
"select '[\"x\", \"c\"]'::jsonb ?| array[?1]::text[] FROM foo WHERE foo BETWEEN ?1 and ?2", true);
assertThat(query.getParameterBindings()).hasSize(2);
query = new StringQuery("select '[\"x\", \"c\"]'::jsonb ?& array[:foo]::text[] FROM foo WHERE foo = :bar", true);
assertThat(query.getParameterBindings()).hasSize(2);
}
@Test // DATAJPA-712, GH-3619
void shouldReplaceAllPositionExpressionParametersWithInClause() {