diff --git a/spring-batch-infrastructure/pom.xml b/spring-batch-infrastructure/pom.xml
index e37bec53b2..1823e8b1ff 100644
--- a/spring-batch-infrastructure/pom.xml
+++ b/spring-batch-infrastructure/pom.xml
@@ -347,6 +347,84 @@
${derby.version}
test
+
+ org.testcontainers
+ junit-jupiter
+ ${testcontainers.version}
+ test
+
+
+ com.mysql
+ mysql-connector-j
+ ${mysql-connector-j.version}
+ test
+
+
+ org.testcontainers
+ mysql
+ ${testcontainers.version}
+ test
+
+
+ org.testcontainers
+ oracle-xe
+ ${testcontainers.version}
+ test
+
+
+ com.oracle.database.jdbc
+ ojdbc10
+ ${oracle.version}
+ test
+
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ ${mariadb-java-client.version}
+ test
+
+
+ org.testcontainers
+ mariadb
+ ${testcontainers.version}
+ test
+
+
+ org.postgresql
+ postgresql
+ ${postgresql.version}
+ test
+
+
+ org.testcontainers
+ postgresql
+ ${testcontainers.version}
+ test
+
+
+ com.ibm.db2
+ jcc
+ ${db2.version}
+ test
+
+
+ org.testcontainers
+ db2
+ ${testcontainers.version}
+ test
+
+
+ org.testcontainers
+ mssqlserver
+ ${testcontainers.version}
+ test
+
+
+ com.microsoft.sqlserver
+ mssql-jdbc
+ ${sqlserver.version}
+ test
+
com.thoughtworks.xstream
xstream
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/AbstractPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/AbstractPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..15f3ced073
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/AbstractPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.sql.DataSource;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.batch.item.database.Order;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author Henning Pöttker
+ */
+abstract class AbstractPagingQueryProviderIntegrationTests {
+
+ private final JdbcTemplate jdbcTemplate;
+
+ private final AbstractSqlPagingQueryProvider queryProvider;
+
+ AbstractPagingQueryProviderIntegrationTests(DataSource dataSource, AbstractSqlPagingQueryProvider queryProvider) {
+ this.jdbcTemplate = new JdbcTemplate(dataSource);
+ this.queryProvider = queryProvider;
+ }
+
+ @Test
+ void testWithoutGrouping() {
+ queryProvider.setSelectClause("ID, STRING");
+ queryProvider.setFromClause("TEST_TABLE");
+ Map sortKeys = new HashMap<>();
+ sortKeys.put("ID", Order.ASCENDING);
+ queryProvider.setSortKeys(sortKeys);
+
+ List- firstPage = jdbcTemplate.query(queryProvider.generateFirstPageQuery(2), MAPPER);
+ assertEquals(List.of(new Item(1, "Spring"), new Item(2, "Batch")), firstPage);
+
+ List
- secondPage = jdbcTemplate.query(queryProvider.generateRemainingPagesQuery(2), MAPPER, 2);
+ assertEquals(List.of(new Item(3, "Infrastructure")), secondPage);
+ }
+
+ @Test
+ void testWithGrouping() {
+ queryProvider.setSelectClause("STRING");
+ queryProvider.setFromClause("GROUPING_TEST_TABLE");
+ queryProvider.setGroupClause("STRING");
+ Map sortKeys = new HashMap<>();
+ sortKeys.put("STRING", Order.ASCENDING);
+ queryProvider.setSortKeys(sortKeys);
+
+ List firstPage = jdbcTemplate.queryForList(queryProvider.generateFirstPageQuery(2), String.class);
+ assertEquals(List.of("Batch", "Infrastructure"), firstPage);
+
+ List secondPage = jdbcTemplate.queryForList(queryProvider.generateRemainingPagesQuery(2), String.class,
+ "Infrastructure");
+ assertEquals(List.of("Spring"), secondPage);
+ }
+
+ private record Item(Integer id, String string) {
+ }
+
+ private static final RowMapper
- MAPPER = (rs, rowNum) -> new Item(rs.getInt("id"), rs.getString("string"));
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/Db2PagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/Db2PagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..19d876b9d1
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/Db2PagingQueryProviderIntegrationTests.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import com.ibm.db2.jcc.DB2SimpleDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.Db2Container;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class Db2PagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName DB2_IMAGE = DockerImageName.parse("ibmcom/db2:11.5.5.1");
+
+ @Container
+ public static Db2Container db2 = new Db2Container(DB2_IMAGE).acceptLicense();
+
+ Db2PagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new Db2PagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ DB2SimpleDataSource dataSource = new DB2SimpleDataSource();
+ dataSource.setDatabaseName(db2.getDatabaseName());
+ dataSource.setUser(db2.getUsername());
+ dataSource.setPassword(db2.getPassword());
+ dataSource.setDriverType(4);
+ dataSource.setServerName(db2.getHost());
+ dataSource.setPortNumber(db2.getMappedPort(Db2Container.DB2_PORT));
+ dataSource.setSslConnection(false);
+ return dataSource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderIntegrationTests.java
index fb3820c61c..9a06de9369 100644
--- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderIntegrationTests.java
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DerbyPagingQueryProviderIntegrationTests.java
@@ -15,84 +15,36 @@
*/
package org.springframework.batch.item.database.support;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import javax.sql.DataSource;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.springframework.batch.item.database.Order;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.RowMapper;
-import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
/**
* @author Henning Pöttker
*/
-class DerbyPagingQueryProviderIntegrationTests {
-
- private static EmbeddedDatabase embeddedDatabase;
-
- private static JdbcTemplate jdbcTemplate;
-
- @BeforeAll
- static void setUp() {
- embeddedDatabase = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY)
- .addScript("/org/springframework/batch/item/database/support/query-provider-fixture.sql")
- .generateUniqueName(true)
- .build();
- jdbcTemplate = new JdbcTemplate(embeddedDatabase);
- }
-
- @AfterAll
- static void tearDown() {
- if (embeddedDatabase != null) {
- embeddedDatabase.shutdown();
- }
- }
-
- @Test
- void testWithoutGrouping() {
- var queryProvider = new DerbyPagingQueryProvider();
- queryProvider.setSelectClause("ID, STRING");
- queryProvider.setFromClause("TEST_TABLE");
- Map sortKeys = new HashMap<>();
- sortKeys.put("ID", Order.ASCENDING);
- queryProvider.setSortKeys(sortKeys);
+@SpringJUnitConfig
+class DerbyPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
- List
- firstPage = jdbcTemplate.query(queryProvider.generateFirstPageQuery(2), MAPPER);
- assertEquals(List.of(new Item(1, "Spring"), new Item(2, "Batch")), firstPage);
-
- List
- secondPage = jdbcTemplate.query(queryProvider.generateRemainingPagesQuery(2), MAPPER, 2);
- assertEquals(List.of(new Item(3, "Infrastructure")), secondPage);
+ DerbyPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new DerbyPagingQueryProvider());
}
- @Test
- void testWithGrouping() {
- var queryProvider = new DerbyPagingQueryProvider();
- queryProvider.setSelectClause("STRING");
- queryProvider.setFromClause("GROUPING_TEST_TABLE");
- queryProvider.setGroupClause("STRING");
- Map sortKeys = new HashMap<>();
- sortKeys.put("STRING", Order.ASCENDING);
- queryProvider.setSortKeys(sortKeys);
-
- List firstPage = jdbcTemplate.queryForList(queryProvider.generateFirstPageQuery(2), String.class);
- assertEquals(List.of("Batch", "Infrastructure"), firstPage);
+ @Configuration
+ static class TestConfiguration {
- List secondPage = jdbcTemplate.queryForList(queryProvider.generateRemainingPagesQuery(2), String.class,
- "Infrastructure");
- assertEquals(List.of("Spring"), secondPage);
- }
+ @Bean
+ public DataSource dataSource() throws Exception {
+ return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.DERBY)
+ .addScript("/org/springframework/batch/item/database/support/query-provider-fixture.sql")
+ .generateUniqueName(true)
+ .build();
+ }
- private record Item(Integer id, String string) {
}
- private static final RowMapper
- MAPPER = (rs, rowNum) -> new Item(rs.getInt("id"), rs.getString("string"));
-
}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/HsqlPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/HsqlPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..f0ce2f3821
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/HsqlPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+
+/**
+ * @author Henning Pöttker
+ */
+@SpringJUnitConfig
+class HsqlPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ HsqlPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new HsqlPagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.HSQL)
+ .addScript("/org/springframework/batch/item/database/support/query-provider-fixture.sql")
+ .generateUniqueName(true)
+ .build();
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..e96aeb1242
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import org.mariadb.jdbc.MariaDbDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.MariaDBContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class MariaDBPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName MARIADB_IMAGE = DockerImageName.parse("mariadb:10.9.3");
+
+ @Container
+ public static MariaDBContainer> mariaDBContainer = new MariaDBContainer<>(MARIADB_IMAGE);
+
+ MariaDBPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new MySqlPagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ MariaDbDataSource datasource = new MariaDbDataSource();
+ datasource.setUrl(mariaDBContainer.getJdbcUrl());
+ datasource.setUser(mariaDBContainer.getUsername());
+ datasource.setPassword(mariaDBContainer.getPassword());
+ return datasource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MySqlPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MySqlPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..4b1da2044b
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MySqlPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import com.mysql.cj.jdbc.MysqlDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.MySQLContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class MySqlPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName MYSQL_IMAGE = DockerImageName.parse("mysql:8.0.31");
+
+ @Container
+ public static MySQLContainer> mysql = new MySQLContainer<>(MYSQL_IMAGE);
+
+ MySqlPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new MySqlPagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ MysqlDataSource datasource = new MysqlDataSource();
+ datasource.setURL(mysql.getJdbcUrl());
+ datasource.setUser(mysql.getUsername());
+ datasource.setPassword(mysql.getPassword());
+ datasource.setUseSSL(false);
+ return datasource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..23d767c384
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/OraclePagingQueryProviderIntegrationTests.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import oracle.jdbc.pool.OracleDataSource;
+import org.junit.jupiter.api.Disabled;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.OracleContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * Official Docker images for Oracle are not publicly available. Oracle support is tested
+ * semi-manually for the moment: 1. Build a docker image for oracle/database:11.2.0.2-xe:
+ * ...
+ * 2. Run the test `testJobExecution`
+ *
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+@Disabled("Official Docker images for Oracle are not publicly available")
+class OraclePagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName ORACLE_IMAGE = DockerImageName.parse("oracle/database:11.2.0.2-xe");
+
+ @Container
+ public static OracleContainer oracle = new OracleContainer(ORACLE_IMAGE);
+
+ OraclePagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new OraclePagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ OracleDataSource oracleDataSource = new OracleDataSource();
+ oracleDataSource.setUser(oracle.getUsername());
+ oracleDataSource.setPassword(oracle.getPassword());
+ oracleDataSource.setDatabaseName(oracle.getDatabaseName());
+ oracleDataSource.setServerName(oracle.getHost());
+ oracleDataSource.setPortNumber(oracle.getOraclePort());
+ return oracleDataSource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/PostgresPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/PostgresPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..44798f79fa
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/PostgresPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import org.postgresql.ds.PGSimpleDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.PostgreSQLContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class PostgresPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName POSTGRESQL_IMAGE = DockerImageName.parse("postgres:13.3");
+
+ @Container
+ public static PostgreSQLContainer> postgres = new PostgreSQLContainer<>(POSTGRESQL_IMAGE);
+
+ PostgresPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new PostgresPagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ PGSimpleDataSource datasource = new PGSimpleDataSource();
+ datasource.setURL(postgres.getJdbcUrl());
+ datasource.setUser(postgres.getUsername());
+ datasource.setPassword(postgres.getPassword());
+ return datasource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlServerPagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlServerPagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..21bc1eede6
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlServerPagingQueryProviderIntegrationTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import javax.sql.DataSource;
+
+import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.testcontainers.containers.MSSQLServerContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@Testcontainers(disabledWithoutDocker = true)
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class SqlServerPagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ // TODO find the best way to externalize and manage image versions
+ private static final DockerImageName SQLSERVER_IMAGE = DockerImageName
+ .parse("mcr.microsoft.com/mssql/server:2022-CU14-ubuntu-22.04");
+
+ @Container
+ public static MSSQLServerContainer> sqlserver = new MSSQLServerContainer<>(SQLSERVER_IMAGE).acceptLicense();
+
+ SqlServerPagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new SqlServerPagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ SQLServerDataSource dataSource = new SQLServerDataSource();
+ dataSource.setUser(sqlserver.getUsername());
+ dataSource.setPassword(sqlserver.getPassword());
+ dataSource.setURL(sqlserver.getJdbcUrl());
+ return dataSource;
+ }
+
+ }
+
+}
diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlitePagingQueryProviderIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlitePagingQueryProviderIntegrationTests.java
new file mode 100644
index 0000000000..db6826c832
--- /dev/null
+++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/SqlitePagingQueryProviderIntegrationTests.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2024 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.batch.item.database.support;
+
+import java.nio.file.Path;
+import javax.sql.DataSource;
+
+import org.junit.jupiter.api.io.TempDir;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.jdbc.Sql;
+import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
+import org.sqlite.SQLiteDataSource;
+
+import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_CLASS;
+
+/**
+ * @author Henning Pöttker
+ */
+@SpringJUnitConfig
+@Sql(scripts = "query-provider-fixture.sql", executionPhase = BEFORE_TEST_CLASS)
+class SqlitePagingQueryProviderIntegrationTests extends AbstractPagingQueryProviderIntegrationTests {
+
+ @TempDir
+ private static Path TEMP_DIR;
+
+ SqlitePagingQueryProviderIntegrationTests(@Autowired DataSource dataSource) {
+ super(dataSource, new SqlitePagingQueryProvider());
+ }
+
+ @Configuration
+ static class TestConfiguration {
+
+ @Bean
+ public DataSource dataSource() throws Exception {
+ SQLiteDataSource dataSource = new SQLiteDataSource();
+ dataSource.setUrl("jdbc:sqlite:" + TEMP_DIR.resolve("spring-batch.sqlite"));
+ return dataSource;
+ }
+
+ }
+
+}