Skip to content

Commit ad1b257

Browse files
committed
rework interval/datetime arithmetic on Informix
1 parent 63289fb commit ad1b257

File tree

2 files changed

+47
-17
lines changed

2 files changed

+47
-17
lines changed

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

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,6 @@ public String extractPattern(TemporalUnit unit) {
436436
case DAY_OF_WEEK -> "(weekday(?2)+1)";
437437
case DAY_OF_MONTH -> "day(?2)";
438438
case EPOCH -> "(to_number(cast(cast(sum(?2-datetime(1970-1-1) year to day) as interval day(9) to day) as varchar(12)))*86400+to_number(cast(cast(sum(cast(?2 as datetime hour to second)-datetime(00:00:00) hour to second) as interval second(6) to second) as varchar(9))))";
439-
case NATIVE -> "((to_number(cast(cast(sum(?2) as interval day(9) to day) as varchar(12)))*86400+mod(to_number(cast(cast(sum(?2) as interval second(6) to second) as varchar(9))),86400)+to_number(cast(cast(sum(?2) as interval fraction to fraction) as varchar(6))))*1e3)";
440439
default -> "?1(?2)";
441440
};
442441
}
@@ -695,16 +694,21 @@ public String getCurrentTimestampSelectString() {
695694

696695
@Override @SuppressWarnings("deprecation")
697696
public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) {
698-
return intervalType != null ? "(?2 + ?3)" : "(?3 + " + intervalPattern( unit ) + ")";
697+
return intervalType != null ? "(?2 + ?3)" : "(?3 + " + intervalPattern( unit, temporalType ) + ")";
699698
}
700699

701-
private static String intervalPattern(TemporalUnit unit) {
700+
@SuppressWarnings("deprecation")
701+
private static String intervalPattern(TemporalUnit unit, TemporalType temporalType) {
702702
return switch (unit) {
703-
case NANOSECOND -> "?2/1e9 * interval (1) second to fraction";
704-
case NATIVE, SECOND -> "?2 * interval (1) second to fraction";
705-
case QUARTER -> "?2 * interval (3) month to month";
706-
case WEEK -> "?2 * interval (7) day to day";
707-
default -> "?2 * interval (1) " + unit + " to " + unit;
703+
case NANOSECOND -> "?2/1e9 * interval (1) second(9) to fraction";
704+
case NATIVE -> "?2/1e3 * interval (1) second(9) to fraction"; // millis
705+
case SECOND ->
706+
temporalType == TemporalType.TIME
707+
? "?2 * 1 units second" // times don't usually come equipped with fractional seconds
708+
: "?2 * interval (1) second(9) to fraction"; // datetimes do have fractional seconds
709+
case QUARTER -> "?2 * 3 units month";
710+
case WEEK -> "?2 * 7 units day";
711+
default -> "?2 * 1 units " + unit;
708712
};
709713
}
710714

@@ -717,11 +721,21 @@ public long getFractionalSecondPrecisionInNanos() {
717721

718722
@Override @SuppressWarnings("deprecation")
719723
public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) {
720-
return unit == null
721-
? "(?3-?2)"
722-
: extractPattern( unit )
723-
.replace( "?1", unit.toString() )
724-
.replace( "?2", "?3-?2" );
724+
if ( unit == null ) {
725+
return "(?3-?2)";
726+
}
727+
else {
728+
return switch ( unit ) {
729+
case NATIVE ->
730+
fromTemporalType == TemporalType.TIME
731+
// arguably, we don't really need to retain the milliseconds for a time, since times don't usually come with millis
732+
? "((mod(to_number(cast(cast(sum(?3-?2) as interval second(6) to second) as varchar(9))),86400)+to_number(cast(cast(sum(?3-?2) as interval fraction to fraction) as varchar(6))))*1e3)"
733+
: "((to_number(cast(cast(sum(?3-?2) as interval day(9) to day) as varchar(12)))*86400+mod(to_number(cast(cast(sum(?3-?2) as interval second(6) to second) as varchar(9))),86400)+to_number(cast(cast(sum(?3-?2) as interval fraction to fraction) as varchar(6))))*1e3)";
734+
case SECOND -> "to_number(cast(cast(sum(?3-?2) as interval second(9) to fraction) as varchar(15)))";
735+
case NANOSECOND -> "(to_number(cast(cast(sum(?3-?2) as interval second(9) to fraction) as varchar(15)))*1e9)";
736+
default -> "to_number(cast(cast(sum(?3-?2) as interval ?1(9) to ?1) as varchar(12)))";
737+
};
738+
}
725739
}
726740

727741
@Override
@@ -948,7 +962,7 @@ public void appendDateTimeLiteral(
948962
break;
949963
case TIME:
950964
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
951-
appender.appendSql( ") hour to fraction" );
965+
appender.appendSql( ") hour to second" ); // we ignore the milliseconds
952966
break;
953967
case TIMESTAMP:
954968
appendAsTimestampWithMillis( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );

hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/FunctionTests.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,10 +1794,12 @@ public void testDurationArithmetic(SessionFactoryScope scope) {
17941794
reason = "numeric overflow")
17951795
@SkipForDialect(dialectClass = OracleDialect.class,
17961796
reason = "numeric overflow")
1797-
@SkipForDialect( dialectClass = TiDBDialect.class,
1797+
@SkipForDialect(dialectClass = TiDBDialect.class,
17981798
reason = "Bug in the TiDB timestampadd function (https://github.com/pingcap/tidb/issues/41052)")
1799-
@SkipForDialect( dialectClass = AltibaseDialect.class,
1799+
@SkipForDialect(dialectClass = AltibaseDialect.class,
18001800
reason = "exceeds timestampadd limit in Altibase")
1801+
@SkipForDialect(dialectClass = InformixDialect.class,
1802+
reason = "Overflow occurred on a datetime or interval")
18011803
public void testDurationArithmeticOverflowing(SessionFactoryScope scope) {
18021804
scope.inTransaction(
18031805
session -> {
@@ -1910,6 +1912,8 @@ public void testDurationSubtractionWithTimeLiterals(SessionFactoryScope scope) {
19101912
@SkipForDialect(dialectClass = SybaseDialect.class,
19111913
matchSubTypes = true,
19121914
reason = "numeric overflow")
1915+
@SkipForDialect(dialectClass = InformixDialect.class,
1916+
reason = "Overflow occurred on a datetime or interval operation")
19131917
public void testDurationSubtractionWithDatetimeLiterals(SessionFactoryScope scope) {
19141918
scope.inTransaction(
19151919
session -> {
@@ -1926,8 +1930,11 @@ public void testDurationSubtractionWithDatetimeLiterals(SessionFactoryScope scop
19261930
);
19271931
}
19281932

1929-
@Test @SkipForDialect(dialectClass = MySQLDialect.class,
1933+
@Test
1934+
@SkipForDialect(dialectClass = MySQLDialect.class,
19301935
reason = "MySQL has a really weird TIME type")
1936+
@SkipForDialect(dialectClass = InformixDialect.class,
1937+
reason = "The result of a datetime computation is out of range")
19311938
public void testTimeDurationArithmeticWrapAroundWithLiterals(SessionFactoryScope scope) {
19321939
scope.inTransaction(
19331940
session -> {
@@ -1975,6 +1982,8 @@ public void testDateDurationArithmeticWithLiterals(SessionFactoryScope scope) {
19751982

19761983
@Test
19771984
@JiraKey("HHH-17074")
1985+
@SkipForDialect(dialectClass = InformixDialect.class,
1986+
reason = "Bad use of aggregate in this context")
19781987
public void testDurationArithmeticWithParameters(SessionFactoryScope scope) {
19791988
scope.inTransaction(
19801989
session -> {
@@ -2025,6 +2034,11 @@ public void testIntervalDiffExpressions(SessionFactoryScope scope) {
20252034
.list();
20262035
session.createQuery("select (e.theTimestamp - (e.theTimestamp + (4 day + 2 hour))) by second from EntityOfBasics e", Long.class)
20272036
.list();
2037+
2038+
assertThat( session.createQuery("select (local datetime + 2 day) - local datetime").getSingleResult(),
2039+
is( Duration.ofDays( 2 ) ) );
2040+
assertThat( session.createQuery("select (local datetime - 12 hour) - local datetime").getSingleResult(),
2041+
is( Duration.ofHours( -12 ) ) );
20282042
}
20292043
);
20302044
}
@@ -2035,6 +2049,8 @@ public void testIntervalDiffExpressions(SessionFactoryScope scope) {
20352049
reason = "result in numeric overflow")
20362050
@SkipForDialect(dialectClass = PostgresPlusDialect.class,
20372051
reason = "trivial rounding error")
2052+
@SkipForDialect(dialectClass = InformixDialect.class,
2053+
reason = "Overflow occurred on a datetime or interval operation")
20382054
public void testMoreIntervalDiffExpressions(SessionFactoryScope scope) {
20392055
scope.inTransaction(
20402056
session -> {

0 commit comments

Comments
 (0)