From 64b6beed5b135344b6f0d15bc50bf4c08c2ab9bb Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 14 Dec 2021 11:34:48 +0100 Subject: [PATCH] Consistent support for square brackets around named parameter See gh-27716 --- .../core/namedparam/NamedParameterUtils.java | 2 +- .../namedparam/NamedParameterUtilsTests.java | 8 ++++ .../r2dbc/core/NamedParameterUtils.java | 5 +-- .../core/NamedParameterUtilsUnitTests.java | 39 +++---------------- 4 files changed, 16 insertions(+), 38 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 981dfc22e7..1efea4e803 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 @@ -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. 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 7a1df2928a..bf501d0465 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 @@ -319,4 +319,12 @@ public class NamedParameterUtilsTests { assertThat(psql2.getParameterNames().get(0)).isEqualTo("xxx"); } + @Test // gh-27716 + public void parseSqlStatementWithSquareBracket() { + String sql = "SELECT ARRAY[:ext]"; + ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); + assertThat(psql.getNamedParameterCount()).isEqualTo(1); + assertThat(psql.getParameterNames()).containsExactly("ext"); + } + } diff --git a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java index 724ab440bc..49eecd68e9 100644 --- a/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java +++ b/spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -37,8 +37,7 @@ import org.springframework.util.Assert; /** * Helper methods for named parameter parsing. * - *

Only intended for internal use within Spring's R2DBC - * framework. + *

Only intended for internal use within Spring's R2DBC framework. * *

References to the same parameter name are substituted with * the same bind marker placeholder if a {@link BindMarkersFactory} uses diff --git a/spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsUnitTests.java b/spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsUnitTests.java index 679bcc1fc5..5663c63073 100644 --- a/spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsUnitTests.java +++ b/spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsUnitTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2021 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. @@ -44,6 +44,7 @@ public class NamedParameterUtilsUnitTests { private final BindMarkersFactory BIND_MARKERS = BindMarkersFactory.indexed("$", 1); + @Test public void shouldParseSql() { String sql = "xxx :a yyyy :b :c :a zzzzz"; @@ -146,7 +147,6 @@ public class NamedParameterUtilsUnitTests { String sql = "select 'first name' from artists where info->'stat'->'albums' = ?? :album and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'"; ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getTotalParameterCount()).isEqualTo(1); assertThat(expand(parsedSql)).isEqualTo(expectedSql); } @@ -157,7 +157,6 @@ public class NamedParameterUtilsUnitTests { String sql = "select '[\"3\", \"11\"]'::jsonb ?| '{1,3,11,12,17}'::text[]"; ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getTotalParameterCount()).isEqualTo(0); assertThat(expand(parsedSql)).isEqualTo(expectedSql); } @@ -178,7 +177,6 @@ public class NamedParameterUtilsUnitTests { 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); - assertThat(parsedSql.getParameterNames()).containsExactly("p1", "p2"); assertThat(expand(parsedSql)).isEqualTo(expectedSql); } @@ -199,7 +197,6 @@ public class NamedParameterUtilsUnitTests { String sql = "select foo from bar where baz = b:{}z"; ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsedSql.getParameterNames()).isEmpty(); assertThat(expand(parsedSql)).isEqualTo(expectedSql); @@ -226,13 +223,11 @@ public class NamedParameterUtilsUnitTests { String expectedSql = "xxx & yyyy"; ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(expectedSql); - assertThat(expand(parsedSql)).isEqualTo(expectedSql); } @Test public void substituteNamedParametersWithLogicalAnd() { - String expectedSql = "xxx & yyyy"; assertThat(expand(expectedSql)).isEqualTo(expectedSql); @@ -250,7 +245,6 @@ public class NamedParameterUtilsUnitTests { String sql = "SELECT ':foo'':doo', :xxx FROM DUAL"; ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(psql.getTotalParameterCount()).isEqualTo(1); assertThat(psql.getParameterNames()).containsExactly("xxx"); } @@ -260,7 +254,6 @@ public class NamedParameterUtilsUnitTests { String sql = "SELECT /*:doo*/':foo', :xxx FROM DUAL"; ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - assertThat(psql.getTotalParameterCount()).isEqualTo(1); assertThat(psql.getParameterNames()).containsExactly("xxx"); } @@ -270,30 +263,24 @@ public class NamedParameterUtilsUnitTests { String sql2 = "SELECT ':foo'/*:doo*/, :xxx FROM DUAL"; ParsedSql psql2 = NamedParameterUtils.parseSqlStatement(sql2); - assertThat(psql2.getTotalParameterCount()).isEqualTo(1); assertThat(psql2.getParameterNames()).containsExactly("xxx"); } - @Test public void parseSqlStatementWithSquareBracket() { - // given + @Test // gh-27716 + public void parseSqlStatementWithSquareBracket() { String sql = "SELECT ARRAY[:ext]"; - // when ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql); - - //then assertThat(psql.getNamedParameterCount()).isEqualTo(1); assertThat(psql.getParameterNames()).containsExactly("ext"); } @Test public void shouldAllowParsingMultipleUseOfParameter() { - String sql = "SELECT * FROM person where name = :id or lastname = :id"; ParsedSql parsed = NamedParameterUtils.parseSqlStatement(sql); - assertThat(parsed.getTotalParameterCount()).isEqualTo(2); assertThat(parsed.getNamedParameterCount()).isEqualTo(1); assertThat(parsed.getParameterNames()).containsExactly("id", "id"); @@ -313,23 +300,19 @@ public class NamedParameterUtilsUnitTests { "SELECT * FROM person where name = $0 or lastname = $0"); operation.bindTo(new BindTarget() { - @Override public void bind(String identifier, Object value) { throw new UnsupportedOperationException(); } - @Override public void bind(int index, Object value) { assertThat(index).isEqualTo(0); assertThat(value).isEqualTo("foo"); } - @Override public void bindNull(String identifier, Class type) { throw new UnsupportedOperationException(); } - @Override public void bindNull(int index, Class type) { throw new UnsupportedOperationException(); @@ -353,25 +336,20 @@ public class NamedParameterUtilsUnitTests { "SELECT * FROM person where name IN ($0, $1, $2) or lastname IN ($0, $1, $2)"); operation.bindTo(new BindTarget() { - @Override public void bind(String identifier, Object value) { throw new UnsupportedOperationException(); } - @Override public void bind(int index, Object value) { assertThat(index).isIn(0, 1, 2); assertThat(value).isIn("foo", "bar", "baz"); - bindings.add(index, value); } - @Override public void bindNull(String identifier, Class type) { throw new UnsupportedOperationException(); } - @Override public void bindNull(int index, Class type) { throw new UnsupportedOperationException(); @@ -399,22 +377,18 @@ public class NamedParameterUtilsUnitTests { Map bindValues = new LinkedHashMap<>(); operation.bindTo(new BindTarget() { - @Override public void bind(String identifier, Object value) { throw new UnsupportedOperationException(); } - @Override public void bind(int index, Object value) { bindValues.put(index, value); } - @Override public void bindNull(String identifier, Class type) { throw new UnsupportedOperationException(); } - @Override public void bindNull(int index, Class type) { throw new UnsupportedOperationException(); @@ -438,22 +412,18 @@ public class NamedParameterUtilsUnitTests { "SELECT * FROM person where name = $0 or lastname = $0"); operation.bindTo(new BindTarget() { - @Override public void bind(String identifier, Object value) { throw new UnsupportedOperationException(); } - @Override public void bind(int index, Object value) { throw new UnsupportedOperationException(); } - @Override public void bindNull(String identifier, Class type) { throw new UnsupportedOperationException(); } - @Override public void bindNull(int index, Class type) { assertThat(index).isEqualTo(0); @@ -462,6 +432,7 @@ public class NamedParameterUtilsUnitTests { }); } + private String expand(ParsedSql sql) { return NamedParameterUtils.substituteNamedParameters(sql, BIND_MARKERS, new MapBindParameterSource()).toQuery();