Skip to content

Commit 5dc72a3

Browse files
carlblanbeikov
authored andcommitted
Various fix for TimesTen Dialect, SqlAstTranslator, LimitHandler and SequenceSupport
1 parent 49c9369 commit 5dc72a3

File tree

5 files changed

+321
-54
lines changed

5 files changed

+321
-54
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java

Lines changed: 209 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl;
1616
import org.hibernate.community.dialect.sequence.TimesTenSequenceSupport;
1717
import org.hibernate.dialect.Dialect;
18+
import org.hibernate.dialect.BooleanDecoder;
1819
import org.hibernate.dialect.function.CommonFunctionFactory;
20+
import org.hibernate.dialect.function.OracleTruncFunction;
21+
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
1922
import org.hibernate.dialect.lock.LockingStrategy;
2023
import org.hibernate.dialect.lock.PessimisticReadUpdateLockingStrategy;
2124
import org.hibernate.dialect.lock.PessimisticWriteUpdateLockingStrategy;
@@ -30,6 +33,7 @@
3033
import org.hibernate.metamodel.mapping.EntityMappingType;
3134
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
3235
import org.hibernate.persister.entity.EntityPersister;
36+
import org.hibernate.query.sqm.CastType;
3337
import org.hibernate.query.sqm.IntervalType;
3438
import org.hibernate.query.common.TemporalUnit;
3539
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
@@ -38,6 +42,7 @@
3842
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
3943
import org.hibernate.sql.ast.SqlAstTranslator;
4044
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
45+
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
4146
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
4247
import org.hibernate.sql.ast.tree.Statement;
4348
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -48,6 +53,13 @@
4853
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
4954
import org.hibernate.type.spi.TypeConfiguration;
5055

56+
import org.hibernate.type.BasicType;
57+
import org.hibernate.type.BasicTypeRegistry;
58+
import org.hibernate.dialect.function.StandardSQLFunction;
59+
import org.hibernate.dialect.function.CurrentFunction;
60+
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
61+
import java.util.Date;
62+
5163
import jakarta.persistence.TemporalType;
5264

5365
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
@@ -56,14 +68,13 @@
5668
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
5769

5870
/**
59-
* A SQL dialect for TimesTen 5.1.
71+
* A SQL dialect for Oracle TimesTen
6072
* <p>
6173
* Known limitations:
6274
* joined-subclass support because of no CASE support in TimesTen
6375
* No support for subqueries that includes aggregation
6476
* - size() in HQL not supported
6577
* - user queries that does subqueries with aggregation
66-
* No CLOB/BLOB support
6778
* No cascade delete support.
6879
* No Calendar support
6980
* No support for updating primary keys.
@@ -87,6 +98,7 @@ protected String columnType(int sqlTypeCode) {
8798
// for the default Oracle type mode
8899
// TypeMode=0
89100
case SqlTypes.BOOLEAN:
101+
case SqlTypes.BIT:
90102
case SqlTypes.TINYINT:
91103
return "tt_tinyint";
92104
case SqlTypes.SMALLINT:
@@ -98,15 +110,26 @@ protected String columnType(int sqlTypeCode) {
98110
//note that 'binary_float'/'binary_double' might
99111
//be better mappings for Java Float/Double
100112

113+
case SqlTypes.VARCHAR:
114+
case SqlTypes.LONGVARCHAR:
115+
return "varchar2($l)";
116+
117+
case SqlTypes.LONGVARBINARY:
118+
return "varbinary($l)";
119+
101120
//'numeric'/'decimal' are synonyms for 'number'
102121
case SqlTypes.NUMERIC:
103122
case SqlTypes.DECIMAL:
104123
return "number($p,$s)";
124+
case SqlTypes.FLOAT:
125+
return "binary_float";
126+
case SqlTypes.DOUBLE:
127+
return "binary_double";
128+
105129
case SqlTypes.DATE:
106130
return "tt_date";
107131
case SqlTypes.TIME:
108132
return "tt_time";
109-
//`timestamp` has more precision than `tt_timestamp`
110133
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
111134
return "timestamp($p)";
112135

@@ -154,22 +177,97 @@ public int getDefaultDecimalPrecision() {
154177
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
155178
super.initializeFunctionRegistry(functionContributions);
156179

157-
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
180+
final TypeConfiguration typeConfiguration = functionContributions.getTypeConfiguration();
181+
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
182+
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
183+
final BasicType<Date> timestampType = basicTypeRegistry.resolve( StandardBasicTypes.TIMESTAMP );
184+
final BasicType<String> stringType = basicTypeRegistry.resolve( StandardBasicTypes.STRING );
185+
final BasicType<Long> longType = basicTypeRegistry.resolve( StandardBasicTypes.LONG );
186+
final BasicType<Integer>intType = basicTypeRegistry.resolve( StandardBasicTypes.INTEGER );
187+
188+
// String Functions
158189
functionFactory.trim2();
159-
functionFactory.soundex();
160-
functionFactory.trunc();
190+
functionFactory.characterLength_length( SqlAstNodeRenderingMode.DEFAULT );
191+
functionFactory.concat_pipeOperator();
161192
functionFactory.toCharNumberDateTimestamp();
162-
functionFactory.ceiling_ceil();
193+
functionFactory.char_chr();
163194
functionFactory.instr();
164195
functionFactory.substr();
165196
functionFactory.substring_substr();
166-
functionFactory.leftRight_substr();
167-
functionFactory.char_chr();
168-
functionFactory.rownumRowid();
169-
functionFactory.sysdate();
197+
functionFactory.soundex();
198+
199+
// Date/Time Functions
200+
functionContributions.getFunctionRegistry().register(
201+
"sysdate", new CurrentFunction("sysdate", "sysdate", timestampType)
202+
);
203+
functionContributions.getFunctionRegistry().register(
204+
"getdate", new CurrentFunction("getdate", "getdate()", timestampType )
205+
);
206+
207+
// Multi-param date dialect functions
170208
functionFactory.addMonths();
171209
functionFactory.monthsBetween();
172210

211+
// Math functions
212+
functionFactory.ceiling_ceil();
213+
functionFactory.radians_acos();
214+
functionFactory.degrees_acos();
215+
functionFactory.sinh();
216+
functionFactory.tanh();
217+
functionContributions.getFunctionRegistry().register(
218+
"trunc",
219+
new OracleTruncFunction( functionContributions.getTypeConfiguration() )
220+
);
221+
functionContributions.getFunctionRegistry().registerAlternateKey( "truncate", "trunc" );
222+
functionFactory.round();
223+
224+
// Bitwise functions
225+
functionContributions.getFunctionRegistry()
226+
.patternDescriptorBuilder( "bitor", "(?1+?2-bitand(?1,?2))")
227+
.setExactArgumentCount( 2 )
228+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
229+
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
230+
.register();
231+
232+
functionContributions.getFunctionRegistry()
233+
.patternDescriptorBuilder( "bitxor", "(?1+?2-2*bitand(?1,?2))")
234+
.setExactArgumentCount( 2 )
235+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
236+
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
237+
.register();
238+
239+
// Misc. functions
240+
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "nvl" )
241+
.setMinArgumentCount( 2 )
242+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
243+
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useFirstNonNull() )
244+
.register();
245+
246+
functionContributions.getFunctionRegistry().register(
247+
"user", new CurrentFunction("user", "user", stringType)
248+
);
249+
functionContributions.getFunctionRegistry().register(
250+
"rowid", new CurrentFunction("rowid", "rowid", stringType)
251+
);
252+
functionContributions.getFunctionRegistry().register(
253+
"uid", new CurrentFunction("uid", "uid", intType)
254+
);
255+
functionContributions.getFunctionRegistry().register(
256+
"rownum", new CurrentFunction("rownum", "rownum", longType)
257+
);
258+
functionContributions.getFunctionRegistry().register(
259+
"vsize", new StandardSQLFunction("vsize", StandardBasicTypes.DOUBLE)
260+
);
261+
functionContributions.getFunctionRegistry().register(
262+
"SESSION_USER", new CurrentFunction("SESSION_USER","SESSION_USER", stringType)
263+
);
264+
functionContributions.getFunctionRegistry().register(
265+
"SYSTEM_USER", new CurrentFunction("SYSTEM_USER", "SYSTEM_USER", stringType)
266+
);
267+
functionContributions.getFunctionRegistry().register(
268+
"CURRENT_USER", new CurrentFunction("CURRENT_USER","CURRENT_USER", stringType)
269+
);
270+
173271
functionContributions.getFunctionRegistry().registerBinaryTernaryPattern(
174272
"locate",
175273
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
@@ -426,6 +524,106 @@ public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfi
426524
}
427525
}
428526

527+
@Override
528+
public String getNativeIdentifierGeneratorStrategy() {
529+
return "sequence";
530+
}
531+
532+
@Override
533+
public String currentDate() {
534+
return "sysdate";
535+
}
536+
537+
@Override
538+
public String currentTime() {
539+
return "sysdate";
540+
}
541+
542+
@Override
543+
public String currentTimestamp() {
544+
return "sysdate";
545+
}
546+
547+
@Override
548+
public int getMaxVarcharLength() {
549+
// 1 to 4,194,304 bytes according to TimesTen Doc
550+
return 4194304;
551+
}
552+
553+
@Override
554+
public int getMaxVarbinaryLength() {
555+
// 1 to 4,194,304 bytes according to TimesTen Doc
556+
return 4194304;
557+
}
558+
559+
@Override
560+
public boolean isEmptyStringTreatedAsNull() {
561+
return true;
562+
}
563+
564+
@Override
565+
public boolean supportsTupleDistinctCounts() {
566+
return false;
567+
}
568+
569+
@Override
570+
public String getDual() {
571+
return "dual";
572+
}
573+
574+
@Override
575+
public String getFromDualForSelectOnly() {
576+
return " from dual";
577+
}
578+
579+
@Override
580+
public String castPattern(CastType from, CastType to) {
581+
String result;
582+
switch ( to ) {
583+
case INTEGER:
584+
case LONG:
585+
result = BooleanDecoder.toInteger( from );
586+
if ( result != null ) {
587+
return result;
588+
}
589+
break;
590+
case STRING:
591+
switch ( from ) {
592+
case BOOLEAN:
593+
case INTEGER_BOOLEAN:
594+
case TF_BOOLEAN:
595+
case YN_BOOLEAN:
596+
return BooleanDecoder.toString( from );
597+
case DATE:
598+
return "to_char(?1,'YYYY-MM-DD')";
599+
case TIME:
600+
return "to_char(?1,'HH24:MI:SS')";
601+
case TIMESTAMP:
602+
return "to_char(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
603+
}
604+
break;
605+
case CLOB:
606+
return "to_clob(?1)";
607+
case DATE:
608+
if ( from == CastType.STRING ) {
609+
return "to_date(?1,'YYYY-MM-DD')";
610+
}
611+
break;
612+
case TIME:
613+
if ( from == CastType.STRING ) {
614+
return "to_date(?1,'HH24:MI:SS')";
615+
}
616+
break;
617+
case TIMESTAMP:
618+
if ( from == CastType.STRING ) {
619+
return "to_timestamp(?1,'YYYY-MM-DD HH24:MI:SS.FF9')";
620+
}
621+
break;
622+
}
623+
return super.castPattern(from, to);
624+
}
625+
626+
429627
@Override
430628
public boolean supportsRowValueConstructorSyntax() {
431629
return false;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenSqlAstTranslator.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import org.hibernate.sql.ast.tree.select.QuerySpec;
2323
import org.hibernate.sql.ast.tree.select.SelectClause;
2424
import org.hibernate.sql.exec.spi.JdbcOperation;
25+
import org.hibernate.internal.util.collections.Stack;
26+
import org.hibernate.sql.ast.Clause;
2527

2628
/**
2729
* A SQL AST translator for TimesTen.
@@ -107,4 +109,65 @@ else if ( expression instanceof Summarization ) {
107109
}
108110
}
109111

112+
protected void renderRowsToClause(QuerySpec querySpec) {
113+
if ( querySpec.isRoot() && hasLimit() ) {
114+
prepareLimitOffsetParameters();
115+
renderRowsToClause( getOffsetParameter(), getLimitParameter() );
116+
}
117+
else {
118+
assertRowsOnlyFetchClauseType( querySpec );
119+
renderRowsToClause( querySpec.getOffsetClauseExpression(), querySpec.getFetchClauseExpression() );
120+
}
121+
}
122+
123+
protected void renderRowsToClause(Expression offsetClauseExpression, Expression fetchClauseExpression) {
124+
// offsetClauseExpression -> firstRow
125+
// fetchClauseExpression -> maxRows
126+
final Stack<Clause> clauseStack = getClauseStack();
127+
128+
if ( offsetClauseExpression == null && fetchClauseExpression != null ) {
129+
// We only have a maxRows/limit. We use 'SELECT FIRST n' syntax
130+
appendSql("first ");
131+
clauseStack.push( Clause.FETCH );
132+
try {
133+
renderFetchExpression( fetchClauseExpression );
134+
}
135+
finally {
136+
clauseStack.pop();
137+
}
138+
}
139+
else if ( offsetClauseExpression != null ) {
140+
// We have an offset. We use 'SELECT ROWS m TO n' syntax
141+
appendSql( "rows " );
142+
143+
// Render offset parameter
144+
clauseStack.push( Clause.OFFSET );
145+
try {
146+
renderOffsetExpression( offsetClauseExpression );
147+
}
148+
finally {
149+
clauseStack.pop();
150+
}
151+
152+
appendSql( " to " );
153+
154+
// Render maxRows/limit parameter
155+
clauseStack.push( Clause.FETCH );
156+
try {
157+
if ( fetchClauseExpression != null ) {
158+
// We need to substract 1 row to fit maxRows
159+
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, -1 );
160+
}
161+
else{
162+
// We dont have a maxRows param, we will just use a MAX_VALUE
163+
appendSql( Integer.MAX_VALUE );
164+
}
165+
}
166+
finally {
167+
clauseStack.pop();
168+
}
169+
}
170+
171+
appendSql( WHITESPACE );
172+
}
110173
}

0 commit comments

Comments
 (0)