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
92d6e5a14c
commit
aec82fbd4a
|
@ -73,13 +73,18 @@ public abstract class NamedParameterUtils {
|
||||||
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>();
|
||||||
ParsedSql parsedSql = new ParsedSql(sql);
|
String sqlToUse = sql;
|
||||||
|
if (sql.contains("\\:")) {
|
||||||
|
sqlToUse = sql.replace("\\:", ":");
|
||||||
|
}
|
||||||
|
ParsedSql parsedSql = new ParsedSql(sqlToUse);
|
||||||
|
|
||||||
char[] statement = sql.toCharArray();
|
char[] statement = sql.toCharArray();
|
||||||
int namedParameterCount = 0;
|
int namedParameterCount = 0;
|
||||||
int unnamedParameterCount = 0;
|
int unnamedParameterCount = 0;
|
||||||
int totalParameterCount = 0;
|
int totalParameterCount = 0;
|
||||||
|
|
||||||
|
int escapes = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < statement.length) {
|
while (i < statement.length) {
|
||||||
int skipToPosition = skipCommentsAndQuotes(statement, i);
|
int skipToPosition = skipCommentsAndQuotes(statement, i);
|
||||||
|
@ -97,21 +102,41 @@ public abstract class NamedParameterUtils {
|
||||||
i = i + 2;
|
i = i + 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
while (j < statement.length && !isParameterSeparator(statement[j])) {
|
String parameter = null;
|
||||||
|
if (j < statement.length && c == ':' && statement[j] == '{') {
|
||||||
|
// :{x} style parameter
|
||||||
|
while (j < statement.length && !('}' == statement[j])) {
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
if (j - i > 3) {
|
||||||
|
parameter = sql.substring(i + 2, j);
|
||||||
|
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||||
|
totalParameterCount = addNamedParameter(parsedSql, totalParameterCount, escapes, i, j + 1, parameter);
|
||||||
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
if (j - i > 1) {
|
else {
|
||||||
String parameter = sql.substring(i + 1, j);
|
while (j < statement.length && !isParameterSeparator(statement[j])) {
|
||||||
if (!namedParameters.contains(parameter)) {
|
j++;
|
||||||
namedParameters.add(parameter);
|
}
|
||||||
namedParameterCount++;
|
if (j - i > 1) {
|
||||||
|
parameter = sql.substring(i + 1, j);
|
||||||
|
namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter);
|
||||||
|
totalParameterCount = addNamedParameter(parsedSql, totalParameterCount, escapes, i, j, parameter);
|
||||||
}
|
}
|
||||||
parsedSql.addNamedParameter(parameter, i, j);
|
|
||||||
totalParameterCount++;
|
|
||||||
}
|
}
|
||||||
i = j - 1;
|
i = j - 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (c == '\\') {
|
||||||
|
int j = i + 1;
|
||||||
|
if (j < statement.length && statement[j] == ':') {
|
||||||
|
// this is an escaped : and should be skipped
|
||||||
|
escapes++;
|
||||||
|
i = i + 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (c == '?') {
|
if (c == '?') {
|
||||||
unnamedParameterCount++;
|
unnamedParameterCount++;
|
||||||
totalParameterCount++;
|
totalParameterCount++;
|
||||||
|
@ -125,6 +150,21 @@ public abstract class NamedParameterUtils {
|
||||||
return parsedSql;
|
return parsedSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static int addNamedParameter(ParsedSql parsedSql, int totalParameterCount, int escapes, int i, int j,
|
||||||
|
String parameter) {
|
||||||
|
parsedSql.addNamedParameter(parameter, i - escapes, j - escapes);
|
||||||
|
totalParameterCount++;
|
||||||
|
return totalParameterCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static int addNewNamedParameter(Set<String> namedParameters, int namedParameterCount, String parameter) {
|
||||||
|
if (!namedParameters.contains(parameter)) {
|
||||||
|
namedParameters.add(parameter);
|
||||||
|
namedParameterCount++;
|
||||||
|
}
|
||||||
|
return namedParameterCount;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Skip over comments and quoted names present in an SQL statement
|
* Skip over comments and quoted names present in an SQL statement
|
||||||
* @param statement character array containing SQL statement
|
* @param statement character array containing SQL statement
|
||||||
|
|
|
@ -55,7 +55,6 @@ public class NamedParameterUtilsTests {
|
||||||
assertEquals("a", psql3.getParameterNames().get(0));
|
assertEquals("a", psql3.getParameterNames().get(0));
|
||||||
assertEquals("b", psql3.getParameterNames().get(1));
|
assertEquals("b", psql3.getParameterNames().get(1));
|
||||||
assertEquals("c", psql3.getParameterNames().get(2));
|
assertEquals("c", psql3.getParameterNames().get(2));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -185,6 +184,56 @@ public class NamedParameterUtilsTests {
|
||||||
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
|
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPR-7476
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void parseSqlStatementWithEscapedColon() throws Exception {
|
||||||
|
String expectedSql = "select 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";
|
||||||
|
|
||||||
|
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||||
|
assertEquals(2, parsedSql.getParameterNames().size());
|
||||||
|
String finalSql = NamedParameterUtils.substituteNamedParameters(parsedSql, null);
|
||||||
|
assertEquals(expectedSql, finalSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPR-7476
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void parseSqlStatementWithBracketDelimitedParameterNames() throws Exception {
|
||||||
|
String expectedSql = "select foo from bar where baz = b??z";
|
||||||
|
String sql = "select foo from bar where baz = b:{p1}:{p2}z";
|
||||||
|
|
||||||
|
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||||
|
assertEquals(2, parsedSql.getParameterNames().size());
|
||||||
|
String finalSql = NamedParameterUtils.substituteNamedParameters(parsedSql, null);
|
||||||
|
assertEquals(expectedSql, finalSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SPR-7476
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void parseSqlStatementWithEmptyBracketsOrBracketsInQuotes() throws Exception {
|
||||||
|
String expectedSql = "select foo from bar where baz = b:{}z";
|
||||||
|
String sql = "select foo from bar where baz = b:{}z";
|
||||||
|
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
|
||||||
|
assertEquals(0, parsedSql.getParameterNames().size());
|
||||||
|
String finalSql = NamedParameterUtils.substituteNamedParameters(parsedSql, null);
|
||||||
|
assertEquals(expectedSql, finalSql);
|
||||||
|
|
||||||
|
String expectedSql2 = "select foo from bar where baz = 'b:{p1}z'";
|
||||||
|
String sql2 = "select foo from bar where baz = 'b:{p1}z'";
|
||||||
|
|
||||||
|
ParsedSql parsedSql2 = NamedParameterUtils.parseSqlStatement(sql2);
|
||||||
|
assertEquals(0, parsedSql2.getParameterNames().size());
|
||||||
|
String finalSql2 = NamedParameterUtils.substituteNamedParameters(parsedSql2, null);
|
||||||
|
assertEquals(expectedSql2, finalSql2);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPR-2544
|
* SPR-2544
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue