SPR-7476 Improving named parameter parsing skipping escaped colons like '\:' and allowing for delimiting parameter names with curly brackets like :{p1}
This commit is contained in:
parent
40d88fd991
commit
4f5248bb5c
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.jdbc.core.namedparam;
|
package org.springframework.jdbc.core.namedparam;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
@ -69,15 +70,12 @@ public abstract class NamedParameterUtils {
|
||||||
* @param sql the SQL statement
|
* @param sql the SQL statement
|
||||||
* @return the parsed statement, represented as ParsedSql instance
|
* @return the parsed statement, represented as ParsedSql instance
|
||||||
*/
|
*/
|
||||||
public static ParsedSql parseSqlStatement(String sql) {
|
public static ParsedSql parseSqlStatement(final String sql) {
|
||||||
Assert.notNull(sql, "SQL must not be null");
|
Assert.notNull(sql, "SQL must not be null");
|
||||||
|
|
||||||
Set<String> namedParameters = new HashSet<String>();
|
Set<String> namedParameters = new HashSet<String>();
|
||||||
String sqlToUse = sql;
|
String sqlToUse = sql;
|
||||||
if (sql.contains("\\:")) {
|
List<ParameterHolder> parameterList = new ArrayList<ParameterHolder>();
|
||||||
sqlToUse = sql.replace("\\:", ":");
|
|
||||||
}
|
|
||||||
ParsedSql parsedSql = new ParsedSql(sqlToUse);
|
|
||||||
|
|
||||||
char[] statement = sql.toCharArray();
|
char[] statement = sql.toCharArray();
|
||||||
int namedParameterCount = 0;
|
int namedParameterCount = 0;
|
||||||
|
|
@ -111,7 +109,7 @@ public abstract class NamedParameterUtils {
|
||||||
if (j - i > 3) {
|
if (j - i > 3) {
|
||||||
parameter = sql.substring(i + 2, j);
|
parameter = sql.substring(i + 2, j);
|
||||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||||
totalParameterCount = addNamedParameter(parsedSql, totalParameterCount, escapes, i, j + 1, parameter);
|
totalParameterCount = addNamedParameter(parameterList, totalParameterCount, escapes, i, j + 1, parameter);
|
||||||
}
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +120,7 @@ public abstract class NamedParameterUtils {
|
||||||
if (j - i > 1) {
|
if (j - i > 1) {
|
||||||
parameter = sql.substring(i + 1, j);
|
parameter = sql.substring(i + 1, j);
|
||||||
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||||
totalParameterCount = addNamedParameter(parsedSql, totalParameterCount, escapes, i, j, parameter);
|
totalParameterCount = addNamedParameter(parameterList, totalParameterCount, escapes, i, j, parameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = j - 1;
|
i = j - 1;
|
||||||
|
|
@ -132,6 +130,7 @@ public abstract class NamedParameterUtils {
|
||||||
int j = i + 1;
|
int j = i + 1;
|
||||||
if (j < statement.length && statement[j] == ':') {
|
if (j < statement.length && statement[j] == ':') {
|
||||||
// this is an escaped : and should be skipped
|
// this is an escaped : and should be skipped
|
||||||
|
sqlToUse = sqlToUse.substring(0, i - escapes) + sqlToUse.substring(i - escapes + 1);
|
||||||
escapes++;
|
escapes++;
|
||||||
i = i + 2;
|
i = i + 2;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -144,20 +143,24 @@ public abstract class NamedParameterUtils {
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
ParsedSql parsedSql = new ParsedSql(sqlToUse);
|
||||||
|
for (ParameterHolder ph : parameterList) {
|
||||||
|
parsedSql.addNamedParameter(ph.getParameterName(), ph.getStartIndex(), ph.getEndIndex());
|
||||||
|
}
|
||||||
parsedSql.setNamedParameterCount(namedParameterCount);
|
parsedSql.setNamedParameterCount(namedParameterCount);
|
||||||
parsedSql.setUnnamedParameterCount(unnamedParameterCount);
|
parsedSql.setUnnamedParameterCount(unnamedParameterCount);
|
||||||
parsedSql.setTotalParameterCount(totalParameterCount);
|
parsedSql.setTotalParameterCount(totalParameterCount);
|
||||||
return parsedSql;
|
return parsedSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int addNamedParameter(ParsedSql parsedSql, int totalParameterCount, int escapes, int i, int j,
|
private static int addNamedParameter(List<ParameterHolder> parameterList, int totalParameterCount, int escapes, int i, int j,
|
||||||
String parameter) {
|
String parameter) {
|
||||||
parsedSql.addNamedParameter(parameter, i - escapes, j - escapes);
|
parameterList.add(new ParameterHolder(parameter, i - escapes, j - escapes));
|
||||||
totalParameterCount++;
|
totalParameterCount++;
|
||||||
return totalParameterCount;
|
return totalParameterCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int addNewNamedParameter(Set<String> namedParameters, int namedParameterCount, String parameter) {
|
private static int addNewNamedParameter(Set<String> namedParameters, int namedParameterCount, String parameter) {
|
||||||
if (!namedParameters.contains(parameter)) {
|
if (!namedParameters.contains(parameter)) {
|
||||||
namedParameters.add(parameter);
|
namedParameters.add(parameter);
|
||||||
namedParameterCount++;
|
namedParameterCount++;
|
||||||
|
|
@ -445,4 +448,28 @@ public abstract class NamedParameterUtils {
|
||||||
return buildValueArray(parsedSql, new MapSqlParameterSource(paramMap), null);
|
return buildValueArray(parsedSql, new MapSqlParameterSource(paramMap), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class ParameterHolder {
|
||||||
|
private String parameterName;
|
||||||
|
private int startIndex;
|
||||||
|
private int endIndex;
|
||||||
|
|
||||||
|
public ParameterHolder(String parameterName, int startIndex, int endIndex) {
|
||||||
|
super();
|
||||||
|
this.parameterName = parameterName;
|
||||||
|
this.startIndex = startIndex;
|
||||||
|
this.endIndex = endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParameterName() {
|
||||||
|
return parameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStartIndex() {
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEndIndex() {
|
||||||
|
return endIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -189,8 +189,8 @@ public class NamedParameterUtilsTests {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void parseSqlStatementWithEscapedColon() throws Exception {
|
public void parseSqlStatementWithEscapedColon() throws Exception {
|
||||||
String expectedSql = "select foo from bar where baz < DATE(? 23:59:59) and baz = ?";
|
String expectedSql = "select '0\\:0' as a, foo from bar where baz < DATE(? 23:59:59) and baz = ?";
|
||||||
String sql = "select foo from bar where baz < DATE(:p1 23\\:59\\:59) and baz = :p2";
|
String sql = "select '0\\:0' as a, foo from bar where baz < DATE(:p1 23\\:59\\:59) and baz = :p2";
|
||||||
|
|
||||||
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||||
assertEquals(2, parsedSql.getParameterNames().size());
|
assertEquals(2, parsedSql.getParameterNames().size());
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue