org.hibernate.community.dialect.TimesTenDialect Maven / Gradle / Ivy
Show all versions of hibernate-community-dialects Show documentation
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.community.dialect;
import java.sql.Types;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.boot.model.FunctionContributions;
import org.hibernate.community.dialect.pagination.TimesTenLimitHandler;
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl;
import org.hibernate.community.dialect.sequence.TimesTenSequenceSupport;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
import org.hibernate.dialect.lock.PessimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
import org.hibernate.dialect.lock.SelectLockingStrategy;
import org.hibernate.dialect.lock.UpdateLockingStrategy;
import org.hibernate.dialect.pagination.LimitHandler;
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.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.common.TemporalUnit;
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableMutationStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
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.spi.SequenceInformationExtractor;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import jakarta.persistence.TemporalType;
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
/**
* A SQL dialect for TimesTen 5.1.
*
* Known limitations:
* joined-subclass support because of no CASE support in TimesTen
* No support for subqueries that includes aggregation
* - size() in HQL not supported
* - user queries that does subqueries with aggregation
* No CLOB/BLOB support
* No cascade delete support.
* No Calendar support
* No support for updating primary keys.
*
* @author Sherry Listgarten, Max Andersen, Chris Jenkins
*/
public class TimesTenDialect extends Dialect {
public TimesTenDialect() {
super( ZERO_VERSION );
}
public TimesTenDialect(DialectResolutionInfo info) {
super( info );
}
@Override
protected String columnType(int sqlTypeCode) {
switch ( sqlTypeCode ) {
//Note: these are the correct type mappings
// for the default Oracle type mode
// TypeMode=0
case SqlTypes.BOOLEAN:
case SqlTypes.TINYINT:
return "tt_tinyint";
case SqlTypes.SMALLINT:
return "tt_smallint";
case SqlTypes.INTEGER:
return "tt_integer";
case SqlTypes.BIGINT:
return "tt_bigint";
//note that 'binary_float'/'binary_double' might
//be better mappings for Java Float/Double
//'numeric'/'decimal' are synonyms for 'number'
case SqlTypes.NUMERIC:
case SqlTypes.DECIMAL:
return "number($p,$s)";
case SqlTypes.DATE:
return "tt_date";
case SqlTypes.TIME:
return "tt_time";
//`timestamp` has more precision than `tt_timestamp`
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
return "timestamp($p)";
default:
return super.columnType( sqlTypeCode );
}
}
@Override
public int getDefaultStatementBatchSize() {
return 15;
}
@Override
public JdbcType resolveSqlTypeDescriptor(
String columnTypeName,
int jdbcTypeCode,
int precision,
int scale,
JdbcTypeRegistry jdbcTypeRegistry) {
if ( jdbcTypeCode == Types.BIT ) {
return jdbcTypeRegistry.getDescriptor( Types.BOOLEAN );
}
return super.resolveSqlTypeDescriptor(
columnTypeName,
jdbcTypeCode,
precision,
scale,
jdbcTypeRegistry
);
}
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return Types.BIT;
}
@Override
public int getDefaultDecimalPrecision() {
//the maximum
return 40;
}
@Override
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
functionFactory.trim2();
functionFactory.soundex();
functionFactory.trunc();
functionFactory.toCharNumberDateTimestamp();
functionFactory.ceiling_ceil();
functionFactory.instr();
functionFactory.substr();
functionFactory.substring_substr();
functionFactory.leftRight_substr();
functionFactory.char_chr();
functionFactory.rownumRowid();
functionFactory.sysdate();
functionFactory.addMonths();
functionFactory.monthsBetween();
functionContributions.getFunctionRegistry().registerBinaryTernaryPattern(
"locate",
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
"instr(?2,?1)",
"instr(?2,?1,?3)",
STRING, STRING, INTEGER,
functionContributions.getTypeConfiguration()
).setArgumentListSignature("(pattern, string[, start])");
}
@Override
public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
return new StandardSqlAstTranslatorFactory() {
@Override
protected SqlAstTranslator buildTranslator(
SessionFactoryImplementor sessionFactory, Statement statement) {
return new TimesTenSqlAstTranslator<>( sessionFactory, statement );
}
};
}
@Override
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampadd(sql_tsi_frac_second,?2,?3)";
default:
return "timestampadd(sql_tsi_?1,?2,?3)";
}
}
@Override
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
switch (unit) {
case NANOSECOND:
case NATIVE:
return "timestampdiff(sql_tsi_frac_second,?2,?3)";
default:
return "timestampdiff(sql_tsi_?1,?2,?3)";
}
}
@Override
public boolean qualifyIndexName() {
return false;
}
@Override
public String getAddColumnString() {
return "add";
}
@Override
public SequenceSupport getSequenceSupport() {
return TimesTenSequenceSupport.INSTANCE;
}
@Override
public String getQuerySequencesString() {
return "select name from sys.sequences";
}
@Override
public SequenceInformationExtractor getSequenceInformationExtractor() {
return SequenceInformationExtractorTimesTenDatabaseImpl.INSTANCE;
}
@Override
public boolean supportsNoWait() {
return true;
}
@Override
public RowLockStrategy getWriteRowLockStrategy() {
return RowLockStrategy.COLUMN;
}
@Override
public String getForUpdateString(String aliases) {
return " for update of " + aliases;
}
@Override
public String getForUpdateNowaitString() {
return " for update nowait";
}
@Override
public String getWriteLockString(int timeout) {
return withTimeout( getForUpdateString(), timeout );
}
@Override
public String getWriteLockString(String aliases, int timeout) {
return withTimeout( getForUpdateString(aliases), timeout );
}
@Override
public String getReadLockString(int timeout) {
return getWriteLockString( timeout );
}
@Override
public String getReadLockString(String aliases, int timeout) {
return getWriteLockString( aliases, timeout );
}
private String withTimeout(String lockString, int timeout) {
switch (timeout) {
case LockOptions.NO_WAIT:
return supportsNoWait() ? lockString + " nowait" : lockString;
case LockOptions.SKIP_LOCKED:
case LockOptions.WAIT_FOREVER:
return lockString;
default:
return supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString;
}
}
@Override
public boolean supportsColumnCheck() {
return false;
}
@Override
public boolean supportsTableCheck() {
return false;
}
@Override
public boolean supportsOffsetInSubquery() {
return true;
}
@Override
public LimitHandler getLimitHandler() {
return TimesTenLimitHandler.INSTANCE;
}
@Override
public boolean supportsCurrentTimestampSelection() {
return true;
}
@Override
public String getCurrentTimestampSelectString() {
return "select sysdate from sys.dual";
}
@Override
public boolean isCurrentTimestampSelectStringCallable() {
return false;
}
@Override
public SqmMultiTableMutationStrategy getFallbackSqmMutationStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new GlobalTemporaryTableMutationStrategy(
TemporaryTable.createIdTable(
rootEntityDescriptor,
name -> TemporaryTable.ID_TABLE_PREFIX + name,
this,
runtimeModelCreationContext
),
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public SqmMultiTableInsertStrategy getFallbackSqmInsertStrategy(
EntityMappingType rootEntityDescriptor,
RuntimeModelCreationContext runtimeModelCreationContext) {
return new GlobalTemporaryTableInsertStrategy(
TemporaryTable.createEntityTable(
rootEntityDescriptor,
name -> TemporaryTable.ENTITY_TABLE_PREFIX + name,
this,
runtimeModelCreationContext
),
runtimeModelCreationContext.getSessionFactory()
);
}
@Override
public TemporaryTableKind getSupportedTemporaryTableKind() {
return TemporaryTableKind.GLOBAL;
}
@Override
public String getTemporaryTableCreateOptions() {
return "on commit delete rows";
}
@Override
public LockingStrategy getLockingStrategy(EntityPersister lockable, LockMode lockMode) {
// TimesTen has no known variation of a "SELECT ... FOR UPDATE" syntax...
switch ( lockMode ) {
case OPTIMISTIC:
return new OptimisticLockingStrategy( lockable, lockMode );
case OPTIMISTIC_FORCE_INCREMENT:
return new OptimisticForceIncrementLockingStrategy( lockable, lockMode );
case PESSIMISTIC_READ:
return new PessimisticReadUpdateLockingStrategy( lockable, lockMode );
case PESSIMISTIC_WRITE:
return new PessimisticWriteUpdateLockingStrategy( lockable, lockMode );
case PESSIMISTIC_FORCE_INCREMENT:
return new PessimisticForceIncrementLockingStrategy( lockable, lockMode );
}
if ( lockMode.greaterThan( LockMode.READ ) ) {
return new UpdateLockingStrategy( lockable, lockMode );
}
else {
return new SelectLockingStrategy( lockable, lockMode );
}
}
@Override
public int getMaxAliasLength() {
// Max identifier length is 30, but Hibernate needs to add "uniqueing info" so we account for that
return 20;
}
@Override
public int getMaxIdentifierLength() {
return 30;
}
@Override
public boolean supportsCircularCascadeDeleteConstraints() {
return false;
}
@Override
public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfiguration) {
switch (sqlType) {
case Types.VARCHAR:
case Types.CHAR:
return "to_char(null)";
case Types.DATE:
case Types.TIME:
case Types.TIMESTAMP:
case Types.TIMESTAMP_WITH_TIMEZONE:
return "to_date(null)";
default:
return "to_number(null)";
}
}
}