Skip to content

Commit 362c59c

Browse files
committed
Consistently return empty array in case of empty batch arguments
Issue: SPR-17476
1 parent b6e8674 commit 362c59c

File tree

4 files changed

+69
-50
lines changed

4 files changed

+69
-50
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -27,24 +27,29 @@
2727
* Mainly for internal use within the framework.
2828
*
2929
* @author Thomas Risberg
30+
* @author Juergen Hoeller
3031
* @since 3.0
3132
*/
3233
public abstract class BatchUpdateUtils {
3334

3435
public static int[] executeBatchUpdate(
35-
String sql, final List<Object[]> batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) {
36+
String sql, final List<Object[]> batchArgs, final int[] columnTypes, JdbcOperations jdbcOperations) {
37+
38+
if (batchArgs.isEmpty()) {
39+
return new int[0];
40+
}
3641

3742
return jdbcOperations.batchUpdate(
3843
sql,
3944
new BatchPreparedStatementSetter() {
4045
@Override
4146
public void setValues(PreparedStatement ps, int i) throws SQLException {
42-
Object[] values = batchValues.get(i);
47+
Object[] values = batchArgs.get(i);
4348
setStatementParameters(values, ps, columnTypes);
4449
}
4550
@Override
4651
public int getBatchSize() {
47-
return batchValues.size();
52+
return batchArgs.size();
4853
}
4954
});
5055
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -28,15 +28,16 @@
2828
* Mainly for internal use within the framework.
2929
*
3030
* @author Thomas Risberg
31+
* @author Juergen Hoeller
3132
* @since 3.0
3233
*/
3334
public abstract class NamedParameterBatchUpdateUtils extends BatchUpdateUtils {
3435

35-
public static int[] executeBatchUpdateWithNamedParameters(final ParsedSql parsedSql,
36-
final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) {
36+
public static int[] executeBatchUpdateWithNamedParameters(
37+
final ParsedSql parsedSql, final SqlParameterSource[] batchArgs, JdbcOperations jdbcOperations) {
3738

38-
if (batchArgs.length <= 0) {
39-
return new int[] {0};
39+
if (batchArgs.length == 0) {
40+
return new int[0];
4041
}
4142

4243
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, batchArgs[0]);

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

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ private void doTestStrings(Integer fetchSize, Integer maxRows, Integer queryTime
192192
Object argument, JdbcTemplateCallback jdbcTemplateCallback) throws Exception {
193193

194194
String sql = "SELECT FORENAME FROM CUSTMR";
195-
String[] results = { "rod", "gary", " portia" };
195+
String[] results = {"rod", "gary", " portia"};
196196

197197
class StringHandler implements RowCallbackHandler {
198198
private List<String> list = new LinkedList<>();
@@ -491,8 +491,8 @@ public void testBatchUpdateWithNoBatchSupportAndSelect() throws Exception {
491491
@Test
492492
public void testBatchUpdateWithPreparedStatement() throws Exception {
493493
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
494-
final int[] ids = new int[] { 100, 200 };
495-
final int[] rowsAffected = new int[] { 1, 2 };
494+
final int[] ids = new int[] {100, 200};
495+
final int[] rowsAffected = new int[] {1, 2};
496496

497497
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
498498
mockDatabaseMetaData(true);
@@ -525,8 +525,8 @@ public int getBatchSize() {
525525
@Test
526526
public void testInterruptibleBatchUpdate() throws Exception {
527527
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
528-
final int[] ids = new int[] { 100, 200 };
529-
final int[] rowsAffected = new int[] { 1, 2 };
528+
final int[] ids = new int[] {100, 200};
529+
final int[] rowsAffected = new int[] {1, 2};
530530

531531
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
532532
mockDatabaseMetaData(true);
@@ -566,8 +566,8 @@ public boolean isBatchExhausted(int i) {
566566
@Test
567567
public void testInterruptibleBatchUpdateWithBaseClass() throws Exception {
568568
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
569-
final int[] ids = new int[] { 100, 200 };
570-
final int[] rowsAffected = new int[] { 1, 2 };
569+
final int[] ids = new int[] {100, 200};
570+
final int[] rowsAffected = new int[] {1, 2};
571571

572572
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
573573
mockDatabaseMetaData(true);
@@ -603,8 +603,8 @@ protected boolean setValuesIfAvailable(PreparedStatement ps, int i) throws SQLEx
603603
@Test
604604
public void testInterruptibleBatchUpdateWithBaseClassAndNoBatchSupport() throws Exception {
605605
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
606-
final int[] ids = new int[] { 100, 200 };
607-
final int[] rowsAffected = new int[] { 1, 2 };
606+
final int[] ids = new int[] {100, 200};
607+
final int[] rowsAffected = new int[] {1, 2};
608608

609609
given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]);
610610
mockDatabaseMetaData(false);
@@ -640,8 +640,8 @@ protected boolean setValuesIfAvailable(PreparedStatement ps, int i) throws SQLEx
640640
@Test
641641
public void testBatchUpdateWithPreparedStatementAndNoBatchSupport() throws Exception {
642642
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
643-
final int[] ids = new int[] { 100, 200 };
644-
final int[] rowsAffected = new int[] { 1, 2 };
643+
final int[] ids = new int[] {100, 200};
644+
final int[] rowsAffected = new int[] {1, 2};
645645

646646
given(this.preparedStatement.executeUpdate()).willReturn(rowsAffected[0], rowsAffected[1]);
647647

@@ -671,7 +671,7 @@ public int getBatchSize() {
671671
@Test
672672
public void testBatchUpdateFails() throws Exception {
673673
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
674-
final int[] ids = new int[] { 100, 200 };
674+
final int[] ids = new int[] {100, 200};
675675
SQLException sqlException = new SQLException();
676676

677677
given(this.preparedStatement.executeBatch()).willThrow(sqlException);
@@ -702,6 +702,15 @@ public int getBatchSize() {
702702
}
703703
}
704704

705+
@Test
706+
public void testBatchUpdateWithEmptyList() throws Exception {
707+
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
708+
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
709+
710+
int[] actualRowsAffected = template.batchUpdate(sql, Collections.emptyList());
711+
assertTrue("executed 0 updates", actualRowsAffected.length == 0);
712+
}
713+
705714
@Test
706715
public void testBatchUpdateWithListOfObjectArrays() throws Exception {
707716
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
@@ -712,11 +721,9 @@ public void testBatchUpdateWithListOfObjectArrays() throws Exception {
712721

713722
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
714723
mockDatabaseMetaData(true);
715-
716724
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
717725

718726
int[] actualRowsAffected = template.batchUpdate(sql, ids);
719-
720727
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
721728
assertEquals(rowsAffected[0], actualRowsAffected[0]);
722729
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@@ -739,10 +746,9 @@ public void testBatchUpdateWithListOfObjectArraysPlusTypeInfo() throws Exception
739746

740747
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected);
741748
mockDatabaseMetaData(true);
742-
743749
this.template = new JdbcTemplate(this.dataSource, false);
744-
int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes);
745750

751+
int[] actualRowsAffected = this.template.batchUpdate(sql, ids, sqlTypes);
746752
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
747753
assertEquals(rowsAffected[0], actualRowsAffected[0]);
748754
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@@ -757,8 +763,8 @@ public void testBatchUpdateWithListOfObjectArraysPlusTypeInfo() throws Exception
757763
public void testBatchUpdateWithCollectionOfObjects() throws Exception {
758764
final String sql = "UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = ?";
759765
final List<Integer> ids = Arrays.asList(100, 200, 300);
760-
final int[] rowsAffected1 = new int[] { 1, 2 };
761-
final int[] rowsAffected2 = new int[] { 3 };
766+
final int[] rowsAffected1 = new int[] {1, 2};
767+
final int[] rowsAffected2 = new int[] {3};
762768

763769
given(this.preparedStatement.executeBatch()).willReturn(rowsAffected1, rowsAffected2);
764770
mockDatabaseMetaData(true);
@@ -781,50 +787,52 @@ public void testBatchUpdateWithCollectionOfObjects() throws Exception {
781787
}
782788

783789
@Test
784-
public void testCouldntGetConnectionForOperationOrExceptionTranslator() throws SQLException {
790+
public void testCouldNotGetConnectionForOperationOrExceptionTranslator() throws SQLException {
785791
SQLException sqlException = new SQLException("foo", "07xxx");
786792
this.dataSource = mock(DataSource.class);
787793
given(this.dataSource.getConnection()).willThrow(sqlException);
788794
JdbcTemplate template = new JdbcTemplate(this.dataSource, false);
789795
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
796+
790797
this.thrown.expect(CannotGetJdbcConnectionException.class);
791798
this.thrown.expect(exceptionCause(sameInstance(sqlException)));
792799
template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch);
793800
}
794801

795802
@Test
796-
public void testCouldntGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException {
803+
public void testCouldNotGetConnectionForOperationWithLazyExceptionTranslator() throws SQLException {
797804
SQLException sqlException = new SQLException("foo", "07xxx");
798805
this.dataSource = mock(DataSource.class);
799806
given(this.dataSource.getConnection()).willThrow(sqlException);
800807
this.template = new JdbcTemplate();
801808
this.template.setDataSource(this.dataSource);
802809
this.template.afterPropertiesSet();
803810
RowCountCallbackHandler rcch = new RowCountCallbackHandler();
811+
804812
this.thrown.expect(CannotGetJdbcConnectionException.class);
805813
this.thrown.expect(exceptionCause(sameInstance(sqlException)));
806814
this.template.query("SELECT ID, FORENAME FROM CUSTMR WHERE ID < 3", rcch);
807815
}
808816

809817
@Test
810-
public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty()
818+
public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedViaBeanProperty()
811819
throws SQLException {
812820

813-
doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(true);
821+
doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(true);
814822
}
815823

816824
@Test
817-
public void testCouldntGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet()
825+
public void testCouldNotGetConnectionInOperationWithExceptionTranslatorInitializedInAfterPropertiesSet()
818826
throws SQLException {
819827

820-
doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(false);
828+
doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(false);
821829
}
822830

823831
/**
824832
* If beanProperty is true, initialize via exception translator bean property;
825833
* if false, use afterPropertiesSet().
826834
*/
827-
private void doTestCouldntGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty)
835+
private void doTestCouldNotGetConnectionInOperationWithExceptionTranslatorInitialized(boolean beanProperty)
828836
throws SQLException {
829837

830838
SQLException sqlException = new SQLException("foo", "07xxx");
@@ -884,7 +892,7 @@ public void testPreparedStatementSetterFails() throws Exception {
884892
}
885893

886894
@Test
887-
public void testCouldntClose() throws Exception {
895+
public void testCouldNotClose() throws Exception {
888896
SQLException sqlException = new SQLException("bar");
889897
given(this.connection.createStatement()).willReturn(this.statement);
890898
given(this.resultSet.next()).willReturn(false);

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -418,12 +418,10 @@ public void testBatchUpdateWithPlainMap() throws Exception {
418418

419419
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
420420
given(connection.getMetaData()).willReturn(databaseMetaData);
421+
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
421422

422-
JdbcTemplate template = new JdbcTemplate(dataSource, false);
423-
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
424-
assertSame(template, namedParameterTemplate.getJdbcTemplate());
425-
426-
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
423+
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
424+
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
427425
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
428426
assertEquals(rowsAffected[0], actualRowsAffected[0]);
429427
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@@ -435,6 +433,17 @@ public void testBatchUpdateWithPlainMap() throws Exception {
435433
verify(connection, atLeastOnce()).close();
436434
}
437435

436+
@Test
437+
public void testBatchUpdateWithEmptyMap() throws Exception {
438+
@SuppressWarnings("unchecked")
439+
final Map<String, Integer>[] ids = new Map[0];
440+
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
441+
442+
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
443+
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
444+
assertTrue("executed 0 updates", actualRowsAffected.length == 0);
445+
}
446+
438447
@Test
439448
public void testBatchUpdateWithSqlParameterSource() throws Exception {
440449
SqlParameterSource[] ids = new SqlParameterSource[2];
@@ -444,12 +453,10 @@ public void testBatchUpdateWithSqlParameterSource() throws Exception {
444453

445454
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
446455
given(connection.getMetaData()).willReturn(databaseMetaData);
456+
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
447457

448-
JdbcTemplate template = new JdbcTemplate(dataSource, false);
449-
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
450-
assertSame(template, namedParameterTemplate.getJdbcTemplate());
451-
452-
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
458+
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
459+
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
453460
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
454461
assertEquals(rowsAffected[0], actualRowsAffected[0]);
455462
assertEquals(rowsAffected[1], actualRowsAffected[1]);
@@ -470,12 +477,10 @@ public void testBatchUpdateWithSqlParameterSourcePlusTypeInfo() throws Exception
470477

471478
given(preparedStatement.executeBatch()).willReturn(rowsAffected);
472479
given(connection.getMetaData()).willReturn(databaseMetaData);
480+
namedParameterTemplate = new NamedParameterJdbcTemplate(new JdbcTemplate(dataSource, false));
473481

474-
JdbcTemplate template = new JdbcTemplate(dataSource, false);
475-
namedParameterTemplate = new NamedParameterJdbcTemplate(template);
476-
assertSame(template, namedParameterTemplate.getJdbcTemplate());
477-
478-
int[] actualRowsAffected = namedParameterTemplate.batchUpdate("UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
482+
int[] actualRowsAffected = namedParameterTemplate.batchUpdate(
483+
"UPDATE NOSUCHTABLE SET DATE_DISPATCHED = SYSDATE WHERE ID = :id", ids);
479484
assertTrue("executed 2 updates", actualRowsAffected.length == 2);
480485
assertEquals(rowsAffected[0], actualRowsAffected[0]);
481486
assertEquals(rowsAffected[1], actualRowsAffected[1]);

0 commit comments

Comments
 (0)