Skip to content

Commit 64f3b7f

Browse files
committed
improvements to HQL casting and datetime handling on Informix
1 parent b4539db commit 64f3b7f

File tree

1 file changed

+93
-43
lines changed

1 file changed

+93
-43
lines changed

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

Lines changed: 93 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
import org.hibernate.exception.ConstraintViolationException;
2828
import org.hibernate.exception.LockAcquisitionException;
2929
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
30+
import org.hibernate.query.sqm.CastType;
31+
import org.hibernate.query.sqm.IntervalType;
3032
import org.hibernate.type.descriptor.jdbc.VarcharUUIDJdbcType;
3133
import org.hibernate.dialect.function.CaseLeastGreatestEmulation;
3234
import org.hibernate.dialect.function.CommonFunctionFactory;
@@ -110,14 +112,10 @@
110112
import static org.hibernate.type.SqlTypes.UUID;
111113
import static org.hibernate.type.SqlTypes.VARBINARY;
112114
import static org.hibernate.type.SqlTypes.VARCHAR;
113-
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_END;
114-
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_DATE;
115-
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIME;
116-
import static org.hibernate.type.descriptor.DateTimeUtils.JDBC_ESCAPE_START_TIMESTAMP;
117115
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
118116
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
119117
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
120-
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
118+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
121119

122120
/**
123121
* Dialect for Informix 7.31.UD3 with Informix
@@ -285,8 +283,9 @@ public int getDefaultDecimalPrecision() {
285283

286284
@Override
287285
public int getDefaultTimestampPrecision() {
288-
//the maximum
289-
return 5;
286+
//the maximum is 5, but default to 3
287+
//because Informix defaults to milliseconds
288+
return 3;
290289
}
291290

292291
@Override
@@ -424,21 +423,14 @@ protected <T extends JdbcOperation> SqlAstTranslator<T> buildTranslator(
424423
*/
425424
@Override
426425
public String extractPattern(TemporalUnit unit) {
427-
switch (unit) {
428-
case SECOND:
429-
return "to_number(to_char(?2,'%S'))";
430-
case MINUTE:
431-
return "to_number(to_char(?2,'%M'))";
432-
case HOUR:
433-
return "to_number(to_char(?2,'%H'))";
434-
case DAY_OF_WEEK:
435-
return "(weekday(?2)+1)";
436-
case DAY_OF_MONTH:
437-
return "day(?2)";
438-
default:
439-
//I think week() returns the ISO week number
440-
return "?1(?2)";
441-
}
426+
return switch ( unit ) {
427+
case SECOND -> "to_number(to_char(?2,'%S'))";
428+
case MINUTE -> "to_number(to_char(?2,'%M'))";
429+
case HOUR -> "to_number(to_char(?2,'%H'))";
430+
case DAY_OF_WEEK -> "(weekday(?2)+1)";
431+
case DAY_OF_MONTH -> "day(?2)";
432+
default -> "?1(?2)";
433+
};
442434
}
443435

444436
@Override
@@ -545,6 +537,18 @@ public boolean supportsIfExistsBeforeConstraintName() {
545537
return getVersion().isSameOrAfter( 11, 70 );
546538
}
547539

540+
@Override
541+
public String getCascadeConstraintsString() {
542+
return getVersion().isSameOrAfter( 12, 10 )
543+
? " cascade"
544+
: "";
545+
}
546+
547+
@Override
548+
public boolean dropConstraints() {
549+
return !getVersion().isSameOrAfter( 12, 10 );
550+
}
551+
548552
@Override
549553
public boolean supportsOrderByInSubquery() {
550554
// This is just a guess
@@ -664,7 +668,60 @@ public boolean isCurrentTimestampSelectStringCallable() {
664668

665669
@Override
666670
public String getCurrentTimestampSelectString() {
667-
return "select distinct current timestamp from informix.systables";
671+
return "select sysdate";
672+
}
673+
674+
@Override @SuppressWarnings("deprecation")
675+
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
676+
return intervalType != null ? "(?2 + ?3)" : "(?3 + " + intervalPattern( unit ) + ")";
677+
}
678+
679+
private static String intervalPattern(TemporalUnit unit) {
680+
return switch (unit) {
681+
case NANOSECOND -> "?2/1e9 * interval (1) second to fraction";
682+
case NATIVE, SECOND -> "?2 * interval (1) second to fraction";
683+
case QUARTER -> "?2 * interval (3) month to month";
684+
case WEEK -> "?2 * interval (7) day to day";
685+
default -> "?2 * interval (1) " + unit + " to " + unit;
686+
};
687+
}
688+
689+
@Override
690+
public long getFractionalSecondPrecisionInNanos() {
691+
// Informix actually supports up to 10 microseconds
692+
// but defaults to milliseconds (so use that)
693+
return 1_000_000;
694+
}
695+
696+
@Override @SuppressWarnings("deprecation")
697+
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
698+
return unit == null
699+
? "(?3-?2)"
700+
: extractPattern( unit )
701+
.replace( "?1", unit.toString() )
702+
.replace( "?2", "?3-?2" );
703+
}
704+
705+
@Override
706+
public String castPattern(CastType from, CastType to) {
707+
if ( from == CastType.BOOLEAN ) {
708+
switch ( to ) {
709+
case STRING:
710+
return "trim(case ?1 when 't' then 'true' when 'f' then 'false' else null end)";
711+
case TF_BOOLEAN:
712+
return "upper(cast(?1 as varchar))";
713+
case YN_BOOLEAN:
714+
return "case ?1 when 't' then 'Y' when 'f' then 'N' else null end";
715+
case INTEGER_BOOLEAN:
716+
return "case ?1 when 't' then 1 when 'f' then 0 else null end";
717+
}
718+
}
719+
return super.castPattern( from, to );
720+
}
721+
722+
@Override
723+
public void appendBinaryLiteral(SqlAppender appender, byte[] bytes) {
724+
throw new UnsupportedOperationException( "Informix does not support binary literals" );
668725
}
669726

670727
@Override
@@ -764,7 +821,9 @@ public Exporter<Table> getTableExporter() {
764821

765822
@Override
766823
public void appendBooleanValueString(SqlAppender appender, boolean bool) {
824+
appender.appendSql( "cast(" );
767825
appender.appendSql( bool ? "'t'" : "'f'" );
826+
appender.appendSql( " as boolean)" );
768827
}
769828

770829
@Override
@@ -774,7 +833,7 @@ public String currentDate() {
774833

775834
@Override
776835
public String currentTime() {
777-
return currentTimestamp();
836+
return "current hour to fraction";
778837
}
779838

780839
@Override
@@ -851,21 +910,19 @@ public void appendDateTimeLiteral(
851910
TemporalAccessor temporalAccessor,
852911
TemporalType precision,
853912
TimeZone jdbcTimeZone) {
913+
appender.append( "datetime (" );
854914
switch ( precision ) {
855915
case DATE:
856-
appender.appendSql( JDBC_ESCAPE_START_DATE );
857916
appendAsDate( appender, temporalAccessor );
858-
appender.appendSql( JDBC_ESCAPE_END );
917+
appender.appendSql( ") year to day" );
859918
break;
860919
case TIME:
861-
appender.appendSql( JDBC_ESCAPE_START_TIME );
862920
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
863-
appender.appendSql( JDBC_ESCAPE_END );
921+
appender.appendSql( ") hour to fraction" );
864922
break;
865923
case TIMESTAMP:
866-
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
867-
appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
868-
appender.appendSql( JDBC_ESCAPE_END );
924+
appendAsTimestampWithMillis( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
925+
appender.appendSql( ") year to fraction" );
869926
break;
870927
default:
871928
throw new IllegalArgumentException();
@@ -874,21 +931,19 @@ public void appendDateTimeLiteral(
874931

875932
@Override
876933
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
934+
appender.append( "datetime (" );
877935
switch ( precision ) {
878936
case DATE:
879-
appender.appendSql( JDBC_ESCAPE_START_DATE );
880937
appendAsDate( appender, date );
881-
appender.appendSql( JDBC_ESCAPE_END );
938+
appender.appendSql( ") year to day" );
882939
break;
883940
case TIME:
884-
appender.appendSql( JDBC_ESCAPE_START_TIME );
885941
appendAsLocalTime( appender, date );
886-
appender.appendSql( JDBC_ESCAPE_END );
942+
appender.appendSql( ") hour to fraction" );
887943
break;
888944
case TIMESTAMP:
889-
appender.appendSql( JDBC_ESCAPE_START_TIMESTAMP );
890-
appendAsTimestampWithMicros( appender, date, jdbcTimeZone );
891-
appender.appendSql( JDBC_ESCAPE_END );
945+
appendAsTimestampWithMillis( appender, date, jdbcTimeZone );
946+
appender.appendSql( ") year to fraction" );
892947
break;
893948
default:
894949
throw new IllegalArgumentException();
@@ -944,11 +999,6 @@ public String getDual() {
944999
return "(select 0 from systables where tabid=1)";
9451000
}
9461001

947-
@Override
948-
public String getFromDualForSelectOnly() {
949-
return " from " + getDual() + " dual";
950-
}
951-
9521002
@Override
9531003
public boolean supportsRowValueConstructorSyntax() {
9541004
return false;

0 commit comments

Comments
 (0)