From f3dd22da5b6a40922dca8a41f400281239152490 Mon Sep 17 00:00:00 2001 From: nkjackzhang Date: Thu, 29 Mar 2018 05:57:33 +0200 Subject: [PATCH] NamedParameterUtils.parseSqlStatement should parse :{x} style parameter correctly In my opinion, we should parse ":{x}" style parameter as "x" is parameter using "NamedParameterUtils.parseSqlStatement", so the condition "j - i > 2" is the correct condition, not "j - i > 3", because if "i" is the index of ":" in ":{x}", and "j" is the index of "}" in ":{x}", "j - i == 3" is true. Also add a test case for SPR-16663. (cherry picked from commit 82cb5db) --- .../core/namedparam/NamedParameterUtils.java | 26 +++++++++---------- .../namedparam/NamedParameterUtilsTests.java | 14 +++++++++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java index 6cf6fd315b7..42b4c0427ad 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java @@ -41,23 +41,21 @@ import org.springframework.util.Assert; public abstract class NamedParameterUtils { /** - * Set of characters that qualify as parameter separators, - * indicating that a parameter name in a SQL String has ended. + * Set of characters that qualify as comment or quotes starting characters. */ - private static final char[] PARAMETER_SEPARATORS = - new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^'}; + private static final String[] START_SKIP = new String[] {"'", "\"", "--", "/*"}; /** - * Set of characters that qualify as comment or quotes starting characters. + * Set of characters that at are the corresponding comment or quotes ending characters. */ - private static final String[] START_SKIP = - new String[] {"'", "\"", "--", "/*"}; + private static final String[] STOP_SKIP = new String[] {"'", "\"", "\n", "*/"}; /** - * Set of characters that at are the corresponding comment or quotes ending characters. + * Set of characters that qualify as parameter separators, + * indicating that a parameter name in a SQL String has ended. */ - private static final String[] STOP_SKIP = - new String[] {"'", "\"", "\n", "*/"}; + private static final char[] PARAMETER_SEPARATORS = + new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^'}; //------------------------------------------------------------------------- @@ -109,7 +107,7 @@ public abstract class NamedParameterUtils { String parameter = null; if (j < statement.length && c == ':' && statement[j] == '{') { // :{x} style parameter - while (j < statement.length && !('}' == statement[j])) { + while (j < statement.length && '}' != statement[j]) { j++; if (':' == statement[j] || '{' == statement[j]) { throw new InvalidDataAccessApiUsageException("Parameter name contains invalid character '" + @@ -120,7 +118,7 @@ public abstract class NamedParameterUtils { throw new InvalidDataAccessApiUsageException( "Non-terminated named parameter declaration at position " + i + " in statement: " + sql); } - if (j - i > 3) { + if (j - i > 2) { parameter = sql.substring(i + 2, j); namedParameterCount = addNewNamedParameter(namedParameters, namedParameterCount, parameter); totalParameterCount = addNamedParameter(parameterList, totalParameterCount, escapes, i, j + 1, parameter); @@ -200,7 +198,7 @@ public abstract class NamedParameterUtils { if (statement[position] == START_SKIP[i].charAt(0)) { boolean match = true; for (int j = 1; j < START_SKIP[i].length(); j++) { - if (!(statement[position + j] == START_SKIP[i].charAt(j))) { + if (statement[position + j] != START_SKIP[i].charAt(j)) { match = false; break; } @@ -216,7 +214,7 @@ public abstract class NamedParameterUtils { // last comment not closed properly return statement.length; } - if (!(statement[m + n] == STOP_SKIP[i].charAt(n))) { + if (statement[m + n] != STOP_SKIP[i].charAt(n)) { endMatch = false; break; } diff --git a/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java b/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java index b18eb901247..949634f4bb0 100644 --- a/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java +++ b/spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -253,6 +253,18 @@ public class NamedParameterUtilsTests { assertEquals(expectedSql2, finalSql2); } + @Test + public void parseSqlStatementWithSingleLetterInBrackets() { + String expectedSql = "select foo from bar where baz = b?z"; + String sql = "select foo from bar where baz = b:{p}z"; + + ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); + assertEquals(1, parsedSql.getParameterNames().size()); + assertEquals("p", parsedSql.getParameterNames().get(0)); + String finalSql = NamedParameterUtils.substituteNamedParameters(parsedSql, null); + assertEquals(expectedSql, finalSql); + } + @Test // SPR-2544 public void parseSqlStatementWithLogicalAnd() { String expectedSql = "xxx & yyyy";