Skip to content

Commit 90609c8

Browse files
committed
HHH-18589 Properly handle temporals in BC era
1 parent 513bbb7 commit 90609c8

28 files changed

+1569
-261
lines changed

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import org.hibernate.sql.exec.spi.JdbcOperation;
7373
import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
7474
import org.hibernate.type.JavaObjectType;
75+
import org.hibernate.type.descriptor.DateTimeUtils;
7576
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
7677
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
7778
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -129,11 +130,10 @@
129130
import static org.hibernate.type.SqlTypes.UUID;
130131
import static org.hibernate.type.SqlTypes.VARBINARY;
131132
import static org.hibernate.type.SqlTypes.VARCHAR;
132-
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate;
133+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDateWithEraSuffix;
133134
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
134135
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
135-
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros;
136-
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis;
136+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicrosAndEraSuffix;
137137

138138
/**
139139
* A {@linkplain Dialect SQL dialect} for CockroachDB.
@@ -742,7 +742,7 @@ public void appendDateTimeLiteral(
742742
switch ( precision ) {
743743
case DATE:
744744
appender.appendSql( "date '" );
745-
appendAsDate( appender, temporalAccessor );
745+
appendAsDateWithEraSuffix( appender, temporalAccessor );
746746
appender.appendSql( '\'' );
747747
break;
748748
case TIME:
@@ -759,12 +759,12 @@ public void appendDateTimeLiteral(
759759
case TIMESTAMP:
760760
if ( supportsTemporalLiteralOffset() && temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS ) ) {
761761
appender.appendSql( "timestamp with time zone '" );
762-
appendAsTimestampWithMicros( appender, temporalAccessor, true, jdbcTimeZone );
762+
appendAsTimestampWithMicrosAndEraSuffix( appender, temporalAccessor, true, jdbcTimeZone );
763763
appender.appendSql( '\'' );
764764
}
765765
else {
766766
appender.appendSql( "timestamp '" );
767-
appendAsTimestampWithMicros( appender, temporalAccessor, false, jdbcTimeZone );
767+
appendAsTimestampWithMicrosAndEraSuffix( appender, temporalAccessor, false, jdbcTimeZone );
768768
appender.appendSql( '\'' );
769769
}
770770
break;
@@ -778,7 +778,7 @@ public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType
778778
switch ( precision ) {
779779
case DATE:
780780
appender.appendSql( "date '" );
781-
appendAsDate( appender, date );
781+
appendAsDateWithEraSuffix( appender, date );
782782
appender.appendSql( '\'' );
783783
break;
784784
case TIME:
@@ -788,7 +788,7 @@ public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType
788788
break;
789789
case TIMESTAMP:
790790
appender.appendSql( "timestamp with time zone '" );
791-
appendAsTimestampWithMicros( appender,date, jdbcTimeZone );
791+
appendAsTimestampWithMicrosAndEraSuffix( appender,date, jdbcTimeZone );
792792
appender.appendSql( '\'' );
793793
break;
794794
default:
@@ -805,7 +805,7 @@ public void appendDateTimeLiteral(
805805
switch ( precision ) {
806806
case DATE:
807807
appender.appendSql( "date '" );
808-
appendAsDate( appender, calendar );
808+
appendAsDateWithEraSuffix( appender, calendar );
809809
appender.appendSql( '\'' );
810810
break;
811811
case TIME:
@@ -815,7 +815,7 @@ public void appendDateTimeLiteral(
815815
break;
816816
case TIMESTAMP:
817817
appender.appendSql( "timestamp with time zone '" );
818-
appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone );
818+
DateTimeUtils.appendAsTimestampWithMillisAndEraSuffix( appender, calendar, jdbcTimeZone );
819819
appender.appendSql( '\'' );
820820
break;
821821
default:

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@
7878
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
7979
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
8080
import org.hibernate.type.descriptor.jdbc.EnumJdbcType;
81+
import org.hibernate.type.descriptor.jdbc.GregorianEpochBasedDateJdbcType;
82+
import org.hibernate.type.descriptor.jdbc.GregorianEpochBasedTimestampJdbcType;
8183
import org.hibernate.type.descriptor.jdbc.JdbcType;
8284
import org.hibernate.type.descriptor.jdbc.OrdinalEnumJdbcType;
8385
import org.hibernate.type.descriptor.jdbc.TimeAsTimestampWithTimeZoneJdbcType;
@@ -294,6 +296,8 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
294296
jdbcTypeRegistry.addDescriptor( TimeUtcAsOffsetTimeJdbcType.INSTANCE );
295297
}
296298
jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, TimestampUtcAsInstantJdbcType.INSTANCE );
299+
jdbcTypeRegistry.addDescriptor( GregorianEpochBasedDateJdbcType.INSTANCE );
300+
jdbcTypeRegistry.addDescriptor( GregorianEpochBasedTimestampJdbcType.INSTANCE );
297301
if ( getVersion().isSameOrAfter( 1, 4, 197 ) ) {
298302
jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE );
299303
}

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

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.hibernate.Locking;
1212
import org.hibernate.StaleObjectStateException;
1313
import org.hibernate.boot.model.FunctionContributions;
14+
import org.hibernate.boot.model.TypeContributions;
1415
import org.hibernate.community.dialect.pagination.LegacyHSQLLimitHandler;
1516
import org.hibernate.dialect.BooleanDecoder;
1617
import org.hibernate.dialect.DatabaseVersion;
@@ -67,6 +68,7 @@
6768
import org.hibernate.query.sqm.mutation.spi.BeforeUseAction;
6869
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
6970
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
71+
import org.hibernate.service.ServiceRegistry;
7072
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
7173
import org.hibernate.sql.ast.SqlAstTranslator;
7274
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
@@ -76,20 +78,31 @@
7678
import org.hibernate.sql.exec.spi.JdbcOperation;
7779
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorHSQLDBDatabaseImpl;
7880
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
81+
import org.hibernate.type.descriptor.DateTimeUtils;
82+
import org.hibernate.type.descriptor.jdbc.GregorianEpochBasedDateJdbcType;
83+
import org.hibernate.type.descriptor.jdbc.GregorianEpochBasedTimestampJdbcType;
84+
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
7985
import org.hibernate.type.spi.TypeConfiguration;
8086
import org.jboss.logging.Logger;
8187

8288
import java.lang.invoke.MethodHandles;
8389
import java.sql.DatabaseMetaData;
8490
import java.sql.SQLException;
8591
import java.sql.Types;
92+
import java.time.temporal.TemporalAccessor;
93+
import java.util.Calendar;
94+
import java.util.Date;
95+
import java.util.TimeZone;
8696

8797
import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate;
8898
import static org.hibernate.type.SqlTypes.BLOB;
8999
import static org.hibernate.type.SqlTypes.CLOB;
90100
import static org.hibernate.type.SqlTypes.DOUBLE;
91101
import static org.hibernate.type.SqlTypes.NCLOB;
92102
import static org.hibernate.type.SqlTypes.NUMERIC;
103+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDateWithEraPrefix;
104+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillisAndEraPrefix;
105+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithNanosAndEraPrefix;
93106

94107
/**
95108
* A {@linkplain Dialect SQL dialect} for HSQLDB (HyperSQL) 1.8 up to (but not including) 2.6.1.
@@ -294,6 +307,85 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio
294307
) );
295308
}
296309

310+
@Override
311+
public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
312+
super.contributeTypes( typeContributions, serviceRegistry );
313+
final JdbcTypeRegistry jdbcTypeRegistry =
314+
typeContributions.getTypeConfiguration().getJdbcTypeRegistry();
315+
316+
jdbcTypeRegistry.addDescriptor( GregorianEpochBasedDateJdbcType.INSTANCE );
317+
jdbcTypeRegistry.addDescriptor( GregorianEpochBasedTimestampJdbcType.INSTANCE );
318+
}
319+
320+
@Override
321+
public void appendDateTimeLiteral(SqlAppender appender, TemporalAccessor temporalAccessor, TemporalType precision, TimeZone jdbcTimeZone) {
322+
if ( precision != TemporalType.TIME && DateTimeUtils.isBcEra( temporalAccessor ) ) {
323+
switch ( precision ) {
324+
case DATE:
325+
appender.appendSql( "to_date('" );
326+
appendAsDateWithEraPrefix( appender, temporalAccessor );
327+
appender.appendSql( "','BC YYYY-MM-DD')" );
328+
break;
329+
case TIMESTAMP:
330+
appender.appendSql( "to_timestamp('" );
331+
appendAsTimestampWithNanosAndEraPrefix( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
332+
appender.appendSql( "','BC YYYY-MM-DD HH:MI:SS.FF')" );
333+
break;
334+
default:
335+
throw new IllegalArgumentException();
336+
}
337+
}
338+
else {
339+
super.appendDateTimeLiteral( appender, temporalAccessor, precision, jdbcTimeZone );
340+
}
341+
}
342+
343+
@Override
344+
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
345+
if ( precision != TemporalType.TIME && DateTimeUtils.isBcEra( date ) ) {
346+
switch ( precision ) {
347+
case DATE:
348+
appender.appendSql( "to_date('" );
349+
appendAsDateWithEraPrefix( appender, date );
350+
appender.appendSql( "','BC YYYY-MM-DD')" );
351+
break;
352+
case TIMESTAMP:
353+
appender.appendSql( "to_timestamp('" );
354+
appendAsTimestampWithNanosAndEraPrefix( appender, date, jdbcTimeZone );
355+
appender.appendSql( "','BC YYYY-MM-DD HH:MI:SS.FF')" );
356+
break;
357+
default:
358+
throw new IllegalArgumentException();
359+
}
360+
}
361+
else {
362+
super.appendDateTimeLiteral( appender, date, precision, jdbcTimeZone );
363+
}
364+
}
365+
366+
@Override
367+
public void appendDateTimeLiteral(SqlAppender appender, Calendar calendar, TemporalType precision, TimeZone jdbcTimeZone) {
368+
if ( precision != TemporalType.TIME && DateTimeUtils.isBcEra( calendar ) ) {
369+
switch ( precision ) {
370+
case DATE:
371+
appender.appendSql( "to_date('" );
372+
appendAsDateWithEraPrefix( appender, calendar );
373+
appender.appendSql( "','BC YYYY-MM-DD')" );
374+
break;
375+
case TIMESTAMP:
376+
appender.appendSql( "to_timestamp('" );
377+
appendAsTimestampWithMillisAndEraPrefix( appender, calendar, jdbcTimeZone );
378+
appender.appendSql( "','BC YYYY-MM-DD HH:MI:SS.FF')" );
379+
break;
380+
default:
381+
throw new IllegalArgumentException();
382+
}
383+
}
384+
else {
385+
super.appendDateTimeLiteral( appender, calendar, precision, jdbcTimeZone );
386+
}
387+
}
388+
297389
/**
298390
* HSQLDB doesn't support the {@code generate_series} function or {@code lateral} recursive CTEs,
299391
* so it has to be emulated with a top level recursive CTE which requires an upper bound on the amount

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

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
import java.sql.ResultSet;
1010
import java.sql.SQLException;
1111
import java.sql.Types;
12-
import java.time.temporal.ChronoField;
1312
import java.time.temporal.TemporalAccessor;
13+
import java.util.Calendar;
14+
import java.util.Date;
1415
import java.util.List;
1516
import java.util.Locale;
1617
import java.util.TimeZone;
@@ -158,7 +159,11 @@
158159
import static org.hibernate.type.SqlTypes.TINYINT;
159160
import static org.hibernate.type.SqlTypes.VARBINARY;
160161
import static org.hibernate.type.SqlTypes.VARCHAR;
161-
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithNanos;
162+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDateWithoutYear0;
163+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime;
164+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTime;
165+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillisWithoutYear0;
166+
import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithNanosWithoutYear0;
162167

163168
/**
164169
* A {@linkplain Dialect SQL dialect} for Oracle 8i and above.
@@ -1469,27 +1474,80 @@ public String getReadLockString(String aliases, int timeout) {
14691474

14701475
@Override
14711476
public boolean supportsTemporalLiteralOffset() {
1472-
// Oracle *does* support offsets, but only
1473-
// in the ANSI syntax, not in the JDBC
1474-
// escape-based syntax, which we use in
1475-
// almost all circumstances (see below)
1476-
return false;
1477+
return true;
14771478
}
14781479

14791480
@Override
1480-
public void appendDateTimeLiteral(SqlAppender appender, TemporalAccessor temporalAccessor, TemporalType precision, TimeZone jdbcTimeZone) {
1481-
// we usually use the JDBC escape-based syntax
1482-
// because we want to let the JDBC driver handle
1483-
// TIME (a concept which does not exist in Oracle)
1484-
// but for the special case of timestamps with an
1485-
// offset we need to use the ANSI syntax
1486-
if ( precision == TemporalType.TIMESTAMP && temporalAccessor.isSupported( ChronoField.OFFSET_SECONDS ) ) {
1487-
appender.appendSql( "timestamp '" );
1488-
appendAsTimestampWithNanos( appender, temporalAccessor, true, jdbcTimeZone, false );
1489-
appender.appendSql( '\'' );
1481+
public void appendDateTimeLiteral(
1482+
SqlAppender appender,
1483+
TemporalAccessor temporalAccessor,
1484+
@SuppressWarnings("deprecation")
1485+
TemporalType precision,
1486+
TimeZone jdbcTimeZone) {
1487+
switch ( precision ) {
1488+
case DATE:
1489+
appender.appendSql( "date '" );
1490+
appendAsDateWithoutYear0( appender, temporalAccessor );
1491+
appender.appendSql( '\'' );
1492+
break;
1493+
case TIME:
1494+
appender.appendSql( "time '" );
1495+
appendAsTime( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone );
1496+
appender.appendSql( '\'' );
1497+
break;
1498+
case TIMESTAMP:
1499+
appender.appendSql( "timestamp '" );
1500+
appendAsTimestampWithNanosWithoutYear0( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone, false );
1501+
appender.appendSql( '\'' );
1502+
break;
1503+
default:
1504+
throw new IllegalArgumentException();
14901505
}
1491-
else {
1492-
super.appendDateTimeLiteral( appender, temporalAccessor, precision, jdbcTimeZone );
1506+
}
1507+
1508+
@Override
1509+
public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) {
1510+
switch ( precision ) {
1511+
case DATE:
1512+
appender.appendSql( "date '" );
1513+
appendAsDateWithoutYear0( appender, date );
1514+
appender.appendSql( '\'' );
1515+
break;
1516+
case TIME:
1517+
appender.appendSql( "time '" );
1518+
appendAsLocalTime( appender, date );
1519+
appender.appendSql( '\'' );
1520+
break;
1521+
case TIMESTAMP:
1522+
appender.appendSql( "timestamp '" );
1523+
appendAsTimestampWithNanosWithoutYear0( appender, date, jdbcTimeZone );
1524+
appender.appendSql( '\'' );
1525+
break;
1526+
default:
1527+
throw new IllegalArgumentException();
1528+
}
1529+
}
1530+
1531+
@Override
1532+
public void appendDateTimeLiteral(SqlAppender appender, Calendar calendar, TemporalType precision, TimeZone jdbcTimeZone) {
1533+
switch ( precision ) {
1534+
case DATE:
1535+
appender.appendSql( "date '" );
1536+
appendAsDateWithoutYear0( appender, calendar );
1537+
appender.appendSql( '\'' );
1538+
break;
1539+
case TIME:
1540+
appender.appendSql( "time '" );
1541+
appendAsLocalTime( appender, calendar );
1542+
appender.appendSql( '\'' );
1543+
break;
1544+
case TIMESTAMP:
1545+
appender.appendSql( "timestamp '" );
1546+
appendAsTimestampWithMillisWithoutYear0( appender, calendar, jdbcTimeZone );
1547+
appender.appendSql( '\'' );
1548+
break;
1549+
default:
1550+
throw new IllegalArgumentException();
14931551
}
14941552
}
14951553

0 commit comments

Comments
 (0)