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 1878032a6..c078e602b 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 @@ -31,10 +31,12 @@ import javax.sql.DataSource; */ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider { + private String version; + @Override public void init(DataSource dataSource) throws Exception { super.init(dataSource); - String version = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString(); + version = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductVersion").toString(); if ("10.4.1.3".compareTo(version) > 0) { throw new InvalidDataAccessResourceUsageException("Apache Derby version " + version + " is not supported by this class, Only version 10.4.1.3 or later is supported"); } @@ -49,5 +51,14 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider { protected String getOverClause() { return ""; } + + @Override + protected String getAfterWhereClause() { + if (version!=null && "10.6.1".compareTo(version) > 0) { + // Old behaviour retained, even though it is broken + return ""; + } + return " " + super.getOverClause(); + } } 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 7c3f6a8b5..e62d8ad00 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 @@ -37,6 +37,7 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append(") AS ROW_NUMBER"); sql.append(" FROM ").append(getFromClause()).append( getWhereClause() == null ? "" : " WHERE " + getWhereClause()); + sql.append(getAfterWhereClause()); String alias = extractTableAlias(); sql.append(") ").append(getSubQueryAlias()).append("WHERE " + alias + "ROW_NUMBER <= ").append(pageSize); @@ -76,12 +77,17 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append(" < "); } sql.append(getSortKeyPlaceHolder()); + sql.append(getAfterWhereClause()); String alias = extractTableAlias(); sql.append(") ").append(getSubQueryAlias()).append("WHERE " + alias + "ROW_NUMBER <= ").append(pageSize); return sql.toString(); } + protected String getAfterWhereClause() { + return ""; + } + @Override public String generateJumpToItemQuery(int itemIndex, int pageSize) { int page = itemIndex / pageSize; @@ -97,6 +103,7 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append(") AS ROW_NUMBER"); sql.append(" FROM ").append(getFromClause()).append( getWhereClause() == null ? "" : " WHERE " + getWhereClause()); + sql.append(getAfterWhereClause()); String alias = extractTableAlias(); sql.append(") ").append(getSubQueryAlias()).append("WHERE " + alias + "ROW_NUMBER = ").append(lastRowNum); 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 5643ca2e0..92af44284 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 @@ -19,7 +19,7 @@ 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.assertTrue; import static org.junit.Assert.fail; import java.sql.Connection; @@ -83,7 +83,7 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide @Test @Override public void testGenerateFirstPageQuery() { - String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1) AS TMP_SUB WHERE TMP_SUB.ROW_NUMBER <= 100"; + String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1 ORDER BY id ASC) AS TMP_SUB WHERE TMP_SUB.ROW_NUMBER <= 100"; String s = pagingQueryProvider.generateFirstPageQuery(pageSize); Assert.assertEquals("", sql, s); } @@ -91,7 +91,7 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide @Test @Override public void testGenerateRemainingPagesQuery() { - 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 TMP_SUB.ROW_NUMBER <= 100"; + String sql = "SELECT * FROM ( SELECT id, name, age, ROW_NUMBER() OVER () AS ROW_NUMBER FROM foo WHERE bar = 1 AND id > ? ORDER BY id ASC) AS TMP_SUB WHERE TMP_SUB.ROW_NUMBER <= 100"; String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize); Assert.assertEquals("", sql, s); } @@ -99,7 +99,7 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide @Test @Override public void testGenerateJumpToItemQuery() { - 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 TMP_SUB.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 ORDER BY id ASC) AS TMP_SUB WHERE TMP_SUB.ROW_NUMBER = 100"; String s = pagingQueryProvider.generateJumpToItemQuery(145, pageSize); Assert.assertEquals("", sql, s); } @@ -107,31 +107,30 @@ public class DerbyPagingQueryProviderTests extends AbstractSqlPagingQueryProvide @Test @Override public void testGenerateJumpToItemQueryForFirstPage() { - 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 TMP_SUB.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 ORDER BY id ASC) AS TMP_SUB WHERE TMP_SUB.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) + * Older versions of Derby don't allow order by in the sub select. This should work with 10.6.1 and above. */ @Test @Override public void testQueryContainsSortKey() { String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase(); - assertFalse("Wrong query: " + s, s.contains("id asc")); + assertTrue("Wrong query: " + s, s.contains("id asc")); } /** - * Derby doesn't allow order by in the sub select + * Older versions of Derby don't allow order by in the sub select. This should work with 10.6.1 and above. */ @Test @Override public void testQueryContainsSortKeyDesc() { pagingQueryProvider.setAscending(false); String s = pagingQueryProvider.generateFirstPageQuery(pageSize).toLowerCase(); - assertFalse("Wrong query: " + s, s.contains("id desc")); + assertTrue("Wrong query: " + s, s.contains("id desc")); } } diff --git a/spring-batch-parent/pom.xml b/spring-batch-parent/pom.xml index 23adfae03..20b4a817c 100644 --- a/spring-batch-parent/pom.xml +++ b/spring-batch-parent/pom.xml @@ -426,7 +426,7 @@ org.apache.derby derby - 10.4.2.0 + 10.6.2.1 test