diff --git a/spring-batch-core-tests/pom.xml b/spring-batch-core-tests/pom.xml
index d1dab9180..bed360b3b 100644
--- a/spring-batch-core-tests/pom.xml
+++ b/spring-batch-core-tests/pom.xml
@@ -108,7 +108,6 @@
commons-lang
commons-lang
- test
org.apache.derby
diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml
index e9899a6af..64a06307e 100644
--- a/spring-batch-infrastructure/pom.xml
+++ b/spring-batch-infrastructure/pom.xml
@@ -109,6 +109,11 @@
h2
test
+
+ org.apache.derby
+ derby
+ test
+
org.hibernate
hibernate-core
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DerbyPagingQueryProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DerbyPagingQueryProvider.java
index d9c769aa1..1878032a6 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DerbyPagingQueryProvider.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DerbyPagingQueryProvider.java
@@ -39,4 +39,15 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider {
throw new InvalidDataAccessResourceUsageException("Apache Derby version " + version + " is not supported by this class, Only version 10.4.1.3 or later is supported");
}
}
+
+ @Override
+ protected Object getSubQueryAlias() {
+ return "AS TMP_SUB ";
+ }
+
+ @Override
+ protected String getOverClause() {
+ return "";
+ }
+
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/OraclePagingQueryProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/OraclePagingQueryProvider.java
index df45606ab..e8eb4f86f 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/OraclePagingQueryProvider.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/OraclePagingQueryProvider.java
@@ -17,13 +17,14 @@
package org.springframework.batch.item.database.support;
/**
- * Oracle implementation of a {@link org.springframework.batch.item.database.PagingQueryProvider} using
+ * Oracle implementation of a
+ * {@link org.springframework.batch.item.database.PagingQueryProvider} using
* database specific features.
- *
+ *
* @author Thomas Risberg
* @since 2.0
*/
-public class OraclePagingQueryProvider extends SqlWindowingPagingQueryProvider {
+public class OraclePagingQueryProvider extends AbstractSqlPagingQueryProvider {
@Override
public String generateFirstPageQuery(int pageSize) {
@@ -36,6 +37,15 @@ public class OraclePagingQueryProvider extends SqlWindowingPagingQueryProvider {
return SqlPagingQueryUtils.generateRowNumSqlQuery(this, true, buildRowNumClause(pageSize));
}
+ @Override
+ public String generateJumpToItemQuery(int itemIndex, int pageSize) {
+ int page = itemIndex / pageSize;
+ int offset = (page * pageSize);
+ offset = offset==0 ? 1 : offset;
+ return SqlPagingQueryUtils.generateRowNumSqlQuery(this, this.getSortKey() + " AS SORT_KEY", false,
+ "ROWNUM = " + offset);
+ }
+
private String buildRowNumClause(int pageSize) {
return new StringBuilder().append("ROWNUM <= ").append(pageSize).toString();
}
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryUtils.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryUtils.java
index f59d63839..763424d27 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryUtils.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryUtils.java
@@ -76,15 +76,32 @@ public class SqlPagingQueryUtils {
*
* @param provider {@link AbstractSqlPagingQueryProvider} providing the
* implementation specifics
- * @param remainingPageQuery is this query for the ramining pages (true) as
+ * @param remainingPageQuery is this query for the remaining pages (true) as
* opposed to the first page (false)
* @param rowNumClause the implementation specific row num clause to be used
* @return the generated query
*/
public static String generateRowNumSqlQuery(AbstractSqlPagingQueryProvider provider, boolean remainingPageQuery,
String rowNumClause) {
+
+ return generateRowNumSqlQuery(provider, provider.getSelectClause(), remainingPageQuery, rowNumClause);
+
+ }
+
+ /**
+ * Generate SQL query string using a ROW_NUM condition
+ *
+ * @param provider {@link AbstractSqlPagingQueryProvider} providing the
+ * implementation specifics
+ * @param remainingPageQuery is this query for the remaining pages (true) as
+ * opposed to the first page (false)
+ * @param rowNumClause the implementation specific row num clause to be used
+ * @return the generated query
+ */
+ public static String generateRowNumSqlQuery(AbstractSqlPagingQueryProvider provider, String selectClause, boolean remainingPageQuery,
+ String rowNumClause) {
StringBuilder sql = new StringBuilder();
- sql.append("SELECT * FROM (SELECT ").append(provider.getSelectClause());
+ sql.append("SELECT * FROM (SELECT ").append(selectClause);
sql.append(" FROM ").append(provider.getFromClause());
buildWhereClause(provider, remainingPageQuery, sql);
sql.append(" ORDER BY ").append(provider.getSortKey());
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlWindowingPagingQueryProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlWindowingPagingQueryProvider.java
index b885e84a2..670579c89 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlWindowingPagingQueryProvider.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlWindowingPagingQueryProvider.java
@@ -17,9 +17,10 @@
package org.springframework.batch.item.database.support;
/**
- * Generic Paging Query Provider using standard SQL:2003 windowing functions. These features are supported by
- * DB2, Oracle, SQL Server 2005, Sybase and Apache Derby version 10.4.1.3
- *
+ * Generic Paging Query Provider using standard SQL:2003 windowing functions.
+ * These features are supported by DB2, Oracle, SQL Server 2005, Sybase and
+ * Apache Derby version 10.4.1.3
+ *
* @author Thomas Risberg
* @since 2.0
*/
@@ -30,22 +31,25 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ( ");
sql.append("SELECT ").append(getSelectClause()).append(", ");
- sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
- buildAscendingClause(sql);
+ sql.append("ROW_NUMBER() OVER (").append(getOverClause());
sql.append(") AS ROW_NUMBER");
- sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
- sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
+ sql.append(" FROM ").append(getFromClause()).append(
+ getWhereClause() == null ? "" : " WHERE " + getWhereClause());
+ sql.append(") ").append(getSubQueryAlias()).append("WHERE ROW_NUMBER <= ").append(pageSize);
return sql.toString();
}
+ protected Object getSubQueryAlias() {
+ return "";
+ }
+
@Override
public String generateRemainingPagesQuery(int pageSize) {
StringBuilder sql = new StringBuilder();
sql.append("SELECT * FROM ( ");
sql.append("SELECT ").append(getSelectClause()).append(", ");
- sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
- buildAscendingClause(sql);
+ sql.append("ROW_NUMBER() OVER (").append(getOverClause());
sql.append(") AS ROW_NUMBER");
sql.append(" FROM ").append(getFromClause());
sql.append(" WHERE ");
@@ -61,7 +65,7 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
sql.append(" < ");
}
sql.append(getSortKeyPlaceHolder());
- sql.append(") WHERE ROW_NUMBER <= ").append(pageSize);
+ sql.append(") ").append(getSubQueryAlias()).append("WHERE ROW_NUMBER <= ").append(pageSize);
return sql.toString();
}
@@ -70,28 +74,32 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi
public String generateJumpToItemQuery(int itemIndex, int pageSize) {
int page = itemIndex / pageSize;
int lastRowNum = (page * pageSize);
- if (lastRowNum<=0) {
+ if (lastRowNum <= 0) {
lastRowNum = 1;
}
StringBuilder sql = new StringBuilder();
sql.append("SELECT SORT_KEY FROM ( ");
sql.append("SELECT ").append(getSortKey()).append(" AS SORT_KEY, ");
- sql.append("ROW_NUMBER() OVER (ORDER BY ").append(getSortKey());
- buildAscendingClause(sql);
+ sql.append("ROW_NUMBER() OVER (").append(getOverClause());
sql.append(") AS ROW_NUMBER");
- sql.append(" FROM ").append(getFromClause()).append(getWhereClause() == null ? "" : " WHERE " + getWhereClause());
- sql.append(") WHERE ROW_NUMBER = ").append(lastRowNum);
+ sql.append(" FROM ").append(getFromClause()).append(
+ getWhereClause() == null ? "" : " WHERE " + getWhereClause());
+ sql.append(") ").append(getSubQueryAlias()).append("WHERE ROW_NUMBER = ").append(lastRowNum);
return sql.toString();
}
- private void buildAscendingClause(StringBuilder sql) {
+ protected String getOverClause() {
+ return "ORDER BY " + getSortKey() + " " + getAscendingClause();
+ }
+
+ private String getAscendingClause() {
if (isAscending()) {
- sql.append(" ASC");
+ return "ASC";
}
else {
- sql.append(" DESC");
+ return "DESC";
}
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderTests.java
index 98b47cab8..1e7420645 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderTests.java
@@ -15,19 +15,21 @@
*/
package org.springframework.batch.item.database.support;
-import static org.junit.Assert.fail;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
-import org.junit.Test;
-import org.junit.Assert;
-import org.springframework.dao.InvalidDataAccessResourceUsageException;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
import javax.sql.DataSource;
-import java.sql.DatabaseMetaData;
-import java.sql.Connection;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.dao.InvalidDataAccessResourceUsageException;
/**
* @author Thomas Risberg
@@ -69,7 +71,8 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide
try {
pagingQueryProvider.init(ds);
fail();
- } catch (InvalidDataAccessResourceUsageException e) {
+ }
+ catch (InvalidDataAccessResourceUsageException e) {
// expected
}
verify(ds);
@@ -80,30 +83,55 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide
@Test
@Override
public void testGenerateFirstPageQuery() {
- String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER <= 100";
+ String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1) AS TMP_SUB WHERE ROW_NUMBER <= 100";
String s = pagingQueryProvider.generateFirstPageQuery(pageSize);
Assert.assertEquals("", sql, s);
}
- @Test @Override
+ @Test
+ @Override
public void testGenerateRemainingPagesQuery() {
- String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1 AND id > ?) WHERE ROW_NUMBER <= 100";
+ String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1 AND id > ?) AS TMP_SUB WHERE ROW_NUMBER <= 100";
String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize);
Assert.assertEquals("", sql, s);
}
- @Test @Override
+ @Test
+ @Override
public void testGenerateJumpToItemQuery() {
- String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 100";
+ String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1) AS TMP_SUB WHERE ROW_NUMBER = 100";
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
- @Test @Override
+ @Test
+ @Override
public void testGenerateJumpToItemQueryForFirstPage() {
- String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
+ String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1) AS TMP_SUB WHERE ROW_NUMBER = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
+ /**
+ * Derby doesn't allow order by in the sub select (so it's pretty useless in
+ * general for paging)
+ */
+ @Test
+ @Override
+ public void testQueryContainsSortKey() {
+ String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase();
+ assertFalse("Wrong query: " + s, s.contains("id asc"));
+ }
+
+ /**
+ * Derby doesn't allow order by in the sub select
+ */
+ @Test
+ @Override
+ public void testQueryContainsSortKeyDesc() {
+ pagingQueryProvider.setAscending(false);
+ String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase();
+ assertFalse("Wrong query: " + s, s.contains("id desc"));
+ }
+
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderTests.java
index 628de16b6..6983d2504 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderTests.java
@@ -33,14 +33,14 @@ public class OraclePagingQueryProviderTests extends AbstractSqlPagingQueryProvid
@Test @Override
public void testGenerateJumpToItemQuery() {
- String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 100";
+ String sql = "SELECT * FROM (SELECT id AS SORT_KEY FROM foo WHERE bar = 1 ORDER BY id ASC) WHERE ROWNUM = 100";
String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize);
Assert.assertEquals("", sql, s);
}
@Test @Override
public void testGenerateJumpToItemQueryForFirstPage() {
- String sql = "SELECT SORT_KEY FROM ( SELECT id AS SORT_KEY, ROW_NUMBER() OVER (ORDER BY id ASC) AS ROW_NUMBER FROM foo WHERE bar = 1) WHERE ROW_NUMBER = 1";
+ String sql = "SELECT * FROM (SELECT id AS SORT_KEY FROM foo WHERE bar = 1 ORDER BY id ASC) WHERE ROWNUM = 1";
String s = pagingQueryProvider.generateJumpToItemQuery(45, pageSize);
Assert.assertEquals("", sql, s);
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeIntegrationTests.java
index eca7e389f..5c6baec0d 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeIntegrationTests.java
@@ -22,18 +22,26 @@ import javax.sql.DataSource;
import org.junit.Test;
-
/**
* @author Dave Syer
- *
+ *
*/
public class DatabaseTypeIntegrationTests {
-
+
@Test
public void testH2() throws Exception {
- DataSource dataSource = DatabaseTypeTestUtils.getDataSource(org.h2.Driver.class, "jdbc:h2:file:target/data/sample");
+ DataSource dataSource = DatabaseTypeTestUtils.getDataSource(org.h2.Driver.class,
+ "jdbc:h2:file:target/data/sample");
assertEquals(DatabaseType.H2, DatabaseType.fromMetaData(dataSource));
dataSource.getConnection();
}
+ @Test
+ public void testDerby() throws Exception {
+ DataSource dataSource = DatabaseTypeTestUtils.getDataSource(org.apache.derby.jdbc.EmbeddedDriver.class,
+ "jdbc:derby:derby-home/test;create=true", "sa", "");
+ assertEquals(DatabaseType.DERBY, DatabaseType.fromMetaData(dataSource));
+ dataSource.getConnection();
+ }
+
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTestUtils.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTestUtils.java
index fc04c9546..dc12f27a6 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTestUtils.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/support/DatabaseTypeTestUtils.java
@@ -32,12 +32,18 @@ import org.apache.commons.dbcp.BasicDataSource;
*/
public class DatabaseTypeTestUtils {
- public static DataSource getDataSource(Class> driver, String url) throws Exception {
+ public static DataSource getDataSource(Class> driver, String url, String username, String password) throws Exception {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(driver.getName());
dataSource.setUrl(url);
+ dataSource.setUsername(username);
+ dataSource.setPassword(password);
return dataSource;
}
+
+ public static DataSource getDataSource(Class> driver, String url) throws Exception {
+ return getDataSource(driver, url, null, null);
+ }
public static DataSource getMockDataSource() throws Exception {
return getMockDataSource(DatabaseType.HSQL.getProductName());
diff --git a/spring-batch-samples/src/main/resources/batch-derby.properties b/spring-batch-samples/src/main/resources/batch-derby.properties
index 9270541d1..380004cd1 100644
--- a/spring-batch-samples/src/main/resources/batch-derby.properties
+++ b/spring-batch-samples/src/main/resources/batch-derby.properties
@@ -4,15 +4,13 @@ batch.jdbc.driver=org.apache.derby.jdbc.EmbeddedDriver
batch.jdbc.url=jdbc:derby:derby-home/test;create=true
batch.jdbc.user=sa
batch.jdbc.password=
-batch.schema=
-batch.jndi.name=
-batch.naming.factory.initial=
-batch.naming.provider.url=
-batch.schema.script=/org/springframework/batch/core/schema-derby.sql
+batch.jdbc.testWhileIdle=false
+batch.jdbc.validationQuery=
+batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-derby.sql
+batch.schema.script=classpath:/org/springframework/batch/core/schema-derby.sql
batch.business.schema.script=business-schema-derby.sql
+batch.data.source.init=true
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.DerbyMaxValueIncrementer
-batch.lob.handler.class=org.springframework.jdbc.support.lob.DefaultLobHandler
-
-# Bean Properties for override
-# when not using sequences:
-incrementerParent.columnName=ID
+batch.database.incrementer.parent=columnIncrementerParent
+batch.grid.size=2
+batch.verify.cursor.position=false
\ No newline at end of file
diff --git a/spring-batch-samples/src/main/resources/batch-hsql.properties b/spring-batch-samples/src/main/resources/batch-hsql.properties
index 362846da7..87d2d3919 100644
--- a/spring-batch-samples/src/main/resources/batch-hsql.properties
+++ b/spring-batch-samples/src/main/resources/batch-hsql.properties
@@ -15,3 +15,4 @@ batch.data.source.init=true
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer
batch.database.incrementer.parent=columnIncrementerParent
batch.grid.size=2
+batch.verify.cursor.position=true
diff --git a/spring-batch-samples/src/main/resources/batch-mysql.properties b/spring-batch-samples/src/main/resources/batch-mysql.properties
index 59bc4a9a4..4fe7a243e 100644
--- a/spring-batch-samples/src/main/resources/batch-mysql.properties
+++ b/spring-batch-samples/src/main/resources/batch-mysql.properties
@@ -13,3 +13,4 @@ batch.data.source.init=true
batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer
batch.database.incrementer.parent=columnIncrementerParent
batch.grid.size=50
+batch.verify.cursor.position=true
diff --git a/spring-batch-samples/src/main/resources/data-source-context.xml b/spring-batch-samples/src/main/resources/data-source-context.xml
index ae90208ce..2399ec377 100644
--- a/spring-batch-samples/src/main/resources/data-source-context.xml
+++ b/spring-batch-samples/src/main/resources/data-source-context.xml
@@ -28,16 +28,17 @@
-
+
+
-
+
@@ -49,7 +50,7 @@
-
+
diff --git a/spring-batch-samples/src/main/resources/jobs/iosample/jdbcPaging.xml b/spring-batch-samples/src/main/resources/jobs/iosample/jdbcPaging.xml
index 271062e12..3647fa413 100644
--- a/spring-batch-samples/src/main/resources/jobs/iosample/jdbcPaging.xml
+++ b/spring-batch-samples/src/main/resources/jobs/iosample/jdbcPaging.xml
@@ -11,6 +11,7 @@
+