Skip to content

Commit 99327b7

Browse files
committed
Preserve nested square brackets within parameter name
Closes gh-31596
1 parent 3e06441 commit 99327b7

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ public abstract class NamedParameterUtils {
5555
* Set of characters that qualify as parameter separators,
5656
* indicating that a parameter name in an SQL String has ended.
5757
*/
58-
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
58+
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^";
5959

6060
/**
6161
* An index with separator flags per character code.
@@ -142,16 +142,25 @@ public static ParsedSql parseSqlStatement(String sql) {
142142
j++;
143143
}
144144
else {
145-
while (j < statement.length && !isParameterSeparator(statement[j])) {
145+
boolean paramWithSquareBrackets = false;
146+
while (j < statement.length) {
147+
c = statement[j];
148+
if (isParameterSeparator(c)) {
149+
break;
150+
}
151+
if (c == '[') {
152+
paramWithSquareBrackets = true;
153+
}
154+
else if (c == ']') {
155+
if (!paramWithSquareBrackets) {
156+
break;
157+
}
158+
paramWithSquareBrackets = false;
159+
}
146160
j++;
147161
}
148162
if (j - i > 1) {
149163
parameter = sql.substring(i + 1, j);
150-
if (j < statement.length && statement[j] == ']' && parameter.contains("[")) {
151-
// preserve end bracket for index/key
152-
j++;
153-
parameter = sql.substring(i + 1, j);
154-
}
155164
namedParameterCount = addNewNamedParameter(
156165
namedParameters, namedParameterCount, parameter);
157166
totalParameterCount = addNamedParameter(

spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -330,6 +330,18 @@ public void parseSqlStatementWithSquareBracket() {
330330
assertThat(sqlToUse).isEqualTo("SELECT ARRAY[?]");
331331
}
332332

333+
@Test // gh-31596
334+
void paramNameWithNestedSquareBrackets() {
335+
String sql = "insert into GeneratedAlways (id, first_name, last_name) values " +
336+
"(:records[0].id, :records[0].firstName, :records[0].lastName), " +
337+
"(:records[1].id, :records[1].firstName, :records[1].lastName)";
338+
339+
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
340+
assertThat(parsedSql.getParameterNames()).containsOnly(
341+
"records[0].id", "records[0].firstName", "records[0].lastName",
342+
"records[1].id", "records[1].firstName", "records[1].lastName");
343+
}
344+
333345
@Test // gh-27925
334346
void namedParamMapReference() {
335347
String sql = "insert into foos (id) values (:headers[id])";

spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ abstract class NamedParameterUtils {
6767
* Set of characters that qualify as parameter separators,
6868
* indicating that a parameter name in an SQL String has ended.
6969
*/
70-
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
70+
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^";
7171

7272
/**
7373
* An index with separator flags per character code.
@@ -83,12 +83,12 @@ abstract class NamedParameterUtils {
8383

8484

8585
// -------------------------------------------------------------------------
86-
// Core methods used by NamedParameterSupport.
86+
// Core methods used by NamedParameterExpander
8787
// -------------------------------------------------------------------------
8888

8989
/**
9090
* Parse the SQL statement and locate any placeholders or named parameters.
91-
* Named parameters are substituted for a R2DBC placeholder.
91+
* Named parameters are substituted for an R2DBC placeholder.
9292
* @param sql the SQL statement
9393
* @return the parsed statement, represented as {@link ParsedSql} instance
9494
*/
@@ -154,16 +154,25 @@ public static ParsedSql parseSqlStatement(String sql) {
154154
j++;
155155
}
156156
else {
157-
while (j < statement.length && !isParameterSeparator(statement[j])) {
157+
boolean paramWithSquareBrackets = false;
158+
while (j < statement.length) {
159+
c = statement[j];
160+
if (isParameterSeparator(c)) {
161+
break;
162+
}
163+
if (c == '[') {
164+
paramWithSquareBrackets = true;
165+
}
166+
else if (c == ']') {
167+
if (!paramWithSquareBrackets) {
168+
break;
169+
}
170+
paramWithSquareBrackets = false;
171+
}
158172
j++;
159173
}
160174
if (j - i > 1) {
161175
parameter = sql.substring(i + 1, j);
162-
if (j < statement.length && statement[j] == ']' && parameter.contains("[")) {
163-
// preserve end bracket for index/key
164-
j++;
165-
parameter = sql.substring(i + 1, j);
166-
}
167176
namedParameterCount = addNewNamedParameter(
168177
namedParameters, namedParameterCount, parameter);
169178
totalParameterCount = addNamedParameter(
@@ -261,7 +270,7 @@ private static int skipCommentsAndQuotes(char[] statement, int position) {
261270

262271
/**
263272
* Parse the SQL statement and locate any placeholders or named parameters. Named
264-
* parameters are substituted for a R2DBC placeholder, and any select list is expanded
273+
* parameters are substituted for an R2DBC placeholder, and any select list is expanded
265274
* to the required number of placeholders. Select lists may contain an array of objects,
266275
* and in that case the placeholders will be grouped and enclosed with parentheses.
267276
* This allows for the use of "expression lists" in the SQL statement like:

0 commit comments

Comments
 (0)