Skip to content

Commit 5c4b43c

Browse files
carlblanbeikov
authored andcommitted
Various fix for TimesTen Dialect, SqlAstTranslator, LimitHandler and SequenceSupport
1 parent 408cdd9 commit 5c4b43c

File tree

5 files changed

+351
-55
lines changed

5 files changed

+351
-55
lines changed

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

Lines changed: 214 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
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.RowLockStrategy;
1920
import org.hibernate.dialect.function.CommonFunctionFactory;
21+
import org.hibernate.dialect.function.OracleTruncFunction;
22+
import org.hibernate.query.sqm.produce.function.StandardFunctionReturnTypeResolvers;
2023
import org.hibernate.dialect.lock.LockingStrategy;
2124
import org.hibernate.dialect.lock.OptimisticForceIncrementLockingStrategy;
2225
import org.hibernate.dialect.lock.OptimisticLockingStrategy;
@@ -34,6 +37,7 @@
3437
import org.hibernate.metamodel.mapping.EntityMappingType;
3538
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
3639
import org.hibernate.persister.entity.Lockable;
40+
import org.hibernate.query.sqm.CastType;
3741
import org.hibernate.query.sqm.IntervalType;
3842
import org.hibernate.query.sqm.TemporalUnit;
3943
import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableInsertStrategy;
@@ -42,6 +46,7 @@
4246
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
4347
import org.hibernate.sql.ast.SqlAstTranslator;
4448
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
49+
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
4550
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
4651
import org.hibernate.sql.ast.tree.Statement;
4752
import org.hibernate.sql.exec.spi.JdbcOperation;
@@ -52,21 +57,29 @@
5257
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
5358
import org.hibernate.type.spi.TypeConfiguration;
5459

60+
import org.hibernate.type.BasicType;
61+
import org.hibernate.type.BasicTypeRegistry;
62+
import org.hibernate.type.StandardBasicTypes;
63+
import org.hibernate.dialect.function.StandardSQLFunction;
64+
import org.hibernate.dialect.function.CurrentFunction;
65+
import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers;
66+
import jakarta.persistence.GenerationType;
67+
import java.util.Date;
68+
5569
import jakarta.persistence.TemporalType;
5670

5771
import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION;
5872
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER;
5973
import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING;
6074

6175
/**
62-
* A SQL dialect for TimesTen 5.1.
76+
* A SQL dialect for Oracle TimesTen
6377
* <p>
6478
* Known limitations:
6579
* joined-subclass support because of no CASE support in TimesTen
6680
* No support for subqueries that includes aggregation
6781
* - size() in HQL not supported
6882
* - user queries that does subqueries with aggregation
69-
* No CLOB/BLOB support
7083
* No cascade delete support.
7184
* No Calendar support
7285
* No support for updating primary keys.
@@ -90,6 +103,7 @@ protected String columnType(int sqlTypeCode) {
90103
// for the default Oracle type mode
91104
// TypeMode=0
92105
case SqlTypes.BOOLEAN:
106+
case SqlTypes.BIT:
93107
case SqlTypes.TINYINT:
94108
return "tt_tinyint";
95109
case SqlTypes.SMALLINT:
@@ -101,15 +115,26 @@ protected String columnType(int sqlTypeCode) {
101115
//note that 'binary_float'/'binary_double' might
102116
//be better mappings for Java Float/Double
103117

118+
case SqlTypes.VARCHAR:
119+
case SqlTypes.LONGVARCHAR:
120+
return "varchar2($l)";
121+
122+
case SqlTypes.LONGVARBINARY:
123+
return "varbinary($l)";
124+
104125
//'numeric'/'decimal' are synonyms for 'number'
105126
case SqlTypes.NUMERIC:
106127
case SqlTypes.DECIMAL:
107128
return "number($p,$s)";
129+
case SqlTypes.FLOAT:
130+
return "binary_float";
131+
case SqlTypes.DOUBLE:
132+
return "binary_double";
133+
108134
case SqlTypes.DATE:
109135
return "tt_date";
110136
case SqlTypes.TIME:
111137
return "tt_time";
112-
//`timestamp` has more precision than `tt_timestamp`
113138
case SqlTypes.TIMESTAMP_WITH_TIMEZONE:
114139
return "timestamp($p)";
115140

@@ -157,22 +182,97 @@ public int getDefaultDecimalPrecision() {
157182
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
158183
super.initializeFunctionRegistry(functionContributions);
159184

160-
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
185+
final TypeConfiguration typeConfiguration = functionContributions.getTypeConfiguration();
186+
CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions);
187+
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
188+
final BasicType<Date> timestampType = basicTypeRegistry.resolve( StandardBasicTypes.TIMESTAMP );
189+
final BasicType<String> stringType = basicTypeRegistry.resolve( StandardBasicTypes.STRING );
190+
final BasicType<Long> longType = basicTypeRegistry.resolve( StandardBasicTypes.LONG );
191+
final BasicType<Integer>intType = basicTypeRegistry.resolve( StandardBasicTypes.INTEGER );
192+
193+
// String Functions
161194
functionFactory.trim2();
162-
functionFactory.soundex();
163-
functionFactory.trunc();
195+
functionFactory.characterLength_length( SqlAstNodeRenderingMode.DEFAULT );
196+
functionFactory.concat_pipeOperator();
164197
functionFactory.toCharNumberDateTimestamp();
165-
functionFactory.ceiling_ceil();
198+
functionFactory.char_chr();
166199
functionFactory.instr();
167200
functionFactory.substr();
168201
functionFactory.substring_substr();
169-
functionFactory.leftRight_substr();
170-
functionFactory.char_chr();
171-
functionFactory.rownumRowid();
172-
functionFactory.sysdate();
202+
functionFactory.soundex();
203+
204+
// Date/Time Functions
205+
functionContributions.getFunctionRegistry().register(
206+
"sysdate", new CurrentFunction("sysdate", "sysdate", timestampType)
207+
);
208+
functionContributions.getFunctionRegistry().register(
209+
"getdate", new CurrentFunction("getdate", "getdate()", timestampType )
210+
);
211+
212+
// Multi-param date dialect functions
173213
functionFactory.addMonths();
174214
functionFactory.monthsBetween();
175215

216+
// Math functions
217+
functionFactory.ceiling_ceil();
218+
functionFactory.radians_acos();
219+
functionFactory.degrees_acos();
220+
functionFactory.sinh();
221+
functionFactory.tanh();
222+
functionContributions.getFunctionRegistry().register(
223+
"trunc",
224+
new OracleTruncFunction( functionContributions.getTypeConfiguration() )
225+
);
226+
functionContributions.getFunctionRegistry().registerAlternateKey( "truncate", "trunc" );
227+
functionFactory.round();
228+
229+
// Bitwise functions
230+
functionContributions.getFunctionRegistry()
231+
.patternDescriptorBuilder( "bitor", "(?1+?2-bitand(?1,?2))")
232+
.setExactArgumentCount( 2 )
233+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
234+
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
235+
.register();
236+
237+
functionContributions.getFunctionRegistry()
238+
.patternDescriptorBuilder( "bitxor", "(?1+?2-2*bitand(?1,?2))")
239+
.setExactArgumentCount( 2 )
240+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers
241+
.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
242+
.register();
243+
244+
// Misc. functions
245+
functionContributions.getFunctionRegistry().namedDescriptorBuilder( "nvl" )
246+
.setMinArgumentCount( 2 )
247+
.setArgumentTypeResolver( StandardFunctionArgumentTypeResolvers.ARGUMENT_OR_IMPLIED_RESULT_TYPE )
248+
.setReturnTypeResolver( StandardFunctionReturnTypeResolvers.useFirstNonNull() )
249+
.register();
250+
251+
functionContributions.getFunctionRegistry().register(
252+
"user", new CurrentFunction("user", "user", stringType)
253+
);
254+
functionContributions.getFunctionRegistry().register(
255+
"rowid", new CurrentFunction("rowid", "rowid", stringType)
256+
);
257+
functionContributions.getFunctionRegistry().register(
258+
"uid", new CurrentFunction("uid", "uid", intType)
259+
);
260+
functionContributions.getFunctionRegistry().register(
261+
"rownum", new CurrentFunction("rownum", "rownum", longType)
262+
);
263+
functionContributions.getFunctionRegistry().register(
264+
"vsize", new StandardSQLFunction("vsize", StandardBasicTypes.DOUBLE)
265+
);
266+
functionContributions.getFunctionRegistry().register(
267+
"SESSION_USER", new CurrentFunction("SESSION_USER","SESSION_USER", stringType)
268+
);
269+
functionContributions.getFunctionRegistry().register(
270+
"SYSTEM_USER", new CurrentFunction("SYSTEM_USER", "SYSTEM_USER", stringType)
271+
);
272+
functionContributions.getFunctionRegistry().register(
273+
"CURRENT_USER", new CurrentFunction("CURRENT_USER","CURRENT_USER", stringType)
274+
);
275+
176276
functionContributions.getFunctionRegistry().registerBinaryTernaryPattern(
177277
"locate",
178278
functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ),
@@ -251,9 +351,10 @@ public RowLockStrategy getWriteRowLockStrategy() {
251351
return RowLockStrategy.COLUMN;
252352
}
253353

354+
254355
@Override
255-
public String getForUpdateString(String aliases) {
256-
return " for update of " + aliases;
356+
public String getForUpdateString() {
357+
return " for update";
257358
}
258359

259360
@Override
@@ -426,4 +527,104 @@ public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfi
426527
}
427528
}
428529

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

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.hibernate.sql.ast.tree.select.QuerySpec;
2929
import org.hibernate.sql.ast.tree.select.SelectClause;
3030
import org.hibernate.sql.exec.spi.JdbcOperation;
31+
import org.hibernate.internal.util.collections.Stack;
32+
import org.hibernate.sql.ast.Clause;
3133

3234
/**
3335
* A SQL AST translator for TimesTen.
@@ -143,4 +145,66 @@ protected boolean supportsRowValueConstructorSyntaxInInList() {
143145
protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() {
144146
return false;
145147
}
148+
149+
protected void renderRowsToClause(QuerySpec querySpec) {
150+
if ( querySpec.isRoot() && hasLimit() ) {
151+
prepareLimitOffsetParameters();
152+
renderRowsToClause( getOffsetParameter(), getLimitParameter() );
153+
}
154+
else {
155+
assertRowsOnlyFetchClauseType( querySpec );
156+
renderRowsToClause( querySpec.getOffsetClauseExpression(), querySpec.getFetchClauseExpression() );
157+
}
158+
}
159+
160+
protected void renderRowsToClause(Expression offsetClauseExpression, Expression fetchClauseExpression) {
161+
// offsetClauseExpression -> firstRow
162+
// fetchClauseExpression -> maxRows
163+
final Stack<Clause> clauseStack = getClauseStack();
164+
165+
if ( offsetClauseExpression == null && fetchClauseExpression != null ) {
166+
// We only have a maxRows/limit. We use 'SELECT FIRST n' syntax
167+
appendSql("first ");
168+
clauseStack.push( Clause.FETCH );
169+
try {
170+
renderFetchExpression( fetchClauseExpression );
171+
}
172+
finally {
173+
clauseStack.pop();
174+
}
175+
}
176+
else if ( offsetClauseExpression != null ) {
177+
// We have an offset. We use 'SELECT ROWS m TO n' syntax
178+
appendSql( "rows " );
179+
180+
// Render offset parameter
181+
clauseStack.push( Clause.OFFSET );
182+
try {
183+
renderOffsetExpression( offsetClauseExpression );
184+
}
185+
finally {
186+
clauseStack.pop();
187+
}
188+
189+
appendSql( " to " );
190+
191+
// Render maxRows/limit parameter
192+
clauseStack.push( Clause.FETCH );
193+
try {
194+
if ( fetchClauseExpression != null ) {
195+
// We need to substract 1 row to fit maxRows
196+
renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, -1 );
197+
}
198+
else{
199+
// We dont have a maxRows param, we will just use a MAX_VALUE
200+
appendSql( Integer.MAX_VALUE );
201+
}
202+
}
203+
finally {
204+
clauseStack.pop();
205+
}
206+
}
207+
208+
appendSql( WHITESPACE );
209+
}
146210
}

0 commit comments

Comments
 (0)