diff --git a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/Db2PagingQueryProvider.java b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/Db2PagingQueryProvider.java
index 07c3b36a..66424c18 100755
--- a/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/Db2PagingQueryProvider.java
+++ b/spring-cloud-task-core/src/main/java/org/springframework/cloud/task/repository/database/support/Db2PagingQueryProvider.java
@@ -24,6 +24,7 @@ import org.springframework.data.domain.Pageable;
* database specific features.
*
* @author Thomas Schuettel
+ * @author Ryan DCruz
*/
public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
@@ -31,8 +32,7 @@ public class Db2PagingQueryProvider extends AbstractSqlPagingQueryProvider {
public String getPageQuery(Pageable pageable) {
long offset = pageable.getOffset() + 1;
return generateRowNumSqlQueryWithNesting(getSelectClause(), false,
- "TMP_ROW_NUM BETWEEN " + offset + " AND "
- + (offset + pageable.getPageSize()));
+ "TMP_ROW_NUM >= " + offset + " AND TMP_ROW_NUM < " + (offset + pageable.getPageSize()));
}
private String generateRowNumSqlQueryWithNesting(String selectClause,
diff --git a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java
index f091e3b6..a4802014 100644
--- a/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java
+++ b/spring-cloud-task-core/src/test/java/org/springframework/cloud/task/repository/database/support/FindAllPagingQueryProviderTests.java
@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Glenn Renfro
+ * @author Ryan DCruz
*/
public class FindAllPagingQueryProviderTests {
@@ -66,7 +67,16 @@ public class FindAllPagingQueryProviderTests {
+ "OVER (ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC) AS "
+ "TMP_ROW_NUM FROM %PREFIX%EXECUTION) TASK_EXECUTION_PAGE "
+ "WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11 ORDER BY START_TIME DESC, "
- + "TASK_EXECUTION_ID DESC" } });
+ + "TASK_EXECUTION_ID DESC" },
+ { "DB2/Linux",
+ "SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, "
+ + "TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM "
+ + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, "
+ + "EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID, ROW_NUMBER() "
+ + "OVER() as TMP_ROW_NUM FROM "
+ + "(SELECT TASK_EXECUTION_ID, START_TIME, END_TIME, TASK_NAME, EXIT_CODE, EXIT_MESSAGE, ERROR_MESSAGE, LAST_UPDATED, "
+ + "EXTERNAL_EXECUTION_ID, PARENT_EXECUTION_ID FROM %PREFIX%EXECUTION ORDER BY START_TIME DESC, TASK_EXECUTION_ID DESC)) "
+ + "WHERE TMP_ROW_NUM >= 1 AND TMP_ROW_NUM < 11"}});
}
@ParameterizedTest
diff --git a/spring-cloud-task-integration-tests/pom.xml b/spring-cloud-task-integration-tests/pom.xml
index d76eb75a..0b0d2588 100644
--- a/spring-cloud-task-integration-tests/pom.xml
+++ b/spring-cloud-task-integration-tests/pom.xml
@@ -17,6 +17,7 @@
1.16.3
1.16.3
1.0.8
+ 11.5.7.0
@@ -28,6 +29,13 @@
pom
import
+
+ org.testcontainers
+ testcontainers-bom
+ ${test.containers.version}
+ pom
+ import
+
@@ -103,12 +111,29 @@
${test.containers.version}
test
+
+ org.testcontainers
+ junit-jupiter
+ test
+
org.testcontainers
rabbitmq
${test.rabbit.containers.version}
test
+
+ org.testcontainers
+ db2
+ ${test.containers.version}
+ test
+
+
+ com.ibm.db2
+ jcc
+ ${db2-jdbc.version}
+ test
+
org.rnorth.duct-tape
duct-tape
diff --git a/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/database/support/db2/Db2PagingQueryProviderTest.java b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/database/support/db2/Db2PagingQueryProviderTest.java
new file mode 100644
index 00000000..738f063d
--- /dev/null
+++ b/spring-cloud-task-integration-tests/src/test/java/org/springframework/cloud/task/database/support/db2/Db2PagingQueryProviderTest.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2015-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://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,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.task.database.support.db2;
+
+
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.containers.Db2Container;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.cloud.task.executionid.TaskStartApplication;
+import org.springframework.cloud.task.repository.TaskExecution;
+import org.springframework.cloud.task.repository.dao.TaskExecutionDao;
+import org.springframework.cloud.task.repository.database.support.Db2PagingQueryProvider;
+import org.springframework.cloud.task.repository.support.SimpleTaskExplorer;
+import org.springframework.cloud.task.repository.support.TaskExecutionDaoFactoryBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.jdbc.datasource.DriverManagerDataSource;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.jdbc.SqlConfig;
+
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.context.jdbc.SqlConfig.ErrorMode.CONTINUE_ON_ERROR;
+
+/**
+ * @author Tyler Carpenter-Rivers
+ * @author Ryan DCruz
+ * @see Db2PagingQueryProvider
+ */
+@SpringBootTest(
+ classes = {TaskStartApplication.class, Db2PagingQueryProviderTest.TestConfig.class},
+ properties = "spring.cloud.task.events.enabled=false"
+)
+@Testcontainers(disabledWithoutDocker = true)
+@DirtiesContext
+@Sql(
+ scripts = "classpath:/org/springframework/cloud/task/schema-db2.sql",
+ config = @SqlConfig(errorMode = CONTINUE_ON_ERROR)
+)
+@Sql(statements = {
+ " DELETE FROM TASK_EXECUTION_PARAMS ",
+ " DELETE FROM TASK_TASK_BATCH ",
+ " DELETE FROM TASK_EXECUTION "
+})
+class Db2PagingQueryProviderTest {
+
+ @Container
+ public static Db2Container db2Container =
+ new Db2Container(DockerImageName.parse("ibmcom/db2:11.5.7.0"))
+ .acceptLicense()
+ .withDatabaseName("test")
+ .withStartupTimeoutSeconds(30)
+ .withExposedPorts(50000);
+
+ @DynamicPropertySource
+ static void properties(DynamicPropertyRegistry registry) {
+ registry.add("spring.datasource.url", db2Container::getJdbcUrl);
+ registry.add("spring.datasource.username", db2Container::getUsername);
+ registry.add("spring.datasource.password", db2Container::getPassword);
+ }
+
+ @Autowired
+ private SimpleTaskExplorer simpleTaskExplorer;
+
+ @Autowired
+ private TaskExecutionDao taskExecutionDao;
+
+ @DisplayName("Scenario: The page request size is less than the total number of elements" +
+ "Given the total number of elements is 3" +
+ "And the page request size is 2" +
+ "When the query is executed" +
+ "Then the returned page has 2 elements")
+ @Test
+ void pageRequest() {
+ // setup test data
+ taskExecutionDao.createTaskExecution(
+ UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
+ taskExecutionDao.createTaskExecution(
+ UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
+ taskExecutionDao.createTaskExecution(
+ UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
+
+ PageRequest pageRequest = PageRequest.of(0, 2);
+
+ // run subject under test
+ Page page = simpleTaskExplorer.findAll(pageRequest);
+
+ // assert and verify
+ assertThat(page.getTotalElements())
+ .as("Expected the total number of records in the table to be 3")
+ .isEqualTo(3);
+
+ assertThat(pageRequest.getPageSize())
+ .as("Expected the size of the returned page to be 2")
+ .isEqualTo(2);
+ }
+
+ @DisplayName("Scenario: the page request size is larger than the total number of elements" +
+ "Given the total number of elements is 1" +
+ "And the page request size is 2" +
+ "When the query is executed" +
+ "Then the returned page has 1 element")
+ @Test
+ void pageRequestSinglePageEntries() {
+ // setup test data
+ taskExecutionDao.createTaskExecution(
+ UUID.randomUUID().toString(), new Date(), List.of(), UUID.randomUUID().toString());
+
+ PageRequest pageRequest = PageRequest.of(0, 2);
+
+ // run subject under test
+ Page page = simpleTaskExplorer.findAll(pageRequest);
+
+ // assert and verify
+ assertThat(page.getTotalElements())
+ .as("Should only have one record in the table")
+ .isEqualTo(1);
+
+ assertThat(page.getNumberOfElements())
+ .as("Should have one record in the returned page")
+ .isEqualTo(1);
+
+ assertThat(page.getTotalPages())
+ .as("Should expect the total number of pages to be 1")
+ .isEqualTo(1);
+ }
+
+ @TestConfiguration
+ public static class TestConfig {
+ @Bean
+ @ConfigurationProperties("spring.datasource")
+ public DataSource dataSource() {
+ return new DriverManagerDataSource();
+ }
+
+ @Bean
+ public TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean(DataSource dataSource) {
+ return new TaskExecutionDaoFactoryBean(dataSource);
+ }
+
+ @Bean
+ public TaskExecutionDao taskExecutionDao(TaskExecutionDaoFactoryBean taskExecutionDaoFactoryBean) throws Exception {
+ return taskExecutionDaoFactoryBean.getObject();
+ }
+ }
+}