Browse Source

Consistently return empty array in case of empty batch arguments

Issue: SPR-17476
pull/2013/head
Juergen Hoeller 6 years ago
parent
commit
362c59c310
  1. 13
      spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java
  2. 11
      spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterBatchUpdateUtils.java
  3. 60
      spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java
  4. 35
      spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplateTests.java

13
spring-jdbc/src/main/java/org/springframework/jdbc/core/BatchUpdateUtils.java

@ -1,5 +1,5 @@ @@ -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.
@ -27,24 +27,29 @@ import org.springframework.lang.Nullable; @@ -27,24 +27,29 @@ import org.springframework.lang.Nullable;
* Mainly for internal use within the framework.
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @since 3.0
*/
public abstract class BatchUpdateUtils {
public static int[] executeBatchUpdate(
String sql, final List<Object[]> batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) {
String sql, final List<Object[]> batchArgs, final int[] columnTypes, JdbcOperations jdbcOperations) {
if (batchArgs.isEmpty()) {
return new int[0];
}
return jdbcOperations.batchUpdate(
sql,
new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
Object[] values = batchValues.get(i);
Object[] values = batchArgs.get(i);
setStatementParameters(values, ps, columnTypes);
}
@Override
public int getBatchSize() {
return batchValues.size();
return batchArgs.size();
}
});
}

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

@ -1,5 +1,5 @@ @@ -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.
@ -28,15 +28,16 @@ import org.springframework.jdbc.core.JdbcOperations; @@ -28,15 +28,16 @@ import org.springframework.jdbc.core.JdbcOperations;
* Mainly for internal use within the framework.
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @since 3.0
*/
public abstract class NamedParameterBatchUpdateUtils extends BatchUpdateUtils {
public static int[] executeBatchUpdateWithNamedParameters(final ParsedSql parsedSql,
final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) {
public static int[] executeBatchUpdateWithNamedParameters(
final ParsedSql parsedSql, final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) {
if (batchArgs.length <= 0) {
return new int[] {0};
if (batchArgs.length == 0) {
return new int[0];
}
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, batchArgs[0]);

60
spring-jdbc/src/test/java/org/springframework/jdbc/core/JdbcTemplateTests.java

@ -192,7 +192,7 @@ public class JdbcTemplateTests { @@ -192,7 +192,7 @@ public class JdbcTemplateTests {
Object argument, JdbcTemplateCallback jdbcTemplateCallback) throws Exception {
String sql = "SELECT FORENAME FROM CUSTMR";
String[] results = { "rod", "gary", " portia" };
String[] results = {"rod", "gary", " portia"};
class StringHandler implements RowCallbackHandler {
private List<String> list = new LinkedList<>();
@ -491,8 +491,8 @@ public class JdbcTemplateTests { @@ -491,8 +491,8 @@ public class JdbcTemplateTests {
@Test
public void testBatchUpdateWithPreparedStatement() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] rowsAffected = new int[] { 1, 2 };
final int[] ids = new int[] {100, 200};
final int[] rowsAffected = new int[] {1, 2};
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
mockDatabaseMetaData(true);
@ -525,8 +525,8 @@ public class JdbcTemplateTests { @@ -525,8 +525,8 @@ public class JdbcTemplateTests {
@Test
public void testInterruptibleBatchUpdate() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] rowsAffected = new int[] { 1, 2 };
final int[] ids = new int[] {100, 200};
final int[] rowsAffected = new int[] {1, 2};
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
mockDatabaseMetaData(true);
@ -566,8 +566,8 @@ public class JdbcTemplateTests { @@ -566,8 +566,8 @@ public class JdbcTemplateTests {
@Test
public void testInterruptibleBatchUpdateWithBaseClass() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] rowsAffected = new int[] { 1, 2 };
final int[] ids = new int[] {100, 200};
final int[] rowsAffected = new int[] {1, 2};
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
mockDatabaseMetaData(true);
@ -603,8 +603,8 @@ public class JdbcTemplateTests { @@ -603,8 +603,8 @@ public class JdbcTemplateTests {
@Test
public void testInterruptibleBatchUpdateWithBaseClassAndNoBatchSupport() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] rowsAffected = new int[] { 1, 2 };
final int[] ids = new int[] {100, 200};
final int[] rowsAffected = new int[] {1, 2};
given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]);
mockDatabaseMetaData(false);
@ -640,8 +640,8 @@ public class JdbcTemplateTests { @@ -640,8 +640,8 @@ public class JdbcTemplateTests {
@Test
public void testBatchUpdateWithPreparedStatementAndNoBatchSupport() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] rowsAffected = new int[] { 1, 2 };
final int[] ids = new int[] {100, 200};
final int[] rowsAffected = new int[] {1, 2};
given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]);
@ -671,7 +671,7 @@ public class JdbcTemplateTests { @@ -671,7 +671,7 @@ public class JdbcTemplateTests {
@Test
public void testBatchUpdateFails() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final int[] ids = new int[] { 100, 200 };
final int[] ids = new int[] {100, 200};
SQLException sqlException = new SQLException();
given(this.preparedStatement.executeBatch()).willThrow(sqlException);
@ -702,6 +702,15 @@ public class JdbcTemplateTests { @@ -702,6 +702,15 @@ public class JdbcTemplateTests {
}
}
@Test
public void testBatchUpdateWithEmptyList() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
int[] actualRowsAffected = template.batchUpdate(sql, Collections.emptyList());
assertTrue("executed 0 updates", actualRowsAffected.length == 0);
}
@Test
public void testBatchUpdateWithListOfObjectArrays() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
@ -712,11 +721,9 @@ public class JdbcTemplateTests { @@ -712,11 +721,9 @@ public class JdbcTemplateTests {
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
mockDatabaseMetaData(true);
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
int[] actualRowsAffected = template.batchUpdate(sql, ids);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@ -739,10 +746,9 @@ public class JdbcTemplateTests { @@ -739,10 +746,9 @@ public class JdbcTemplateTests {
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
mockDatabaseMetaData(true);
this.template = new JdbcTemplate(this.dataSource, false);
int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes);
int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@ -757,8 +763,8 @@ public class JdbcTemplateTests { @@ -757,8 +763,8 @@ public class JdbcTemplateTests {
public void testBatchUpdateWithCollectionOfObjects() throws Exception {
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
final List<Integer> ids = Arrays.asList(100, 200, 300);
final int[] rowsAffected1 = new int[] { 1, 2 };
final int[] rowsAffected2 = new int[] { 3 };
final int[] rowsAffected1 = new int[] {1, 2};
final int[] rowsAffected2 = new int[] {3};
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected1, rowsAffected2);
mockDatabaseMetaData(true);
@ -781,19 +787,20 @@ public class JdbcTemplateTests { @@ -781,19 +787,20 @@ public class JdbcTemplateTests {
}
@Test
public void testCouldntGetConnectionForOperationOrExceptionTranslator() throws SQLException {
public void testCouldNotGetConnectionForOperationOrExceptionTranslator() throws SQLException {
SQLException sqlException = new SQLException("foo", "07xxx");
this.dataSource = mock(DataSource.class);
given(this.dataSource.getConnection()).willThrow(sqlException);
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
this.thrown.expect(CannotGetJdbcConnectionException.class);
this.thrown.expect(exceptionCause(sameInstance(sqlException)));
template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch);
}
@Test
public void testCouldntGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException {
public void testCouldNotGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException {
SQLException sqlException = new SQLException("foo", "07xxx");
this.dataSource = mock(DataSource.class);
given(this.dataSource.getConnection()).willThrow(sqlException);
@ -801,30 +808,31 @@ public class JdbcTemplateTests { @@ -801,30 +808,31 @@ public class JdbcTemplateTests {
this.template.setDataSource(this.dataSource);
this.template.afterPropertiesSet();
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
this.thrown.expect(CannotGetJdbcConnectionException.class);
this.thrown.expect(exceptionCause(sameInstance(sqlException)));
this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch);
}
@Test
public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty()
public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty()
throws SQLException {
doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(true);
doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(true);
}
@Test
public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet()
public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet()
throws SQLException {
doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(false);
doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(false);
}
/**
* If beanProperty is true, initialize via exception translator bean property;
* if false, use afterPropertiesSet().
*/
private void doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty)
private void doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty)
throws SQLException {
SQLException sqlException = new SQLException("foo", "07xxx");
@ -884,7 +892,7 @@ public class JdbcTemplateTests { @@ -884,7 +892,7 @@ public class JdbcTemplateTests {
}
@Test
public void testCouldntClose() throws Exception {
public void testCouldNotClose() throws Exception {
SQLException sqlException = new SQLException("bar");
given(this.connection.createStatement()).willReturn(this.statement);
given(this.resultSet.next()).willReturn(false);

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

@ -418,12 +418,10 @@ public class NamedParameterJdbcTemplateTests { @@ -418,12 +418,10 @@ public class NamedParameterJdbcTemplateTests {
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
given(connection.getMetaData()).willReturn(databaseMetaData);
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
JdbcTemplate template = new JdbcTemplate(dataSource, false);
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
assertSame(template, namedParameterTemplate.getJdbcTemplate());
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@ -435,6 +433,17 @@ public class NamedParameterJdbcTemplateTests { @@ -435,6 +433,17 @@ public class NamedParameterJdbcTemplateTests {
verify(connection, atLeastOnce()).close();
}
@Test
public void testBatchUpdateWithEmptyMap() throws Exception {
@SuppressWarnings("unchecked")
final Map<String, Integer>[] ids = new Map[0];
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertTrue("executed 0 updates", actualRowsAffected.length == 0);
}
@Test
public void testBatchUpdateWithSqlParameterSource() throws Exception {
SqlParameterSource[] ids = new SqlParameterSource[2];
@ -444,12 +453,10 @@ public class NamedParameterJdbcTemplateTests { @@ -444,12 +453,10 @@ public class NamedParameterJdbcTemplateTests {
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
given(connection.getMetaData()).willReturn(databaseMetaData);
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
JdbcTemplate template = new JdbcTemplate(dataSource, false);
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
assertSame(template, namedParameterTemplate.getJdbcTemplate());
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@ -470,12 +477,10 @@ public class NamedParameterJdbcTemplateTests { @@ -470,12 +477,10 @@ public class NamedParameterJdbcTemplateTests {
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
given(connection.getMetaData()).willReturn(databaseMetaData);
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
JdbcTemplate template = new JdbcTemplate(dataSource, false);
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
assertSame(template, namedParameterTemplate.getJdbcTemplate());
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
assertEquals(rowsAffected[0], actualRowsAffected[0]);
assertEquals(rowsAffected[1], actualRowsAffected[1]);

Loading…
Cancel
Save