diff --git a/src/main/java/io/ebean/config/ServerConfig.java b/src/main/java/io/ebean/config/ServerConfig.java index b0b5f362a..f32473ec6 100644 --- a/src/main/java/io/ebean/config/ServerConfig.java +++ b/src/main/java/io/ebean/config/ServerConfig.java @@ -1740,7 +1740,7 @@ public class ServerConfig { * that you don't have access to. *
*- * Values are oracle, h2, postgres, mysql, mssqlserver2005. + * Values are oracle, h2, postgres, mysql, sqlserver16, sqlserver17. *
*/ public void setDatabasePlatformName(String databasePlatformName) { diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java new file mode 100644 index 000000000..af0d7582a --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer16Platform.java @@ -0,0 +1,26 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.annotation.Platform; +import io.ebean.config.dbplatform.DbPlatformType; +import io.ebean.config.dbplatform.DbType; +import io.ebean.config.dbplatform.IdType; + +/** + * Microsoft SQL Server platform that has non-UTF8 types (char, varchar, text) and default to Identity rather than Sequence. + */ +public class SqlServer16Platform extends SqlServerBasePlatform { + + public SqlServer16Platform() { + super(); + this.platform = Platform.SQLSERVER16; + // default to use Identity rather than sequences + this.dbIdentity.setIdType(IdType.IDENTITY); + + // non-utf8 column types + dbTypeMap.put(DbType.CHAR, new DbPlatformType("char", 1)); + dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("varchar", 255)); + dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text")); + dbTypeMap.put(DbType.CLOB, new DbPlatformType("text")); + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java new file mode 100644 index 000000000..fd17bbe9f --- /dev/null +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer17Platform.java @@ -0,0 +1,16 @@ +package io.ebean.config.dbplatform.sqlserver; + +import io.ebean.annotation.Platform; + +/** + * Microsoft SQL Server platform - NVarchar UTF types and Sequence preference. + */ +public class SqlServer17Platform extends SqlServerBasePlatform { + + public SqlServer17Platform() { + super(); + this.platform = Platform.SQLSERVER17; + this.columnAliasPrefix = null; + } + +} diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java index 0473e9d3f..44eea1a04 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServer2005Platform.java @@ -3,7 +3,7 @@ package io.ebean.config.dbplatform.sqlserver; /** * SQL Server platform using the older ROW_NUMBER() mechanism. */ -public class SqlServer2005Platform extends SqlServerPlatform { +public class SqlServer2005Platform extends SqlServer16Platform { public SqlServer2005Platform() { this.sqlLimiter = new SqlServer2005SqlLimiter(); diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java similarity index 86% rename from src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java rename to src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index 31e1a8525..39727c7b2 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerPlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -16,11 +16,11 @@ import javax.sql.DataSource; import java.sql.Types; /** - * Microsoft SQL Server platform. + * Base Microsoft SQL Server platform - NVarchar UTF types and Sequence preference by default. */ -public class SqlServerPlatform extends DatabasePlatform { +abstract class SqlServerBasePlatform extends DatabasePlatform { - public SqlServerPlatform() { + SqlServerBasePlatform() { super(); this.platform = Platform.SQLSERVER; // disable persistBatchOnCascade mode for @@ -31,7 +31,7 @@ public class SqlServerPlatform extends DatabasePlatform { this.sqlLimiter = new SqlServerSqlLimiter(); this.basicSqlLimiter = new SqlServerBasicSqlLimiter(); this.historySupport = new SqlServerHistorySupport(); - this.dbIdentity.setIdType(IdType.IDENTITY); + this.dbIdentity.setIdType(IdType.SEQUENCE); this.dbIdentity.setSupportsGetGeneratedKeys(true); this.dbIdentity.setSupportsIdentity(true); this.dbIdentity.setSupportsSequence(true); @@ -63,18 +63,22 @@ public class SqlServerPlatform extends DatabasePlatform { dbTypeMap.put(DbType.TINYINT, new DbPlatformType("smallint")); dbTypeMap.put(DbType.DECIMAL, new DbPlatformType("numeric", 28)); - dbTypeMap.put(DbType.BLOB, new DbPlatformType("image")); - dbTypeMap.put(DbType.CLOB, new DbPlatformType("text")); - dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image")); - dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("text")); dbTypeMap.put(DbType.DATE, new DbPlatformType("date")); dbTypeMap.put(DbType.TIME, new DbPlatformType("time")); dbTypeMap.put(DbType.TIMESTAMP, new DbPlatformType("datetime2")); + // UTF8 aware types - overwritten in SqlServer16 platform + dbTypeMap.put(DbType.CHAR, new DbPlatformType("nchar", 1)); + dbTypeMap.put(DbType.VARCHAR, new DbPlatformType("nvarchar", 255)); + dbTypeMap.put(DbType.LONGVARCHAR, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.CLOB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.JSON, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); dbTypeMap.put(DbType.JSONB, new DbPlatformType("nvarchar", Integer.MAX_VALUE)); + dbTypeMap.put(DbType.BLOB, new DbPlatformType("image")); + dbTypeMap.put(DbType.LONGVARBINARY, new DbPlatformType("image")); } @Override diff --git a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java index d767d62a6..c548bbc64 100644 --- a/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java +++ b/src/main/java/io/ebeaninternal/dbmigration/DefaultDbMigration.java @@ -15,7 +15,8 @@ import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform; import io.ebean.config.dbplatform.sqlite.SQLitePlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebean.dbmigration.DbMigration; import io.ebeaninternal.api.SpiEbeanServer; import io.ebeaninternal.dbmigration.ddlgeneration.DdlWrite; @@ -554,8 +555,12 @@ public class DefaultDbMigration implements DbMigration { return new OraclePlatform(); case SQLANYWHERE: return new SqlAnywherePlatform(); + case SQLSERVER16: + return new SqlServer16Platform(); + case SQLSERVER17: + return new SqlServer17Platform(); case SQLSERVER: - return new SqlServerPlatform(); + throw new IllegalArgumentException("Please choose the more specific SQLSERVER16 or SQLSERVER17 platform. Refer to issue #1340 for details"); case DB2: return new DB2Platform(); case SQLITE: diff --git a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java index 629c9d202..a478a1ac7 100644 --- a/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java +++ b/src/main/java/io/ebeaninternal/extraddl/model/ExtraDdlXmlReader.java @@ -1,5 +1,6 @@ package io.ebeaninternal.extraddl.model; +import io.ebean.annotation.Platform; import io.ebean.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,6 +17,8 @@ public class ExtraDdlXmlReader { private static final Logger logger = LoggerFactory.getLogger(ExtraDdlXmlReader.class); + private static final String SQLSERVER = Platform.SQLSERVER.name().toLowerCase(); + /** * Return the combined extra DDL that should be run given the platform name. */ @@ -52,14 +55,33 @@ public class ExtraDdlXmlReader { return true; } + String genericMatch = genericPlatformMatch(platformName); + for (String name : StringHelper.splitNames(platforms)) { if (name.toLowerCase().contains(platformName)) { return true; + } else if (genericMatch != null && genericMatch.equals(name.toLowerCase())) { + // allow sqlserver ... to match sqlserver17 and sqlserver16 platforms + return true; } } return false; } + /** + * Return a "generic" platform name that can be used. e.g. sqlserver17 -> sqlserver. + */ + private static String genericPlatformMatch(String platformName) { + switch (platformName) { + case "sqlserver17": + return SQLSERVER; + case "sqlserver16": + return SQLSERVER; + default: + return null; + } + } + /** * Read and return a ExtraDdl from an xml document at the given resource path. */ diff --git a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java index 496f67cbb..3f98a1c6d 100644 --- a/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java +++ b/src/main/java/io/ebeaninternal/server/core/DatabasePlatformFactory.java @@ -1,17 +1,18 @@ package io.ebeaninternal.server.core; import io.ebean.config.ServerConfig; -import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.DatabasePlatform; +import io.ebean.config.dbplatform.db2.DB2Platform; import io.ebean.config.dbplatform.h2.H2Platform; import io.ebean.config.dbplatform.hsqldb.HsqldbPlatform; -import io.ebean.config.dbplatform.sqlserver.SqlServerPlatform; import io.ebean.config.dbplatform.mysql.MySqlPlatform; import io.ebean.config.dbplatform.oracle.OraclePlatform; import io.ebean.config.dbplatform.postgres.Postgres8Platform; import io.ebean.config.dbplatform.postgres.PostgresPlatform; -import io.ebean.config.dbplatform.sqlite.SQLitePlatform; import io.ebean.config.dbplatform.sqlanywhere.SqlAnywherePlatform; +import io.ebean.config.dbplatform.sqlite.SQLitePlatform; +import io.ebean.config.dbplatform.sqlserver.SqlServer16Platform; +import io.ebean.config.dbplatform.sqlserver.SqlServer17Platform; import io.ebeaninternal.dbmigration.DbOffline; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,8 +53,7 @@ public class DatabasePlatformFactory { } if (serverConfig.getDataSourceConfig().isOffline()) { - String m = "You must specify a DatabasePlatformName when you are offline"; - throw new PersistenceException(m); + throw new PersistenceException("You must specify a DatabasePlatformName when you are offline"); } // guess using meta data from driver return byDataSource(serverConfig.getDataSource()); @@ -84,8 +84,14 @@ public class DatabasePlatformFactory { if (dbName.equals("oracle") || dbName.equals("oracle10") || dbName.equals("oracle9")) { return new OraclePlatform(); } + if (dbName.equals("sqlserver16")) { + return new SqlServer16Platform(); + } + if (dbName.equals("sqlserver17")) { + return new SqlServer17Platform(); + } if (dbName.equals("sqlserver")) { - return new SqlServerPlatform(); + throw new IllegalArgumentException("Please choose the more specific sqlserver16 or sqlserver17 platform. Refer to issue #1340 for details"); } if (dbName.equals("sqlanywhere")) { return new SqlAnywherePlatform(); @@ -137,7 +143,7 @@ public class DatabasePlatformFactory { if (dbProductName.contains("oracle")) { return new OraclePlatform(); } else if (dbProductName.contains("microsoft")) { - return new SqlServerPlatform(); + 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 new MySqlPlatform(); } else if (dbProductName.contains("h2")) { diff --git a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java index 560bc519e..efd69538e 100644 --- a/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java +++ b/src/main/java/io/ebeaninternal/server/core/PlatformDdlBuilder.java @@ -38,10 +38,12 @@ public class PlatformDdlBuilder { return new PlatformDdl(platform); case POSTGRES: return new PostgresDdl(platform); - case SQLSERVER: - return new SqlServerDdl(platform); case SQLANYWHERE: return new PlatformDdl(platform); + case SQLSERVER16: + case SQLSERVER17: + case SQLSERVER: + return new SqlServerDdl(platform); default: return new PlatformDdl(platform); }