diff --git a/pom.xml b/pom.xml
index 769a9e4fb..e4b3bd468 100644
--- a/pom.xml
+++ b/pom.xml
@@ -248,6 +248,13 @@
test
+
+ org.mariadb.jdbc
+ mariadb-java-client
+ 2.6.0
+ test
+
+
com.sap.cloud.db.jdbc
ngdbc
diff --git a/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbHistorySupport.java b/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbHistorySupport.java
new file mode 100644
index 000000000..4a8210863
--- /dev/null
+++ b/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbHistorySupport.java
@@ -0,0 +1,38 @@
+package io.ebean.config.dbplatform.mariadb;
+
+import io.ebean.config.dbplatform.DbStandardHistorySupport;
+
+/**
+ * History support for MariaDB.
+ */
+public class MariaDbHistorySupport extends DbStandardHistorySupport {
+
+ /**
+ * Return the ' as of timestamp ?' clause appended after the table name.
+ */
+ @Override
+ public String getAsOfViewSuffix(String asOfViewSuffix) {
+ return " for system_time as of ?";
+ }
+
+ @Override
+ public String getVersionsBetweenSuffix(String asOfViewSuffix) {
+ return " for system_time between ? and ?";
+ }
+
+ /**
+ * Returns the SQL Server specific effective start column.
+ */
+ @Override
+ public String getSysPeriodLower(String tableAlias, String sysPeriod) {
+ return tableAlias + "." + sysPeriod + "From";
+ }
+
+ /**
+ * Returns the SQL Server specific effective end column.
+ */
+ @Override
+ public String getSysPeriodUpper(String tableAlias, String sysPeriod) {
+ return tableAlias + "." + sysPeriod + "To";
+ }
+}
diff --git a/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java b/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java
new file mode 100644
index 000000000..082f31c11
--- /dev/null
+++ b/src/main/java/io/ebean/config/dbplatform/mariadb/MariaDbPlatform.java
@@ -0,0 +1,16 @@
+package io.ebean.config.dbplatform.mariadb;
+
+import io.ebean.annotation.Platform;
+import io.ebean.config.dbplatform.mysql.BaseMySqlPlatform;
+
+/**
+ * MariaDB platform.
+ */
+public class MariaDbPlatform extends BaseMySqlPlatform {
+
+ public MariaDbPlatform() {
+ super();
+ this.platform = Platform.MARIADB;
+ this.historySupport = new MariaDbHistorySupport();
+ }
+}
diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java
new file mode 100644
index 000000000..7cd33008c
--- /dev/null
+++ b/src/main/java/io/ebean/config/dbplatform/mysql/BaseMySqlPlatform.java
@@ -0,0 +1,68 @@
+package io.ebean.config.dbplatform.mysql;
+
+import io.ebean.Query;
+import io.ebean.config.dbplatform.DatabasePlatform;
+import io.ebean.config.dbplatform.DbPlatformType;
+import io.ebean.config.dbplatform.DbType;
+import io.ebean.config.dbplatform.IdType;
+import io.ebean.config.dbplatform.SqlErrorCodes;
+
+import java.sql.Types;
+
+/**
+ * Base platform for both MySql and MariaDB.
+ */
+public abstract class BaseMySqlPlatform extends DatabasePlatform {
+
+ public BaseMySqlPlatform() {
+ super();
+ this.useExtraTransactionOnIterateSecondaryQueries = true;
+ this.selectCountWithAlias = true;
+ this.supportsSavepointId = false;
+ this.inlineSqlUpdateLimit = true;
+ this.dbEncrypt = new MySqlDbEncrypt();
+ this.historySupport = new MySqlHistorySupport();
+ this.dbIdentity.setIdType(IdType.IDENTITY);
+ this.dbIdentity.setSupportsGetGeneratedKeys(true);
+ this.dbIdentity.setSupportsIdentity(true);
+ this.dbIdentity.setSupportsSequence(false);
+
+ this.dbDefaultValue.setNow("now(6)"); // must have same precision as TIMESTAMP
+ this.dbDefaultValue.setFalse("0");
+ this.dbDefaultValue.setTrue("1");
+
+
+ this.exceptionTranslator =
+ new SqlErrorCodes()
+ .addAcquireLock("1205")
+ .addDuplicateKey("1062", "1169")
+ .addDataIntegrity("630", "839", "840", "893", "1215", "1216", "1217", "1364", "1451", "1452", "1557")
+ .build();
+
+ this.openQuote = "`";
+ this.closeQuote = "`";
+ // use pipe for escaping as it depends if mysql runs in no_backslash_escapes or not.
+ this.likeClauseRaw = "like ? escape''";
+ this.likeClauseEscaped = "like ? escape'|'";
+
+ this.forwardOnlyHintOnFindIterate = true;
+ this.booleanDbType = Types.BIT;
+
+ dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1)"));
+ dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1)"));
+ dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
+ dbTypeMap.put(DbType.CLOB, new MySqlClob());
+ dbTypeMap.put(DbType.BLOB, new MySqlBlob());
+ dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
+ dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
+ dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
+ dbTypeMap.put(DbType.JSONB, new DbPlatformType("json", false));
+ }
+
+ @Override
+ protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
+ // NOWAIT and SKIP LOCKED currently not supported with MySQL
+ return sql + " for update";
+ }
+
+}
diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java
index f1d24b768..780668f02 100644
--- a/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java
+++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySql55Platform.java
@@ -4,7 +4,7 @@ import io.ebean.annotation.Platform;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.config.dbplatform.DbType;
-public class MySql55Platform extends MySqlPlatform {
+public class MySql55Platform extends BaseMySqlPlatform {
public MySql55Platform() {
super();
diff --git a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
index 944da83ab..be4aaa166 100644
--- a/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
+++ b/src/main/java/io/ebean/config/dbplatform/mysql/MySqlPlatform.java
@@ -1,77 +1,15 @@
package io.ebean.config.dbplatform.mysql;
-import io.ebean.Query;
import io.ebean.annotation.Platform;
-import io.ebean.config.dbplatform.DatabasePlatform;
-import io.ebean.config.dbplatform.DbPlatformType;
-import io.ebean.config.dbplatform.DbType;
-import io.ebean.config.dbplatform.IdType;
-import io.ebean.config.dbplatform.SqlErrorCodes;
-
-import java.sql.Types;
/**
* MySQL specific platform.
- *
- *
- * - supportsGetGeneratedKeys = true
- * - Uses LIMIT OFFSET clause
- * - Uses ` for quoted identifiers
- *
- *
*/
-public class MySqlPlatform extends DatabasePlatform {
+public class MySqlPlatform extends BaseMySqlPlatform {
public MySqlPlatform() {
super();
this.platform = Platform.MYSQL;
- this.useExtraTransactionOnIterateSecondaryQueries = true;
- this.selectCountWithAlias = true;
- this.supportsSavepointId = false;
- this.inlineSqlUpdateLimit = true;
- this.dbEncrypt = new MySqlDbEncrypt();
- this.historySupport = new MySqlHistorySupport();
- this.dbIdentity.setIdType(IdType.IDENTITY);
- this.dbIdentity.setSupportsGetGeneratedKeys(true);
- this.dbIdentity.setSupportsIdentity(true);
- this.dbIdentity.setSupportsSequence(false);
-
- this.dbDefaultValue.setNow("now(6)"); // must have same precision as TIMESTAMP
- this.dbDefaultValue.setFalse("0");
- this.dbDefaultValue.setTrue("1");
-
-
- this.exceptionTranslator =
- new SqlErrorCodes()
- .addAcquireLock("1205")
- .addDuplicateKey("1062", "1169")
- .addDataIntegrity("630", "839", "840", "893", "1215", "1216", "1217", "1364", "1451", "1452", "1557")
- .build();
-
- this.openQuote = "`";
- this.closeQuote = "`";
- // use pipe for escaping as it depends if mysql runs in no_backslash_escapes or not.
- this.likeClauseRaw = "like ? escape''";
- this.likeClauseEscaped = "like ? escape'|'";
-
- this.forwardOnlyHintOnFindIterate = true;
- this.booleanDbType = Types.BIT;
-
- dbTypeMap.put(DbType.BIT, new DbPlatformType("tinyint(1)"));
- dbTypeMap.put(DbType.BOOLEAN, new DbPlatformType("tinyint(1)"));
- dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime(6)"));
- dbTypeMap.put(DbType.CLOB, new MySqlClob());
- dbTypeMap.put(DbType.BLOB, new MySqlBlob());
- dbTypeMap.put(DbType.BINARY, new DbPlatformType("binary", 255));
- dbTypeMap.put(DbType.VARBINARY, new DbPlatformType("varbinary", 255));
- dbTypeMap.put(DbType.JSON, new DbPlatformType("json", false));
- dbTypeMap.put(DbType.JSONB, new DbPlatformType("json", false));
- }
-
- @Override
- protected String withForUpdate(String sql, Query.ForUpdate forUpdateMode) {
- // NOWAIT and SKIP LOCKED currently not supported with MySQL
- return sql + " for update";
}
}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java
index 7b36be18b..8130293ef 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java
@@ -15,6 +15,7 @@ import io.ebean.config.dbplatform.db2.DB2Platform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.config.dbplatform.hana.HanaPlatform;
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
+import io.ebean.config.dbplatform.mariadb.MariaDbPlatform;
import io.ebean.config.dbplatform.mysql.MySql55Platform;
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
@@ -820,6 +821,8 @@ public class DefaultDbMigration implements DbMigration {
return new Postgres9Platform();
case POSTGRES:
return new PostgresPlatform();
+ case MARIADB:
+ return new MariaDbPlatform();
case MYSQL55:
return new MySql55Platform();
case MYSQL:
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbDdl.java
new file mode 100644
index 000000000..a4f5775b5
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbDdl.java
@@ -0,0 +1,14 @@
+package io.ebeaninternal.dbmigration.ddlgeneration.platform;
+
+import io.ebean.config.dbplatform.DatabasePlatform;
+
+/**
+ * MariaDB platform DDL.
+ */
+public class MariaDbDdl extends MySqlDdl {
+
+ public MariaDbDdl(DatabasePlatform platform) {
+ super(platform);
+ this.historyDdl = new MariaDbHistoryDdl();
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbHistoryDdl.java b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbHistoryDdl.java
new file mode 100644
index 000000000..e33e53686
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/dbmigration/ddlgeneration/platform/MariaDbHistoryDdl.java
@@ -0,0 +1,98 @@
+package io.ebeaninternal.dbmigration.ddlgeneration.platform;
+
+import io.ebean.config.ServerConfig;
+import io.ebeaninternal.dbmigration.ddlgeneration.DdlBuffer;
+import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite;
+import io.ebeaninternal.dbmigration.migration.AddHistoryTable;
+import io.ebeaninternal.dbmigration.migration.DropHistoryTable;
+import io.ebeaninternal.dbmigration.model.MTable;
+
+import java.io.IOException;
+
+/**
+ * History DDL for MariaDB.
+ */
+public class MariaDbHistoryDdl implements PlatformHistoryDdl {
+
+ private String systemPeriodStart;
+ private String systemPeriodEnd;
+ private PlatformDdl platformDdl;
+
+ @Override
+ public void configure(ServerConfig serverConfig, PlatformDdl platformDdl) {
+ this.systemPeriodStart = serverConfig.getAsOfSysPeriod() + "From";
+ this.systemPeriodEnd = serverConfig.getAsOfSysPeriod() + "To";
+ this.platformDdl = platformDdl;
+ }
+
+ @Override
+ public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
+ String baseTable = table.getName();
+ enableSystemVersioning(writer, baseTable);
+ }
+
+ String getHistoryTable(String baseTable) {
+ String historyTable = baseTable + "_history";
+ if (baseTable.startsWith("[")) {
+ historyTable = historyTable.replace("]", "") + "]";
+ }
+ if (historyTable.indexOf('.') == -1) {
+ // history must contain schema, add the default schema if none was specified
+ historyTable = "dbo." + historyTable;
+ }
+ return historyTable;
+ }
+
+ private void enableSystemVersioning(DdlWrite writer, String baseTable) throws IOException {
+ DdlBuffer apply = writer.applyHistoryView();
+
+ final String systemTime = String.format("system_time(%s, %s),", systemPeriodStart, systemPeriodEnd);
+ apply.append("alter table ").append(baseTable).newLine()
+ .append(" add column ").append(systemPeriodStart).append(" timestamp(6) generated always as row start,").newLine()
+ .append(" add column ").append(systemPeriodEnd).append(" timestamp(6) generated always as row end,").newLine()
+ .append(" add period for ").append(systemTime).newLine()
+ .append(" add system versioning;").newLine();
+
+ DdlBuffer drop = writer.dropAll();
+ //drop.append("IF OBJECT_ID('").append(baseTable).append("', 'U') IS NOT NULL alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
+ //drop.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
+ }
+
+ @Override
+ public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
+ String baseTable = dropHistoryTable.getBaseTable();
+ DdlBuffer apply = writer.applyHistoryView();
+ apply.append("-- dropping history support for ").append(baseTable).endOfStatement();
+ // drop default constraints
+
+ apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodStart, DdlHelp.DROP_DEFAULT)).endOfStatement();
+ apply.append(platformDdl.alterColumnDefaultValue(baseTable, systemPeriodEnd, DdlHelp.DROP_DEFAULT)).endOfStatement();
+ // switch of versioning & period
+ apply.append("alter table ").append(baseTable).append(" set (system_versioning = off)").endOfStatement();
+ apply.append("alter table ").append(baseTable).append(" drop period for system_time").endOfStatement();
+ // now drop tables & columns
+ apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodStart).endOfStatement();
+ apply.append("alter table ").append(baseTable).append(" drop column ").append(systemPeriodEnd).endOfStatement();
+ //apply.append("IF OBJECT_ID('").append(baseTable).append("_history', 'U') IS NOT NULL drop table ").append(baseTable).append("_history").endOfStatement();
+ apply.end();
+ }
+
+ @Override
+ public void addHistoryTable(DdlWrite writer, AddHistoryTable addHistoryTable) throws IOException {
+ String baseTable = addHistoryTable.getBaseTable();
+ enableSystemVersioning(writer, baseTable);
+ }
+
+ @Override
+ public void updateTriggers(DdlWrite writer, HistoryTableUpdate baseTable) throws IOException {
+ // SQL Server 2016 does not need triggers
+ DdlBuffer apply = writer.applyHistoryView();
+ String baseTableName = baseTable.getBaseTable();
+ apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = off (history_table=")
+ .append(getHistoryTable(baseTableName)).append("))").endOfStatement();
+ apply.append("-- history migration goes here").newLine();
+ apply.append("-- alter table ").append(baseTableName).append(" set (system_versioning = on (history_table=")
+ .append(getHistoryTable(baseTableName)).append("))").endOfStatement();
+
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java
index 15858e8d9..7c65d7f0e 100644
--- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java
+++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java
@@ -8,6 +8,7 @@ import io.ebean.config.dbplatform.db2.DB2Platform;
import io.ebean.config.dbplatform.h2.H2Platform;
import io.ebean.config.dbplatform.hana.HanaPlatform;
import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform;
+import io.ebean.config.dbplatform.mariadb.MariaDbPlatform;
import io.ebean.config.dbplatform.mysql.MySql55Platform;
import io.ebean.config.dbplatform.mysql.MySqlPlatform;
import io.ebean.config.dbplatform.nuodb.NuoDbPlatform;
@@ -76,11 +77,13 @@ public class DatabasePlatformFactory {
* Lookup the platform by name.
*/
private DatabasePlatform byDatabaseName(String dbName) {
-
dbName = dbName.toLowerCase();
if (dbName.equals("h2")) {
return new H2Platform();
}
+ if (dbName.equals("mariadb")) {
+ return new MariaDbPlatform();
+ }
if (dbName.equals("mysql")) {
return new MySqlPlatform();
}
@@ -123,7 +126,6 @@ public class DatabasePlatformFactory {
if (dbName.equals("hana")) {
return new HanaPlatform();
}
-
throw new RuntimeException("database platform " + dbName + " is not known?");
}
@@ -160,14 +162,16 @@ public class DatabasePlatformFactory {
return new OraclePlatform();
} else if (dbProductName.contains("microsoft")) {
throw new IllegalArgumentException("For SqlServer please explicitly choose either sqlserver16 or sqlserver17 as the platform via ServerConfig.setDatabasePlatformName. Refer to issue #1340 for more details");
- } else if (dbProductName.contains("mysql")) {
- return mysqlVersion(majorVersion, minorVersion);
} else if (dbProductName.contains("h2")) {
return new H2Platform();
} else if (dbProductName.contains("hsql database engine")) {
return new HsqldbPlatform();
} else if (dbProductName.contains("postgres")) {
return readPostgres(connection, majorVersion);
+ } else if (dbProductName.contains("mariadb")) {
+ return new MariaDbPlatform();
+ } else if (dbProductName.contains("mysql")) {
+ return mysqlVersion(majorVersion, minorVersion);
} else if (dbProductName.contains("nuo")) {
return new NuoDbPlatform();
} else if (dbProductName.contains("sqlite")) {
diff --git a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
index 033841ab6..5fa296997 100644
--- a/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
+++ b/src/main/java/io/ebeaninternal/server/core/InternalConfiguration.java
@@ -503,10 +503,9 @@ public class InternalConfiguration {
* Create the DataTimeZone implementation to use.
*/
private DataTimeZone initDataTimeZone() {
-
String tz = serverConfig.getDataTimeZone();
if (tz == null) {
- if (isMySql(getPlatform())) {
+ if (isMySqlOrMariaDB(getPlatform())) {
return new MySqlDataTimeZone();
}
return new NoDataTimeZone();
@@ -518,8 +517,8 @@ public class InternalConfiguration {
}
}
- private boolean isMySql(Platform platform) {
- return platform.base() == Platform.MYSQL;
+ private boolean isMySqlOrMariaDB(Platform platform) {
+ return platform.base() == Platform.MYSQL || platform.base() == Platform.MARIADB;
}
public DataTimeZone getDataTimeZone() {
diff --git a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java
index 1c39dbbb8..7e6701bc0 100644
--- a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java
+++ b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java
@@ -7,6 +7,7 @@ import io.ebeaninternal.dbmigration.ddlgeneration.platform.DB2Ddl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.H2Ddl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.HanaColumnStoreDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.HsqldbDdl;
+import io.ebeaninternal.dbmigration.ddlgeneration.platform.MariaDbDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.MySqlDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.NuoDbDdl;
import io.ebeaninternal.dbmigration.ddlgeneration.platform.OracleDdl;
@@ -31,6 +32,8 @@ public class PlatformDdlBuilder {
return new H2Ddl(platform);
case DB2:
return new DB2Ddl(platform);
+ case MARIADB:
+ return new MariaDbDdl(platform);
case MYSQL55:
case MYSQL:
return new MySqlDdl(platform);
diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java
index 2a99dcab4..c4b24fc84 100644
--- a/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java
+++ b/src/main/java/io/ebeaninternal/server/expression/platform/DbExpressionHandlerFactory.java
@@ -18,6 +18,8 @@ public class DbExpressionHandlerFactory {
case POSTGRES:
case POSTGRES9:
return new PostgresDbExpression();
+ case MARIADB:
+ return new MariaDbExpression();
case MYSQL55:
case MYSQL:
return new MySqlDbExpression();
diff --git a/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java b/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java
new file mode 100644
index 000000000..8e4c0be1d
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/expression/platform/MariaDbExpression.java
@@ -0,0 +1,16 @@
+package io.ebeaninternal.server.expression.platform;
+
+import io.ebeaninternal.api.SpiExpressionRequest;
+import io.ebeaninternal.server.expression.Op;
+
+/**
+ * MariaDB specific handling of platform specific expressions.
+ */
+class MariaDbExpression extends BasicDbExpression {
+
+ @Override
+ public void json(SpiExpressionRequest request, String propName, String path, Op operator, Object value) {
+ request.append("(").append(propName).append(" ->> '$.").append(path).append("')");
+ request.append(operator.bind());
+ }
+}
diff --git a/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java b/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java
index 13182705a..abaefd095 100644
--- a/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java
+++ b/src/main/java/io/ebeaninternal/server/persist/dml/InsertMeta.java
@@ -13,6 +13,9 @@ import io.ebeaninternal.server.persist.dmlbind.BindableList;
import java.sql.SQLException;
+import static io.ebean.annotation.Platform.MARIADB;
+import static io.ebean.annotation.Platform.MYSQL;
+
/**
* Meta data for insert handler. The meta data is for a particular bean type. It
* is considered immutable and is thread safe.
@@ -166,12 +169,7 @@ final class InsertMeta {
request.append("insert into ").append(table);
if (nullId && noColumnsForInsert(draftTable)) {
- if (this.platform.base() == Platform.MYSQL) {
- request.append(" values (default)");
- } else {
- request.append(" default values");
- }
- return request.toString();
+ return request.append(defaultValues()).toString();
}
request.append(" (");
@@ -199,6 +197,10 @@ final class InsertMeta {
return request.toString();
}
+ private String defaultValues() {
+ return platform.base() == MYSQL || platform.base() == MARIADB ? " values (default)" : " default values";
+ }
+
/**
* Return true if the insert actually contains no columns.
*/
diff --git a/src/test/java/io/ebean/BaseTestCase.java b/src/test/java/io/ebean/BaseTestCase.java
index 6c1326d77..df0d732ed 100644
--- a/src/test/java/io/ebean/BaseTestCase.java
+++ b/src/test/java/io/ebean/BaseTestCase.java
@@ -206,6 +206,10 @@ public abstract class BaseTestCase {
return Platform.MYSQL == platform();
}
+ public boolean isMariaDB() {
+ return Platform.MARIADB == platform();
+ }
+
public boolean isHana() {
return Platform.HANA == platform();
}
diff --git a/src/test/java/io/ebean/UpdateQueryTest.java b/src/test/java/io/ebean/UpdateQueryTest.java
index 9096c20e1..43ca6d7f7 100644
--- a/src/test/java/io/ebean/UpdateQueryTest.java
+++ b/src/test/java/io/ebean/UpdateQueryTest.java
@@ -168,7 +168,7 @@ public class UpdateQueryTest extends BaseTestCase {
assertSql(query).contains("update o_customer cust set status=?, updtime=? where id > ?");
}
- @IgnorePlatform(Platform.MYSQL)
+ @IgnorePlatform({Platform.MYSQL, Platform.MARIADB})
@Test
public void withJoin() {
@@ -214,7 +214,7 @@ public class UpdateQueryTest extends BaseTestCase {
assertSql(sql.get(0)).contains("update o_customer set status=? where id in (select t0.id from o_customer t0 left join o_address t1 on t1.id = t0.billing_address_id where t1.country_code = ? and t0.id > ? limit 100)");
}
- @ForPlatform({Platform.H2, Platform.POSTGRES, Platform.MYSQL})
+ @ForPlatform({Platform.H2, Platform.POSTGRES, Platform.MYSQL, Platform.MARIADB})
@Test
public void simpleWithLimit() {
@@ -230,7 +230,7 @@ public class UpdateQueryTest extends BaseTestCase {
.update();
final List sql = LoggedSqlCollector.stop();
- if (isMySql() || isH2()) {
+ if (isMySql() || isH2() || isMariaDB()) {
assertSql(sql.get(0)).contains("update o_customer set status=? where id > ? limit 100");
} else {
assertSql(sql.get(0)).contains("update o_customer set status=? where id in (select t0.id from o_customer t0 where t0.id > ? limit 100)");
diff --git a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
index 53c477266..e16414594 100644
--- a/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
+++ b/src/test/java/io/ebeaninternal/dbmigration/DbMigrationTest.java
@@ -24,7 +24,7 @@ public class DbMigrationTest extends BaseTestCase {
server().script().runScript(scriptName, content, useAutoCommit);
}
- @IgnorePlatform({Platform.ORACLE, Platform.NUODB})
+ @IgnorePlatform({Platform.ORACLE, Platform.NUODB, Platform.MARIADB})
@Test
public void testRunMigration() throws IOException {
// first clean up previously created objects
diff --git a/src/test/java/main/StartMariaDb.java b/src/test/java/main/StartMariaDb.java
new file mode 100644
index 000000000..8bdf82bd7
--- /dev/null
+++ b/src/test/java/main/StartMariaDb.java
@@ -0,0 +1,18 @@
+package main;
+
+import io.ebean.docker.commands.MariaDBConfig;
+import io.ebean.docker.commands.MariaDBContainer;
+
+public class StartMariaDb {
+
+ public static void main(String[] args) {
+
+ MariaDBConfig config = new MariaDBConfig("10.5");
+ config.setDbName("unit");
+ config.setUser("unit");
+ config.setPassword("unit");
+
+ MariaDBContainer container = new MariaDBContainer(config);
+ container.startWithDropCreate();
+ }
+}
diff --git a/src/test/java/org/tests/aggregateformula/TestAggregateFormula.java b/src/test/java/org/tests/aggregateformula/TestAggregateFormula.java
index f646ff9e8..b9dc68a03 100644
--- a/src/test/java/org/tests/aggregateformula/TestAggregateFormula.java
+++ b/src/test/java/org/tests/aggregateformula/TestAggregateFormula.java
@@ -19,7 +19,7 @@ import static org.junit.Assert.assertNotNull;
public class TestAggregateFormula extends BaseTestCase {
- @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.NUODB})
+ @IgnorePlatform({Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB, Platform.NUODB})
@Test
public void minDistinctOrderByNulls() {
diff --git a/src/test/java/org/tests/basic/TestMetaAnnotation.java b/src/test/java/org/tests/basic/TestMetaAnnotation.java
index 3b4c781f6..f4638884e 100644
--- a/src/test/java/org/tests/basic/TestMetaAnnotation.java
+++ b/src/test/java/org/tests/basic/TestMetaAnnotation.java
@@ -49,7 +49,7 @@ public class TestMetaAnnotation extends BaseTestCase {
* This test writes 101 spaces to "line1" which is annotated with @Size(max=100).
*/
@Test
- @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL}) // pg & mssql does not fail if string is too long.
+ @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB}) // pg & mssql does not fail if string is too long.
public void testWrite101SpacesToLine1() {
Address address = new Address();
@@ -66,7 +66,7 @@ public class TestMetaAnnotation extends BaseTestCase {
* This test writes 101 spaces to "line1" which is meta-annotated with {@link SizeMedium}.
*/
@Test
- @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL})
+ @IgnorePlatform({Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testWrite101SpacesToLine2() {
Address address = new Address();
diff --git a/src/test/java/org/tests/basic/TestQueryForUpdate.java b/src/test/java/org/tests/basic/TestQueryForUpdate.java
index 2f4800a82..45c5d5b9f 100644
--- a/src/test/java/org/tests/basic/TestQueryForUpdate.java
+++ b/src/test/java/org/tests/basic/TestQueryForUpdate.java
@@ -23,7 +23,7 @@ public class TestQueryForUpdate extends BaseTestCase {
@Test
- @ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL})
+ @ForPlatform({Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testForUpdate() {
ResetBasicData.reset();
@@ -41,7 +41,7 @@ public class TestQueryForUpdate extends BaseTestCase {
}
@Test
- @ForPlatform({ Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL})
+ @ForPlatform({ Platform.H2, Platform.ORACLE, Platform.POSTGRES, Platform.SQLSERVER, Platform.MYSQL, Platform.MARIADB})
public void testForUpdate_when_alreadyInPC() {
EBasic basic = new EBasic("test PC cache");
diff --git a/src/test/java/org/tests/defaultvalues/TestDefaults.java b/src/test/java/org/tests/defaultvalues/TestDefaults.java
index b2bc6e2d1..a5f7affb2 100644
--- a/src/test/java/org/tests/defaultvalues/TestDefaults.java
+++ b/src/test/java/org/tests/defaultvalues/TestDefaults.java
@@ -26,7 +26,7 @@ public class TestDefaults extends BaseTestCase {
final List current = LoggedSqlCollector.current();
assertThat(current).isNotEmpty();
- if (isMySql()) {
+ if (isMySql() || isMariaDB()) {
assertThat(current.get(0)).contains("insert into defaults_model_draft values (default);");
} else if (isSqlServer()) {
assertThat(current.get(0)).contains("insert into defaults_model_draft (id) values (?)");
diff --git a/src/test/java/org/tests/delete/TestDeleteByQuery.java b/src/test/java/org/tests/delete/TestDeleteByQuery.java
index 52fc8eb73..9aceaacb1 100644
--- a/src/test/java/org/tests/delete/TestDeleteByQuery.java
+++ b/src/test/java/org/tests/delete/TestDeleteByQuery.java
@@ -27,7 +27,7 @@ public class TestDeleteByQuery extends BaseTestCase {
}
@Test
- @IgnorePlatform(Platform.MYSQL)
+ @IgnorePlatform({Platform.MYSQL, Platform.MARIADB})
public void deleteWithLimit() {
createUser("deleteWithLimit1");
createUser("deleteWithLimit2");
diff --git a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java
index 72a2bd691..cf451eee2 100644
--- a/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java
+++ b/src/test/java/org/tests/query/orderby/TestOrderByWithDistinct.java
@@ -41,7 +41,7 @@ public class TestOrderByWithDistinct extends BaseTestCase {
}
@Test
- @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER, Platform.NUODB}) // do not support nulls first/last
+ @IgnorePlatform({Platform.MYSQL, Platform.MARIADB, Platform.SQLSERVER, Platform.NUODB}) // do not support nulls first/last
public void testDistinctOn() {
MRole role = Ebean.getReference(MRole.class, 1);
diff --git a/src/test/java/org/tests/query/other/TestWhereLikeWithSlash.java b/src/test/java/org/tests/query/other/TestWhereLikeWithSlash.java
index 71dfe5600..c36cd28c8 100644
--- a/src/test/java/org/tests/query/other/TestWhereLikeWithSlash.java
+++ b/src/test/java/org/tests/query/other/TestWhereLikeWithSlash.java
@@ -26,7 +26,7 @@ public class TestWhereLikeWithSlash extends BaseTestCase {
Query query1 = Ebean.find(EBasic.class).where().like("name", "slash\\mon%").query();
List list1 = query1.findList();
- if (!isMySql() && !isNuoDb()) {
+ if (!isMySql() && !isNuoDb() && !isMariaDB()) {
// For mysql this assert depends on no_backslash_escapes setting so we won't assert here
// Still good on Postgres which was the original issue
assertEquals(1, list1.size());
diff --git a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java
index 58b8c2285..e29798c6b 100644
--- a/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java
+++ b/src/test/java/org/tests/rawsql/TestRawSqlOrmQuery.java
@@ -117,7 +117,7 @@ public class TestRawSqlOrmQuery extends BaseTestCase {
}
@Test
- @IgnorePlatform({Platform.MYSQL, Platform.SQLSERVER})
+ @IgnorePlatform({Platform.MYSQL, Platform.MARIADB, Platform.SQLSERVER})
public void test_upperCaseSql() {
ResetBasicData.reset();
diff --git a/src/test/java/org/tests/types/TestNewTypes.java b/src/test/java/org/tests/types/TestNewTypes.java
index e8a75a4de..ca02e91bc 100644
--- a/src/test/java/org/tests/types/TestNewTypes.java
+++ b/src/test/java/org/tests/types/TestNewTypes.java
@@ -36,6 +36,9 @@ public class TestNewTypes extends BaseTestCase {
@Test
public void testInsertUpdate() throws InterruptedException {
+
+ DB.find(SomeNewTypesBean.class).delete();
+
SomeNewTypesBean bean = new SomeNewTypesBean();
bean.setLocalDate(LocalDate.now());
bean.setLocalDateTime(LocalDateTime.now());
@@ -65,55 +68,55 @@ public class TestNewTypes extends BaseTestCase {
DB.save(bean);
Thread.sleep(DB_CLOCK_DELTA); // wait, to ensure that instant < Instant.now()
List list = DB.find(SomeNewTypesBean.class).where().lt("instant", Instant.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("localDate", LocalDate.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().lt("localDateTime", LocalDateTime.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().lt("offsetDateTime", OffsetDateTime.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().lt("zonedDateTime", ZonedDateTime.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("sqlDate", bean.getSqlDate()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("sqlTime", bean.getSqlTime()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("localTime", LocalTime.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("zoneId", ZoneId.systemDefault().getId()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("zoneOffset", ZonedDateTime.now().getOffset()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("yearMonth", YearMonth.of(2014, 9)).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("monthDay", MonthDay.of(9,22)).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("year", Year.now()).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().le("month", Month.SEPTEMBER).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("path", Paths.get(TEMP_PATH)).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("period", Period.of(4,3,2)).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
list = DB.find(SomeNewTypesBean.class).where().eq("duration", Duration.ofMinutes(5)).findList();
- assertTrue(!list.isEmpty());
+ assertThat(list).isNotEmpty();
SomeNewTypesBean fetched = DB.find(SomeNewTypesBean.class, bean.getId());
diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties
index 7fcde144e..7c6ce5d89 100644
--- a/src/test/resources/ebean.properties
+++ b/src/test/resources/ebean.properties
@@ -22,7 +22,7 @@ ebean.ddl.generate=true
ebean.ddl.run=true
ebean.ddl.header=-- Generated by ebean ${version} at ${timestamp}
ebean.packages=org.tests
-datasource.default=h2
+datasource.default=mariadb
#datasource.h2.capturestacktrace=true
ebean.dumpMetricsOnShutdown=true
@@ -135,6 +135,10 @@ datasource.mysql.url=jdbc:mysql://127.0.0.1:4306/unit
#datasource.mysql.url=jdbc:mysql://127.0.0.1:4306/test_ebean
#datasource.mysql.driver=com.mysql.cj.jdbc.Driver
+datasource.mariadb.username=unit
+datasource.mariadb.password=unit
+datasource.mariadb.url=jdbc:mariadb://localhost:4306/unit
+
datasource.cockroach.username=root
datasource.cockroach.password=
datasource.cockroach.url=jdbc:postgresql://localhost:26257/unit?sslmode=disable