Skip to content

Commit 11d1f05

Browse files
committed
NamedParameterUtils skips Postgres-style ?? operator
Issue: SPR-13582
1 parent 5386e8a commit 11d1f05

File tree

2 files changed

+29
-40
lines changed

2 files changed

+29
-40
lines changed

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -103,7 +103,7 @@ public static ParsedSql parseSqlStatement(final String sql) {
103103
if (c == ':' || c == '&') {
104104
int j = i + 1;
105105
if (j < statement.length && statement[j] == ':' && c == ':') {
106-
// Postgres-style "::" casting operator - to be skipped.
106+
// Postgres-style "::" casting operator should be skipped
107107
i = i + 2;
108108
continue;
109109
}
@@ -144,14 +144,20 @@ public static ParsedSql parseSqlStatement(final String sql) {
144144
if (c == '\\') {
145145
int j = i + 1;
146146
if (j < statement.length && statement[j] == ':') {
147-
// this is an escaped : and should be skipped
147+
// escaped ":" should be skipped
148148
sqlToUse = sqlToUse.substring(0, i - escapes) + sqlToUse.substring(i - escapes + 1);
149149
escapes++;
150150
i = i + 2;
151151
continue;
152152
}
153153
}
154154
if (c == '?') {
155+
int j = i + 1;
156+
if (j < statement.length && statement[j] == '?') {
157+
// Postgres-style "??" operator should be skipped
158+
i = i + 2;
159+
continue;
160+
}
155161
unnamedParameterCount++;
156162
totalParameterCount++;
157163
}

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

Lines changed: 20 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2015 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.
@@ -30,6 +30,7 @@
3030
* @author Thomas Risberg
3131
* @author Juergen Hoeller
3232
* @author Rick Evans
33+
* @author Artur Geraschenko
3334
*/
3435
public class NamedParameterUtilsTests {
3536

@@ -137,10 +138,7 @@ public void testParseSqlStatementWithStringContainingQuotes() throws Exception {
137138
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
138139
}
139140

140-
/*
141-
* SPR-4789
142-
*/
143-
@Test
141+
@Test // SPR-4789
144142
public void parseSqlContainingComments() {
145143
String sql1 = "/*+ HINT */ xxx /* comment ? */ :a yyyy :b :c :a zzzzz -- :xx XX\n";
146144
ParsedSql psql1 = NamedParameterUtils.parseSqlStatement(sql1);
@@ -174,21 +172,24 @@ public void parseSqlContainingComments() {
174172
NamedParameterUtils.substituteNamedParameters(psql4, new MapSqlParameterSource(parameters)));
175173
}
176174

177-
/*
178-
* SPR-4612
179-
*/
180-
@Test
175+
@Test // SPR-4612
181176
public void parseSqlStatementWithPostgresCasting() throws Exception {
182177
String expectedSql = "select 'first name' from artists where id = ? and birth_date=?::timestamp";
183178
String sql = "select 'first name' from artists where id = :id and birth_date=:birthDate::timestamp";
184179
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
185180
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
186181
}
187182

188-
/*
189-
* SPR-7476
190-
*/
191-
@Test
183+
@Test // SPR-13582
184+
public void parseSqlStatementWithPostgresContainedOperator() throws Exception {
185+
String expectedSql = "select 'first name' from artists where info->'stat'->'albums' = ?? ? and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'";
186+
String sql = "select 'first name' from artists where info->'stat'->'albums' = ?? :album and '[\"1\",\"2\",\"3\"]'::jsonb ?? '4'";
187+
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
188+
assertEquals(1, parsedSql.getTotalParameterCount());
189+
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
190+
}
191+
192+
@Test // SPR-7476
192193
public void parseSqlStatementWithEscapedColon() throws Exception {
193194
String expectedSql = "select '0\\:0' as a, foo from bar where baz < DATE(? 23:59:59) and baz = ?";
194195
String sql = "select '0\\:0' as a, foo from bar where baz < DATE(:p1 23\\:59\\:59) and baz = :p2";
@@ -201,10 +202,7 @@ public void parseSqlStatementWithEscapedColon() throws Exception {
201202
assertEquals(expectedSql, finalSql);
202203
}
203204

204-
/*
205-
* SPR-7476
206-
*/
207-
@Test
205+
@Test // SPR-7476
208206
public void parseSqlStatementWithBracketDelimitedParameterNames() throws Exception {
209207
String expectedSql = "select foo from bar where baz = b??z";
210208
String sql = "select foo from bar where baz = b:{p1}:{p2}z";
@@ -217,10 +215,7 @@ public void parseSqlStatementWithBracketDelimitedParameterNames() throws Excepti
217215
assertEquals(expectedSql, finalSql);
218216
}
219217

220-
/*
221-
* SPR-7476
222-
*/
223-
@Test
218+
@Test // SPR-7476
224219
public void parseSqlStatementWithEmptyBracketsOrBracketsInQuotes() throws Exception {
225220
String expectedSql = "select foo from bar where baz = b:{}z";
226221
String sql = "select foo from bar where baz = b:{}z";
@@ -238,40 +233,28 @@ public void parseSqlStatementWithEmptyBracketsOrBracketsInQuotes() throws Except
238233
assertEquals(expectedSql2, finalSql2);
239234
}
240235

241-
/*
242-
* SPR-2544
243-
*/
244-
@Test
236+
@Test // SPR-2544
245237
public void parseSqlStatementWithLogicalAnd() {
246238
String expectedSql = "xxx & yyyy";
247239
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(expectedSql);
248240
assertEquals(expectedSql, NamedParameterUtils.substituteNamedParameters(parsedSql, null));
249241
}
250242

251-
/*
252-
* SPR-2544
253-
*/
254-
@Test
243+
@Test // SPR-2544
255244
public void substituteNamedParametersWithLogicalAnd() throws Exception {
256245
String expectedSql = "xxx & yyyy";
257246
String newSql = NamedParameterUtils.substituteNamedParameters(expectedSql, new MapSqlParameterSource());
258247
assertEquals(expectedSql, newSql);
259248
}
260249

261-
/*
262-
* SPR-3173
263-
*/
264-
@Test
250+
@Test // SPR-3173
265251
public void variableAssignmentOperator() throws Exception {
266252
String expectedSql = "x := 1";
267253
String newSql = NamedParameterUtils.substituteNamedParameters(expectedSql, new MapSqlParameterSource());
268254
assertEquals(expectedSql, newSql);
269255
}
270256

271-
/*
272-
* SPR-8280
273-
*/
274-
@Test
257+
@Test // SPR-8280
275258
public void parseSqlStatementWithQuotedSingleQuote() {
276259
String sql = "SELECT ':foo'':doo', :xxx FROM DUAL";
277260
ParsedSql psql = NamedParameterUtils.parseSqlStatement(sql);

0 commit comments

Comments
 (0)