Add full support for MariaDB

This commit adds full support for MariaDB as
a job repository and removes the code that
treats it as MySQL.

Resolves #3891
Resolves #4217
This commit is contained in:
Mahmoud Ben Hassine
2022-10-25 11:11:57 +02:00
parent 724cc97ed6
commit 524e9564c0
15 changed files with 503 additions and 3 deletions

View File

@@ -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<T> {
case MYSQL:
provider = new MySqlPagingQueryProvider();
break;
case MARIADB:
provider = new MariaDBPagingQueryProvider();
break;
case ORACLE:
provider = new OraclePagingQueryProvider();
break;

View File

@@ -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);
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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<PagingQueryProvider> {
@@ -80,6 +82,7 @@ public class SqlPagingQueryProviderFactoryBean implements FactoryBean<PagingQuer
providers.put(H2, new H2PagingQueryProvider());
providers.put(HANA, new HanaPagingQueryProvider());
providers.put(MYSQL, new MySqlPagingQueryProvider());
providers.put(MARIADB, new MariaDBPagingQueryProvider());
providers.put(ORACLE, new OraclePagingQueryProvider());
providers.put(POSTGRES, new PostgresPagingQueryProvider());
providers.put(SQLITE, new SqlitePagingQueryProvider());

View File

@@ -31,13 +31,14 @@ import java.util.Map;
* database driver's metadata.
*
* @author Lucas Ward
* @author Mahmoud Ben Hassine
* @since 2.0
*/
public enum DatabaseType {
DERBY("Apache Derby"), DB2("DB2"), DB2VSE("DB2VSE"), DB2ZOS("DB2ZOS"), DB2AS400("DB2AS400"),
HSQL("HSQL Database Engine"), SQLSERVER("Microsoft SQL Server"), MYSQL("MySQL"), ORACLE("Oracle"),
POSTGRES("PostgreSQL"), SYBASE("Sybase"), H2("H2"), SQLITE("SQLite"), HANA("HDB");
POSTGRES("PostgreSQL"), SYBASE("Sybase"), H2("H2"), SQLITE("SQLite"), HANA("HDB"), MARIADB("MariaDB");
private static final Map<String, DatabaseType> 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 + "]");
}

View File

@@ -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");

View File

@@ -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<String, Order> 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";
}
}

View File

@@ -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);
}
}