HHH-16174 support for extract(epoch from ...) in HQL

This commit is contained in:
Gavin King 2023-02-11 00:11:01 +01:00 committed by Christian Beikov
parent 6c7603f83a
commit bb14d5b288
12 changed files with 47 additions and 5 deletions

View File

@ -814,7 +814,7 @@ There are two very important function for working with dates and times.
The special function `extract()` obtains a single field of a date, time, or datetime.
Field types include: `day`, `month`, `year`, `second`, `minute`, `hour`, `day of week`, `day of month`, `week of year`, `date`, `time` and more.
Field types include: `day`, `month`, `year`, `second`, `minute`, `hour`, `day of week`, `day of month`, `week of year`, `date`, `time`, `epoch` and more.
For a full list of field types, see the Javadoc for https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/query/TemporalUnit.html[`TemporalUnit`].
====

View File

@ -181,6 +181,7 @@ ELSE : [eE] [lL] [sS] [eE];
EMPTY : [eE] [mM] [pP] [tT] [yY];
END : [eE] [nN] [dD];
ENTRY : [eE] [nN] [tT] [rR] [yY];
EPOCH : [eE] [pP] [oO] [cC] [hH];
ERROR : [eE] [rR] [rR] [oO] [rR];
ESCAPE : [eE] [sS] [cC] [aA] [pP] [eE];
EVERY : [eE] [vV] [eE] [rR] [yY];

View File

@ -1473,6 +1473,7 @@ datetimeField
| MINUTE
| SECOND
| NANOSECOND
| EPOCH
;
dayField
@ -1577,6 +1578,7 @@ rollup
| EMPTY
| END
| ENTRY
| EPOCH
| ERROR
| ESCAPE
| EVERY

View File

@ -368,6 +368,8 @@ public class DerbyDialect extends Dialect {
return "(({fn timestampdiff(sql_tsi_day,date(char(year(?2),4)||'-01-01'),{fn timestampadd(sql_tsi_day,{fn timestampdiff(sql_tsi_day,{d '1753-01-01'},?2)}/7*7,{d '1753-01-04'})})}+7)/7)";
case QUARTER:
return "((month(?2)+2)/3)";
case EPOCH:
return "{fn timestampdiff(sql_tsi_second,{ts '1970-01-01 00:00:00'},?2)}";
default:
return "?1(?2)";
}

View File

@ -319,6 +319,16 @@ public class HSQLDialect extends Dialect {
return pattern.toString();
}
@Override
public String extractPattern(TemporalUnit unit) {
if ( unit == TemporalUnit.EPOCH ) {
return "unix_timestamp(?2)";
}
else {
return super.extractPattern(unit);
}
}
@Override
public boolean supportsDistinctFromPredicate() {
return true;

View File

@ -745,6 +745,8 @@ public class MySQLDialect extends Dialect {
case DAY_OF_YEAR:
return "dayofyear(?2)";
//TODO: case WEEK_YEAR: yearweek(?2, 3)/100
case EPOCH:
return "unix_timestamp(?2)";
default:
return "?1(?2)";
}

View File

@ -480,6 +480,8 @@ public class OracleDialect extends Dialect {
return "to_number(to_char(?2,'MI'))";
case SECOND:
return "to_number(to_char(?2,'SS'))";
case EPOCH:
return "trunc((cast(?2 at time zone 'UTC' as date) - date '1970-1-1')*86400)";
default:
return super.extractPattern(unit);
}

View File

@ -753,6 +753,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
case SECOND:
//this should evaluate to a floating point type
return "(datepart(second,?2)+datepart(nanosecond,?2)/1e9)";
case EPOCH:
return "datediff_big(second, '1970-01-01', ?2)";
default:
return "datepart(?1,?2)";
}

View File

@ -300,8 +300,13 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
@Override
public String extractPattern(TemporalUnit unit) {
//TODO!!
return "datepart(?1,?2)";
if ( unit == TemporalUnit.EPOCH ) {
return "datediff(second, '1970-01-01 00:00:00', ?2)";
}
else {
//TODO!!
return "datepart(?1,?2)";
}
}
@Override

View File

@ -4199,6 +4199,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
resolveExpressibleTypeBasic( Integer.class ),
nodeBuilder
);
case HqlParser.EPOCH:
return new SqmExtractUnit<>(
TemporalUnit.EPOCH,
resolveExpressibleTypeBasic( Long.class ),
nodeBuilder
);
}
throw new ParsingException( "Unsupported datetime field [" + ctx.getText() + "]" );
}

View File

@ -154,8 +154,7 @@ public enum TemporalUnit {
TIME,
/**
* An internal value representing the Unix epoch, the elapsed
* seconds since January 1, 1970. Currently not supported in
* HQL.
* seconds since January 1, 1970.
*/
EPOCH,
/**

View File

@ -1518,6 +1518,17 @@ public class FunctionTests {
);
}
@Test
public void testExtractFunctionEpoch(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery("select extract(epoch from local datetime)", Long.class).getSingleResult();
session.createQuery("select extract(epoch from offset datetime)", Long.class).getSingleResult();
assertThat( session.createQuery("select extract(epoch from datetime 1974-03-23 12:35)", Long.class).getSingleResult(), is(133274100L) );
}
);
}
@Test
public void testExtractFunctionWeek(SessionFactoryScope scope) {
scope.inTransaction(