diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/StoredProcedureItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/StoredProcedureItemReader.java index c8eb7844f..8488585dd 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/StoredProcedureItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/StoredProcedureItemReader.java @@ -151,8 +151,11 @@ public class StoredProcedureItemReader extends AbstractCursorItemReader { protected void openCursor(Connection con) { Assert.state(procedureName != null, "Procedure Name must not be null."); - Assert.state(refCursorPosition == 0 || refCursorPosition > parameters.length, - "refCursorPosition specified as " + refCursorPosition + " but there are only " + + Assert.state(refCursorPosition >= 0, + "invalid refCursorPosition specified as " + refCursorPosition + "; it can't be " + + "specified as a negative number."); + Assert.state(refCursorPosition == 0 || refCursorPosition > 0, + "invalid refCursorPosition specified as " + refCursorPosition + "; there are " + parameters.length + " parameters defined."); CallMetaDataContext callContext = new CallMetaDataContext(); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/StoredprocedureItemReaderConfigTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/StoredprocedureItemReaderConfigTests.java index 30991a77b..3432a0bdd 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/StoredprocedureItemReaderConfigTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/StoredprocedureItemReaderConfigTests.java @@ -9,14 +9,19 @@ import static org.easymock.EasyMock.verify; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import javax.sql.DataSource; +import org.hsqldb.Types; import org.junit.Test; import org.junit.internal.runners.JUnit4ClassRunner; import org.junit.runner.RunWith; import org.springframework.batch.item.ExecutionContext; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.SqlParameter; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; @@ -99,4 +104,49 @@ public class StoredprocedureItemReaderConfigTests { verify(ds); } + /* + * Should fail if trying to call getConnection() twice + */ + @Test + public void testHandlesRefCursorPosition() throws Exception { + + DataSource ds = createMock(DataSource.class); + DatabaseMetaData dmd = createNiceMock(DatabaseMetaData.class); + expect(dmd.getDatabaseProductName()).andReturn("Oracle").times(2); + Connection con = createMock(Connection.class); + expect(con.getMetaData()).andReturn(dmd); + expect(con.getMetaData()).andReturn(dmd); + expect(con.getAutoCommit()).andReturn(false); + CallableStatement cs = createNiceMock(CallableStatement.class); + expect(con.prepareCall("{call foo_bar(?, ?)}", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)).andReturn(cs); + expect(ds.getConnection()).andReturn(con); + expect(ds.getConnection()).andReturn(con); + con.commit(); + replay(con,dmd, ds, cs); + PlatformTransactionManager tm = new DataSourceTransactionManager(ds); + TransactionTemplate tt = new TransactionTemplate(tm); + final StoredProcedureItemReader reader = new StoredProcedureItemReader(); + reader.setDataSource(ds); + reader.setProcedureName("foo_bar"); + reader.setParameters(new SqlParameter[] { + new SqlParameter("foo", Types.VARCHAR), + new SqlParameter("bar", Types.OTHER)}); + reader.setPreparedStatementSetter( + new PreparedStatementSetter() { + public void setValues(PreparedStatement ps) + throws SQLException { + } + }); + reader.setRefCursorPosition(3); + final ExecutionContext ec = new ExecutionContext(); + tt.execute( + new TransactionCallback() { + public Object doInTransaction(TransactionStatus status) { + reader.open(ec); + reader.close(); + return null; + } + }); + verify(ds); + } }