HHH-15190 - Remove support for H2 versions older than 1.4.197
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
89f04d2274
commit
f33d3ed308
|
@ -0,0 +1,711 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.PessimisticLockException;
|
||||
import org.hibernate.boot.model.TypeContributions;
|
||||
import org.hibernate.dialect.DatabaseVersion;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2DurationIntervalSecondJdbcType;
|
||||
import org.hibernate.dialect.OracleDialect;
|
||||
import org.hibernate.dialect.Replacer;
|
||||
import org.hibernate.dialect.SelectItemReferenceStrategy;
|
||||
import org.hibernate.dialect.SimpleDatabaseVersion;
|
||||
import org.hibernate.dialect.TimeZoneSupport;
|
||||
import org.hibernate.dialect.function.CommonFunctionFactory;
|
||||
import org.hibernate.dialect.hint.IndexQueryHintHandler;
|
||||
import org.hibernate.dialect.identity.H2IdentityColumnSupport;
|
||||
import org.hibernate.dialect.identity.IdentityColumnSupport;
|
||||
import org.hibernate.dialect.pagination.LimitHandler;
|
||||
import org.hibernate.dialect.pagination.LimitOffsetLimitHandler;
|
||||
import org.hibernate.dialect.pagination.OffsetFetchLimitHandler;
|
||||
import org.hibernate.dialect.sequence.H2V1SequenceSupport;
|
||||
import org.hibernate.dialect.sequence.H2V2SequenceSupport;
|
||||
import org.hibernate.dialect.sequence.SequenceSupport;
|
||||
import org.hibernate.dialect.temptable.TemporaryTable;
|
||||
import org.hibernate.dialect.temptable.TemporaryTableKind;
|
||||
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.hibernate.exception.LockAcquisitionException;
|
||||
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.IntervalType;
|
||||
import org.hibernate.query.sqm.NullOrdering;
|
||||
import org.hibernate.query.sqm.TemporalUnit;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.BeforeUseAction;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2DatabaseImpl;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
|
||||
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
|
||||
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
|
||||
import org.hibernate.type.descriptor.jdbc.InstantJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.UUIDJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
|
||||
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import static org.hibernate.query.sqm.TemporalUnit.SECOND;
|
||||
import static org.hibernate.type.SqlTypes.ARRAY;
|
||||
import static org.hibernate.type.SqlTypes.BINARY;
|
||||
import static org.hibernate.type.SqlTypes.CHAR;
|
||||
import static org.hibernate.type.SqlTypes.DECIMAL;
|
||||
import static org.hibernate.type.SqlTypes.DOUBLE;
|
||||
import static org.hibernate.type.SqlTypes.FLOAT;
|
||||
import static org.hibernate.type.SqlTypes.GEOMETRY;
|
||||
import static org.hibernate.type.SqlTypes.INTERVAL_SECOND;
|
||||
import static org.hibernate.type.SqlTypes.LONG32NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.LONG32VARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NCHAR;
|
||||
import static org.hibernate.type.SqlTypes.NUMERIC;
|
||||
import static org.hibernate.type.SqlTypes.NVARCHAR;
|
||||
import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
||||
import static org.hibernate.type.SqlTypes.UUID;
|
||||
import static org.hibernate.type.SqlTypes.VARBINARY;
|
||||
import static org.hibernate.type.SqlTypes.VARCHAR;
|
||||
|
||||
/**
|
||||
* A legacy {@linkplain Dialect SQL dialect} for H2.
|
||||
*
|
||||
* @author Thomas Mueller
|
||||
*/
|
||||
public class H2LegacyDialect extends Dialect {
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( H2LegacyDialect.class );
|
||||
|
||||
private final LimitHandler limitHandler;
|
||||
|
||||
private final boolean ansiSequence;
|
||||
private final boolean cascadeConstraints;
|
||||
private final boolean useLocalTime;
|
||||
|
||||
private final SequenceInformationExtractor sequenceInformationExtractor;
|
||||
private final String querySequenceString;
|
||||
|
||||
public H2LegacyDialect(DialectResolutionInfo info) {
|
||||
this( parseVersion( info ) );
|
||||
registerKeywords( info );
|
||||
}
|
||||
|
||||
public H2LegacyDialect() {
|
||||
this( SimpleDatabaseVersion.ZERO_VERSION );
|
||||
}
|
||||
|
||||
public H2LegacyDialect(DatabaseVersion version) {
|
||||
super(version);
|
||||
|
||||
// https://github.com/h2database/h2database/commit/b2cdf84e0b84eb8a482fa7dccdccc1ab95241440
|
||||
limitHandler = version.isSameOrAfter( 1, 4, 195 )
|
||||
? OffsetFetchLimitHandler.INSTANCE
|
||||
: LimitOffsetLimitHandler.INSTANCE;
|
||||
|
||||
if ( version.isBefore( 1, 2, 139 ) ) {
|
||||
LOG.unsupportedMultiTableBulkHqlJpaql( version.getMajor(), version.getMinor(), version.getMicro() );
|
||||
}
|
||||
|
||||
// supportsTuplesInSubqueries = version.isSameOrAfter( 1, 4, 198 );
|
||||
|
||||
// Prior to 1.4.200 there was no support for 'current value for sequence_name'
|
||||
// After 2.0.202 there is no support for 'sequence_name.nextval' and 'sequence_name.currval'
|
||||
ansiSequence = version.isSameOrAfter( 1, 4, 200 );
|
||||
|
||||
// Prior to 1.4.200 the 'cascade' in 'drop table' was implicit
|
||||
cascadeConstraints = version.isSameOrAfter( 1, 4, 200 );
|
||||
// 1.4.200 introduced changes in current_time and current_timestamp
|
||||
useLocalTime = version.isSameOrAfter( 1, 4, 200 );
|
||||
|
||||
if ( version.isSameOrAfter( 1, 4, 32 ) ) {
|
||||
this.sequenceInformationExtractor = version.isSameOrAfter( 1, 4, 201 )
|
||||
? SequenceInformationExtractorLegacyImpl.INSTANCE
|
||||
: SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
|
||||
this.querySequenceString = "select * from INFORMATION_SCHEMA.SEQUENCES";
|
||||
}
|
||||
else {
|
||||
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
|
||||
this.querySequenceString = null;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
public boolean getDefaultNonContextualLobCreation() {
|
||||
// http://code.google.com/p/h2database/issues/detail?id=235
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsStandardArrays() {
|
||||
return getVersion().isSameOrAfter( 2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String columnType(int sqlTypeCode) {
|
||||
switch ( sqlTypeCode ) {
|
||||
// prior to version 2.0, H2 reported NUMERIC columns as DECIMAL,
|
||||
// which caused problems for schema update tool
|
||||
case NUMERIC:
|
||||
return getVersion().isBefore( 2 ) ? columnType( DECIMAL ) : super.columnType( sqlTypeCode );
|
||||
case NCHAR:
|
||||
return columnType( CHAR );
|
||||
case NVARCHAR:
|
||||
return columnType( VARCHAR );
|
||||
}
|
||||
return super.columnType( sqlTypeCode );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String castType(int sqlTypeCode) {
|
||||
switch ( sqlTypeCode ) {
|
||||
case CHAR:
|
||||
case NCHAR:
|
||||
return "char";
|
||||
case VARCHAR:
|
||||
case NVARCHAR:
|
||||
case LONG32VARCHAR:
|
||||
case LONG32NVARCHAR:
|
||||
return "varchar";
|
||||
case BINARY:
|
||||
case VARBINARY:
|
||||
case LONG32VARBINARY:
|
||||
return "varbinary";
|
||||
}
|
||||
return super.castType( sqlTypeCode );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerColumnTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
super.registerColumnTypes( typeContributions, serviceRegistry );
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeContributions.getTypeConfiguration().getDdlTypeRegistry();
|
||||
|
||||
if ( getVersion().isBefore( 2 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( ARRAY, "array", this ) );
|
||||
}
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( UUID, "uuid", this ) );
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( GEOMETRY, "geometry", this ) );
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 198 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( INTERVAL_SECOND, "interval second($p,$s)", this ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
super.contributeTypes( typeContributions, serviceRegistry );
|
||||
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
|
||||
jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantJdbcType.INSTANCE );
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
}
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 198 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( H2DurationIntervalSecondJdbcType.INSTANCE );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultStatementBatchSize() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
public boolean hasOddDstBehavior() {
|
||||
// H2 1.4.200 has a bug: https://github.com/h2database/h2database/issues/3184
|
||||
return getVersion().isSameOrAfter( 1, 4, 200 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeFunctionRegistry(QueryEngine queryEngine) {
|
||||
super.initializeFunctionRegistry( queryEngine );
|
||||
|
||||
CommonFunctionFactory functionFactory = new CommonFunctionFactory(queryEngine);
|
||||
|
||||
// H2 needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type
|
||||
functionFactory.aggregates( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
// AVG by default uses the input type, so we possibly need to cast the argument type, hence a special function
|
||||
functionFactory.avg_castingNonDoubleArguments( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
|
||||
functionFactory.pi();
|
||||
functionFactory.cot();
|
||||
functionFactory.radians();
|
||||
functionFactory.degrees();
|
||||
functionFactory.log10();
|
||||
functionFactory.rand();
|
||||
functionFactory.truncate();
|
||||
functionFactory.soundex();
|
||||
functionFactory.translate();
|
||||
functionFactory.bitand();
|
||||
functionFactory.bitor();
|
||||
functionFactory.bitxor();
|
||||
functionFactory.bitAndOr();
|
||||
functionFactory.yearMonthDay();
|
||||
functionFactory.hourMinuteSecond();
|
||||
functionFactory.dayOfWeekMonthYear();
|
||||
functionFactory.weekQuarter();
|
||||
functionFactory.daynameMonthname();
|
||||
if ( useLocalTime ) {
|
||||
functionFactory.localtimeLocaltimestamp();
|
||||
}
|
||||
functionFactory.bitLength();
|
||||
functionFactory.octetLength();
|
||||
functionFactory.ascii();
|
||||
functionFactory.octetLength();
|
||||
functionFactory.space();
|
||||
functionFactory.repeat();
|
||||
functionFactory.chr_char();
|
||||
functionFactory.instr();
|
||||
functionFactory.substr();
|
||||
//also natively supports ANSI-style substring()
|
||||
functionFactory.position();
|
||||
functionFactory.trim1();
|
||||
functionFactory.concat_pipeOperator();
|
||||
functionFactory.nowCurdateCurtime();
|
||||
functionFactory.sysdate();
|
||||
functionFactory.insert();
|
||||
// functionFactory.everyAny(); //this would work too
|
||||
functionFactory.everyAny_boolAndOr();
|
||||
functionFactory.median();
|
||||
functionFactory.stddevPopSamp();
|
||||
functionFactory.varPopSamp();
|
||||
if ( getVersion().isSame( 1, 4, 200 ) ) {
|
||||
// See https://github.com/h2database/h2database/issues/2518
|
||||
functionFactory.format_toChar();
|
||||
}
|
||||
else {
|
||||
functionFactory.format_formatdatetime();
|
||||
}
|
||||
functionFactory.rownum();
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 200 ) ) {
|
||||
functionFactory.windowFunctions();
|
||||
if ( getVersion().isSameOrAfter( 2 ) ) {
|
||||
functionFactory.listagg( null );
|
||||
functionFactory.inverseDistributionOrderedSetAggregates();
|
||||
functionFactory.hypotheticalOrderedSetAggregates();
|
||||
}
|
||||
else {
|
||||
// Use group_concat until 2.x as listagg was buggy
|
||||
functionFactory.listagg_groupConcat();
|
||||
}
|
||||
}
|
||||
else {
|
||||
functionFactory.listagg_groupConcat();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void augmentPhysicalTableTypes(List<String> tableTypesList) {
|
||||
if ( getVersion().isSameOrAfter( 2 ) ) {
|
||||
tableTypesList.add( "BASE TABLE" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer resolveSqlTypeCode(String columnTypeName, TypeConfiguration typeConfiguration) {
|
||||
switch ( columnTypeName ) {
|
||||
case "FLOAT(24)":
|
||||
// Use REAL instead of FLOAT to get Float as recommended Java type
|
||||
return Types.REAL;
|
||||
}
|
||||
return super.resolveSqlTypeCode( columnTypeName, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType resolveSqlTypeDescriptor(
|
||||
String columnTypeName,
|
||||
int jdbcTypeCode,
|
||||
int precision,
|
||||
int scale,
|
||||
JdbcTypeRegistry jdbcTypeRegistry) {
|
||||
// As of H2 2.0 we get a FLOAT type code even though it is a DOUBLE
|
||||
if ( jdbcTypeCode == FLOAT && "DOUBLE PRECISION".equals( columnTypeName ) ) {
|
||||
return jdbcTypeRegistry.getDescriptor( DOUBLE );
|
||||
}
|
||||
return super.resolveSqlTypeDescriptor( columnTypeName, jdbcTypeCode, precision, scale, jdbcTypeRegistry );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer resolveSqlTypeCode(String typeName, String baseTypeName, TypeConfiguration typeConfiguration) {
|
||||
switch ( baseTypeName ) {
|
||||
case "CHARACTER VARYING":
|
||||
return VARCHAR;
|
||||
}
|
||||
return super.resolveSqlTypeCode( typeName, baseTypeName, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxVarcharLength() {
|
||||
return 1_048_576;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentTime() {
|
||||
return useLocalTime ? "localtime" : super.currentTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentTimestamp() {
|
||||
return useLocalTime ? "localtimestamp" : super.currentTimestamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String currentTimestampWithTimeZone() {
|
||||
return "current_timestamp";
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
|
||||
return new StandardSqlAstTranslatorFactory() {
|
||||
@Override
|
||||
protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
|
||||
SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
return new H2LegacySqlAstTranslator<>( sessionFactory, statement );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* In H2, the extract() function does not return
|
||||
* fractional seconds for the field
|
||||
* {@link TemporalUnit#SECOND}. We work around
|
||||
* this here with two calls to extract().
|
||||
*/
|
||||
@Override
|
||||
public String extractPattern(TemporalUnit unit) {
|
||||
return unit == SECOND
|
||||
? "(" + super.extractPattern(unit) + "+extract(nanosecond from ?2)/1e9)"
|
||||
: super.extractPattern(unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
|
||||
if ( intervalType != null ) {
|
||||
return "(?2+?3)";
|
||||
}
|
||||
return "dateadd(?1,?2,?3)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
|
||||
if ( unit == null ) {
|
||||
return "(?3-?2)";
|
||||
}
|
||||
return "datediff(?1,?2,?3)";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporalLiteralOffset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimeZoneSupport getTimeZoneSupport() {
|
||||
return TimeZoneSupport.NATIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
|
||||
appender.appendSql( bool );
|
||||
}
|
||||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
return limitHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsDistinctFromPredicate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIfExistsAfterTableName() {
|
||||
return !supportsIfExistsBeforeTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIfExistsBeforeTableName() {
|
||||
return cascadeConstraints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIfExistsAfterAlterTable() {
|
||||
return cascadeConstraints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIfExistsBeforeConstraintName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCascadeConstraintsString() {
|
||||
return cascadeConstraints ? " cascade "
|
||||
: super.getCascadeConstraintsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCommentOn() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dropConstraints() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequenceSupport getSequenceSupport() {
|
||||
return ansiSequence ? H2V2SequenceSupport.INSTANCE: H2V1SequenceSupport.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySequencesString() {
|
||||
return querySequenceString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SequenceInformationExtractor getSequenceInformationExtractor() {
|
||||
return sequenceInformationExtractor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NullOrdering getNullOrdering() {
|
||||
return NullOrdering.SMALLEST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableMutationStrategy(
|
||||
TemporaryTable.createIdTable(
|
||||
entityDescriptor,
|
||||
basename -> TemporaryTable.ID_TABLE_PREFIX + basename,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
|
||||
EntityMappingType entityDescriptor,
|
||||
RuntimeModelCreationContext runtimeModelCreationContext) {
|
||||
return new LocalTemporaryTableInsertStrategy(
|
||||
TemporaryTable.createEntityTable(
|
||||
entityDescriptor,
|
||||
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
|
||||
this,
|
||||
runtimeModelCreationContext
|
||||
),
|
||||
runtimeModelCreationContext.getSessionFactory()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporaryTableKind getSupportedTemporaryTableKind() {
|
||||
return TemporaryTableKind.LOCAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeforeUseAction getTemporaryTableBeforeUseAction() {
|
||||
return BeforeUseAction.CREATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
|
||||
return EXTRACTOR;
|
||||
}
|
||||
|
||||
private static final ViolatedConstraintNameExtractor EXTRACTOR =
|
||||
new TemplatedViolatedConstraintNameExtractor( sqle -> {
|
||||
// 23000: Check constraint violation: {0}
|
||||
// 23001: Unique index or primary key violation: {0}
|
||||
if ( sqle.getSQLState().startsWith( "23" ) ) {
|
||||
final String message = sqle.getMessage();
|
||||
final int idx = message.indexOf( "violation: " );
|
||||
if ( idx > 0 ) {
|
||||
String constraintName = message.substring( idx + "violation: ".length() );
|
||||
if ( sqle.getSQLState().equals( "23506" ) ) {
|
||||
constraintName = constraintName.substring( 1, constraintName.indexOf( ":" ) );
|
||||
}
|
||||
return constraintName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} );
|
||||
|
||||
@Override
|
||||
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
|
||||
return (sqlException, message, sql) -> {
|
||||
final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException );
|
||||
|
||||
switch (errorCode) {
|
||||
case 40001:
|
||||
// DEADLOCK DETECTED
|
||||
return new LockAcquisitionException(message, sqlException, sql);
|
||||
case 50200:
|
||||
// LOCK NOT AVAILABLE
|
||||
return new PessimisticLockException(message, sqlException, sql);
|
||||
case 90006:
|
||||
// NULL not allowed for column [90006-145]
|
||||
final String constraintName = getViolatedConstraintNameExtractor().extractConstraintName(sqlException);
|
||||
return new ConstraintViolationException(message, sqlException, sql, constraintName);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCurrentTimestampSelection() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentTimestampSelectStringCallable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentTimestampSelectString() {
|
||||
return "call current_timestamp()";
|
||||
}
|
||||
|
||||
|
||||
// Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@Override
|
||||
public boolean supportsLobValueChangePropagation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTupleCounts() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresParensForTupleDistinctCounts() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesReadCommittedCauseWritersToBlockReaders() {
|
||||
// see http://groups.google.com/group/h2-database/browse_thread/thread/562d8a49e2dabe99?hl=en
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectItemReferenceStrategy getGroupBySelectItemReferenceStrategy() {
|
||||
return SelectItemReferenceStrategy.ALIAS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsOffsetInSubquery() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWindowFunctions() {
|
||||
return getVersion().isSameOrAfter( 1, 4, 200 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFetchClause(FetchClauseType type) {
|
||||
return getVersion().isSameOrAfter( 1, 4, 198 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IdentityColumnSupport getIdentityColumnSupport() {
|
||||
return new H2IdentityColumnSupport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int registerResultSetOutParameter(CallableStatement statement, int position) throws SQLException {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryHintString(String query, String hints) {
|
||||
return IndexQueryHintHandler.INSTANCE.addQueryHints( query, hints );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendDatetimeFormat(SqlAppender appender, String format) {
|
||||
if ( getVersion().isSame( 1, 4, 200 ) ) {
|
||||
// See https://github.com/h2database/h2database/issues/2518
|
||||
appender.appendSql( OracleDialect.datetimeFormat( format, true, true ).result() );
|
||||
}
|
||||
else {
|
||||
appender.appendSql(
|
||||
new Replacer( format, "'", "''" )
|
||||
.replace("e", "u")
|
||||
.replace( "xxx", "XXX" )
|
||||
.replace( "xx", "XX" )
|
||||
.replace( "x", "X" )
|
||||
.result()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public String translateExtractField(TemporalUnit unit) {
|
||||
switch ( unit ) {
|
||||
case DAY_OF_MONTH: return "day";
|
||||
case WEEK: return "iso_week";
|
||||
default: return unit.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generatedAs(String generatedAs) {
|
||||
return " generated always as (" + generatedAs + ")";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.community.dialect;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.sqm.ComparisonOperator;
|
||||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
|
||||
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.Statement;
|
||||
import org.hibernate.sql.ast.tree.cte.CteStatement;
|
||||
import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.Literal;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
|
||||
import org.hibernate.sql.ast.tree.expression.Summarization;
|
||||
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
|
||||
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
|
||||
import org.hibernate.sql.ast.tree.select.QueryPart;
|
||||
import org.hibernate.sql.ast.tree.select.SelectClause;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperation;
|
||||
|
||||
/**
|
||||
* A legacy SQL AST translator for H2.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class H2LegacySqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstTranslator<T> {
|
||||
|
||||
private boolean renderAsArray;
|
||||
|
||||
public H2LegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
|
||||
super( sessionFactory, statement );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderExpressionAsClauseItem(Expression expression) {
|
||||
expression.accept( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) {
|
||||
final boolean isNegated = booleanExpressionPredicate.isNegated();
|
||||
if ( isNegated ) {
|
||||
appendSql( "not(" );
|
||||
}
|
||||
booleanExpressionPredicate.getExpression().accept( this );
|
||||
if ( isNegated ) {
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOffsetFetchClause(QueryPart queryPart) {
|
||||
if ( isRowsOnlyFetchClauseType( queryPart ) ) {
|
||||
if ( supportsOffsetFetchClause() ) {
|
||||
renderOffsetFetchClause( queryPart, true );
|
||||
}
|
||||
else {
|
||||
renderLimitOffsetClause( queryPart );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( supportsOffsetFetchClausePercentWithTies() ) {
|
||||
renderOffsetFetchClause( queryPart, true );
|
||||
}
|
||||
else {
|
||||
// FETCH PERCENT and WITH TIES were introduced along with window functions
|
||||
throw new IllegalArgumentException( "Can't emulate fetch clause type: " + queryPart.getFetchClauseType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderSearchClause(CteStatement cte) {
|
||||
// H2 does not support this, but it's just a hint anyway
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCycleClause(CteStatement cte) {
|
||||
// H2 does not support this, but it can be emulated
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderSelectTupleComparison(
|
||||
List<SqlSelection> lhsExpressions,
|
||||
SqlTuple tuple,
|
||||
ComparisonOperator operator) {
|
||||
emulateSelectTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInSubQueryPredicate(InSubQueryPredicate inSubQueryPredicate) {
|
||||
final SqlTuple lhsTuple;
|
||||
// As of 1.4.200 this is supported
|
||||
if ( getDialect().getVersion().isBefore( 1, 4, 200 )
|
||||
&& ( lhsTuple = SqlTupleContainer.getSqlTuple( inSubQueryPredicate.getTestExpression() ) ) != null
|
||||
&& lhsTuple.getExpressions().size() != 1 ) {
|
||||
inSubQueryPredicate.getTestExpression().accept( this );
|
||||
if ( inSubQueryPredicate.isNegated() ) {
|
||||
appendSql( " not" );
|
||||
}
|
||||
appendSql( " in" );
|
||||
final boolean renderAsArray = this.renderAsArray;
|
||||
this.renderAsArray = true;
|
||||
inSubQueryPredicate.getSubQuery().accept( this );
|
||||
this.renderAsArray = renderAsArray;
|
||||
}
|
||||
else {
|
||||
super.visitInSubQueryPredicate( inSubQueryPredicate );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitSqlSelections(SelectClause selectClause) {
|
||||
final boolean renderAsArray = this.renderAsArray;
|
||||
this.renderAsArray = false;
|
||||
if ( renderAsArray ) {
|
||||
append( OPEN_PARENTHESIS );
|
||||
}
|
||||
super.visitSqlSelections( selectClause );
|
||||
if ( renderAsArray ) {
|
||||
append( CLOSE_PARENTHESIS );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderPartitionItem(Expression expression) {
|
||||
if ( expression instanceof Literal ) {
|
||||
appendSql( "'0' || '0'" );
|
||||
}
|
||||
else if ( expression instanceof Summarization ) {
|
||||
// This could theoretically be emulated by rendering all grouping variations of the query and
|
||||
// connect them via union all but that's probably pretty inefficient and would have to happen
|
||||
// on the query spec level
|
||||
throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" );
|
||||
}
|
||||
else {
|
||||
expression.accept( this );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
appendSql( OPEN_PARENTHESIS );
|
||||
render( arithmeticExpression.getLeftHandOperand(), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
appendSql( arithmeticExpression.getOperator().getOperatorSqlTextString() );
|
||||
render( arithmeticExpression.getRightHandOperand(), SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER );
|
||||
appendSql( CLOSE_PARENTHESIS );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
|
||||
final TableReference tableRef = tableGroup.getPrimaryTableReference();
|
||||
// The H2 parser can't handle a sub-query as first element in a nested join
|
||||
// i.e. `join ( (select ...) alias join ... )`, so we have to introduce a dummy table reference
|
||||
if ( tableRef instanceof QueryPartTableReference || tableRef.getTableId().startsWith( "(select" ) ) {
|
||||
final boolean realTableGroup = tableGroup.isRealTableGroup()
|
||||
&& ( CollectionHelper.isNotEmpty( tableGroup.getTableReferenceJoins() )
|
||||
|| hasNestedTableGroupsToRender( tableGroup.getNestedTableGroupJoins() ) );
|
||||
if ( realTableGroup ) {
|
||||
appendSql( "dual cross join " );
|
||||
}
|
||||
}
|
||||
return super.renderPrimaryTableReference( tableGroup, lockMode );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntax() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntaxInInList() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsNullPrecedence() {
|
||||
// Support for nulls clause in listagg was added in 2.0
|
||||
return getClauseStack().getCurrent() != Clause.WITHIN_GROUP || getDialect().getVersion().isSameOrAfter( 2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFromDual() {
|
||||
return " from dual";
|
||||
}
|
||||
|
||||
private boolean supportsOffsetFetchClause() {
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 195 );
|
||||
}
|
||||
|
||||
private boolean supportsOffsetFetchClausePercentWithTies() {
|
||||
// Introduction of TIES clause https://github.com/h2database/h2database/commit/876e9fbe7baf11d01675bfe871aac2cf1b6104ce
|
||||
// Introduction of PERCENT support https://github.com/h2database/h2database/commit/f45913302e5f6ad149155a73763c0c59d8205849
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 198 );
|
||||
}
|
||||
}
|
|
@ -96,8 +96,7 @@ import static org.hibernate.type.SqlTypes.TIMESTAMP_UTC;
|
|||
*/
|
||||
public class H2Dialect extends Dialect {
|
||||
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( H2Dialect.class );
|
||||
|
||||
private final LimitHandler limitHandler;
|
||||
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 1, 4, 197 );
|
||||
|
||||
private final boolean ansiSequence;
|
||||
private final boolean cascadeConstraints;
|
||||
|
@ -112,21 +111,12 @@ public class H2Dialect extends Dialect {
|
|||
}
|
||||
|
||||
public H2Dialect() {
|
||||
this( SimpleDatabaseVersion.ZERO_VERSION );
|
||||
this( MINIMUM_VERSION );
|
||||
}
|
||||
|
||||
public H2Dialect(DatabaseVersion version) {
|
||||
super(version);
|
||||
|
||||
// https://github.com/h2database/h2database/commit/b2cdf84e0b84eb8a482fa7dccdccc1ab95241440
|
||||
limitHandler = version.isSameOrAfter( 1, 4, 195 )
|
||||
? OffsetFetchLimitHandler.INSTANCE
|
||||
: LimitOffsetLimitHandler.INSTANCE;
|
||||
|
||||
if ( version.isBefore( 1, 2, 139 ) ) {
|
||||
LOG.unsupportedMultiTableBulkHqlJpaql( version.getMajor(), version.getMinor(), version.getMicro() );
|
||||
}
|
||||
|
||||
// supportsTuplesInSubqueries = version.isSameOrAfter( 1, 4, 198 );
|
||||
|
||||
// Prior to 1.4.200 there was no support for 'current value for sequence_name'
|
||||
|
@ -138,17 +128,11 @@ public class H2Dialect extends Dialect {
|
|||
// 1.4.200 introduced changes in current_time and current_timestamp
|
||||
useLocalTime = version.isSameOrAfter( 1, 4, 200 );
|
||||
|
||||
if ( version.isSameOrAfter( 1, 4, 32 ) ) {
|
||||
this.sequenceInformationExtractor = version.isSameOrAfter( 1, 4, 201 )
|
||||
? SequenceInformationExtractorLegacyImpl.INSTANCE
|
||||
: SequenceInformationExtractorH2DatabaseImpl.INSTANCE;
|
||||
this.querySequenceString = "select * from INFORMATION_SCHEMA.SEQUENCES";
|
||||
}
|
||||
else {
|
||||
this.sequenceInformationExtractor = SequenceInformationExtractorNoOpImpl.INSTANCE;
|
||||
this.querySequenceString = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static DatabaseVersion parseVersion(DialectResolutionInfo info) {
|
||||
return DatabaseVersion.make( info.getMajor(), info.getMinor(), parseBuildId( info ) );
|
||||
|
@ -217,14 +201,12 @@ public class H2Dialect extends Dialect {
|
|||
if ( getVersion().isBefore( 2 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( ARRAY, "array", this ) );
|
||||
}
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( UUID, "uuid", this ) );
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( GEOMETRY, "geometry", this ) );
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 198 ) ) {
|
||||
ddlTypeRegistry.addDescriptor( new DdlTypeImpl( INTERVAL_SECOND, "interval second($p,$s)", this ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
|
||||
|
@ -234,9 +216,7 @@ public class H2Dialect extends Dialect {
|
|||
.getJdbcTypeRegistry();
|
||||
|
||||
jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantJdbcType.INSTANCE );
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
|
||||
}
|
||||
if ( getVersion().isSameOrAfter( 1, 4, 198 ) ) {
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( H2DurationIntervalSecondJdbcType.INSTANCE );
|
||||
}
|
||||
|
@ -447,7 +427,7 @@ public class H2Dialect extends Dialect {
|
|||
|
||||
@Override
|
||||
public LimitHandler getLimitHandler() {
|
||||
return limitHandler;
|
||||
return OffsetFetchLimitHandler.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -182,19 +182,19 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
|
|||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntax() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntaxInInList() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
|
||||
// Just a guess
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 197 );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -209,7 +209,7 @@ public class H2SqlAstTranslator<T extends JdbcOperation> extends AbstractSqlAstT
|
|||
}
|
||||
|
||||
private boolean supportsOffsetFetchClause() {
|
||||
return getDialect().getVersion().isSameOrAfter( 1, 4, 195 );
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean supportsOffsetFetchClausePercentWithTies() {
|
||||
|
|
Loading…
Reference in New Issue