Skip to content

Commit 0559c38

Browse files
committed
Correctly validate mixed parameter bind marker usage.
We now inspect individual parameters instead of the resulting query whether the query contains JDBC-style bind markers. Previously, we inspected the final (rewritten) query which might have contained question marks in literals leading to improper validation failures. Closes #3125
1 parent a9279c7 commit 0559c38

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

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

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.springframework.data.jpa.repository.query;
1717

18+
import static java.util.regex.Pattern.*;
19+
1820
import java.util.ArrayList;
1921
import java.util.Collection;
2022
import java.util.List;
@@ -39,8 +41,6 @@
3941
import org.springframework.util.ObjectUtils;
4042
import org.springframework.util.StringUtils;
4143

42-
import static java.util.regex.Pattern.*;
43-
4444
/**
4545
* Encapsulation of a JPA query String. Offers access to parameters as bindings. The internal query String is cleaned
4646
* from decorated parameters like {@literal %:lastname%} and the matching bindings take care of applying the decorations
@@ -244,13 +244,6 @@ private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(St
244244
int currentIndex = 0;
245245

246246
boolean usesJpaStyleParameters = false;
247-
if (JDBC_STYLE_PARAM.matcher(resultingQuery).find()) {
248-
queryMeta.usesJdbcStyleParameters = true;
249-
}
250-
251-
if (NUMBERED_STYLE_PARAM.matcher(resultingQuery).find() || NAMED_STYLE_PARAM.matcher(resultingQuery).find()) {
252-
usesJpaStyleParameters = true;
253-
}
254247

255248
while (matcher.find()) {
256249

@@ -262,6 +255,19 @@ private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(St
262255
String parameterName = parameterIndexString != null ? null : matcher.group(NAMED_PARAMETER_GROUP);
263256
Integer parameterIndex = getParameterIndex(parameterIndexString);
264257

258+
String match = matcher.group(0);
259+
if (JDBC_STYLE_PARAM.matcher(match).find()) {
260+
queryMeta.usesJdbcStyleParameters = true;
261+
}
262+
263+
if (NUMBERED_STYLE_PARAM.matcher(match).find() || NAMED_STYLE_PARAM.matcher(match).find()) {
264+
usesJpaStyleParameters = true;
265+
}
266+
267+
if (usesJpaStyleParameters && queryMeta.usesJdbcStyleParameters) {
268+
throw new IllegalArgumentException("Mixing of ? parameters and other forms like ?1 is not supported");
269+
}
270+
265271
String typeSource = matcher.group(COMPARISION_TYPE_GROUP);
266272
Assert.isTrue(parameterIndexString != null || parameterName != null,
267273
() -> String.format("We need either a name or an index; Offending query string: %s", query));
@@ -273,9 +279,6 @@ private String parseParameterBindingsOfQueryIntoBindingsAndReturnCleanedQuery(St
273279
parameterIndex = expressionParameterIndex;
274280
}
275281

276-
if (usesJpaStyleParameters && queryMeta.usesJdbcStyleParameters) {
277-
throw new IllegalArgumentException("Mixing of ? parameters and other forms like ?1 is not supported");
278-
}
279282

280283
BindingIdentifier queryParameter;
281284
if (parameterIndex != null) {

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ void questionMarkInStringLiteral() {
656656
softly.assertThat(query.getQueryString()).isEqualTo(queryString);
657657
softly.assertThat(query.hasParameterBindings()).isFalse();
658658
softly.assertThat(query.getParameterBindings()).hasSize(0);
659+
softly.assertThat(query.usesJdbcStyleParameters()).isFalse();
659660

660661
softly.assertAll();
661662
}
@@ -697,6 +698,20 @@ void isNotDefaultProjection() {
697698
softly.assertAll();
698699
}
699700

701+
@Test // GH-3125
702+
void questionMarkInStringLiteralWithParameters() {
703+
704+
String queryString = "SELECT CAST(REGEXP_SUBSTR(itp.template_as_txt, '(?<=templateId\\\\\\\\=)(\\\\\\\\d+)(?:\\\\\\\\R)') AS INT) AS templateId FROM foo itp WHERE bar = ?1 AND baz = 1";
705+
StringQuery query = new StringQuery(queryString, false);
706+
707+
softly.assertThat(query.getQueryString()).isEqualTo(queryString);
708+
softly.assertThat(query.hasParameterBindings()).isTrue();
709+
softly.assertThat(query.getParameterBindings()).hasSize(1);
710+
softly.assertThat(query.usesJdbcStyleParameters()).isFalse();
711+
712+
softly.assertAll();
713+
}
714+
700715
@Test // DATAJPA-1652
701716
void usingPipesWithNamedParameter() {
702717

0 commit comments

Comments
 (0)