Preserve square brackets for index/key expressions
Closes gh-27925
This commit is contained in:
parent
327eec09ae
commit
d4fac82d68
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -55,7 +55,7 @@ public abstract class NamedParameterUtils {
|
|||
* Set of characters that qualify as parameter separators,
|
||||
* indicating that a parameter name in an SQL String has ended.
|
||||
*/
|
||||
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^[]";
|
||||
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
|
||||
|
||||
/**
|
||||
* An index with separator flags per character code.
|
||||
|
|
@ -78,9 +78,9 @@ public abstract class NamedParameterUtils {
|
|||
* Parse the SQL statement and locate any placeholders or named parameters.
|
||||
* Named parameters are substituted for a JDBC placeholder.
|
||||
* @param sql the SQL statement
|
||||
* @return the parsed statement, represented as ParsedSql instance
|
||||
* @return the parsed statement, represented as {@link ParsedSql} instance
|
||||
*/
|
||||
public static ParsedSql parseSqlStatement(final String sql) {
|
||||
public static ParsedSql parseSqlStatement(String sql) {
|
||||
Assert.notNull(sql, "SQL must not be null");
|
||||
|
||||
Set<String> namedParameters = new HashSet<>();
|
||||
|
|
@ -122,17 +122,20 @@ public abstract class NamedParameterUtils {
|
|||
while (statement[j] != '}') {
|
||||
j++;
|
||||
if (j >= statement.length) {
|
||||
throw new InvalidDataAccessApiUsageException("Non-terminated named parameter declaration " +
|
||||
"at position " + i + " in statement: " + sql);
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Non-terminated named parameter declaration at position " + i +
|
||||
" in statement: " + sql);
|
||||
}
|
||||
if (statement[j] == ':' || statement[j] == '{') {
|
||||
throw new InvalidDataAccessApiUsageException("Parameter name contains invalid character '" +
|
||||
statement[j] + "' at position " + i + " in statement: " + sql);
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Parameter name contains invalid character '" + statement[j] +
|
||||
"' at position " + i + " in statement: " + sql);
|
||||
}
|
||||
}
|
||||
if (j - i > 2) {
|
||||
parameter = sql.substring(i + 2, j);
|
||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||
namedParameterCount = addNewNamedParameter(
|
||||
namedParameters, namedParameterCount, parameter);
|
||||
totalParameterCount = addNamedParameter(
|
||||
parameterList, totalParameterCount, escapes, i, j + 1, parameter);
|
||||
}
|
||||
|
|
@ -144,7 +147,11 @@ public abstract class NamedParameterUtils {
|
|||
}
|
||||
if (j - i > 1) {
|
||||
parameter = sql.substring(i + 1, j);
|
||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||
if (parameter.contains("[")) {
|
||||
parameter += "]"; // preserve end bracket for index/key
|
||||
}
|
||||
namedParameterCount = addNewNamedParameter(
|
||||
namedParameters, namedParameterCount, parameter);
|
||||
totalParameterCount = addNamedParameter(
|
||||
parameterList, totalParameterCount, escapes, i, j, parameter);
|
||||
}
|
||||
|
|
@ -185,8 +192,8 @@ public abstract class NamedParameterUtils {
|
|||
return parsedSql;
|
||||
}
|
||||
|
||||
private static int addNamedParameter(
|
||||
List<ParameterHolder> parameterList, int totalParameterCount, int escapes, int i, int j, String parameter) {
|
||||
private static int addNamedParameter(List<ParameterHolder> parameterList,
|
||||
int totalParameterCount, int escapes, int i, int j, String parameter) {
|
||||
|
||||
parameterList.add(new ParameterHolder(parameter, i - escapes, j - escapes));
|
||||
totalParameterCount++;
|
||||
|
|
@ -271,6 +278,7 @@ public abstract class NamedParameterUtils {
|
|||
if (paramNames.isEmpty()) {
|
||||
return originalSql;
|
||||
}
|
||||
|
||||
StringBuilder actualSql = new StringBuilder(originalSql.length());
|
||||
int lastIndex = 0;
|
||||
for (int i = 0; i < paramNames.size(); i++) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -327,4 +327,29 @@ public class NamedParameterUtilsTests {
|
|||
assertThat(psql.getParameterNames()).containsExactly("ext");
|
||||
}
|
||||
|
||||
@Test // gh-27925
|
||||
void namedParamMapReference() {
|
||||
String sql = "insert into foos (id) values (:headers[id])";
|
||||
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
assertThat(psql.getNamedParameterCount()).isEqualTo(1);
|
||||
assertThat(psql.getParameterNames()).containsExactly("headers[id]");
|
||||
|
||||
class Foo {
|
||||
final Map<String, Object> headers = new HashMap<>();
|
||||
public Foo() {
|
||||
this.headers.put("id", 1);
|
||||
}
|
||||
public Map<String, Object> getHeaders() {
|
||||
return this.headers;
|
||||
}
|
||||
}
|
||||
|
||||
Foo foo = new Foo();
|
||||
Object[] params = NamedParameterUtils.buildValueArray(psql,
|
||||
new BeanPropertySqlParameterSource(foo), null);
|
||||
|
||||
assertThat(params[0]).isInstanceOf(SqlParameterValue.class);
|
||||
assertThat(((SqlParameterValue) params[0]).getValue()).isEqualTo(foo.getHeaders().get("id"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ abstract class NamedParameterUtils {
|
|||
* Set of characters that qualify as parameter separators,
|
||||
* indicating that a parameter name in an SQL String has ended.
|
||||
*/
|
||||
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^[]";
|
||||
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
|
||||
|
||||
/**
|
||||
* An index with separator flags per character code.
|
||||
|
|
@ -160,6 +160,9 @@ abstract class NamedParameterUtils {
|
|||
}
|
||||
if (j - i > 1) {
|
||||
parameter = sql.substring(i + 1, j);
|
||||
if (parameter.contains("[")) {
|
||||
parameter += "]"; // preserve end bracket for index/key
|
||||
}
|
||||
namedParameterCount = addNewNamedParameter(
|
||||
namedParameters, namedParameterCount, parameter);
|
||||
totalParameterCount = addNamedParameter(
|
||||
|
|
@ -295,7 +298,6 @@ abstract class NamedParameterUtils {
|
|||
if (paramSource.hasValue(paramName)) {
|
||||
Parameter parameter = paramSource.getValue(paramName);
|
||||
if (parameter.getValue() instanceof Collection<?> c) {
|
||||
|
||||
Iterator<?> entryIter = c.iterator();
|
||||
int k = 0;
|
||||
int counter = 0;
|
||||
|
|
|
|||
|
|
@ -277,6 +277,14 @@ public class NamedParameterUtilsUnitTests {
|
|||
assertThat(psql.getParameterNames()).containsExactly("ext");
|
||||
}
|
||||
|
||||
@Test // gh-27925
|
||||
void namedParamMapReference() {
|
||||
String sql = "insert into foos (id) values (:headers[id])";
|
||||
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);
|
||||
assertThat(psql.getNamedParameterCount()).isEqualTo(1);
|
||||
assertThat(psql.getParameterNames()).containsExactly("headers[id]");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAllowParsingMultipleUseOfParameter() {
|
||||
String sql = "SELECT * FROM person where name = :id or lastname = :id";
|
||||
|
|
|
|||
Loading…
Reference in New Issue