diff --git a/pom.xml b/pom.xml index 583b2fa47..08d8f575e 100644 --- a/pom.xml +++ b/pom.xml @@ -106,6 +106,7 @@ 6.3.1 1.9.9.1 8.0.31 + 3.0.8 42.5.0 11.5.7.0 19.16.0.0 diff --git a/spring-batch-core/pom.xml b/spring-batch-core/pom.xml index e3dca3eaa..f4211c890 100644 --- a/spring-batch-core/pom.xml +++ b/spring-batch-core/pom.xml @@ -118,6 +118,18 @@ ${testcontainers.version} test + + org.mariadb.jdbc + mariadb-java-client + ${mariadb-java-client.version} + test + + + org.testcontainers + mariadb + ${testcontainers.version} + test + org.postgresql postgresql diff --git a/spring-batch-core/src/main/resources/batch-mariadb.properties b/spring-batch-core/src/main/resources/batch-mariadb.properties new file mode 100644 index 000000000..94be3e911 --- /dev/null +++ b/spring-batch-core/src/main/resources/batch-mariadb.properties @@ -0,0 +1,17 @@ +# Placeholders batch.* +# for MariaDB: +batch.jdbc.driver=org.mariadb.jdbc.Driver +batch.jdbc.url=jdbc:mariadb://localhost/test +batch.jdbc.user=test +batch.jdbc.password=test +batch.database.incrementer.class=org.springframework.batch.item.database.support.MariaDBSequenceMaxValueIncrementer +batch.schema.script=classpath:/org/springframework/batch/core/schema-mariadb.sql +batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-mariadb.sql +batch.jdbc.testWhileIdle=true +batch.jdbc.validationQuery= + + +# Non-platform dependent settings that you might like to change +batch.data.source.init=true +batch.table.prefix=BATCH_ + diff --git a/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-drop-mariadb.sql b/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-drop-mariadb.sql new file mode 100644 index 000000000..f78e4b607 --- /dev/null +++ b/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-drop-mariadb.sql @@ -0,0 +1,10 @@ +DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT; +DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT; +DROP TABLE IF EXISTS BATCH_STEP_EXECUTION; +DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_PARAMS; +DROP TABLE IF EXISTS BATCH_JOB_EXECUTION; +DROP TABLE IF EXISTS BATCH_JOB_INSTANCE; + +DROP SEQUENCE IF EXISTS BATCH_STEP_EXECUTION_SEQ; +DROP SEQUENCE IF EXISTS BATCH_JOB_EXECUTION_SEQ; +DROP SEQUENCE IF EXISTS BATCH_JOB_SEQ; diff --git a/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-mariadb.sql b/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-mariadb.sql new file mode 100644 index 000000000..31f585fbc --- /dev/null +++ b/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-mariadb.sql @@ -0,0 +1,78 @@ +CREATE TABLE BATCH_JOB_INSTANCE ( + JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_NAME VARCHAR(100) NOT NULL, + JOB_KEY VARCHAR(32) NOT NULL, + constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY) +) ENGINE=InnoDB; + +CREATE TABLE BATCH_JOB_EXECUTION ( + JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY , + VERSION BIGINT , + JOB_INSTANCE_ID BIGINT NOT NULL, + CREATE_TIME DATETIME(6) NOT NULL, + START_TIME DATETIME(6) DEFAULT NULL , + END_TIME DATETIME(6) DEFAULT NULL , + STATUS VARCHAR(10) , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED DATETIME(6), + constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID) + references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID) +) ENGINE=InnoDB; + +CREATE TABLE BATCH_JOB_EXECUTION_PARAMS ( + JOB_EXECUTION_ID BIGINT NOT NULL , + PARAMETER_NAME VARCHAR(100) NOT NULL , + PARAMETER_TYPE VARCHAR(100) NOT NULL , + PARAMETER_VALUE VARCHAR(2500) , + IDENTIFYING CHAR(1) NOT NULL , + constraint JOB_EXEC_PARAMS_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ENGINE=InnoDB; + +CREATE TABLE BATCH_STEP_EXECUTION ( + STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY , + VERSION BIGINT NOT NULL, + STEP_NAME VARCHAR(100) NOT NULL, + JOB_EXECUTION_ID BIGINT NOT NULL, + CREATE_TIME DATETIME(6) NOT NULL, + START_TIME DATETIME(6) DEFAULT NULL , + END_TIME DATETIME(6) DEFAULT NULL , + STATUS VARCHAR(10) , + COMMIT_COUNT BIGINT , + READ_COUNT BIGINT , + FILTER_COUNT BIGINT , + WRITE_COUNT BIGINT , + READ_SKIP_COUNT BIGINT , + WRITE_SKIP_COUNT BIGINT , + PROCESS_SKIP_COUNT BIGINT , + ROLLBACK_COUNT BIGINT , + EXIT_CODE VARCHAR(2500) , + EXIT_MESSAGE VARCHAR(2500) , + LAST_UPDATED DATETIME(6), + constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ENGINE=InnoDB; + +CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT ( + STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT TEXT , + constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID) + references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID) +) ENGINE=InnoDB; + +CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT ( + JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY, + SHORT_CONTEXT VARCHAR(2500) NOT NULL, + SERIALIZED_CONTEXT TEXT , + constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID) + references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID) +) ENGINE=InnoDB; + +CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB; +CREATE SEQUENCE BATCH_JOB_EXECUTION_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB; +CREATE SEQUENCE BATCH_JOB_SEQ START WITH 1 MINVALUE 1 MAXVALUE 9223372036854775806 INCREMENT BY 1 NOCACHE NOCYCLE ENGINE=InnoDB; + + diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MariaDBJobRepositoryIntegrationTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MariaDBJobRepositoryIntegrationTests.java new file mode 100644 index 000000000..8ca824b42 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/test/repository/MariaDBJobRepositoryIntegrationTests.java @@ -0,0 +1,121 @@ +/* + * Copyright 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.batch.core.test.repository; + +import javax.sql.DataSource; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mariadb.jdbc.MariaDbDataSource; +import org.testcontainers.containers.MariaDBContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.utility.DockerImageName; + +import org.springframework.batch.core.ExitStatus; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobExecution; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersBuilder; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; +import org.springframework.batch.core.job.builder.JobBuilder; +import org.springframework.batch.core.launch.JobLauncher; +import org.springframework.batch.core.repository.JobRepository; +import org.springframework.batch.core.step.builder.StepBuilder; +import org.springframework.batch.repeat.RepeatStatus; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.ClassPathResource; +import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; +import org.springframework.jdbc.support.JdbcTransactionManager; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import org.springframework.transaction.PlatformTransactionManager; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * @author Mahmoud Ben Hassine + */ +@Testcontainers +@SpringJUnitConfig +class MariaDBJobRepositoryIntegrationTests { + + // 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); + + @Autowired + private DataSource dataSource; + + @Autowired + private JobLauncher jobLauncher; + + @Autowired + private Job job; + + @BeforeEach + void setUp() { + ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(); + databasePopulator.addScript(new ClassPathResource("/org/springframework/batch/core/schema-mariadb.sql")); + databasePopulator.execute(this.dataSource); + } + + @Test + void testJobExecution() throws Exception { + // given + JobParameters jobParameters = new JobParametersBuilder().toJobParameters(); + + // when + JobExecution jobExecution = this.jobLauncher.run(this.job, jobParameters); + + // then + assertNotNull(jobExecution); + assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus()); + } + + @Configuration + @EnableBatchProcessing + 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; + } + + @Bean + public JdbcTransactionManager transactionManager(DataSource dataSource) { + return new JdbcTransactionManager(dataSource); + } + + @Bean + public Job job(JobRepository jobRepository, PlatformTransactionManager transactionManager) { + return new JobBuilder("job", jobRepository) + .start(new StepBuilder("step", jobRepository) + .tasklet((contribution, chunkContext) -> RepeatStatus.FINISHED, transactionManager).build()) + .build(); + } + + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java index eff310378..2c20b25ff 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/builder/JdbcPagingItemReaderBuilder.java @@ -27,6 +27,7 @@ import org.springframework.batch.item.database.support.DerbyPagingQueryProvider; import org.springframework.batch.item.database.support.H2PagingQueryProvider; import org.springframework.batch.item.database.support.HanaPagingQueryProvider; import org.springframework.batch.item.database.support.HsqlPagingQueryProvider; +import org.springframework.batch.item.database.support.MariaDBPagingQueryProvider; import org.springframework.batch.item.database.support.MySqlPagingQueryProvider; import org.springframework.batch.item.database.support.OraclePagingQueryProvider; import org.springframework.batch.item.database.support.PostgresPagingQueryProvider; @@ -49,6 +50,7 @@ import org.springframework.util.Assert; * @author Michael Minella * @author Glenn Renfro * @author Drummond Dawson + * @author Mahmoud Ben Hassine * @since 4.0 * @see JdbcPagingItemReader */ @@ -360,6 +362,9 @@ public class JdbcPagingItemReaderBuilder { case MYSQL: provider = new MySqlPagingQueryProvider(); break; + case MARIADB: + provider = new MariaDBPagingQueryProvider(); + break; case ORACLE: provider = new OraclePagingQueryProvider(); break; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactory.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactory.java index c4df120af..a2cb80cd2 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactory.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactory.java @@ -40,6 +40,7 @@ import static org.springframework.batch.support.DatabaseType.DERBY; import static org.springframework.batch.support.DatabaseType.H2; import static org.springframework.batch.support.DatabaseType.HANA; import static org.springframework.batch.support.DatabaseType.HSQL; +import static org.springframework.batch.support.DatabaseType.MARIADB; import static org.springframework.batch.support.DatabaseType.MYSQL; import static org.springframework.batch.support.DatabaseType.ORACLE; import static org.springframework.batch.support.DatabaseType.POSTGRES; @@ -109,6 +110,9 @@ public class DefaultDataFieldMaxValueIncrementerFactory implements DataFieldMaxV mySQLMaxValueIncrementer.setUseNewConnection(true); return mySQLMaxValueIncrementer; } + else if (databaseType == MARIADB) { + return new MariaDBSequenceMaxValueIncrementer(dataSource, incrementerName); + } else if (databaseType == ORACLE) { return new OracleSequenceMaxValueIncrementer(dataSource, incrementerName); } diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProvider.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProvider.java new file mode 100644 index 000000000..25f47b150 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProvider.java @@ -0,0 +1,50 @@ +/* + * Copyright 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.batch.item.database.support; + +import org.springframework.batch.item.database.PagingQueryProvider; +import org.springframework.util.StringUtils; + +/** + * MariaDB implementation of a {@link PagingQueryProvider} using database specific + * features. + * + * @author Mahmoud Ben Hassine + * @since 5.0 + */ +public class MariaDBPagingQueryProvider extends AbstractSqlPagingQueryProvider { + + @Override + public String generateFirstPageQuery(int pageSize) { + return SqlPagingQueryUtils.generateLimitSqlQuery(this, false, buildLimitClause(pageSize)); + } + + @Override + public String generateRemainingPagesQuery(int pageSize) { + if (StringUtils.hasText(getGroupClause())) { + return SqlPagingQueryUtils.generateLimitGroupedSqlQuery(this, buildLimitClause(pageSize)); + } + else { + return SqlPagingQueryUtils.generateLimitSqlQuery(this, true, buildLimitClause(pageSize)); + } + } + + private String buildLimitClause(int pageSize) { + return new StringBuilder().append("LIMIT ").append(pageSize).toString(); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementer.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementer.java new file mode 100644 index 000000000..249c18e79 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementer.java @@ -0,0 +1,45 @@ +/* + * Copyright 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 + * + * 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, + * 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.jdbc.support.incrementer.AbstractSequenceMaxValueIncrementer; +import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer; + +/** + * {@link DataFieldMaxValueIncrementer} for MariaDB. + * + * @author Mahmoud Ben Hassine + * @since 5.0 + */ +// TODO replace this with the one from Spring Framework when available +public class MariaDBSequenceMaxValueIncrementer extends AbstractSequenceMaxValueIncrementer { + + public MariaDBSequenceMaxValueIncrementer() { + } + + public MariaDBSequenceMaxValueIncrementer(DataSource dataSource, String incrementerName) { + super(dataSource, incrementerName); + } + + @Override + protected String getSequenceQuery() { + return "select next value for " + this.getIncrementerName(); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryProviderFactoryBean.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryProviderFactoryBean.java index 3aae98615..c31b57905 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryProviderFactoryBean.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/database/support/SqlPagingQueryProviderFactoryBean.java @@ -23,6 +23,7 @@ import static org.springframework.batch.support.DatabaseType.DERBY; import static org.springframework.batch.support.DatabaseType.H2; import static org.springframework.batch.support.DatabaseType.HANA; import static org.springframework.batch.support.DatabaseType.HSQL; +import static org.springframework.batch.support.DatabaseType.MARIADB; import static org.springframework.batch.support.DatabaseType.MYSQL; import static org.springframework.batch.support.DatabaseType.ORACLE; import static org.springframework.batch.support.DatabaseType.POSTGRES; @@ -51,6 +52,7 @@ import org.springframework.util.StringUtils; * * @author Dave Syer * @author Michael Minella + * @author Mahmoud Ben Hassine */ public class SqlPagingQueryProviderFactoryBean implements FactoryBean { @@ -80,6 +82,7 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean nameMap; @@ -66,8 +67,6 @@ public enum DatabaseType { * @throws IllegalArgumentException if none is found. */ public static DatabaseType fromProductName(String productName) { - if (productName.equals("MariaDB")) - productName = "MySQL"; if (!nameMap.containsKey(productName)) { throw new IllegalArgumentException("DatabaseType not found for product name: [" + productName + "]"); } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactoryTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactoryTests.java index cdda73ef4..aed4171eb 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactoryTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/DefaultDataFieldMaxValueIncrementerFactoryTests.java @@ -63,6 +63,7 @@ class DefaultDataFieldMaxValueIncrementerFactoryTests { assertTrue(factory.isSupportedIncrementerType("sybase")); assertTrue(factory.isSupportedIncrementerType("sqlite")); assertTrue(factory.isSupportedIncrementerType("hana")); + assertTrue(factory.isSupportedIncrementerType("mariadb")); } @Test @@ -95,6 +96,11 @@ class DefaultDataFieldMaxValueIncrementerFactoryTests { assertTrue(factory.getIncrementer("mysql", "NAME") instanceof MySQLMaxValueIncrementer); } + @Test + void testMariaDB() { + assertTrue(factory.getIncrementer("mariadb", "NAME") instanceof MariaDBSequenceMaxValueIncrementer); + } + @Test void testOracle() { factory.setIncrementerColumnName("ID"); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderTests.java new file mode 100644 index 000000000..7921e6da7 --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBPagingQueryProviderTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 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.batch.item.database.support; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import org.springframework.batch.item.database.Order; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Mahmoud Ben Hassine + */ +class MariaDBPagingQueryProviderTests extends AbstractSqlPagingQueryProviderTests { + + MariaDBPagingQueryProviderTests() { + pagingQueryProvider = new MariaDBPagingQueryProvider(); + } + + @Test + @Override + void testGenerateFirstPageQuery() { + String sql = "SELECT id, name, age FROM foo WHERE bar = 1 ORDER BY id ASC LIMIT 100"; + String s = pagingQueryProvider.generateFirstPageQuery(pageSize); + assertEquals(sql, s); + } + + @Test + @Override + void testGenerateRemainingPagesQuery() { + String sql = "SELECT id, name, age FROM foo WHERE (bar = 1) AND ((id > ?)) ORDER BY id ASC LIMIT 100"; + String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize); + assertEquals(sql, s); + } + + @Override + @Test + void testGenerateFirstPageQueryWithGroupBy() { + pagingQueryProvider.setGroupClause("dep"); + String sql = "SELECT id, name, age FROM foo WHERE bar = 1 GROUP BY dep ORDER BY id ASC LIMIT 100"; + String s = pagingQueryProvider.generateFirstPageQuery(pageSize); + assertEquals(sql, s); + } + + @Override + @Test + void testGenerateRemainingPagesQueryWithGroupBy() { + pagingQueryProvider.setGroupClause("dep"); + String sql = "SELECT * FROM (SELECT id, name, age FROM foo WHERE bar = 1 GROUP BY dep) AS MAIN_QRY WHERE ((id > ?)) ORDER BY id ASC LIMIT 100"; + String s = pagingQueryProvider.generateRemainingPagesQuery(pageSize); + assertEquals(sql, s); + } + + @Test + void testFirstPageSqlWithAliases() { + Map sorts = new HashMap<>(); + sorts.put("owner.id", Order.ASCENDING); + + this.pagingQueryProvider = new MySqlPagingQueryProvider(); + this.pagingQueryProvider.setSelectClause("SELECT owner.id as ownerid, first_name, last_name, dog_name "); + this.pagingQueryProvider.setFromClause("FROM dog_owner owner INNER JOIN dog ON owner.id = dog.id "); + this.pagingQueryProvider.setSortKeys(sorts); + + String firstPage = this.pagingQueryProvider.generateFirstPageQuery(5); + String remainingPagesQuery = this.pagingQueryProvider.generateRemainingPagesQuery(5); + + assertEquals( + "SELECT owner.id as ownerid, first_name, last_name, dog_name FROM dog_owner owner INNER JOIN dog ON owner.id = dog.id ORDER BY owner.id ASC LIMIT 5", + firstPage); + assertEquals( + "SELECT owner.id as ownerid, first_name, last_name, dog_name FROM dog_owner owner INNER JOIN dog ON owner.id = dog.id WHERE ((owner.id > ?)) ORDER BY owner.id ASC LIMIT 5", + remainingPagesQuery); + } + + @Override + String getFirstPageSqlWithMultipleSortKeys() { + return "SELECT id, name, age FROM foo WHERE bar = 1 ORDER BY name ASC, id DESC LIMIT 100"; + } + + @Override + String getRemainingSqlWithMultipleSortKeys() { + return "SELECT id, name, age FROM foo WHERE (bar = 1) AND ((name > ?) OR (name = ? AND id < ?)) ORDER BY name ASC, id DESC LIMIT 100"; + } + +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementerTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementerTests.java new file mode 100644 index 000000000..b27d74272 --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/database/support/MariaDBSequenceMaxValueIncrementerTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 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.batch.item.database.support; + +import javax.sql.DataSource; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author Mahmoud Ben Hassine + */ +@ExtendWith(MockitoExtension.class) +class MariaDBSequenceMaxValueIncrementerTests { + + @Mock + private DataSource dataSource; + + @Test + void testGetSequenceQuery() { + // given + var incrementer = new MariaDBSequenceMaxValueIncrementer(this.dataSource, "BATCH_JOB_SEQ"); + + // when + String sequenceQuery = incrementer.getSequenceQuery(); + + // then + assertEquals("select next value for BATCH_JOB_SEQ", sequenceQuery); + } + +} \ No newline at end of file