Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl;
import org.hibernate.community.dialect.sequence.TimesTenSequenceSupport;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.BooleanDecoder;
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.function.OracleTruncFunction;
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
import org.hibernate.dialect.lock.LockingStrategy;
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
Expand All @@ -34,6 +37,7 @@
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.Lockable;
import org.hibernate.query.sqm.CastType;
import org.hibernate.query.sqm.IntervalType;
import org.hibernate.query.sqm.TemporalUnit;
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
Expand All @@ -42,6 +46,7 @@
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.SqlAstNodeRenderingMode;
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.Statement;
import org.hibernate.sql.exec.spi.JdbcOperation;
Expand All @@ -52,21 +57,29 @@
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration;

import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.CurrentFunction;
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
import jakarta.persistence.GenerationType;
import java.util.Date;

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.
* A SQL dialect for Oracle TimesTen
* <p>
* 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.
Expand All @@ -90,6 +103,7 @@
// for the default Oracle type mode
// TypeMode=0
case SqlTypes.BOOLEAN:
case SqlTypes.BIT:
case SqlTypes.TINYINT:
return "tt_tinyint";
case SqlTypes.SMALLINT:
Expand All @@ -101,15 +115,26 @@
//note that 'binary_float'/'binary_double' might
//be better mappings for Java Float/Double

case SqlTypes.VARCHAR:
case SqlTypes.LONGVARCHAR:
return "varchar2($l)";

case SqlTypes.LONGVARBINARY:
return "varbinary($l)";

//'numeric'/'decimal' are synonyms for 'number'
case SqlTypes.NUMERIC:
case SqlTypes.DECIMAL:
return "number($p,$s)";
case SqlTypes.FLOAT:
return "binary_float";
case SqlTypes.DOUBLE:
return "binary_double";

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)";

Expand Down Expand Up @@ -157,22 +182,97 @@
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);

CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
final TypeConfiguration typeConfiguration = functionContributions.getTypeConfiguration();
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
final BasicType<Date> timestampType = basicTypeRegistry.resolve( StandardBasicTypes.TIMESTAMP );
final BasicType<String> stringType = basicTypeRegistry.resolve( StandardBasicTypes.STRING );
final BasicType<Long> longType = basicTypeRegistry.resolve( StandardBasicTypes.LONG );
final BasicType<Integer>intType = basicTypeRegistry.resolve( StandardBasicTypes.INTEGER );

// String Functions
functionFactory.trim2();
functionFactory.soundex();
functionFactory.trunc();
functionFactory.characterLength_length( SqlAstNodeRenderingMode.DEFAULT );
functionFactory.concat_pipeOperator();
functionFactory.toCharNumberDateTimestamp();
functionFactory.ceiling_ceil();
functionFactory.char_chr();
functionFactory.instr();
functionFactory.substr();
functionFactory.substring_substr();
functionFactory.leftRight_substr();
functionFactory.char_chr();
functionFactory.rownumRowid();
functionFactory.sysdate();
functionFactory.soundex();

// Date/Time Functions
functionContributions.getFunctionRegistry().register(
"sysdate", new CurrentFunction("sysdate", "sysdate", timestampType)
);
functionContributions.getFunctionRegistry().register(
"getdate", new CurrentFunction("getdate", "getdate()", timestampType )
);

// Multi-param date dialect functions
functionFactory.addMonths();
functionFactory.monthsBetween();

// Math functions
functionFactory.ceiling_ceil();
functionFactory.radians_acos();
functionFactory.degrees_acos();
functionFactory.sinh();
functionFactory.tanh();
functionContributions.getFunctionRegistry().register(
"trunc",
new OracleTruncFunction( functionContributions.getTypeConfiguration() )
);
functionContributions.getFunctionRegistry().registerAlternateKey( "truncate", "trunc" );
functionFactory.round();

// Bitwise functions
functionContributions.getFunctionRegistry()
.patternDescriptorBuilder( "bitor", "(?1+?2-bitand(?1,?2))")
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();

functionContributions.getFunctionRegistry()
.patternDescriptorBuilder( "bitxor", "(?1+?2-2*bitand(?1,?2))")
.setExactArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.register();

// Misc. functions
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "nvl" )
.setMinArgumentCount( 2 )
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useFirstNonNull() )
.register();

functionContributions.getFunctionRegistry().register(
"user", new CurrentFunction("user", "user", stringType)
);
functionContributions.getFunctionRegistry().register(
"rowid", new CurrentFunction("rowid", "rowid", stringType)
);
functionContributions.getFunctionRegistry().register(
"uid", new CurrentFunction("uid", "uid", intType)
);
functionContributions.getFunctionRegistry().register(
"rownum", new CurrentFunction("rownum", "rownum", longType)
);
functionContributions.getFunctionRegistry().register(
"vsize", new StandardSQLFunction("vsize", StandardBasicTypes.DOUBLE)
);
functionContributions.getFunctionRegistry().register(
"SESSION_USER", new CurrentFunction("SESSION_USER","SESSION_USER", stringType)
);
functionContributions.getFunctionRegistry().register(
"SYSTEM_USER", new CurrentFunction("SYSTEM_USER", "SYSTEM_USER", stringType)
);
functionContributions.getFunctionRegistry().register(
"CURRENT_USER", new CurrentFunction("CURRENT_USER","CURRENT_USER", stringType)
);

functionContributions.getFunctionRegistry().registerBinaryTernaryPattern(
"locate",
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
Expand Down Expand Up @@ -251,9 +351,10 @@
return RowLockStrategy.COLUMN;
}


@Override
public String getForUpdateString(String aliases) {
return " for update of " + aliases;
public String getForUpdateString() {
return " for update";
}

@Override
Expand Down Expand Up @@ -426,4 +527,104 @@
}
}

@Override
public String getNativeIdentifierGeneratorStrategy() {
return "sequence";
}

@Override
public String currentDate() {
return "sysdate";
}

@Override
public String currentTime() {
return "sysdate";
}

@Override
public String currentTimestamp() {
return "sysdate";
}

@Override
public int getMaxVarcharLength() {
// 1 to 4,194,304 bytes according to TimesTen Doc
return 4194304;
}

@Override
public int getMaxVarbinaryLength() {
// 1 to 4,194,304 bytes according to TimesTen Doc
return 4194304;
}

@Override
public boolean isEmptyStringTreatedAsNull() {
return true;
}

@Override
public boolean supportsTupleDistinctCounts() {
return false;
}

@Override
public String getDual() {
return "dual";
}

@Override
public String getFromDualForSelectOnly() {
return " from dual";
}

@Override
public String castPattern(CastType from, CastType to) {
String result;
switch ( to ) {

Check warning

Code scanning / CodeQL

Missing enum case in switch Warning

Switch statement does not have a case for
BOOLEAN
,
DOUBLE
,
FIXED
, or 8 more.
case INTEGER:
case LONG:
result = BooleanDecoder.toInteger( from );
if ( result != null ) {
return result;
}
break;
case STRING:
switch ( from ) {

Check warning

Code scanning / CodeQL

Missing enum case in switch Warning

Switch statement does not have a case for
CLOB
,
DOUBLE
,
FIXED
, or 8 more.
case BOOLEAN:
case INTEGER_BOOLEAN:
case TF_BOOLEAN:
case YN_BOOLEAN:
return BooleanDecoder.toString( from );
case DATE:
return "to_char(?1,'YYYY-MM-DD')";
case TIME:
return "to_char(?1,'HH24:MI:SS')";
case TIMESTAMP:
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
}
break;
case CLOB:
return "to_clob(?1)";
case DATE:
if ( from == CastType.STRING ) {
return "to_date(?1,'YYYY-MM-DD')";
}
break;
case TIME:
if ( from == CastType.STRING ) {
return "to_date(?1,'HH24:MI:SS')";
}
break;
case TIMESTAMP:
if ( from == CastType.STRING ) {
return "to_timestamp(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
}
break;
}
return super.castPattern(from, to);
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.exec.spi.JdbcOperation;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.sql.ast.Clause;

/**
* A SQL AST translator for TimesTen.
Expand Down Expand Up @@ -143,4 +145,66 @@ protected boolean supportsRowValueConstructorSyntaxInInList() {
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}

protected void renderRowsToClause(QuerySpec querySpec) {
if ( querySpec.isRoot() && hasLimit() ) {
prepareLimitOffsetParameters();
renderRowsToClause( getOffsetParameter(), getLimitParameter() );
}
else {
assertRowsOnlyFetchClauseType( querySpec );
renderRowsToClause( querySpec.getOffsetClauseExpression(), querySpec.getFetchClauseExpression() );
}
}

protected void renderRowsToClause(Expression offsetClauseExpression, Expression fetchClauseExpression) {
// offsetClauseExpression -> firstRow
// fetchClauseExpression -> maxRows
final Stack<Clause> clauseStack = getClauseStack();

if ( offsetClauseExpression == null && fetchClauseExpression != null ) {
// We only have a maxRows/limit. We use 'SELECT FIRST n' syntax
appendSql("first ");
clauseStack.push( Clause.FETCH );
try {
renderFetchExpression( fetchClauseExpression );
}
finally {
clauseStack.pop();
}
}
else if ( offsetClauseExpression != null ) {
// We have an offset. We use 'SELECT ROWS m TO n' syntax
appendSql( "rows " );

// Render offset parameter
clauseStack.push( Clause.OFFSET );
try {
renderOffsetExpression( offsetClauseExpression );
}
finally {
clauseStack.pop();
}

appendSql( " to " );

// Render maxRows/limit parameter
clauseStack.push( Clause.FETCH );
try {
if ( fetchClauseExpression != null ) {
// We need to substract 1 row to fit maxRows
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, -1 );
}
else{
// We dont have a maxRows param, we will just use a MAX_VALUE
appendSql( Integer.MAX_VALUE );
}
}
finally {
clauseStack.pop();
}
}

appendSql( WHITESPACE );
}
}
Loading
Loading