diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 9bd66824fa..93f8dbfc98 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -11,6 +11,11 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; +import java.time.ZonedDateTime; +import java.time.temporal.TemporalAccessor; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; @@ -104,6 +109,11 @@ import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE; import static org.hibernate.type.SqlTypes.TINYINT; import static org.hibernate.type.SqlTypes.VARBINARY; import static org.hibernate.type.SqlTypes.VARCHAR; +import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate; +import static org.hibernate.type.descriptor.DateTimeUtils.appendAsLocalTime; +import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMicros; +import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithMillis; +import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithNanos; /** * A {@linkplain Dialect SQL dialect} for MySQL 5.7 and above. @@ -765,6 +775,91 @@ public class MySQLDialect extends Dialect { } } + @Override + public boolean supportsTemporalLiteralOffset() { + return getMySQLVersion().isSameOrAfter(8,0,19); + } + + @Override + public void appendDateTimeLiteral( + SqlAppender appender, + TemporalAccessor temporalAccessor, + TemporalType precision, + TimeZone jdbcTimeZone) { + switch ( precision ) { + case DATE: + appender.appendSql( "date '" ); + appendAsDate( appender, temporalAccessor ); + appender.appendSql( '\'' ); + break; + case TIME: + appender.appendSql( "time '" ); + appendAsLocalTime( appender, temporalAccessor ); + appender.appendSql( '\'' ); + break; + case TIMESTAMP: + if ( temporalAccessor instanceof ZonedDateTime ) { + temporalAccessor = ((ZonedDateTime) temporalAccessor).toOffsetDateTime(); + } + appender.appendSql( "timestamp '" ); + appendAsTimestampWithMicros( appender, temporalAccessor, supportsTemporalLiteralOffset(), jdbcTimeZone, false ); + appender.appendSql( '\'' ); + break; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public void appendDateTimeLiteral(SqlAppender appender, Date date, TemporalType precision, TimeZone jdbcTimeZone) { + switch ( precision ) { + case DATE: + appender.appendSql( "date '" ); + appendAsDate( appender, date ); + appender.appendSql( '\'' ); + break; + case TIME: + appender.appendSql( "time '" ); + appendAsLocalTime( appender, date ); + appender.appendSql( '\'' ); + break; + case TIMESTAMP: + appender.appendSql( "timestamp '" ); + appendAsTimestampWithMicros( appender, date, jdbcTimeZone ); + appender.appendSql( '\'' ); + break; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public void appendDateTimeLiteral( + SqlAppender appender, + Calendar calendar, + TemporalType precision, + TimeZone jdbcTimeZone) { + switch ( precision ) { + case DATE: + appender.appendSql( "date '" ); + appendAsDate( appender, calendar ); + appender.appendSql( '\'' ); + break; + case TIME: + appender.appendSql( "time '" ); + appendAsLocalTime( appender, calendar ); + appender.appendSql( '\'' ); + break; + case TIMESTAMP: + appender.appendSql( "timestamp '" ); + appendAsTimestampWithMillis( appender, calendar, jdbcTimeZone ); + appender.appendSql( '\'' ); + break; + default: + throw new IllegalArgumentException(); + } + } + @Override public boolean supportsUnionAll() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/DateTimeUtils.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/DateTimeUtils.java index 8c7c35cb07..9882e55437 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/DateTimeUtils.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/DateTimeUtils.java @@ -47,6 +47,7 @@ public final class DateTimeUtils { public static final String FORMAT_STRING_TIMESTAMP_WITH_MILLIS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MILLIS + "XXX"; public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_MICROS + "XXX"; public static final String FORMAT_STRING_TIMESTAMP_WITH_NANOS_AND_OFFSET = FORMAT_STRING_TIMESTAMP_WITH_NANOS + "XXX"; + public static final String FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET_NOZ = FORMAT_STRING_TIMESTAMP_WITH_MICROS + "xxx"; public static final DateTimeFormatter DATE_TIME_FORMATTER_DATE = DateTimeFormatter.ofPattern( FORMAT_STRING_DATE, Locale.ENGLISH ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIME_WITH_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH ); @@ -71,6 +72,10 @@ public final class DateTimeUtils { FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET, Locale.ENGLISH ); + public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET_NOZ = DateTimeFormatter.ofPattern( + FORMAT_STRING_TIMESTAMP_WITH_MICROS_AND_OFFSET_NOZ, + Locale.ENGLISH + ); public static final DateTimeFormatter DATE_TIME_FORMATTER_TIMESTAMP_WITH_NANOS_AND_OFFSET = DateTimeFormatter.ofPattern( FORMAT_STRING_TIMESTAMP_WITH_NANOS_AND_OFFSET, Locale.ENGLISH @@ -99,15 +104,14 @@ public final class DateTimeUtils { .optionalStart().appendZoneOrOffsetId().optionalEnd() .toFormatter(); - private static final ThreadLocal LOCAL_DATE_FORMAT = ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_DATE, Locale.ENGLISH ) ); - private static final ThreadLocal LOCAL_TIME_FORMAT = ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH ) ); - private static final ThreadLocal TIME_WITH_OFFSET_FORMAT = ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH ) ); - private static final ThreadLocal TIMESTAMP_WITH_MILLIS_FORMAT = ThreadLocal.withInitial( - () -> new SimpleDateFormat( - FORMAT_STRING_TIMESTAMP_WITH_MILLIS, - Locale.ENGLISH - ) - ); + private static final ThreadLocal LOCAL_DATE_FORMAT = + ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_DATE, Locale.ENGLISH ) ); + private static final ThreadLocal LOCAL_TIME_FORMAT = + ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIME, Locale.ENGLISH ) ); + private static final ThreadLocal TIME_WITH_OFFSET_FORMAT = + ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIME_WITH_OFFSET, Locale.ENGLISH ) ); + private static final ThreadLocal TIMESTAMP_WITH_MILLIS_FORMAT = + ThreadLocal.withInitial( () -> new SimpleDateFormat( FORMAT_STRING_TIMESTAMP_WITH_MILLIS, Locale.ENGLISH ) ); /** * Pattern used for parsing literal offset datetimes in HQL. @@ -156,6 +160,24 @@ public final class DateTimeUtils { ); } + public static void appendAsTimestampWithMicros( + SqlAppender appender, + TemporalAccessor temporalAccessor, + boolean supportsOffset, + TimeZone jdbcTimeZone, + boolean allowZforZeroOffset) { + appendAsTimestamp( + appender, + temporalAccessor, + supportsOffset, + jdbcTimeZone, + DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS, + allowZforZeroOffset + ? DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET + : DATE_TIME_FORMATTER_TIMESTAMP_WITH_MICROS_AND_OFFSET_NOZ + ); + } + public static void appendAsTimestampWithMillis( SqlAppender appender, TemporalAccessor temporalAccessor,