Skip to content

Oracle TimesTen Dialect for Hibernate 6.6 Updates #10492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: 6.6
Choose a base branch
from
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 @@ -52,21 +52,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,29 +98,56 @@ protected String columnType(int sqlTypeCode) {
// for the default Oracle type mode
// TypeMode=0
case SqlTypes.BOOLEAN:
case SqlTypes.BIT:
case SqlTypes.TINYINT:
return "tt_tinyint";
return "TT_TINYINT";
case SqlTypes.SMALLINT:
return "tt_smallint";
return "TT_SMALLINT";
case SqlTypes.INTEGER:
return "tt_integer";
return "TT_INTEGER";
case SqlTypes.BIGINT:
return "tt_bigint";
return "TT_BIGINT";
//note that 'binary_float'/'binary_double' might
//be better mappings for Java Float/Double

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

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

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

case SqlTypes.DATE:
return "tt_date";
return "TT_DATE";
case SqlTypes.TIME:
return "tt_time";
return "TT_TIME";
case SqlTypes.TIMESTAMP:
return "TIMESTAMP";
//`timestamp` has more precision than `tt_timestamp`
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
return "timestamp($p)";

case SqlTypes.BLOB:
return "BLOB";
case SqlTypes.CLOB:
return "CLOB";
case SqlTypes.NCLOB:
return "NCLOB";

default:
return super.columnType( sqlTypeCode );
}
Expand Down Expand Up @@ -157,21 +192,133 @@ public int getDefaultDecimalPrecision() {
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);

CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
functionFactory.trim2();
functionFactory.soundex();
functionFactory.trunc();
functionFactory.toCharNumberDateTimestamp();
functionFactory.ceiling_ceil();
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<Date> dateType = basicTypeRegistry.resolve( StandardBasicTypes.DATE );
final BasicType<Date> timeType = basicTypeRegistry.resolve( StandardBasicTypes.TIME );
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
functionContributions.getFunctionRegistry().register(
"rtrim", new StandardSQLFunction("rtrim", StandardBasicTypes.STRING)
);
functionContributions.getFunctionRegistry().register(
"ltrim", new StandardSQLFunction("ltrim", StandardBasicTypes.STRING)
);
functionContributions.getFunctionRegistry().register(
"length", new StandardSQLFunction("length", StandardBasicTypes.LONG)
);
functionFactory.concat_pipeOperator();
functionContributions.getFunctionRegistry().register(
"to_char", new StandardSQLFunction("to_char", StandardBasicTypes.STRING)
);
functionFactory.char_chr();
functionFactory.instr();
functionFactory.substr();
functionFactory.substring_substr();
functionFactory.leftRight_substr();
functionFactory.char_chr();
functionFactory.rownumRowid();
functionFactory.sysdate();
functionFactory.addMonths();
functionFactory.monthsBetween();
functionContributions.getFunctionRegistry().register(
"str", new StandardSQLFunction("to_char", StandardBasicTypes.STRING)
);
functionContributions.getFunctionRegistry().register(
"substring", new StandardSQLFunction( "substr", StandardBasicTypes.STRING )
);
functionFactory.soundex();

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

functionContributions.getFunctionRegistry().register(
"current_date", new CurrentFunction("sysdate", "sysdate", dateType)
);
functionContributions.getFunctionRegistry().register(
"current_time", new CurrentFunction("sysdate", "sysdate", timeType)
);
functionContributions.getFunctionRegistry().register(
"current_timestamp", new CurrentFunction("sysdate", "sysdate", timestampType)
);
functionContributions.getFunctionRegistry().register(
"to_timestamp", new StandardSQLFunction("to_timestamp", StandardBasicTypes.TIMESTAMP)
);

// Multi-param date dialect functions
functionContributions.getFunctionRegistry().register(
"add_months", new StandardSQLFunction("add_months", StandardBasicTypes.DATE)
);
functionContributions.getFunctionRegistry().register(
"months_between", new StandardSQLFunction("months_between", StandardBasicTypes.FLOAT)
);

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

// Bitwise functions
functionContributions.getFunctionRegistry().register(
"bitnot", new StandardSQLFunction("bitnot", StandardBasicTypes.INTEGER)
);

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().register(
"nvl", new StandardSQLFunction("nvl")
);
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",
Expand Down Expand Up @@ -251,9 +398,10 @@ public RowLockStrategy getWriteRowLockStrategy() {
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 +574,51 @@ public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfi
}
}

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

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

@Override
public String currentTime() {
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";
}

}
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,56 @@ protected boolean supportsRowValueConstructorSyntaxInInList() {
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
return false;
}

@Override
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 && fetchClauseExpression == null ) {
throw new UnsupportedOperationException(
"Only passing setFirstResult(m) and not setMaxResults(n) to 'ROWS m TO n' clause not supported."
);
}
else if ( offsetClauseExpression != null && fetchClauseExpression != null ) {
// We have offset and maxRows/limit. We use 'SELECT ROWS offset TO limit' 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 {
// TimesTen includes both m and n rows of 'ROWS m to n';
// We need to substract 1 row to fit maxRows
renderFetchPlusOffsetExpressionAsLiteral( fetchClauseExpression, offsetClauseExpression, -1 );
}
finally {
clauseStack.pop();
}
}

appendSql( WHITESPACE );
}
}
Loading
Loading