Skip to content

Commit d472639

Browse files
authored
fix: order parameters by index and not textual value (#239)
Prepared statements with 10 or more parameters would not order the parameters in the DESCRIBE SQL statement according to the parameter index, but by the textual value. This could lead to the wrong type for a parameter to be returned to the client.
1 parent 708fa42 commit d472639

File tree

2 files changed

+36
-25
lines changed

2 files changed

+36
-25
lines changed

src/main/java/com/google/cloud/spanner/pgadapter/statements/IntermediatePreparedStatement.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,7 @@ public IntermediatePortalStatement bind(
133133

134134
@Override
135135
public DescribeMetadata<?> describe() {
136-
Set<String> parameters =
137-
ImmutableSortedSet.<String>orderedBy(Comparator.comparing(o -> o.substring(1)))
138-
.addAll(PARSER.getQueryParameters(this.parsedStatement.getSqlWithoutComments()))
139-
.build();
136+
Set<String> parameters = extractParameters(this.parsedStatement.getSqlWithoutComments());
140137

141138
ResultSet columnsResultSet = null;
142139
try {
@@ -195,6 +192,19 @@ public DescribeMetadata<?> describe() {
195192
}
196193
}
197194

195+
/**
196+
* Extracts the statement parameters from the given sql string and returns these as a sorted set.
197+
* The parameters are ordered by their index and not by the textual value (i.e. "$9" comes before
198+
* "$10").
199+
*/
200+
@VisibleForTesting
201+
static ImmutableSortedSet<String> extractParameters(String sql) {
202+
return ImmutableSortedSet.<String>orderedBy(
203+
Comparator.comparing(o -> Integer.valueOf(o.substring(1))))
204+
.addAll(PARSER.getQueryParameters(sql))
205+
.build();
206+
}
207+
198208
/**
199209
* Transforms a query or DML statement into a SELECT statement that selects the parameters in the
200210
* statements. Examples:

src/test/java/com/google/cloud/spanner/pgadapter/statements/IntermediateStatementTest.java

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.cloud.spanner.pgadapter.statements;
1616

17+
import static com.google.cloud.spanner.pgadapter.statements.IntermediatePreparedStatement.extractParameters;
1718
import static com.google.cloud.spanner.pgadapter.statements.IntermediatePreparedStatement.transformDeleteToSelectParams;
1819
import static com.google.cloud.spanner.pgadapter.statements.IntermediatePreparedStatement.transformInsertToSelectParams;
1920
import static com.google.cloud.spanner.pgadapter.statements.IntermediatePreparedStatement.transformUpdateToSelectParams;
@@ -39,9 +40,6 @@
3940
import com.google.cloud.spanner.pgadapter.ConnectionHandler;
4041
import com.google.cloud.spanner.pgadapter.metadata.OptionsMetadata;
4142
import com.google.common.collect.ImmutableList;
42-
import com.google.common.collect.ImmutableSortedSet;
43-
import java.util.Comparator;
44-
import java.util.Set;
4543
import org.junit.Rule;
4644
import org.junit.Test;
4745
import org.junit.runner.RunWith;
@@ -177,6 +175,13 @@ public void testTransformInsertValuesToSelectParams() {
177175
transformInsert(
178176
"insert\ninto\nfoo\n(col1,\ncol2 ) values ($1 + $2 + 5, $3 || to_char($4) || coalesce($5, ''))")
179177
.getSql());
178+
assertEquals(
179+
"select $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 from "
180+
+ "(select col1=$1, col2=$2, col3=$3, col4=$4, col5=$5, col6=$6, col7=$7, col8=$8, col9=$9, col10=$10 from foo) p",
181+
transformInsert(
182+
"insert into foo (col1, col2, col3, col4, col5, col6, col7, col8, col9, col10) "
183+
+ "values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)")
184+
.getSql());
180185
}
181186

182187
@Test
@@ -225,6 +230,12 @@ public void testTransformUpdateToSelectParams() {
225230
assertNull(transformUpdate("update foo col1=1"));
226231
assertNull(transformUpdate("update foo col1=1 hwere col1=2"));
227232
assertNull(transformUpdate("udpate foo col1=1 where col1=2"));
233+
234+
assertEquals(
235+
"select $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 from (select col1=$1, col2=$2, col3=$3, col4=$4, col5=$5, col6=$6, col7=$7, col8=$8, col9=$9 from foo where id=$10) p",
236+
transformUpdate(
237+
"update foo set col1=$1, col2=$2, col3=$3, col4=$4, col5=$5, col6=$6, col7=$7, col8=$8, col9=$9 where id=$10")
238+
.getSql());
228239
}
229240

230241
@Test
@@ -236,7 +247,7 @@ public void testTransformDeleteToSelectParams() {
236247
"select $1, $2 from (select 1 from foo where id=$1 and bar > $2) p",
237248
transformDelete("delete foo\nwhere id=$1 and bar > $2").getSql());
238249
assertEquals(
239-
"select $1, $2, $3, $4, $5, $6, $7, $8, $9 "
250+
"select $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 "
240251
+ "from (select 1 from all_types "
241252
+ "where col_bigint=$1 "
242253
+ "and col_bool=$2 "
@@ -246,7 +257,8 @@ public void testTransformDeleteToSelectParams() {
246257
+ "and col_numeric=$6 "
247258
+ "and col_timestamptz=$7 "
248259
+ "and col_date=$8 "
249-
+ "and col_varchar=$9"
260+
+ "and col_varchar=$9 "
261+
+ "and col_jsonb=$10"
250262
+ ") p",
251263
transformDelete(
252264
"delete "
@@ -259,7 +271,8 @@ public void testTransformDeleteToSelectParams() {
259271
+ "and col_numeric=$6 "
260272
+ "and col_timestamptz=$7 "
261273
+ "and col_date=$8 "
262-
+ "and col_varchar=$9")
274+
+ "and col_varchar=$9 "
275+
+ "and col_jsonb=$10")
263276
.getSql());
264277

265278
assertNull(transformDelete("delete from foo"));
@@ -268,26 +281,14 @@ public void testTransformDeleteToSelectParams() {
268281
}
269282

270283
private static Statement transformInsert(String sql) {
271-
Set<String> parameters =
272-
ImmutableSortedSet.<String>orderedBy(Comparator.comparing(o -> o.substring(1)))
273-
.addAll(PARSER.getQueryParameters(sql))
274-
.build();
275-
return transformInsertToSelectParams(mock(Connection.class), sql, parameters);
284+
return transformInsertToSelectParams(mock(Connection.class), sql, extractParameters(sql));
276285
}
277286

278287
private static Statement transformUpdate(String sql) {
279-
Set<String> parameters =
280-
ImmutableSortedSet.<String>orderedBy(Comparator.comparing(o -> o.substring(1)))
281-
.addAll(PARSER.getQueryParameters(sql))
282-
.build();
283-
return transformUpdateToSelectParams(sql, parameters);
288+
return transformUpdateToSelectParams(sql, extractParameters(sql));
284289
}
285290

286291
private static Statement transformDelete(String sql) {
287-
Set<String> parameters =
288-
ImmutableSortedSet.<String>orderedBy(Comparator.comparing(o -> o.substring(1)))
289-
.addAll(PARSER.getQueryParameters(sql))
290-
.build();
291-
return transformDeleteToSelectParams(sql, parameters);
292+
return transformDeleteToSelectParams(sql, extractParameters(sql));
292293
}
293294
}

0 commit comments

Comments
 (0)