diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/IbatisPagingItemReaderAsyncTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/IbatisPagingItemReaderAsyncTests.java index 9f561a922..b1732e161 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/IbatisPagingItemReaderAsyncTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/IbatisPagingItemReaderAsyncTests.java @@ -57,7 +57,7 @@ public class IbatisPagingItemReaderAsyncTests { public void init() { SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); maxId = jdbcTemplate.queryForInt("SELECT MAX(ID) from T_FOOS"); - for (int i = maxId + 1; i <= ITEM_COUNT; i++) { + for (int i = ITEM_COUNT; i > maxId; i--) { jdbcTemplate.update("INSERT into T_FOOS (ID,NAME,VALUE) values (?, ?, ?)", i, "foo" + i, i); } assertEquals(ITEM_COUNT, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS")); diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingItemReaderAsyncTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingItemReaderAsyncTests.java index 1da5da798..b6dab960c 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingItemReaderAsyncTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingItemReaderAsyncTests.java @@ -63,7 +63,7 @@ public class JdbcPagingItemReaderAsyncTests { public void init() { SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); maxId = jdbcTemplate.queryForInt("SELECT MAX(ID) from T_FOOS"); - for (int i = maxId + 1; i <= ITEM_COUNT; i++) { + for (int i = ITEM_COUNT; i > maxId; i--) { jdbcTemplate.update("INSERT into T_FOOS (ID,NAME,VALUE) values (?, ?, ?)", i, "foo" + i, i); } assertEquals(ITEM_COUNT, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS")); @@ -141,7 +141,7 @@ public class JdbcPagingItemReaderAsyncTests { factory.setDataSource(dataSource); factory.setSelectClause("select ID, NAME, VALUE"); factory.setFromClause("from T_FOOS"); - factory.setSortKey("ID"); + factory.setSortKey("VALUE"); reader.setQueryProvider((PagingQueryProvider) factory.getObject()); reader.setRowMapper(new ParameterizedRowMapper() { public Foo mapRow(ResultSet rs, int i) throws SQLException { diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingQueryIntegrationTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingQueryIntegrationTests.java index b7d1dd8d2..070fa2cfd 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingQueryIntegrationTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingQueryIntegrationTests.java @@ -63,7 +63,7 @@ public class JdbcPagingQueryIntegrationTests { public void init() { jdbcTemplate = new SimpleJdbcTemplate(dataSource); maxId = jdbcTemplate.queryForInt("SELECT MAX(ID) from T_FOOS"); - for (int i = maxId + 1; i <= itemCount; i++) { + for (int i = itemCount; i > maxId; i--) { jdbcTemplate.update("INSERT into T_FOOS (ID,NAME,VALUE) values (?, ?, ?)", i, "foo" + i, i); } assertEquals(itemCount, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS")); diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingRestartIntegrationTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingRestartIntegrationTests.java index 2e76ca95c..06b19836f 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingRestartIntegrationTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JdbcPagingRestartIntegrationTests.java @@ -70,7 +70,7 @@ public class JdbcPagingRestartIntegrationTests { public void init() { jdbcTemplate = new SimpleJdbcTemplate(dataSource); maxId = jdbcTemplate.queryForInt("SELECT MAX(ID) from T_FOOS"); - for (int i = maxId + 1; i <= itemCount; i++) { + for (int i = itemCount; i > maxId; i--) { jdbcTemplate.update("INSERT into T_FOOS (ID,NAME,VALUE) values (?, ?, ?)", i, "foo" + i, i); } assertEquals(itemCount, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS")); @@ -147,7 +147,7 @@ public class JdbcPagingRestartIntegrationTests { factory.setDataSource(dataSource); factory.setSelectClause("select ID, NAME, VALUE"); factory.setFromClause("from T_FOOS"); - factory.setSortKey("ID"); + factory.setSortKey("VALUE"); reader.setQueryProvider((PagingQueryProvider) factory.getObject()); reader.setRowMapper(new ParameterizedRowMapper() { public Foo mapRow(ResultSet rs, int i) throws SQLException { diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JpaPagingItemReaderAsyncTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JpaPagingItemReaderAsyncTests.java index 7381fa91f..654ae5bb1 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JpaPagingItemReaderAsyncTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/database/JpaPagingItemReaderAsyncTests.java @@ -60,7 +60,7 @@ public class JpaPagingItemReaderAsyncTests { public void init() { SimpleJdbcTemplate jdbcTemplate = new SimpleJdbcTemplate(dataSource); maxId = jdbcTemplate.queryForInt("SELECT MAX(ID) from T_FOOS"); - for (int i = maxId + 1; i <= ITEM_COUNT; i++) { + for (int i = ITEM_COUNT; i > maxId; i--) { jdbcTemplate.update("INSERT into T_FOOS (ID,NAME,VALUE) values (?, ?, ?)", i, "foo" + i, i); } assertEquals(ITEM_COUNT, SimpleJdbcTestUtils.countRowsInTable(jdbcTemplate, "T_FOOS")); diff --git a/spring-batch-infrastructure-tests/src/test/resources/log4j.properties b/spring-batch-infrastructure-tests/src/test/resources/log4j.properties index bd323a20d..0d084f65e 100644 --- a/spring-batch-infrastructure-tests/src/test/resources/log4j.properties +++ b/spring-batch-infrastructure-tests/src/test/resources/log4j.properties @@ -12,3 +12,4 @@ log4j.category.org.springframework.jdbc.datasource=INFO # log4j.category.org.springframework.batch=DEBUG log4j.category.org.springframework.batch.support=INFO # log4j.category.org.springframework.retry=DEBUG +# log4j.category.org.springframework.batch.item.database=DEBUG diff --git a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-derby.sql b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-derby.sql index 4e52c399e..d4e9e150b 100644 --- a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-derby.sql +++ b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-derby.sql @@ -9,11 +9,11 @@ CREATE TABLE T_FOOS ( ALTER TABLE T_FOOS ADD PRIMARY KEY (ID); -INSERT INTO t_foos (id, name, value) VALUES (1, 'bar1', 1); -INSERT INTO t_foos (id, name, value) VALUES (2, 'bar2', 2); -INSERT INTO t_foos (id, name, value) VALUES (3, 'bar3', 3); -INSERT INTO t_foos (id, name, value) VALUES (4, 'bar4', 4); -INSERT INTO t_foos (id, name, value) VALUES (5, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (1, 'bar2', 2); +INSERT INTO t_foos (id, name, value) VALUES (2, 'bar4', 4); +INSERT INTO t_foos (id, name, value) VALUES (3, 'bar1', 1); +INSERT INTO t_foos (id, name, value) VALUES (4, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (5, 'bar3', 3); CREATE TABLE T_WRITE_FOOS ( ID BIGINT NOT NULL, diff --git a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-hsqldb.sql b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-hsqldb.sql index 9fff8df46..0d89dc86a 100644 --- a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-hsqldb.sql +++ b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-hsqldb.sql @@ -9,11 +9,11 @@ CREATE TABLE T_FOOS ( ALTER TABLE T_FOOS ADD PRIMARY KEY (ID); -INSERT INTO t_foos (id, name, value) VALUES (1, 'bar1', 1); -INSERT INTO t_foos (id, name, value) VALUES (2, 'bar2', 2); -INSERT INTO t_foos (id, name, value) VALUES (3, 'bar3', 3); -INSERT INTO t_foos (id, name, value) VALUES (4, 'bar4', 4); -INSERT INTO t_foos (id, name, value) VALUES (5, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (1, 'bar2', 2); +INSERT INTO t_foos (id, name, value) VALUES (2, 'bar4', 4); +INSERT INTO t_foos (id, name, value) VALUES (3, 'bar1', 1); +INSERT INTO t_foos (id, name, value) VALUES (4, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (5, 'bar3', 3); CREATE TABLE T_WRITE_FOOS ( ID BIGINT NOT NULL, diff --git a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-postgres.sql b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-postgres.sql index 8415384da..ef97a6c6d 100644 --- a/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-postgres.sql +++ b/spring-batch-infrastructure-tests/src/test/resources/org/springframework/batch/item/database/init-foo-schema-postgres.sql @@ -9,11 +9,11 @@ CREATE TABLE T_FOOS ( ALTER TABLE T_FOOS ADD PRIMARY KEY (ID); -INSERT INTO t_foos (id, name, VALUE) VALUES (1, 'bar1', 1); -INSERT INTO t_foos (id, name, VALUE) VALUES (2, 'bar2', 2); -INSERT INTO t_foos (id, name, VALUE) VALUES (3, 'bar3', 3); -INSERT INTO t_foos (id, name, VALUE) VALUES (4, 'bar4', 4); -INSERT INTO t_foos (id, name, VALUE) VALUES (5, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (1, 'bar2', 2); +INSERT INTO t_foos (id, name, value) VALUES (2, 'bar4', 4); +INSERT INTO t_foos (id, name, value) VALUES (3, 'bar1', 1); +INSERT INTO t_foos (id, name, value) VALUES (4, 'bar5', 5); +INSERT INTO t_foos (id, name, value) VALUES (5, 'bar3', 3); CREATE TABLE T_WRITE_FOOS ( ID BIGINT NOT NULL, 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 c078e602b..501cecbec 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 @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -26,7 +26,11 @@ import javax.sql.DataSource; * Derby implementation of a {@link PagingQueryProvider} using standard SQL:2003 windowing functions. * These features are supported starting with Apache Derby version 10.4.1.3. * + * As the OVER() function does not support the ORDER BY clause a sub query is instead used to order the results + * before the ROW_NUM restriction is applied + * * @author Thomas Risberg + * @author David Thexton * @since 2.0 */ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider { @@ -42,23 +46,17 @@ public class DerbyPagingQueryProvider extends SqlWindowingPagingQueryProvider { } } - @Override - protected Object getSubQueryAlias() { - return "AS TMP_SUB "; - } - @Override 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(); + + protected String getOverSubstituteClauseStart() { + return " FROM (SELECT " + getSelectClause(); + } + + protected String getOverSubstituteClauseEnd() { + return " " + super.getOverClause() + ") AS TMP_ORDERED"; } } 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 e62d8ad00..25ec9860c 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 @@ -35,16 +35,21 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append("SELECT ").append(getSelectClause()).append(", "); sql.append("ROW_NUMBER() OVER (").append(getOverClause()); sql.append(") AS ROW_NUMBER"); + sql.append(getOverSubstituteClauseStart()); 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); + sql.append(getOverSubstituteClauseEnd()); + sql.append(") ").append(getSubQueryAlias()).append("WHERE ").append(extractTableAlias()).append( + "ROW_NUMBER <= ").append(pageSize); return sql.toString(); } - private String extractTableAlias() { + protected Object getSubQueryAlias() { + return "AS TMP_SUB "; + } + + protected Object extractTableAlias() { String alias = "" + getSubQueryAlias(); if (StringUtils.hasText(alias) && alias.toUpperCase().startsWith("AS")) { alias = alias.substring(3).trim() + "."; @@ -52,10 +57,6 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi return alias; } - protected Object getSubQueryAlias() { - return ""; - } - @Override public String generateRemainingPagesQuery(int pageSize) { StringBuilder sql = new StringBuilder(); @@ -63,6 +64,7 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append("SELECT ").append(getSelectClause()).append(", "); sql.append("ROW_NUMBER() OVER (").append(getOverClause()); sql.append(") AS ROW_NUMBER"); + sql.append(getOverSubstituteClauseStart()); sql.append(" FROM ").append(getFromClause()); sql.append(" WHERE "); if (getWhereClause() != null) { @@ -77,17 +79,13 @@ 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); + sql.append(getOverSubstituteClauseEnd()); + sql.append(") ").append(getSubQueryAlias()).append("WHERE ").append(extractTableAlias()).append( + "ROW_NUMBER <= ").append(pageSize); return sql.toString(); } - protected String getAfterWhereClause() { - return ""; - } - @Override public String generateJumpToItemQuery(int itemIndex, int pageSize) { int page = itemIndex / pageSize; @@ -101,11 +99,12 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi sql.append("SELECT ").append(getSortKey()).append(" AS SORT_KEY, "); sql.append("ROW_NUMBER() OVER (").append(getOverClause()); 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); + sql.append(getOverSubstituteClauseStart()); + sql.append(" FROM ").append(getFromClause()); + sql.append(getWhereClause() == null ? "" : " WHERE " + getWhereClause()); + sql.append(getOverSubstituteClauseEnd()); + sql.append(") ").append(getSubQueryAlias()).append("WHERE ").append(extractTableAlias()).append( + "ROW_NUMBER = ").append(lastRowNum); return sql.toString(); } @@ -114,6 +113,14 @@ public class SqlWindowingPagingQueryProvider extends AbstractSqlPagingQueryProvi return "ORDER BY " + getSortKey() + " " + getAscendingClause(); } + protected String getOverSubstituteClauseStart() { + return ""; + } + + protected String getOverSubstituteClauseEnd() { + return ""; + } + private String getAscendingClause() { if (isAscending()) { return "ASC"; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SybasePagingQueryProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SybasePagingQueryProvider.java index 50534d2ce..91b3e7ca0 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SybasePagingQueryProvider.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SybasePagingQueryProvider.java @@ -37,6 +37,11 @@ public class SybasePagingQueryProvider extends SqlWindowingPagingQueryProvider { return SqlPagingQueryUtils.generateTopSqlQuery(this, true, buildTopClause(pageSize)); } + @Override + protected Object getSubQueryAlias() { + return ""; + } + private String buildTopClause(int pageSize) { return new StringBuilder().append("TOP ").append(pageSize).toString(); } diff --git a/spring-batch-parent/pom.xml b/spring-batch-parent/pom.xml index 70b754aac..3b2c6e4a8 100644 --- a/spring-batch-parent/pom.xml +++ b/spring-batch-parent/pom.xml @@ -519,7 +519,7 @@ org.apache.derby derby - 10.6.2.1 + 10.8.2.2 test