Support for PostgreSQL array syntax
Includes efficient separator determination. Issue: SPR-16340
This commit is contained in:
parent
d9af4d6599
commit
b2322e58d9
|
@ -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.
|
||||
|
@ -42,24 +42,33 @@ 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.
|
||||
*/
|
||||
private static final char[] PARAMETER_SEPARATORS =
|
||||
new char[] {'"', '\'', ':', '&', ',', ';', '(', ')', '|', '=', '+', '-', '*', '%', '/', '\\', '<', '>', '^'};
|
||||
|
||||
/**
|
||||
* Set of characters that qualify as comment or quotes starting characters.
|
||||
*/
|
||||
private static final String[] START_SKIP =
|
||||
new String[] {"'", "\"", "--", "/*"};
|
||||
private static final String[] START_SKIP = new String[] {"'", "\"", "--", "/*"};
|
||||
|
||||
/**
|
||||
* Set of characters that at are the corresponding comment or quotes ending characters.
|
||||
*/
|
||||
private static final String[] STOP_SKIP =
|
||||
new String[] {"'", "\"", "\n", "*/"};
|
||||
private static final String[] STOP_SKIP = new String[] {"'", "\"", "\n", "*/"};
|
||||
|
||||
/**
|
||||
* Set of characters that qualify as parameter separators,
|
||||
* indicating that a parameter name in a SQL String has ended.
|
||||
*/
|
||||
private static final String PARAMETER_SEPARATORS = "\"':&,;()[]|=+-*%/\\<>^";
|
||||
|
||||
/**
|
||||
* An index with separator flags per character code.
|
||||
* Technically only needed between 34 and 124 at this point.
|
||||
*/
|
||||
private static final boolean[] separatorIndex = new boolean[128];
|
||||
|
||||
static {
|
||||
for (char c : PARAMETER_SEPARATORS.toCharArray()) {
|
||||
separatorIndex[c] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
@ -233,7 +242,6 @@ public abstract class NamedParameterUtils {
|
|||
// character sequence ending comment or quote not found
|
||||
return statement.length;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return position;
|
||||
|
@ -384,15 +392,7 @@ public abstract class NamedParameterUtils {
|
|||
* that is, whether the given character qualifies as a separator.
|
||||
*/
|
||||
private static boolean isParameterSeparator(char c) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
return true;
|
||||
}
|
||||
for (char separator : PARAMETER_SEPARATORS) {
|
||||
if (c == separator) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return (separatorIndex[c] || Character.isWhitespace(c));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,8 +425,8 @@ public abstract class NamedParameterUtils {
|
|||
List<String> paramNames = parsedSql.getParameterNames();
|
||||
List<SqlParameter> params = new LinkedList<>();
|
||||
for (String paramName : paramNames) {
|
||||
params.add(
|
||||
new SqlParameter(paramName, paramSource.getSqlType(paramName), paramSource.getTypeName(paramName)));
|
||||
params.add(new SqlParameter(
|
||||
paramName, paramSource.getSqlType(paramName), paramSource.getTypeName(paramName)));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -22,6 +22,7 @@ import java.sql.PreparedStatement;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
|
@ -47,32 +48,45 @@ import static org.mockito.BDDMockito.*;
|
|||
* @author Rick Evans
|
||||
* @author Juergen Hoeller
|
||||
* @author Chris Beams
|
||||
* @author Nikita Khateev
|
||||
*/
|
||||
public class NamedParameterJdbcTemplateTests {
|
||||
|
||||
private static final String SELECT_NAMED_PARAMETERS =
|
||||
"select id, forename from custmr where id = :id and country = :country";
|
||||
"select id, forename from custmr where id = :id and country = :country";
|
||||
private static final String SELECT_NAMED_PARAMETERS_PARSED =
|
||||
"select id, forename from custmr where id = ? and country = ?";
|
||||
"select id, forename from custmr where id = ? and country = ?";
|
||||
private static final String SELECT_NO_PARAMETERS =
|
||||
"select id, forename from custmr";
|
||||
|
||||
private static final String UPDATE_NAMED_PARAMETERS =
|
||||
"update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId";
|
||||
"update seat_status set booking_id = null where performance_id = :perfId and price_band_id = :priceId";
|
||||
private static final String UPDATE_NAMED_PARAMETERS_PARSED =
|
||||
"update seat_status set booking_id = null where performance_id = ? and price_band_id = ?";
|
||||
"update seat_status set booking_id = null where performance_id = ? and price_band_id = ?";
|
||||
|
||||
private static final String UPDATE_ARRAY_PARAMETERS =
|
||||
"update customer set type = array[:typeIds] where id = :id";
|
||||
private static final String UPDATE_ARRAY_PARAMETERS_PARSED =
|
||||
"update customer set type = array[?, ?, ?] where id = ?";
|
||||
|
||||
private static final String[] COLUMN_NAMES = new String[] {"id", "forename"};
|
||||
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
private PreparedStatement preparedStatement;
|
||||
|
||||
private ResultSet resultSet;
|
||||
|
||||
private DatabaseMetaData databaseMetaData;
|
||||
|
||||
private Map<String, Object> params = new HashMap<>();
|
||||
|
||||
private NamedParameterJdbcTemplate namedParameterTemplate;
|
||||
|
||||
|
||||
|
@ -131,6 +145,31 @@ public class NamedParameterJdbcTemplateTests {
|
|||
verify(connection).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteArray() throws SQLException {
|
||||
given(preparedStatement.executeUpdate()).willReturn(1);
|
||||
|
||||
List<Integer> typeIds = Arrays.asList(1, 2, 3);
|
||||
|
||||
params.put("typeIds", typeIds);
|
||||
params.put("id", 1);
|
||||
Object result = namedParameterTemplate.execute(UPDATE_ARRAY_PARAMETERS, params,
|
||||
(PreparedStatementCallback<Object>) ps -> {
|
||||
assertEquals(preparedStatement, ps);
|
||||
ps.executeUpdate();
|
||||
return "result";
|
||||
});
|
||||
|
||||
assertEquals("result", result);
|
||||
verify(connection).prepareStatement(UPDATE_ARRAY_PARAMETERS_PARSED);
|
||||
verify(preparedStatement).setObject(1, 1);
|
||||
verify(preparedStatement).setObject(2, 2);
|
||||
verify(preparedStatement).setObject(3, 3);
|
||||
verify(preparedStatement).setObject(4, 1);
|
||||
verify(preparedStatement).close();
|
||||
verify(connection).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteWithTypedParameters() throws SQLException {
|
||||
given(preparedStatement.executeUpdate()).willReturn(1);
|
||||
|
|
Loading…
Reference in New Issue