reworked approach to Dialect column type customization

This commit is contained in:
Gavin King 2021-12-12 14:42:53 +01:00
parent 103e5c658b
commit eb3bcdb94a
20 changed files with 990 additions and 675 deletions

View File

@ -28,6 +28,8 @@ import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
import static org.hibernate.type.SqlTypes.*;
/**
* SQL Dialect for Sybase Anywhere
* (Tested on ASA 8.x)
@ -35,31 +37,48 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
public class SybaseAnywhereDialect extends SybaseDialect {
public SybaseAnywhereDialect() {
this( DatabaseVersion.make( 8 ), false );
this( DatabaseVersion.make( 8 ) );
}
public SybaseAnywhereDialect(DatabaseVersion version) {
this(version, null);
}
public SybaseAnywhereDialect(DialectResolutionInfo info){
this(
info,
info.getDriverName() != null && info.getDriverName().contains( "jTDS" )
);
this( info.makeCopy(), info );
registerKeywords( info );
}
public SybaseAnywhereDialect(DatabaseVersion version, boolean jtdsDriver) {
super( version, jtdsDriver );
public SybaseAnywhereDialect(DatabaseVersion version, DialectResolutionInfo info) {
super( version, info );
}
registerColumnType( Types.BIGINT, "bigint" );
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp with time zone" );
@Override
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case DATE:
return "date";
case TIME:
return "time";
case TIMESTAMP:
return "timestamp";
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp with time zone";
registerColumnType( Types.VARCHAR, "long varchar)" );
registerColumnType( Types.NVARCHAR, "long nvarchar)" );
//these types hold up to 2 GB
case LONGVARCHAR:
return "long varchar";
case LONGNVARCHAR:
return "long nvarchar";
case LONGVARBINARY:
return "long binary";
//note: 'binary' is actually a synonym for 'varbinary'
registerColumnType( Types.VARBINARY, "long binary)" );
case NCLOB:
return "ntext";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
@ -150,7 +169,6 @@ public class SybaseAnywhereDialect extends SybaseDialect {
}
@Override
@SuppressWarnings("deprecation")
public String applyLocksToSql(String sql, LockOptions aliasedLockOptions, Map<String, String[]> keyColumnNames) {
return getVersion().isBefore( 10 )
? super.applyLocksToSql( sql, aliasedLockOptions, keyColumnNames )

View File

@ -10,6 +10,7 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.dialect.function.CastingConcatFunction;
import org.hibernate.dialect.function.TransactSQLStrFunction;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.query.NullOrdering;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
@ -41,39 +42,53 @@ import java.sql.Types;
import java.util.Iterator;
import java.util.Map;
import static org.hibernate.type.SqlTypes.*;
/**
* An abstract base class for Sybase and MS SQL Server dialects.
*
* @author Gavin King
*/
public abstract class AbstractTransactSQLDialect extends Dialect {
public AbstractTransactSQLDialect() {
super();
registerColumnType( Types.BOOLEAN, "bit" );
//'tinyint' is an unsigned type in Sybase and
//SQL Server, holding values in the range 0-255
//see HHH-6779
registerColumnType( Types.TINYINT, "smallint" );
//it's called 'int' not 'integer'
registerColumnType( Types.INTEGER, "int" );
//note that 'real' is double precision on SQL Server, single precision on Sybase
//but 'float' is single precision on Sybase, double precision on SQL Server
registerColumnType( Types.DATE, "datetime" );
registerColumnType( Types.TIME, "datetime" );
registerColumnType( Types.TIMESTAMP, "datetime" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetime" );
registerColumnType( Types.BLOB, "image" );
registerColumnType( Types.CLOB, "text" );
public AbstractTransactSQLDialect(DatabaseVersion version, DialectResolutionInfo info) {
super(version, info);
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@Override
protected String columnType(int jdbcTypeCode) {
// note that 'real' is double precision on SQL Server, single precision on Sybase
// but 'float' is single precision on Sybase, double precision on SQL Server
switch(jdbcTypeCode) {
case BOOLEAN:
return "bit";
case TINYINT:
//'tinyint' is an unsigned type in Sybase and
//SQL Server, holding values in the range 0-255
//see HHH-6779
return "smallint";
case INTEGER:
//it's called 'int' not 'integer'
return "int";
case DATE:
case TIME:
case TIMESTAMP:
case TIME_WITH_TIMEZONE:
return "datetime";
case BLOB:
return "image";
case CLOB:
return "text";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
public JdbcType resolveSqlTypeDescriptor(
String columnTypeName,

View File

@ -8,11 +8,12 @@ package org.hibernate.dialect;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
@ -55,6 +56,7 @@ import jakarta.persistence.TemporalType;
import static org.hibernate.query.TemporalUnit.DAY;
import static org.hibernate.query.TemporalUnit.NATIVE;
import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
@ -70,7 +72,6 @@ public class CockroachDialect extends Dialect {
// * no support for java.sql.Clob
private final DatabaseVersion version;
private final PostgreSQLDriverKind driverKind;
public CockroachDialect() {
@ -88,45 +89,56 @@ public class CockroachDialect extends Dialect {
}
public CockroachDialect(DatabaseVersion version, PostgreSQLDriverKind driverKind) {
super();
this.version = version;
super(version);
this.driverKind = driverKind;
}
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//use 'string' instead of 'varchar'
registerColumnType( Types.VARCHAR, getMaxVarcharLength(), "string($l)");
registerColumnType( Types.VARCHAR, "string");
//no binary/varbinary
registerColumnType( Types.VARBINARY, "bytes" );
registerColumnType( Types.BINARY, "bytes" );
//no clob
registerColumnType( Types.CLOB, "string" );
//no nchar/nvarchar
registerColumnType( Types.NCHAR, "string($l)" );
registerColumnType( Types.NVARCHAR, getMaxNVarcharLength(), "string($l)" );
registerColumnType( Types.NVARCHAR, "string");
//no nclob
registerColumnType( Types.NCLOB, "string" );
registerColumnType( SqlTypes.UUID, "uuid" );
registerColumnType( SqlTypes.INTERVAL_SECOND, "interval second($s)" );
// Prefer jsonb if possible
if ( getVersion().isSameOrAfter( 20, 0 ) ) {
registerColumnType( SqlTypes.INET, "inet" );
registerColumnType( SqlTypes.JSON, "jsonb" );
}
else {
registerColumnType( SqlTypes.JSON, "json" );
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> typeCodes = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
typeCodes.addAll( List.of(UUID, INTERVAL_SECOND, GEOMETRY, JSON) );
if ( getVersion().isSameOrAfter( 20 ) ) {
typeCodes.add(INET);
}
return typeCodes;
}
registerColumnType( SqlTypes.GEOMETRY, "geometry" );
@Override
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case TINYINT:
return "smallint"; //no tinyint
case CHAR:
case NCHAR:
case VARCHAR:
case NVARCHAR:
return "string($l)";
case NCLOB:
case CLOB:
return "string";
case BINARY:
case VARBINARY:
case BLOB:
return "bytes";
case INET:
return "inet";
case UUID:
return "uuid";
case GEOMETRY:
return "geometry";
case INTERVAL_SECOND:
return "interval second($s)";
case JSON:
// Prefer jsonb if possible
return getVersion().isSameOrAfter( 20 ) ? "jsonb" : "json";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
@ -148,21 +160,21 @@ public class CockroachDialect extends Dialect {
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
if ( jdbcTypeCode == SqlTypes.OTHER ) {
if ( jdbcTypeCode == OTHER ) {
switch ( columnTypeName ) {
case "uuid":
jdbcTypeCode = SqlTypes.UUID;
jdbcTypeCode = UUID;
break;
case "json":
case "jsonb":
jdbcTypeCode = SqlTypes.JSON;
jdbcTypeCode = JSON;
break;
case "inet":
jdbcTypeCode = SqlTypes.INET;
jdbcTypeCode = INET;
break;
case "geometry":
case "geography":
jdbcTypeCode = SqlTypes.GEOMETRY;
jdbcTypeCode = GEOMETRY;
break;
}
}
@ -189,11 +201,6 @@ public class CockroachDialect extends Dialect {
}
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry(queryEngine);

View File

@ -59,6 +59,8 @@ import java.sql.Types;
import jakarta.persistence.TemporalType;
import static org.hibernate.type.SqlTypes.*;
/**
* An SQL dialect for DB2.
*
@ -75,8 +77,6 @@ public class DB2Dialect extends Dialect {
private static final String FOR_SHARE_SKIP_LOCKED_SQL = FOR_SHARE_SQL + SKIP_LOCKED_SQL;
private static final String FOR_UPDATE_SKIP_LOCKED_SQL = FOR_UPDATE_SQL + SKIP_LOCKED_SQL;
private final DatabaseVersion version;
private final LimitHandler limitHandler;
private final UniqueDelegate uniqueDelegate;
@ -90,37 +90,7 @@ public class DB2Dialect extends Dialect {
}
public DB2Dialect(DatabaseVersion version) {
super();
this.version = version;
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
//HHH-12827: map them both to the same type to avoid problems with schema update
//Note that 31 is the maximum precision DB2 supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
if ( getVersion().isBefore( 11 ) ) {
registerColumnType( Types.BINARY, 254, "char($l) for bit data" ); //should use 'binary' since version 11
registerColumnType( Types.BINARY, "varchar($l) for bit data" ); //should use 'binary' since version 11
registerColumnType( Types.VARBINARY, getMaxVarbinaryLength(), "varchar($l) for bit data" ); //should use 'varbinary' since version 11
//prior to DB2 11, the 'boolean' type existed,
//but was not allowed as a column type
registerColumnType( Types.BOOLEAN, "smallint" );
}
registerColumnType( Types.VARBINARY, "blob($l)" );
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)" );
registerColumnType( Types.TIME_WITH_TIMEZONE, "time" );
// The long varchar data type was deprecated in DB2 and shouldn't be used anymore
registerColumnType( Types.VARCHAR, "clob($l)" );
registerColumnType( Types.NVARCHAR, "nclob($l)" );
super(version);
//not keywords, at least not in DB2 11,
//but perhaps they were in older versions?
@ -142,6 +112,51 @@ public class DB2Dialect extends Dialect {
: DB2LimitHandler.INSTANCE;
}
@Override
protected String columnType(int jdbcTypeCode) {
if ( getVersion().isBefore( 11 ) ) {
switch (jdbcTypeCode) {
case BOOLEAN:
// prior to DB2 11, the 'boolean' type existed,
// but was not allowed as a column type
return "smallint";
case BINARY: // should use 'binary' since version 11
case VARBINARY: // should use 'varbinary' since version 11
return "varchar($l) for bit data";
}
}
switch (jdbcTypeCode) {
case TINYINT:
// no tinyint
return "smallint";
case NUMERIC:
// HHH-12827: map them both to the same type to avoid problems with schema update
// Note that 31 is the maximum precision DB2 supports
return super.columnType(DECIMAL);
case BLOB:
return "blob($l)";
case CLOB:
return "clob($l)";
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp($p)";
case TIME_WITH_TIMEZONE:
return "time";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
protected void registerDefaultColumnTypes(int maxVarcharLength, int maxNVarcharLength, int maxVarBinaryLength) {
// Note: the 'long varchar' data type was deprecated in DB2 and shouldn't be used anymore
super.registerDefaultColumnTypes(maxVarcharLength, maxNVarcharLength, maxVarBinaryLength);
if ( getVersion().isBefore( 11 ) ) {
// should use 'binary' since version 11
registerColumnType( BINARY, 254, "char($l) for bit data" );
}
}
protected UniqueDelegate createUniqueDelegate() {
return new DB2UniqueDelegate( this );
}
@ -151,11 +166,6 @@ public class DB2Dialect extends Dialect {
return 32_672;
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public int getDefaultDecimalPrecision() {
//this is the maximum allowed in DB2
@ -541,11 +551,11 @@ public class DB2Dialect extends Dialect {
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration().getJdbcTypeDescriptorRegistry();
if ( version.isBefore( 11 ) ) {
if ( getVersion().isBefore( 11 ) ) {
jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, SmallIntJdbcType.INSTANCE );
// Binary literals were only added in 11. See https://www.ibm.com/support/knowledgecenter/SSEPGG_11.1.0/com.ibm.db2.luw.sql.ref.doc/doc/r0000731.html#d79816e393
jdbcTypeRegistry.addDescriptor( Types.VARBINARY, VarbinaryJdbcType.INSTANCE_WITHOUT_LITERALS );
if ( version.isBefore( 9, 7 ) ) {
if ( getVersion().isBefore( 9, 7 ) ) {
jdbcTypeRegistry.addDescriptor( Types.NUMERIC, DecimalJdbcType.INSTANCE );
}
}

View File

@ -70,6 +70,7 @@ import java.sql.Types;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers.useArgType;
import static org.hibernate.type.SqlTypes.*;
/**
* Hibernate Dialect for Apache Derby / Cloudscape 10
@ -91,8 +92,6 @@ public class DerbyDialect extends Dialect {
// * can't select a parameter unless wrapped
// in a cast or function call
private final DatabaseVersion version;
private final LimitHandler limitHandler;
public DerbyDialect(DialectResolutionInfo info) {
@ -105,35 +104,7 @@ public class DerbyDialect extends Dialect {
}
public DerbyDialect(DatabaseVersion version) {
super();
this.version = version;
if ( getVersion().isBefore( 10, 7 ) ) {
registerColumnType( Types.BOOLEAN, "smallint" ); //no boolean before 10.7
}
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint
registerColumnType( Types.CHAR, 254, "char($l)" );
//HHH-12827: map them both to the same type to avoid problems with schema update
//Note that 31 is the maximum precision Derby supports
// registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
registerColumnType( Types.BINARY, 254, "char($l) for bit data" );
registerColumnType( Types.BINARY, getMaxVarbinaryLength(), "varchar($l) for bit data" );
registerColumnType( Types.BINARY, "long varchar for bit data" );
registerColumnType( Types.VARBINARY, getMaxVarbinaryLength(), "varchar($l) for bit data" );
registerColumnType( Types.VARBINARY, 32_700,"long varchar for bit data" );
registerColumnType( Types.VARBINARY, "blob($l)" );
registerColumnType( Types.BLOB, "blob($l)" );
registerColumnType( Types.CLOB, "clob($l)" );
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
registerColumnType( Types.VARCHAR, 32_700, "long varchar" );
registerColumnType( Types.VARCHAR, "clob($l)" );
super(version);
registerDerbyKeywords();
@ -144,6 +115,52 @@ public class DerbyDialect extends Dialect {
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, NO_BATCH );
}
@Override
protected String columnType(int jdbcTypeCode) {
if ( jdbcTypeCode == BOOLEAN && getVersion().isBefore( 10, 7 ) ) {
return "smallint";
}
switch (jdbcTypeCode) {
case TINYINT:
//no tinyint
return "smallint";
case NUMERIC:
// HHH-12827: map them both to the same type to avoid problems with schema update
// Note that 31 is the maximum precision Derby supports
return super.columnType(DECIMAL);
case VARBINARY:
return "varchar($l) for bit data";
case BLOB:
return "blob($l)";
case CLOB:
return "clob($l)";
case TIMESTAMP:
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
protected void registerDefaultColumnTypes(int maxVarcharLength, int maxNVarcharLength, int maxVarBinaryLength) {
super.registerDefaultColumnTypes(maxVarcharLength, maxNVarcharLength, maxVarBinaryLength);
//long vachar is the right type to use for lengths between 32_672 and 32_700
registerColumnType( VARBINARY, 32_700,"long varchar for bit data" );
registerColumnType( VARCHAR, 32_700, "long varchar" );
registerColumnType( BINARY, 254, "char($l) for bit data" );
registerColumnType( BINARY, 32_672, "varchar($l) for bit data" );
registerColumnType( BINARY, 32_700, "long varchar for bit data" );
}
@Override
public int getMaxVarcharLength() {
return 32_672;
@ -173,11 +190,6 @@ public class DerbyDialect extends Dialect {
: Types.BOOLEAN;
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public NationalizationSupport getNationalizationSupport() {
return NationalizationSupport.IMPLICIT;

View File

@ -163,6 +163,7 @@ import jakarta.persistence.TemporalType;
import static java.lang.Math.ceil;
import static java.lang.Math.log;
import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE;
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME;
@ -223,23 +224,37 @@ public abstract class Dialect implements ConversionContext {
private final SizeStrategy sizeStrategy;
private final DatabaseVersion version;
// constructors and factory methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @deprecated provide a {@link DatabaseVersion}
*/
@Deprecated
protected Dialect() {
this(true);
this(null, null);
}
protected Dialect(boolean autoRegisterColumnTypes) {
protected Dialect(DatabaseVersion version) {
this( version, null );
}
protected Dialect(DatabaseVersion version, DialectResolutionInfo info) {
this.version = version;
uniqueDelegate = new DefaultUniqueDelegate( this );
sizeStrategy = new SizeStrategyImpl();
if (autoRegisterColumnTypes) {
registerDefaultColumnTypes();
}
registerDefaultColumnTypes(info); // pass the info back down to the subclass in case it needs it (MySQL)
registerHibernateTypes();
registerDefaultKeywords();
}
protected void registerDefaultColumnTypes() {
/**
* Register ANSI-standard column types using the length limits defined
* by {@link #getMaxVarcharLength()}, {@link #getMaxNVarcharLength()},
* and {@link #getMaxVarbinaryLength()}.
*/
protected void registerDefaultColumnTypes(DialectResolutionInfo info) {
registerDefaultColumnTypes( getMaxVarcharLength(), getMaxNVarcharLength(), getMaxVarbinaryLength() );
}
@ -249,55 +264,181 @@ public abstract class Dialect implements ConversionContext {
* {@code Dialect} by calling {@link #registerColumnType(int,String)}
* from the constructor.
* <p>
* Note that {@link Types#LONGVARCHAR}, {@link Types#LONGNVARCHAR}
* This method is aware of the notion of a maximum length for each of
* the types {@link Types#VARCHAR}, {@link Types#NVARCHAR}, and
* {@link Types#VARBINARY}, usually the limits defined by
* {@link #getMaxVarcharLength()}, {@link #getMaxNVarcharLength()},
* and {@link #getMaxVarbinaryLength()}, and registers "long" types
* for lengths exceeding the limits.
* <p>
* The "long" types {@link Types#LONGVARCHAR}, {@link Types#LONGNVARCHAR}
* and {@link Types#LONGVARBINARY} are considered synonyms for their
* non-{@code LONG} counterparts, with the only difference being that
* a different default length is used: {@link org.hibernate.Length#LONG}
* instead of {@link org.hibernate.Length#DEFAULT}. Concrete dialects
* should usually avoid registering mappings for these JDBC types.
* instead of {@link org.hibernate.Length#DEFAULT}.
* <p>
* Any registrations made by this method may be overridden by calling
* {@link #registerColumnType(int, String)} explicitly. Alternatively,
* the registrations may be customized by overriding
* {@link #getSupportedJdbcTypeCodes()} and {@link #columnType(int)}.
*
* @param maxVarcharLength the maximum length of the {@link Types#VARCHAR} type
* @param maxNVarcharLength the maximum length of the {@link Types#NVARCHAR} type
* @param maxVarBinaryLength the maximum length of the {@link Types#VARBINARY} type
*/
protected void registerDefaultColumnTypes(int maxVarcharLength, int maxNVarcharLength, int maxVarBinaryLength) {
registerColumnType( Types.BOOLEAN, "boolean" );
for ( int typeCode : getSupportedJdbcTypeCodes() ) {
switch (typeCode) {
case VARCHAR:
registerColumnType( typeCode, maxVarcharLength, columnType(typeCode) );
registerColumnType( typeCode, columnType(LONGVARCHAR) );
break;
case NVARCHAR:
registerColumnType( typeCode, maxNVarcharLength, columnType(typeCode) );
registerColumnType( typeCode, columnType(LONGNVARCHAR) );
break;
case VARBINARY:
registerColumnType( typeCode, maxVarBinaryLength, columnType(typeCode) );
registerColumnType( typeCode, columnType(LONGVARBINARY) );
break;
default:
registerColumnType( typeCode, columnType(typeCode) );
}
}
}
registerColumnType( Types.TINYINT, "tinyint" );
registerColumnType( Types.SMALLINT, "smallint" );
registerColumnType( Types.INTEGER, "integer" );
registerColumnType( Types.BIGINT, "bigint" );
/**
* A list of JDBC types that we expect to be supported on all databases.
*/
private static final List<Integer> ANSI_SQL_TYPES = List.of(
BOOLEAN,
TINYINT, SMALLINT, INTEGER, BIGINT,
REAL, FLOAT, DOUBLE,
NUMERIC, DECIMAL,
DATE,
TIME, TIME_WITH_TIMEZONE,
TIMESTAMP, TIMESTAMP_WITH_TIMEZONE,
CHAR, VARCHAR, CLOB,
NCHAR, NVARCHAR, NCLOB,
BINARY, VARBINARY, BLOB
);
registerColumnType( Types.REAL, "real" );
registerColumnType( Types.FLOAT, "float($p)" );
registerColumnType( Types.DOUBLE, "double precision" );
/**
* The JDBC type codes of types supported by this SQL dialect, from the lists
* defined by {@link Types} and {@link SqlTypes}.
* <p>
* This method may be overridden by concrete {@code Dialect}s as an alternative
* to calling {@link #registerColumnType(int, String)}. In this case,
* {@link #columnType(int)} should also be overridden.
* <p>
* Note that {@link Types#LONGVARCHAR}, {@link Types#LONGNVARCHAR} and
* {@link Types#LONGVARBINARY} are considered synonyms for their
* non-{@code LONG} counterparts, and should not be included in the returned
* array.
*
* @return an array of types from {@link SqlTypes}
*
* @see SqlTypes
* @see #columnType(int)
*/
protected List<Integer> getSupportedJdbcTypeCodes() {
return ANSI_SQL_TYPES;
}
//these are pretty much synonyms, but are considered
//separate types by the ANSI spec, and in some dialects
registerColumnType( Types.NUMERIC, "numeric($p,$s)" );
registerColumnType( Types.DECIMAL, "decimal($p,$s)" );
/**
* The column type name for a given JDBC type code defined in {@link Types} or
* {@link SqlTypes}. This default implementation returns the ANSI-standard type
* name.
* <p>
* This method may be overridden by concrete {@code Dialect}s as an alternative
* to calling {@link #registerColumnType(int,String)}.
*
* @param jdbcTypeCode a JDBC type code
* @return a column type name, with $l, $p, $s placeholders for length, precision, scale
*
* @see SqlTypes
* @see #getSupportedJdbcTypeCodes()
*/
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case BOOLEAN:
return "boolean";
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "timestamp($p)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p) with time zone" );
// type included here for completeness but note that
// very few databases support it, and the general
// advice is to caution against its use (for reasons,
// check the comments in the Postgres documentation).
registerColumnType( Types.TIME_WITH_TIMEZONE, "time with time zone" );
case TINYINT:
return "tinyint";
case SMALLINT:
return "smallint";
case INTEGER:
return "integer";
case BIGINT:
return "bigint";
registerColumnType( Types.BINARY, "binary($l)" );
registerColumnType( Types.VARBINARY, maxVarBinaryLength, "varbinary($l)" );
registerColumnType( Types.BLOB, "blob" );
case FLOAT:
// this is the floating point type we prefer!
return "float($p)";
case REAL:
// this type has very unclear semantics in ANSI SQL,
// so we avoid it and prefer float with an explicit
// precision
return "real";
case DOUBLE:
// this is just a more verbose way to write float(19)
return "double precision";
registerColumnType( Types.CHAR, "char($l)" );
registerColumnType( Types.VARCHAR, maxVarcharLength, "varchar($l)" );
registerColumnType( Types.CLOB, "clob" );
// these are pretty much synonyms, but are considered
// separate types by the ANSI spec, and in some dialects
case NUMERIC:
return "numeric($p,$s)";
case DECIMAL:
return "decimal($p,$s)";
registerColumnType( Types.NCHAR, "nchar($l)" );
registerColumnType( Types.NVARCHAR, maxNVarcharLength, "nvarchar($l)" );
registerColumnType( Types.NCLOB, "nclob" );
case DATE:
return "date";
case TIME:
return "time";
case TIME_WITH_TIMEZONE:
// type included here for completeness but note that
// very few databases support it, and the general
// advice is to caution against its use (for reasons,
// check the comments in the Postgres documentation).
return "time with time zone";
case TIMESTAMP:
return "timestamp($p)";
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp($p) with time zone";
case CHAR:
return "char($l)";
case VARCHAR:
return "varchar($l)";
case CLOB:
return "clob";
case NCHAR:
return "nchar($l)";
case NVARCHAR:
return "nvarchar($l)";
case NCLOB:
return "nclob";
case BINARY:
return "binary($l)";
case VARBINARY:
return "varbinary($l)";
case BLOB:
return "blob";
// by default use the LOB mappings for the "long" types
case LONGVARCHAR:
return columnType(CLOB);
case LONGNVARCHAR:
return columnType(NCLOB);
case LONGVARBINARY:
return columnType(BLOB);
default:
throw new IllegalArgumentException("unknown type: " + jdbcTypeCode);
}
}
protected void registerHibernateTypes() {
@ -353,7 +494,9 @@ public abstract class Dialect implements ConversionContext {
}
}
public abstract DatabaseVersion getVersion();
public DatabaseVersion getVersion() {
return version;
}
public JdbcType resolveSqlTypeDescriptor(
String columnTypeName,

View File

@ -7,6 +7,8 @@
package org.hibernate.dialect;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.PessimisticLockException;
import org.hibernate.boot.model.TypeContributions;
@ -63,6 +65,7 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.TemporalUnit.SECOND;
import static org.hibernate.type.SqlTypes.*;
/**
* A dialect compatible with the H2 database.
@ -77,8 +80,6 @@ public class H2Dialect extends Dialect {
private final boolean cascadeConstraints;
private final boolean useLocalTime;
private final DatabaseVersion version;
private final boolean supportsTuplesInSubqueries;
private final SequenceInformationExtractor sequenceInformationExtractor;
private final String querySequenceString;
@ -88,27 +89,13 @@ public class H2Dialect extends Dialect {
registerKeywords( info );
}
private static DatabaseVersion parseVersion(DialectResolutionInfo info) {
return DatabaseVersion.make( info.getMajor(), info.getMinor(), parseBuildId( info ) );
}
private static int parseBuildId(DialectResolutionInfo info) {
final String databaseVersion = info.getDatabaseVersion();
if ( databaseVersion == null ) {
return 0;
}
final String[] bits = databaseVersion.split("[. ]");
return bits.length > 2 ? Integer.parseInt( bits[2] ) : 0;
}
public H2Dialect() {
this( SimpleDatabaseVersion.ZERO_VERSION );
}
public H2Dialect(DatabaseVersion version) {
super();
this.version = version;
super(version);
// https://github.com/h2database/h2database/commit/b2cdf84e0b84eb8a482fa7dccdccc1ab95241440
limitHandler = version.isSameOrAfter( 1, 4, 195 )
? OffsetFetchLimitHandler.INSTANCE
@ -128,12 +115,6 @@ public class H2Dialect extends Dialect {
// http://code.google.com/p/h2database/issues/detail?id=235
getDefaultProperties().setProperty( AvailableSettings.NON_CONTEXTUAL_LOB_CREATION, "true" );
registerColumnType( Types.VARCHAR, "varchar" );
registerColumnType( Types.NVARCHAR, "varchar" );
registerColumnType( Types.VARBINARY, "varbinary" );
registerColumnType( SqlTypes.ARRAY, "array" );
if ( version.isSameOrAfter( 1, 4, 32 ) ) {
this.sequenceInformationExtractor = version.isSameOrAfter( 1, 4, 201 )
? SequenceInformationExtractorLegacyImpl.INSTANCE
@ -151,14 +132,51 @@ public class H2Dialect extends Dialect {
else {
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
this.querySequenceString = null;
if ( version.isBefore( 2 ) ) {
// prior to version 2.0, H2 reported NUMERIC columns as DECIMAL,
// which caused problems for schema update tool
registerColumnType( Types.NUMERIC, "decimal($p,$s)" );
}
}
}
private static DatabaseVersion parseVersion(DialectResolutionInfo info) {
return DatabaseVersion.make( info.getMajor(), info.getMinor(), parseBuildId( info ) );
}
private static int parseBuildId(DialectResolutionInfo info) {
final String databaseVersion = info.getDatabaseVersion();
if ( databaseVersion == null ) {
return 0;
}
final String[] bits = databaseVersion.split("[. ]");
return bits.length > 2 ? Integer.parseInt( bits[2] ) : 0;
}
@Override
protected String columnType(int jdbcTypeCode) {
if ( jdbcTypeCode == NUMERIC && getVersion().isBefore(2) ) {
// prior to version 2.0, H2 reported NUMERIC columns as DECIMAL,
// which caused problems for schema update tool
return super.columnType(DECIMAL);
}
switch (jdbcTypeCode) {
case LONGVARCHAR:
case LONGNVARCHAR:
return "varchar";
case LONGVARBINARY:
return "varbinary";
case ARRAY:
return "array";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> typeCodes = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
typeCodes.add(ARRAY);
return typeCodes;
}
@Override
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes( typeContributions, serviceRegistry );
@ -166,11 +184,11 @@ public class H2Dialect extends Dialect {
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
if ( version.isSameOrAfter( 1, 4, 197 ) ) {
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
if ( version.isSameOrAfter( 1, 4, 198 ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( DurationIntervalSecondJdbcType.INSTANCE );
}
}
if ( getVersion().isSameOrAfter( 1, 4, 198 ) ) {
jdbcTypeRegistry.addDescriptorIfAbsent( DurationIntervalSecondJdbcType.INSTANCE );
}
}
@ -179,11 +197,6 @@ public class H2Dialect extends Dialect {
return getVersion().isSame( 1, 4, 200 );
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
@ -235,7 +248,7 @@ public class H2Dialect extends Dialect {
CommonFunctionFactory.median( queryEngine );
CommonFunctionFactory.stddevPopSamp( queryEngine );
CommonFunctionFactory.varPopSamp( queryEngine );
if ( version.isSame( 1, 4, 200 ) ) {
if ( getVersion().isSame( 1, 4, 200 ) ) {
// See https://github.com/h2database/h2database/issues/2518
CommonFunctionFactory.format_toChar( queryEngine );
}
@ -524,7 +537,7 @@ public class H2Dialect extends Dialect {
@Override
public void appendDatetimeFormat(SqlAppender appender, String format) {
if ( version.isSame( 1, 4, 200 ) ) {
if ( getVersion().isSame( 1, 4, 200 ) ) {
// See https://github.com/h2database/h2database/issues/2518
appender.appendSql( OracleDialect.datetimeFormat( format, true, true ).result() );
}

View File

@ -71,6 +71,10 @@ import org.jboss.logging.Logger;
import jakarta.persistence.TemporalType;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.type.SqlTypes.BLOB;
import static org.hibernate.type.SqlTypes.CLOB;
import static org.hibernate.type.SqlTypes.NCLOB;
import static org.hibernate.type.SqlTypes.NUMERIC;
/**
* An SQL dialect compatible with HyperSQL (HSQLDB) version 1.8 and above.
@ -85,11 +89,6 @@ public class HSQLDialect extends Dialect {
HSQLDialect.class.getName()
);
/**
* version is 180 for 1.8.0 or 200 for 2.0.0
*/
private final DatabaseVersion version;
public HSQLDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
registerKeywords( info );
@ -100,41 +99,48 @@ public class HSQLDialect extends Dialect {
}
public HSQLDialect(DatabaseVersion version) {
super();
super( version.isSame( 1, 8 ) ? reflectedVersion( version ) : version );
if ( version.isSame( 1, 8 ) ) {
version = reflectedVersion( version );
}
this.version = version;
//Note that all floating point types are synonyms for 'double'
//Note that the HSQL type 'longvarchar' and 'longvarbinary'
//are synonyms for 'varchar(16M)' and 'varbinary(16M)' respectively.
//Using these types though results in schema validation issue like described in HHH-9693
//HSQL has no 'nclob' type, but 'clob' is Unicode
//(See HHH-10364)
registerColumnType( Types.NCLOB, "clob" );
if ( this.version.isBefore( 2 ) ) {
//Older versions of HSQL did not accept
//precision for the 'numeric' type
registerColumnType( Types.NUMERIC, "numeric" );
//Older versions of HSQL had no lob support
registerColumnType( Types.BLOB, "longvarbinary" );
registerColumnType( Types.CLOB, "longvarchar" );
}
if ( this.version.isSameOrAfter( 2, 5 ) ) {
if ( getVersion().isSameOrAfter( 2, 5 ) ) {
registerKeyword( "period" );
}
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
}
@Override
protected String columnType(int jdbcTypeCode) {
// Note that all floating point types are synonyms for 'double'
// Note that the HSQL type 'longvarchar' and 'longvarbinary' are
// synonyms for 'varchar(16M)' and 'varbinary(16M)' respectively.
// But using these types results in schema validation issue as
// described in HHH-9693.
//HSQL has no 'nclob' type, but 'clob' is Unicode (See HHH-10364)
if ( jdbcTypeCode==NCLOB ) {
jdbcTypeCode = CLOB;
}
if ( getVersion().isBefore( 2 ) ) {
switch (jdbcTypeCode) {
case NUMERIC:
// Older versions of HSQL did not accept
// precision for the 'numeric' type
return "numeric";
// Older versions of HSQL had no lob support
case BLOB:
return "longvarbinary";
case CLOB:
return "longvarchar";
}
}
return super.columnType(jdbcTypeCode);
}
private static DatabaseVersion reflectedVersion(DatabaseVersion version) {
try {
final Class<?> props = ReflectHelper.classForName("org.hsqldb.persist.HsqlDatabaseProperties");
@ -152,11 +158,6 @@ public class HSQLDialect extends Dialect {
}
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public void initializeFunctionRegistry(QueryEngine queryEngine) {
super.initializeFunctionRegistry( queryEngine );
@ -208,13 +209,13 @@ public class HSQLDialect extends Dialect {
CommonFunctionFactory.addMonths( queryEngine );
CommonFunctionFactory.monthsBetween( queryEngine );
if ( version.isSameOrAfter( 2 ) ) {
if ( getVersion().isSameOrAfter( 2 ) ) {
//SYSDATE is similar to LOCALTIMESTAMP but it returns the timestamp when it is called
CommonFunctionFactory.sysdate( queryEngine );
}
// from v. 2.2.0 ROWNUM() is supported in all modes as the equivalent of Oracle ROWNUM
if ( version.isSameOrAfter( 2, 2 ) ) {
if ( getVersion().isSameOrAfter( 2, 2 ) ) {
CommonFunctionFactory.rownum( queryEngine );
}
}
@ -357,7 +358,7 @@ public class HSQLDialect extends Dialect {
@Override
public String getForUpdateString() {
if ( version.isSameOrAfter( 2 ) ) {
if ( getVersion().isSameOrAfter( 2 ) ) {
return " for update";
}
else {
@ -367,8 +368,8 @@ public class HSQLDialect extends Dialect {
@Override
public LimitHandler getLimitHandler() {
return version.isBefore( 2 ) ? LegacyHSQLLimitHandler.INSTANCE
: version.isBefore( 2, 5 ) ? LimitOffsetLimitHandler.INSTANCE
return getVersion().isBefore( 2 ) ? LegacyHSQLLimitHandler.INSTANCE
: getVersion().isBefore( 2, 5 ) ? LimitOffsetLimitHandler.INSTANCE
: OffsetFetchLimitHandler.INSTANCE;
}
@ -387,7 +388,7 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsColumnCheck() {
return version.isSameOrAfter( 2 );
return getVersion().isSameOrAfter( 2 );
}
@Override
@ -408,7 +409,7 @@ public class HSQLDialect extends Dialect {
@Override
public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
return version.isBefore( 2 ) ? EXTRACTOR_18 : EXTRACTOR_20;
return getVersion().isBefore( 2 ) ? EXTRACTOR_18 : EXTRACTOR_20;
}
private static final ViolatedConstraintNameExtractor EXTRACTOR_18 =
@ -518,7 +519,7 @@ public class HSQLDialect extends Dialect {
// the definition and data is private to the session and table declaration
// can happen in the middle of a transaction
if ( version.isBefore( 2 ) ) {
if ( getVersion().isBefore( 2 ) ) {
return new GlobalTemporaryTableMutationStrategy(
TemporaryTable.createIdTable(
rootEntityDescriptor,
@ -558,7 +559,7 @@ public class HSQLDialect extends Dialect {
// the definition and data is private to the session and table declaration
// can happen in the middle of a transaction
if ( version.isBefore( 2 ) ) {
if ( getVersion().isBefore( 2 ) ) {
return new GlobalTemporaryTableInsertStrategy(
TemporaryTable.createEntityTable(
rootEntityDescriptor,
@ -586,24 +587,24 @@ public class HSQLDialect extends Dialect {
@Override
public TemporaryTableKind getSupportedTemporaryTableKind() {
return version.isBefore( 2 ) ? TemporaryTableKind.GLOBAL : TemporaryTableKind.LOCAL;
return getVersion().isBefore( 2 ) ? TemporaryTableKind.GLOBAL : TemporaryTableKind.LOCAL;
}
@Override
public String getTemporaryTableCreateCommand() {
return version.isBefore( 2 ) ? super.getTemporaryTableCreateCommand() : "declare local temporary table";
return getVersion().isBefore( 2 ) ? super.getTemporaryTableCreateCommand() : "declare local temporary table";
}
@Override
public AfterUseAction getTemporaryTableAfterUseAction() {
// Version 1.8 GLOBAL TEMPORARY table definitions persist beyond the end
// of the session (by default, data is cleared at commit).
return version.isBefore( 2 ) ? AfterUseAction.CLEAN : AfterUseAction.DROP;
return getVersion().isBefore( 2 ) ? AfterUseAction.CLEAN : AfterUseAction.DROP;
}
@Override
public BeforeUseAction getTemporaryTableBeforeUseAction() {
return version.isBefore( 2 ) ? BeforeUseAction.NONE : BeforeUseAction.CREATE;
return getVersion().isBefore( 2 ) ? BeforeUseAction.NONE : BeforeUseAction.CREATE;
}
// current timestamp support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -651,7 +652,7 @@ public class HSQLDialect extends Dialect {
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy(lockable, lockMode);
}
if ( version.isBefore( 2 ) ) {
if ( getVersion().isBefore( 2 ) ) {
return new ReadUncommittedLockingStrategy( lockable, lockMode );
}
else {
@ -676,19 +677,19 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsCommentOn() {
return version.isSameOrAfter( 2 );
return getVersion().isSameOrAfter( 2 );
}
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public boolean doesReadCommittedCauseWritersToBlockReaders() {
return version.isSameOrAfter( 2 );
return getVersion().isSameOrAfter( 2 );
}
@Override
public boolean doesRepeatableReadCauseReadersToBlockWriters() {
return version.isSameOrAfter( 2 );
return getVersion().isSameOrAfter( 2 );
}
@Override
@ -709,7 +710,7 @@ public class HSQLDialect extends Dialect {
@Override
public boolean supportsTupleDistinctCounts() {
// from v. 2.2.9 is added support for COUNT(DISTINCT ...) with multiple arguments
return version.isSameOrAfter( 2, 2, 9 );
return getVersion().isSameOrAfter( 2, 2, 9 );
}
@Override
@ -724,7 +725,7 @@ public class HSQLDialect extends Dialect {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new HSQLIdentityColumnSupport( this.version );
return new HSQLIdentityColumnSupport( this.getVersion() );
}
@Override

View File

@ -34,35 +34,34 @@ import org.hibernate.type.StandardBasicTypes;
*/
public class MariaDBDialect extends MySQLDialect {
private final DatabaseVersion version;
private final DatabaseVersion mariaVersion;
public MariaDBDialect() {
this( DatabaseVersion.make( 5 ) );
}
public MariaDBDialect(DialectResolutionInfo info) {
this( info.makeCopy(), getCharacterSetBytesPerCharacter( info.unwrap( DatabaseMetaData.class ) ) );
this( info.makeCopy(), info );
registerKeywords( info );
}
public MariaDBDialect(DatabaseVersion version) {
// Let's be conservative and assume people use a 4 byte character set
this( version, 4 );
this(version, null);
}
public MariaDBDialect(DatabaseVersion version, int characterSetBytesPerCharacter) {
protected MariaDBDialect(DatabaseVersion mariaVersion, DialectResolutionInfo info) {
super(
version.isBefore( 5, 3 )
mariaVersion.isBefore( 5, 3 )
? DatabaseVersion.make( 5 )
: DatabaseVersion.make( 5, 7 ),
characterSetBytesPerCharacter
info
);
this.version = version;
this.mariaVersion = mariaVersion;
}
@Override
public DatabaseVersion getVersion() {
return version;
return mariaVersion;
}
@Override

View File

@ -11,6 +11,8 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.LockOptions;
import org.hibernate.PessimisticLockException;
@ -76,6 +78,7 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.type.SqlTypes.*;
/**
* An SQL dialect for MySQL (prior to 5.x).
@ -86,12 +89,12 @@ public class MySQLDialect extends Dialect {
private final UniqueDelegate uniqueDelegate;
private final MySQLStorageEngine storageEngine;
private final DatabaseVersion version;
private final int characterSetBytesPerCharacter;
private final SizeStrategy sizeStrategy;
private int maxVarcharLength;
private int maxVarbinaryLength;
public MySQLDialect(DialectResolutionInfo info) {
this( info.makeCopy(), getCharacterSetBytesPerCharacter( info.unwrap( DatabaseMetaData.class ) ) );
this( info.makeCopy(), info );
registerKeywords( info );
}
@ -100,16 +103,11 @@ public class MySQLDialect extends Dialect {
}
public MySQLDialect(DatabaseVersion version) {
// Let's be conservative and assume people use a 4 byte character set
this( version, 4 );
this(version, null);
}
public MySQLDialect(DatabaseVersion version, int characterSetBytesPerCharacter) {
super(false);
this.version = version;
this.characterSetBytesPerCharacter = characterSetBytesPerCharacter;
registerDefaultColumnTypes();
protected MySQLDialect(DatabaseVersion mySQLVersion, DialectResolutionInfo info) {
super(mySQLVersion, info);
String storageEngine = Environment.getProperties().getProperty( Environment.STORAGE_ENGINE );
if (storageEngine == null) {
@ -128,72 +126,13 @@ public class MySQLDialect extends Dialect {
throw new UnsupportedOperationException( "The " + storageEngine + " storage engine is not supported!" );
}
registerColumnType( Types.BOOLEAN, "bit" ); // HHH-6935: Don't use "boolean" i.e. tinyint(1) due to JDBC ResultSetMetaData
registerColumnType( Types.NUMERIC, "decimal($p,$s)" ); //it's just a synonym
if ( getMySQLVersion().isBefore( 5, 7 ) ) {
registerColumnType( Types.TIMESTAMP, "datetime" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
}
else {
// Since 5.7 we can explicitly specify a fractional second
// precision for the timestamp-like types
registerColumnType(Types.TIMESTAMP, "datetime($p)");
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p)");
}
final int maxTinyLobLen = 255;
final int maxLobLen = 65_535;
final int maxMediumLobLen = 16_777_215;
//the maximum long LOB length is 4_294_967_295, bigger than any Java string
registerColumnType( Types.VARCHAR, "longtext" );
registerColumnType( Types.VARCHAR, maxMediumLobLen, "mediumtext" );
if ( getMaxVarcharLength() < maxLobLen ) {
registerColumnType( Types.VARCHAR, maxLobLen, "text" );
}
registerColumnType( Types.NVARCHAR, "longtext" );
registerColumnType( Types.NVARCHAR, maxMediumLobLen, "mediumtext" );
if ( getMaxNVarcharLength() < maxLobLen ) {
registerColumnType( Types.NVARCHAR, maxLobLen, "text" );
}
registerColumnType( Types.VARBINARY, "longblob" );
registerColumnType( Types.VARBINARY, maxMediumLobLen, "mediumblob" );
if ( getMaxVarbinaryLength() < maxLobLen ) {
registerColumnType( Types.VARBINARY, maxLobLen, "blob" );
}
registerColumnType( Types.BLOB, "longblob" );
registerColumnType( Types.BLOB, maxMediumLobLen, "mediumblob" );
registerColumnType( Types.BLOB, maxLobLen, "blob" );
registerColumnType( Types.BLOB, maxTinyLobLen, "tinyblob" );
registerColumnType( Types.CLOB, "longtext" );
registerColumnType( Types.CLOB, maxMediumLobLen, "mediumtext" );
registerColumnType( Types.CLOB, maxLobLen, "text" );
registerColumnType( Types.CLOB, maxTinyLobLen, "tinytext" );
registerColumnType( Types.NCLOB, "longtext" );
registerColumnType( Types.NCLOB, maxMediumLobLen, "mediumtext" );
registerColumnType( Types.NCLOB, maxLobLen, "text" );
registerColumnType( Types.NCLOB, maxTinyLobLen, "tinytext" );
if ( getMySQLVersion().isBefore( 5, 7 ) ) {
// MySQL 5.7 brings JSON native support with a dedicated datatype
// https://dev.mysql.com/doc/refman/5.7/en/json.html
registerColumnType( SqlTypes.JSON, "json");
}
registerColumnType( SqlTypes.GEOMETRY, "geometry" );
registerKeyword( "key" );
getDefaultProperties().setProperty( Environment.MAX_FETCH_DEPTH, "2" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
uniqueDelegate = new MySQLUniqueDelegate( this );
sizeStrategy = new SizeStrategyImpl() {
@Override
public Size resolveSize(
@ -204,7 +143,7 @@ public class MySQLDialect extends Dialect {
Long length) {
switch ( jdbcType.getDefaultSqlTypeCode() ) {
case Types.BIT:
// MySQL allows BIT with a length up to 64
// MySQL allows BIT with a length up to 64 (less the the default length 255)
if ( length != null ) {
return Size.length( Math.min( Math.max( length, 1 ), 64 ) );
}
@ -214,6 +153,101 @@ public class MySQLDialect extends Dialect {
};
}
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> typeCodes = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
typeCodes.add(GEOMETRY);
if ( getMySQLVersion().isBefore( 5, 7 ) ) {
// MySQL 5.7 brings JSON native support with a dedicated datatype
// https://dev.mysql.com/doc/refman/5.7/en/json.html
typeCodes.add(JSON);
}
return typeCodes;
}
@Override
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case BOOLEAN:
// HHH-6935: Don't use "boolean" i.e. tinyint(1) due to JDBC ResultSetMetaData
return "bit";
case TIMESTAMP:
return getMySQLVersion().isBefore( 5, 7 )
? "datetime" : "datetime($p)";
case TIMESTAMP_WITH_TIMEZONE:
return getMySQLVersion().isBefore( 5, 7 )
? "timestamp" : "timestamp($p)";
case NUMERIC:
// it's just a synonym
return super.columnType(DECIMAL);
case JSON:
return "json";
case GEOMETRY:
return "geometry";
case BLOB:
return "longblob";
case NCLOB:
case CLOB:
return "longtext";
}
return super.columnType(jdbcTypeCode);
}
@Override
protected void registerDefaultColumnTypes(DialectResolutionInfo info) {
// we need to remember the character set before calling getMaxVarcharLength()
// we could not do this earlier because we get called from the constructor
// of the superclass, before our own constructor has run
int bytesPerCharacter = info == null
? 4 // Let's be conservative and assume people use a 4 byte character set
: getCharacterSetBytesPerCharacter( info.unwrap(DatabaseMetaData.class) );
maxVarcharLength = maxVarcharLength(bytesPerCharacter);
maxVarbinaryLength = maxVarbinaryLength();
super.registerDefaultColumnTypes( maxVarcharLength, maxVarcharLength, maxVarbinaryLength );
// MySQL has approximately one million text and blob types. We have
// already registered longtext + longblob via the regular method,
// but we still need to do the rest of them here.
final int maxTinyLobLen = 255;
final int maxLobLen = 65_535;
final int maxMediumLobLen = 16_777_215;
//the maximum long LOB length is 4_294_967_295, bigger than any Java string
registerColumnType( VARCHAR, maxMediumLobLen, "mediumtext" );
if ( getMaxVarcharLength() < maxLobLen ) {
registerColumnType( VARCHAR, maxLobLen, "text" );
}
registerColumnType( NVARCHAR, maxMediumLobLen, "mediumtext" );
if ( getMaxNVarcharLength() < maxLobLen ) {
registerColumnType( NVARCHAR, maxLobLen, "text" );
}
registerColumnType( VARBINARY, maxMediumLobLen, "mediumblob" );
if ( getMaxVarbinaryLength() < maxLobLen ) {
registerColumnType( VARBINARY, maxLobLen, "blob" );
}
registerColumnType( BLOB, maxMediumLobLen, "mediumblob" );
registerColumnType( BLOB, maxLobLen, "blob" );
registerColumnType( BLOB, maxTinyLobLen, "tinyblob" );
registerColumnType( CLOB, maxMediumLobLen, "mediumtext" );
registerColumnType( CLOB, maxLobLen, "text" );
registerColumnType( CLOB, maxTinyLobLen, "tinytext" );
registerColumnType( NCLOB, maxMediumLobLen, "mediumtext" );
registerColumnType( NCLOB, maxLobLen, "text" );
registerColumnType( NCLOB, maxTinyLobLen, "tinytext" );
}
protected static int getCharacterSetBytesPerCharacter(DatabaseMetaData databaseMetaData) {
if ( databaseMetaData != null ) {
try (java.sql.Statement s = databaseMetaData.getConnection().createStatement() ) {
@ -254,14 +288,17 @@ public class MySQLDialect extends Dialect {
return 4;
}
@Override
public int getMaxVarcharLength() {
private int maxVarbinaryLength() {
return getMySQLVersion().isBefore( 5 ) ? 255 : 65_535;
}
private int maxVarcharLength(int bytesPerCharacter) {
// max length for VARCHAR changed in 5.0.3
if ( getMySQLVersion().isBefore( 5 ) ) {
return 255;
}
else {
switch ( characterSetBytesPerCharacter ) {
switch ( bytesPerCharacter ) {
case 1:
return 65_535;
case 2:
@ -275,9 +312,14 @@ public class MySQLDialect extends Dialect {
}
}
@Override
public int getMaxVarcharLength() {
return maxVarcharLength;
}
@Override
public int getMaxVarbinaryLength() {
return getMySQLVersion().isBefore( 5 ) ? 255 : 65_535;
return maxVarbinaryLength;
}
@Override
@ -290,13 +332,8 @@ public class MySQLDialect extends Dialect {
return super.getNullColumnString( columnType );
}
@Override
public DatabaseVersion getVersion() {
return version;
}
public DatabaseVersion getMySQLVersion() {
return version;
return super.getVersion();
}
@Override

View File

@ -10,6 +10,8 @@ import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -68,7 +70,6 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorOr
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.NullType;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
@ -86,6 +87,7 @@ import static org.hibernate.query.TemporalUnit.MINUTE;
import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.SECOND;
import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.type.SqlTypes.*;
/**
* A dialect for Oracle 8i and above.
@ -105,7 +107,6 @@ public class OracleDialect extends Dialect {
public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw";
private final LimitHandler limitHandler;
private final DatabaseVersion version;
public OracleDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
@ -117,15 +118,8 @@ public class OracleDialect extends Dialect {
}
public OracleDialect(DatabaseVersion version) {
super();
this.version = version;
super(version);
registerCharacterTypeMappings();
registerNumericTypeMappings();
registerDateTimeTypeMappings();
registerBinaryTypeMappings();
registerExtendedTypeMappings();
registerReverseHibernateTypeMappings();
registerDefaultProperties();
limitHandler = supportsFetchClause( FetchClauseType.ROWS_ONLY )
@ -133,11 +127,6 @@ public class OracleDialect extends Dialect {
: new LegacyOracleLimitHandler( getVersion() );
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
@ -536,52 +525,69 @@ public class OracleDialect extends Dialect {
pattern.append( unit.conversionFactor( toUnit, this ) );
}
protected void registerCharacterTypeMappings() {
if ( getVersion().isBefore( 9 ) ) {
registerColumnType( Types.VARCHAR, getMaxVarcharLength(), "varchar2($l)" );
registerColumnType( Types.VARCHAR, "clob" );
}
else {
registerColumnType( Types.CHAR, "char($l char)" );
registerColumnType( Types.VARCHAR, getMaxVarcharLength(), "varchar2($l char)" );
registerColumnType( Types.VARCHAR, "clob" );
registerColumnType( Types.NVARCHAR, getMaxNVarcharLength(), "nvarchar2($l)" );
registerColumnType( Types.NVARCHAR, "nclob" );
}
@Override
protected String columnType(int jdbcTypeCode) {
//note: the 'long' type is deprecated
switch (jdbcTypeCode) {
case BOOLEAN:
// still, after all these years...
return "number(1,0)";
case VARCHAR:
return getVersion().isBefore( 9 )
? "varchar2($l)": "varchar2($l char)";
case NVARCHAR:
return "nvarchar2($l)";
case BIGINT:
return "number(19,0)";
case SMALLINT:
return "number(5,0)";
case TINYINT:
return "number(3,0)";
case INTEGER:
return "number(10,0)";
case REAL:
// Oracle's 'real' type is actually double precision
return "float(24)";
case NUMERIC:
case DECIMAL:
// Note that 38 is the maximum precision Oracle supports
return "number($p,$s)";
case DATE:
case TIME:
return "date";
case TIMESTAMP:
// the only difference between date and timestamp
// on Oracle is that date has no fractional seconds
return getVersion().isBefore( 9 )
? "date" : "timestamp($p)";
case TIME_WITH_TIMEZONE:
return getVersion().isBefore( 9 )
? "date" : "timestamp($p) with time zone";
case BINARY:
case VARBINARY:
return "raw($l)";
case GEOMETRY:
return "MDSYS.SDO_GEOMETRY";
default:
return super.columnType(jdbcTypeCode);
}
}
protected void registerNumericTypeMappings() {
registerColumnType( Types.BOOLEAN, "number(1,0)" );
registerColumnType( Types.BIGINT, "number(19,0)" );
registerColumnType( Types.SMALLINT, "number(5,0)" );
registerColumnType( Types.TINYINT, "number(3,0)" );
registerColumnType( Types.INTEGER, "number(10,0)" );
// Oracle has DOUBLE semantics for the REAL type, so we map it to float(24)
registerColumnType( Types.REAL, "float(24)" );
// Note that 38 is the maximum precision Oracle supports
registerColumnType( Types.NUMERIC, "number($p,$s)" );
registerColumnType( Types.DECIMAL, "number($p,$s)" );
}
protected void registerDateTimeTypeMappings() {
if ( getVersion().isBefore( 9 ) ) {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "date" );
registerColumnType( Types.TIMESTAMP, "date" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "date" );
}
else {
//the only difference between date and timestamp
//on Oracle is that date has no fractional seconds
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "date" );
registerColumnType( Types.TIMESTAMP, "timestamp($p)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp($p) with time zone" );
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> list = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
if ( getVersion().isSameOrAfter( 10 ) ) {
list.add(GEOMETRY);
}
return list;
}
@Override
@ -589,23 +595,6 @@ public class OracleDialect extends Dialect {
return getVersion().isSameOrAfter( 9 ) ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;
}
protected void registerBinaryTypeMappings() {
registerColumnType( Types.BINARY, getMaxVarbinaryLength(), "raw($l)" );
registerColumnType( Types.BINARY, "blob" );
registerColumnType( Types.VARBINARY, getMaxVarbinaryLength(), "raw($l)" );
registerColumnType( Types.VARBINARY, "blob" );
}
protected void registerExtendedTypeMappings() {
if ( getVersion().isSameOrAfter( 10 ) ) {
registerColumnType( SqlTypes.GEOMETRY, "MDSYS.SDO_GEOMETRY" );
}
}
protected void registerReverseHibernateTypeMappings() {
}
protected void registerDefaultProperties() {
getDefaultProperties().setProperty( Environment.USE_STREAMS_FOR_BINARY, "true" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );

View File

@ -12,6 +12,7 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
@ -85,6 +86,7 @@ import static org.hibernate.query.TemporalUnit.EPOCH;
import static org.hibernate.query.TemporalUnit.MONTH;
import static org.hibernate.query.TemporalUnit.QUARTER;
import static org.hibernate.query.TemporalUnit.YEAR;
import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
@ -98,7 +100,6 @@ public class PostgreSQLDialect extends Dialect {
private static final PostgreSQLIdentityColumnSupport IDENTITY_COLUMN_SUPPORT = new PostgreSQLIdentityColumnSupport();
private final DatabaseVersion version;
private final PostgreSQLDriverKind driverKind;
public PostgreSQLDialect(DialectResolutionInfo info) {
@ -116,53 +117,77 @@ public class PostgreSQLDialect extends Dialect {
}
public PostgreSQLDialect(DatabaseVersion version, PostgreSQLDriverKind driverKind) {
super();
this.version = version;
super(version);
this.driverKind = driverKind;
registerColumnType( Types.TINYINT, "smallint" ); //no tinyint, not even in Postgres 11
registerColumnType( Types.VARBINARY, "bytea" );
registerColumnType( Types.BINARY, "bytea" );
//use oid as the blob type on Postgres because
//the JDBC driver is rubbish
registerColumnType( Types.BLOB, "oid" );
registerColumnType( Types.CLOB, "oid" );
//there are no nchar/nvarchar types in Postgres
registerColumnType( Types.NCHAR, "char($l)" );
registerColumnType( Types.NVARCHAR, getMaxNVarcharLength(), "varchar($l)" );
registerColumnType( Types.NVARCHAR, "text" );
// since there's no real difference between TEXT and VARCHAR,
// except for the length limit, we can just use 'text' for the
// "long" string types
registerColumnType( Types.VARCHAR, "text" );
registerColumnType( SqlTypes.INET, "inet" );
registerColumnType( SqlTypes.INTERVAL_SECOND, "interval second($s)" );
if ( getVersion().isSameOrAfter( 8, 2 ) ) {
registerColumnType( SqlTypes.UUID, "uuid" );
if ( getVersion().isSameOrAfter( 9, 2 ) ) {
// Prefer jsonb if possible
if ( getVersion().isSameOrAfter( 9, 4 ) ) {
registerColumnType( SqlTypes.JSON, "jsonb" );
}
else {
registerColumnType( SqlTypes.JSON, "json" );
}
}
}
registerColumnType( SqlTypes.GEOMETRY, "geometry" );
getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE );
getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" );
}
@Override
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case TINYINT:
// no tinyint, not even in Postgres 11
return "smallint";
case BINARY:
return "bytea";
case BLOB:
case CLOB:
// use oid as the blob type on Postgres because
// the JDBC driver is rubbish
return "oid";
// there are no nchar/nvarchar types in Postgres
case NCHAR:
return super.columnType(CHAR);
case NVARCHAR:
return super.columnType(VARCHAR);
// since there's no real difference between TEXT and VARCHAR,
// except for the length limit, we can just use 'text' for the
// "long" string types
case LONGVARCHAR:
case LONGNVARCHAR:
return "text";
// use bytea as the "long" binary type (that there is no
// real VARBINARY type in Postgres, so we always use this)
case LONGVARBINARY:
return "bytea";
case INET:
return "inet";
case UUID:
return "uuid";
case GEOMETRY:
return "geometry";
case JSON:
// Prefer jsonb if possible
return getVersion().isSameOrAfter( 9, 4 )
? "jsonb" : "json";
case INTERVAL_SECOND:
return "interval second($s)";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> typeCodes = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
typeCodes.addAll( List.of(INET, INTERVAL_SECOND, GEOMETRY) );
if ( getVersion().isSameOrAfter( 8, 2 ) ) {
typeCodes.add(UUID);
}
if ( getVersion().isSameOrAfter( 9, 2 ) ) {
typeCodes.add(JSON);
}
return typeCodes;
}
@Override
public int getMaxVarcharLength() {
return 10_485_760;
@ -171,17 +196,17 @@ public class PostgreSQLDialect extends Dialect {
@Override
public int getMaxVarbinaryLength() {
//postgres has no varbinary-like type
return 0;
return -1;
}
@Override
public String getTypeName(int code, Size size) throws HibernateException {
// The maximum scale for `interval second` is 6 unfortunately so we have to use numeric by default
switch ( code ) {
case SqlTypes.INTERVAL_SECOND:
case INTERVAL_SECOND:
final Integer scale = size.getScale();
if ( scale == null || scale > 6 ) {
return getTypeName( SqlTypes.NUMERIC, size );
return getTypeName( NUMERIC, size );
}
}
return super.getTypeName( code, size );
@ -194,32 +219,27 @@ public class PostgreSQLDialect extends Dialect {
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
if ( jdbcTypeCode == SqlTypes.OTHER ) {
if ( jdbcTypeCode == OTHER ) {
switch ( columnTypeName ) {
case "uuid":
jdbcTypeCode = SqlTypes.UUID;
jdbcTypeCode = UUID;
break;
case "json":
case "jsonb":
jdbcTypeCode = SqlTypes.JSON;
jdbcTypeCode = JSON;
break;
case "inet":
jdbcTypeCode = SqlTypes.INET;
jdbcTypeCode = INET;
break;
case "geometry":
case "geography":
jdbcTypeCode = SqlTypes.GEOMETRY;
jdbcTypeCode = GEOMETRY;
break;
}
}
return jdbcTypeRegistry.getDescriptor( jdbcTypeCode );
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public String currentTime() {
return "localtime";

View File

@ -50,7 +50,6 @@ import org.hibernate.tool.schema.internal.StandardSequenceExporter;
import org.hibernate.tool.schema.spi.Exporter;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcType;
@ -60,13 +59,16 @@ import java.sql.SQLException;
import java.sql.Types;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import jakarta.persistence.TemporalType;
import static org.hibernate.query.TemporalUnit.NANOSECOND;
import static org.hibernate.type.SqlTypes.*;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
@ -79,12 +81,10 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM
public class SQLServerDialect extends AbstractTransactSQLDialect {
private static final int PARAM_LIST_SIZE_LIMIT = 2100;
private final DatabaseVersion version;
private StandardSequenceExporter exporter;
public SQLServerDialect(DialectResolutionInfo info) {
this( info.makeCopy() );
this( info.makeCopy(), info );
registerKeywords( info );
}
@ -93,53 +93,71 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
public SQLServerDialect(DatabaseVersion version) {
super();
this.version = version;
this(version, null);
}
//there is no 'double' type in SQL server
//but 'float' is double precision by default
registerColumnType( Types.DOUBLE, "float" );
if ( getVersion().isSameOrAfter( 10 ) ) {
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
registerColumnType( Types.TIMESTAMP, "datetime2($p)" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetimeoffset($p)" );
registerColumnType( SqlTypes.GEOMETRY, "geometry" );
}
protected SQLServerDialect(DatabaseVersion version, DialectResolutionInfo info) {
super(version, info);
if ( getVersion().isSameOrAfter( 11 ) ) {
exporter = new SqlServerSequenceExporter( this );
}
if ( getVersion().isBefore( 9 ) ) {
registerColumnType( Types.VARBINARY, "image" );
registerColumnType( Types.VARCHAR, "text" );
registerColumnType( Types.NVARCHAR, "text" );
}
else {
registerKeyword( "top" );
registerKeyword( "key" );
}
// Use 'varchar(max)' and 'varbinary(max)' instead
@Override
protected List<Integer> getSupportedJdbcTypeCodes() {
List<Integer> list = new ArrayList<>( super.getSupportedJdbcTypeCodes() );
if ( getVersion().isSameOrAfter( 10 ) ) {
list.add(GEOMETRY);
}
return list;
}
@Override
protected String columnType(int jdbcTypeCode) {
if ( getVersion().isSameOrAfter( 10 ) ) {
switch (jdbcTypeCode) {
case DATE:
return "date";
case TIME:
return "time";
case TIMESTAMP:
return"datetime2($p)";
case TIMESTAMP_WITH_TIMEZONE:
return "datetimeoffset($p)";
}
}
if ( getVersion().isSameOrAfter(9) ) {
// Prefer 'varchar(max)' and 'varbinary(max)' to
// the deprecated TEXT and IMAGE types. Note that
// the length of a VARCHAR or VARBINARY column must
// be either between 1 and 8000 or exactly MAX, and
// the length of an NVARCHAR column must be either
// between 1 and 4000 or exactly MAX.
// See http://www.sql-server-helper.com/faq/sql-server-2005-varchar-max-p01.aspx
// See HHH-3965
registerColumnType( Types.BLOB, "varbinary(max)" );
registerColumnType( Types.VARBINARY, "varbinary(max)" );
registerColumnType( Types.CLOB, "varchar(max)" );
registerColumnType( Types.NCLOB, "nvarchar(max)" ); // HHH-8435 fix
registerColumnType( Types.VARCHAR, "varchar(max)" );
registerColumnType( Types.NVARCHAR, "nvarchar(max)" );
// between 1 and 4000 or exactly MAX. (HHH-3965)
switch (jdbcTypeCode) {
case BLOB:
return "varbinary(max)";
case CLOB:
return "varchar(max)";
case NCLOB:
return "nvarchar(max)";
}
}
registerKeyword( "top" );
registerKeyword( "key" );
switch (jdbcTypeCode) {
case DOUBLE:
// there is no 'double' type in SQL server
// but 'float' is double precision by default
return "float";
case GEOMETRY:
return "geometry";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
@ -152,11 +170,6 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
return 4000;
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public TimeZoneSupport getTimeZoneSupport() {
return getVersion().isSameOrAfter( 10 ) ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;

View File

@ -53,6 +53,7 @@ import org.hibernate.type.StandardBasicTypes;
import jakarta.persistence.TemporalType;
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
import static org.hibernate.type.SqlTypes.*;
/**
* Hibernate Dialect implementation for Cloud Spanner.
@ -73,50 +74,61 @@ public class SpannerDialect extends Dialect {
private static final UniqueDelegate NOOP_UNIQUE_DELEGATE = new DoNothingUniqueDelegate();
public SpannerDialect() {
registerColumnType( Types.BOOLEAN, "bool" );
registerColumnType( Types.TINYINT, "int64" );
registerColumnType( Types.SMALLINT, "int64" );
registerColumnType( Types.INTEGER, "int64" );
registerColumnType( Types.BIGINT, "int64" );
registerColumnType( Types.REAL, "float64" );
registerColumnType( Types.FLOAT, "float64" );
registerColumnType( Types.DOUBLE, "float64" );
registerColumnType( Types.DECIMAL, "float64" );
registerColumnType( Types.NUMERIC, "float64" );
//timestamp does not accept precision
registerColumnType( Types.TIMESTAMP, "timestamp" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "timestamp" );
//there is no time type of any kind
registerColumnType( Types.TIME, "timestamp" );
registerColumnType( Types.CHAR, getMaxVarcharLength(), "string($l)" );
registerColumnType( Types.CHAR, "string(max)" );
registerColumnType( Types.VARCHAR, getMaxVarcharLength(), "string($l)" );
registerColumnType( Types.VARCHAR, "string(max)" );
registerColumnType( Types.NCHAR, getMaxNVarcharLength(), "string($l)" );
registerColumnType( Types.NCHAR, "string(max)" );
registerColumnType( Types.NVARCHAR, getMaxNVarcharLength(), "string($l)" );
registerColumnType( Types.NVARCHAR, "string(max)" );
registerColumnType( Types.BINARY, getMaxBytesLength(), "bytes($l)" );
registerColumnType( Types.BINARY, "bytes(max)" );
registerColumnType( Types.VARBINARY, getMaxBytesLength(), "bytes($l)" );
registerColumnType( Types.VARBINARY, "bytes(max)" );
registerColumnType( Types.CLOB, "string(max)" );
registerColumnType( Types.NCLOB, "string(max)" );
registerColumnType( Types.BLOB, "bytes(max)" );
super();
}
public SpannerDialect(DialectResolutionInfo info) {
this();
super();
registerKeywords( info );
}
@Override
protected String columnType(int jdbcTypeCode) {
switch (jdbcTypeCode) {
case BOOLEAN:
return "bool";
case TINYINT:
case SMALLINT:
case INTEGER:
case BIGINT:
return "int64";
case REAL:
case FLOAT:
case DOUBLE:
case DECIMAL:
case NUMERIC:
return "float64";
//there is no time type of any kind
case TIME:
//timestamp does not accept precision
case TIMESTAMP:
case TIMESTAMP_WITH_TIMEZONE:
return "timestamp";
case CHAR:
case NCHAR:
case VARCHAR:
case NVARCHAR:
return "string($l)";
case BINARY:
case VARBINARY:
return "bytes($l)";
case CLOB:
case NCLOB:
return "string(max)";
case BLOB:
return "bytes(max)";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
public int getMaxVarcharLength() {
//max is equivalent to 2_621_440

View File

@ -16,6 +16,6 @@ package org.hibernate.dialect;
@Deprecated
public class Sybase11Dialect extends SybaseASEDialect {
public Sybase11Dialect() {
super( DatabaseVersion.make( 11 ), false, false );
super( DatabaseVersion.make( 11 ) );
}
}

View File

@ -17,7 +17,7 @@ package org.hibernate.dialect;
public class SybaseASE157Dialect extends SybaseASEDialect {
public SybaseASE157Dialect() {
super( DatabaseVersion.make( 15, 7 ), false, false );
super( DatabaseVersion.make( 15, 7 ) );
}
}

View File

@ -17,7 +17,7 @@ package org.hibernate.dialect;
public class SybaseASE15Dialect extends SybaseASEDialect {
public SybaseASE15Dialect() {
super( DatabaseVersion.make( 15 ), false, false );
super( DatabaseVersion.make( 15 ) );
}
}

View File

@ -43,6 +43,7 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import jakarta.persistence.TemporalType;
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
import static org.hibernate.type.SqlTypes.*;
/**
* Dialect for Sybase Adaptive Server Enterprise for
@ -54,55 +55,25 @@ public class SybaseASEDialect extends SybaseDialect {
private final boolean ansiNull;
public SybaseASEDialect() {
this( DatabaseVersion.make( 11 ), false, false );
this( DatabaseVersion.make( 11 ) );
}
public SybaseASEDialect(DialectResolutionInfo info) {
this(
info.makeCopy(),
info.getDriverName() != null && info.getDriverName().contains( "jTDS" ),
isAnsiNull( info.unwrap( DatabaseMetaData.class ) )
);
this( info.makeCopy(), info );
registerKeywords( info );
}
public SybaseASEDialect(DatabaseVersion version, boolean jtdsDriver, boolean ansiNull) {
super( version, jtdsDriver );
this.ansiNull = ansiNull;
//On Sybase ASE, the 'bit' type cannot be null,
//and cannot have indexes (while we don't use
//tinyint to store signed bytes, we can use it
//to store boolean values)
registerColumnType( Types.BOOLEAN, "tinyint" );
public SybaseASEDialect(DatabaseVersion version) {
this(version, null);
}
protected SybaseASEDialect(DatabaseVersion version, DialectResolutionInfo info) {
super(version, info);
if ( getVersion().isSameOrAfter( 12 ) ) {
//date / date were introduced in version 12
registerColumnType( Types.DATE, "date" );
registerColumnType( Types.TIME, "time" );
if ( getVersion().isSameOrAfter( 15 ) ) {
//bigint was added in version 15
registerColumnType( Types.BIGINT, "bigint" );
if ( getVersion().isSameOrAfter( 15, 5 ) && !jtdsDriver ) {
//According to Wikipedia bigdatetime and bigtime were added in 15.5
//But with jTDS we can't use them as the driver can't handle the types
registerColumnType( Types.DATE, "bigdatetime" );
registerColumnType( Types.DATE, 3, "datetime" );
registerColumnType( Types.TIME, "bigtime" );
registerColumnType( Types.TIME, 3, "datetime" );
registerColumnType( Types.TIMESTAMP, "bigdatetime" );
registerColumnType( Types.TIMESTAMP, 3, "datetime" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "bigdatetime" );
registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, 3, "datetime" );
}
}
}
registerColumnType( Types.VARBINARY, "image" );
registerColumnType( Types.VARCHAR, "text" );
ansiNull = info != null && isAnsiNull( info.unwrap( DatabaseMetaData.class ) );
registerSybaseKeywords();
sizeStrategy = new SizeStrategyImpl() {
@Override
public Size resolveSize(
@ -123,6 +94,56 @@ public class SybaseASEDialect extends SybaseDialect {
};
}
@Override
protected String columnType(int jdbcTypeCode) {
if ( jdbcTypeCode == BIGINT && getVersion().isBefore( 15 ) ) {
// Sybase ASE didn't introduce 'bigint' until version 15.0
return "numeric(19,0)";
}
if ( getVersion().isSameOrAfter( 12 ) ) {
// 'date' and 'time' were introduced in version 12
// note: 'timestamp' is something weird on ASE,
// not what we're looking for here!
switch (jdbcTypeCode) {
case DATE:
return "date";
case TIME:
return "time";
}
}
switch (jdbcTypeCode) {
case BOOLEAN:
// On Sybase ASE, the 'bit' type cannot be null,
// and cannot have indexes (while we don't use
// tinyint to store signed bytes, we can use it
// to store boolean values)
return "tinyint";
default:
return super.columnType(jdbcTypeCode);
}
}
@Override
protected void registerDefaultColumnTypes(DialectResolutionInfo info) {
super.registerDefaultColumnTypes(info);
// According to Wikipedia bigdatetime and bigtime were added in 15.5
// But with jTDS we can't use them as the driver can't handle the types
if ( getVersion().isSameOrAfter( 15, 5 ) && !jtdsDriver ) {
registerColumnType( DATE, "bigdatetime" );
registerColumnType( DATE, 3, "datetime" );
registerColumnType( TIME, "bigtime" );
registerColumnType( TIME, 3, "datetime" );
registerColumnType( TIMESTAMP, "bigdatetime" );
registerColumnType( TIMESTAMP, 3, "datetime" );
registerColumnType( TIMESTAMP_WITH_TIMEZONE, "bigdatetime" );
registerColumnType( TIMESTAMP_WITH_TIMEZONE, 3, "datetime" );
}
}
@Override
public int getMaxVarcharLength() {
// the maximum length of a VARCHAR or VARBINARY

View File

@ -59,30 +59,39 @@ import jakarta.persistence.TemporalType;
*/
public class SybaseDialect extends AbstractTransactSQLDialect {
private final DatabaseVersion version;
protected final boolean jtdsDriver;
protected boolean jtdsDriver;
//All Sybase dialects share an IN list size limit.
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
public SybaseDialect(){
this( DatabaseVersion.make( 11, 0 ), false );
public SybaseDialect() {
this( DatabaseVersion.make( 11, 0 ) );
}
public SybaseDialect(DialectResolutionInfo info){
this(
info.makeCopy(),
info.getDriverName() != null && info.getDriverName().contains( "jTDS" )
);
public SybaseDialect(DatabaseVersion version) {
this(version, null);
}
public SybaseDialect(DialectResolutionInfo info) {
this( info.makeCopy(), info );
registerKeywords( info );
}
public SybaseDialect(DatabaseVersion version, boolean jtdsDriver) {
super();
this.version = version;
this.jtdsDriver = jtdsDriver;
//Sybase ASE didn't introduce bigint until version 15.0
registerColumnType( Types.BIGINT, "numeric(19,0)" );
protected SybaseDialect(DatabaseVersion version, DialectResolutionInfo info) {
super(version, info);
}
@Override
protected void registerDefaultColumnTypes(DialectResolutionInfo info) {
// we need to check init the jtdsDriver field here,
// because we need it in the registerDefaultColumnTypes()
// of the subclass, which is called from the superclass
// constructor, before our constructor has been called
jtdsDriver = info != null
&& info.getDriverName() != null
&& info.getDriverName().contains( "jTDS" );
super.registerDefaultColumnTypes(info);
}
@Override
@ -146,11 +155,6 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
};
}
@Override
public DatabaseVersion getVersion() {
return version;
}
@Override
public boolean supportsNullPrecedence() {
return false;
@ -314,7 +318,7 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override
public NameQualifierSupport getNameQualifierSupport() {
if ( version.isSameOrAfter( 15 ) ) {
if ( getVersion().isSameOrAfter( 15 ) ) {
return NameQualifierSupport.BOTH;
}
return NameQualifierSupport.CATALOG;

View File

@ -29,29 +29,30 @@ import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
*/
public class TiDBDialect extends MySQLDialect {
private final int tidbVersion;
private final DatabaseVersion tidbVersion;
public TiDBDialect() {
// Let's be conservative and assume people use a 4 byte character set
this( 500, 4 );
this( DatabaseVersion.make(5, 4) );
}
public TiDBDialect(DialectResolutionInfo info) {
this(
info.getDatabaseMajorVersion() * 100 + info.getDatabaseMinorVersion() * 10,
getCharacterSetBytesPerCharacter( info.unwrap( DatabaseMetaData.class ) )
);
this( info.makeCopy(), info );
registerKeywords( info );
}
public TiDBDialect(int version, int characterSetBytesPerCharacter) {
public TiDBDialect(DatabaseVersion version) {
this(version, null);
}
protected TiDBDialect(DatabaseVersion tidbVersion, DialectResolutionInfo info) {
// For simplicitys sake, configure MySQL 5.7 compatibility
super( DatabaseVersion.make( 5, 7 ), characterSetBytesPerCharacter );
this.tidbVersion = version;
super( DatabaseVersion.make( 5, 7 ), info );
this.tidbVersion = tidbVersion;
registerKeywords();
}
public int getTidbVersion() {
@Override
public DatabaseVersion getVersion() {
return tidbVersion;
}