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 1cad9074fd
commit b37a334549
2 changed files with 33 additions and 3 deletions

View File

@@ -176,7 +176,7 @@ public final class PreprocessedQuery 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.
@@ -264,7 +264,9 @@ public final class PreprocessedQuery 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()) {
jdbcStyle = true;
}

View File

@@ -236,6 +236,21 @@ class DefaultEntityQueryUnitTests {
assertThat(bindings).hasSize(3);
}
@Test // GH-3907
void rewritesPositionalLikeToUniqueParametersIfNecessaryUsingPostgresJsonbOperator() {
DefaultEntityQuery query = new TestEntityQuery(
"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() {
@@ -539,7 +554,6 @@ class DefaultEntityQueryUnitTests {
assertThat(bindings).hasSize(1);
assertPositionalBinding(ParameterBinding.class, 1, bindings.get(0));
}
@Test // DATAJPA-473
@@ -638,6 +652,20 @@ class DefaultEntityQueryUnitTests {
.isEqualTo("select a from A a where a.b LIKE :__$synthetic$__1 and a.c LIKE :__$synthetic$__2");
}
@Test // GH-3907
void considersOnlyDedicatedPositionalBindMarkersAsSuch() {
DefaultEntityQuery query = new TestEntityQuery(
"select '[\"x\", \"c\"]'::jsonb ?| array[?1]::text[] FROM foo WHERE foo BETWEEN ?1 and ?2", true);
assertThat(query.getParameterBindings()).hasSize(2);
query = new TestEntityQuery("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() {