misc javadoc and refactorings around TimeZoneStorage stuff
This commit is contained in:
parent
863dda5cf5
commit
e53b55583b
|
@ -7,16 +7,20 @@
|
|||
package org.hibernate;
|
||||
|
||||
/**
|
||||
* Describes the storage strategies understood by Hibernate.
|
||||
* Enumerates the possible storage strategies for offset or zoned datetimes.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
* @author Steve Ebersole
|
||||
* @author Andrea Boriero
|
||||
*
|
||||
* @see org.hibernate.annotations.TimeZoneStorageType
|
||||
* @see org.hibernate.dialect.TimeZoneSupport
|
||||
*/
|
||||
@Incubating
|
||||
public enum TimeZoneStorageStrategy {
|
||||
/**
|
||||
* Stores the time zone through the "with time zone" types which retain the information.
|
||||
* Stores the time zone via the {@code with time zone} SQL types which retain
|
||||
* the information.
|
||||
*/
|
||||
NATIVE,
|
||||
/**
|
||||
|
|
|
@ -16,10 +16,11 @@ import static java.lang.annotation.ElementType.FIELD;
|
|||
import static java.lang.annotation.ElementType.METHOD;
|
||||
|
||||
/**
|
||||
* Specifies the mapped column for storing the time zone information.
|
||||
* The annotation can be used in conjunction with the <code>TimeZoneStorageType.AUTO</code> and
|
||||
* <code>TimeZoneStorageType.COLUMN</code>. The column is simply ignored if <code>TimeZoneStorageType.AUTO</code>
|
||||
* is used and the database supports native time zone storage.
|
||||
* Specifies the mapped column for storing the time zone information,
|
||||
* for use in conjunction with {@link TimeZoneStorageType#COLUMN} or
|
||||
* {@link TimeZoneStorageType#AUTO}. The column is simply ignored if
|
||||
* {@code AUTO} is used and the database supports native time zone
|
||||
* storage.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
* @author Steve Ebersole
|
||||
|
|
|
@ -17,22 +17,27 @@ import static java.lang.annotation.ElementType.METHOD;
|
|||
|
||||
/**
|
||||
* Specifies how the time zone information of a persistent property or field should be persisted.
|
||||
* The <code>TimeZoneStorage</code> annotation may be used in conjunction with the <code>Basic</code> annotation, or in
|
||||
* conjunction with the <code>ElementCollection</code> annotation when the
|
||||
* element collection value is of basic type. If the <code>TimeZoneStorage</code> annotation is not
|
||||
* used, the <code>TimeZoneStorageType</code> value is assumed to be <code>NORMALIZED</code>.
|
||||
* This annotation may be used in conjunction with the {@link jakarta.persistence.Basic} annotation,
|
||||
* or in conjunction with the {@link jakarta.persistence.ElementCollection} annotation when the
|
||||
* element collection value is of basic type. If the {@code TimeZoneStorage} annotation is not used,
|
||||
* the {@link TimeZoneStorageType} has a default value determined by the dialect and by the
|
||||
* configuration property {@value org.hibernate.cfg.AvailableSettings#TIMEZONE_DEFAULT_STORAGE}.
|
||||
*
|
||||
* For example:
|
||||
* <pre>
|
||||
* Example:
|
||||
* {@code
|
||||
* @Entity public class Person {
|
||||
*
|
||||
* @Entity public class Person {
|
||||
* public OffsetDateTime getBirthDateTimeNormalized() {...}
|
||||
* @TimeZoneStorage(COLUMN)
|
||||
* @TimeZoneColumn(column = @Column(...))
|
||||
* public OffsetDateTime birthDate;
|
||||
*
|
||||
* @TimeZoneStorage
|
||||
* @TimeZoneColumn(column = @Column(...))
|
||||
* public OffsetDateTime getBirthDateTimeNativeOrColumn() {...}
|
||||
* ...
|
||||
* @TimeZoneStorage(NATIVE)
|
||||
* public OffsetDateTime registrationDate;
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
*}
|
||||
* </pre>
|
||||
*
|
||||
* @author Christian Beikov
|
||||
|
|
|
@ -11,19 +11,27 @@ import org.hibernate.dialect.Dialect;
|
|||
|
||||
/**
|
||||
* Describes the storage of timezone information for zoned datetime types.
|
||||
* <p>
|
||||
* A default {@code TimeZoneStorageType} may be configured explicitly using
|
||||
* {@value org.hibernate.cfg.AvailableSettings#TIMEZONE_DEFAULT_STORAGE}.
|
||||
* Otherwise, the storage type may be overridden for a given field or
|
||||
* property of an entity using the {@link TimeZoneStorage} annotation.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
* @author Steve Ebersole
|
||||
* @author Andrea Boriero
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @see TimeZoneStorage
|
||||
* @see org.hibernate.TimeZoneStorageStrategy
|
||||
*/
|
||||
@Incubating
|
||||
public enum TimeZoneStorageType {
|
||||
/**
|
||||
* Stores the timezone by using the {@code with time zone}
|
||||
* SQL column type.
|
||||
*
|
||||
* <p>
|
||||
* Error if {@link Dialect#getTimeZoneSupport()} is not
|
||||
* {@link org.hibernate.dialect.TimeZoneSupport#NATIVE}.
|
||||
*/
|
||||
|
@ -34,8 +42,11 @@ public enum TimeZoneStorageType {
|
|||
*/
|
||||
NORMALIZE,
|
||||
/**
|
||||
* Does not store the time zone, and instead normalizes
|
||||
* Does not preserve the time zone, and instead normalizes
|
||||
* timestamps to UTC.
|
||||
* <p>
|
||||
* The DDL column type depends on the setting
|
||||
* {@value org.hibernate.cfg.AvailableSettings#PREFERRED_INSTANT_JDBC_TYPE}.
|
||||
*/
|
||||
NORMALIZE_UTC,
|
||||
/**
|
||||
|
@ -59,5 +70,4 @@ public enum TimeZoneStorageType {
|
|||
* @since 6.2
|
||||
*/
|
||||
DEFAULT
|
||||
|
||||
}
|
||||
|
|
|
@ -63,19 +63,7 @@ public class VersionResolution<E> implements BasicValue.Resolution<E> {
|
|||
|
||||
@Override
|
||||
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
|
||||
if ( timeZoneStorageType != null ) {
|
||||
switch ( timeZoneStorageType ) {
|
||||
case COLUMN:
|
||||
return TimeZoneStorageStrategy.COLUMN;
|
||||
case NATIVE:
|
||||
return TimeZoneStorageStrategy.NATIVE;
|
||||
case NORMALIZE:
|
||||
return TimeZoneStorageStrategy.NORMALIZE;
|
||||
case NORMALIZE_UTC:
|
||||
return TimeZoneStorageStrategy.NORMALIZE_UTC;
|
||||
}
|
||||
}
|
||||
return context.getBuildingOptions().getDefaultTimeZoneStorage();
|
||||
return BasicValue.timeZoneStorageStrategy( timeZoneStorageType, context );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.boot.model.source.internal.hbm.HbmMetadataSourceProcessorIm
|
|||
import org.hibernate.boot.model.source.internal.hbm.MappingDocument;
|
||||
import org.hibernate.boot.model.source.internal.hbm.ModelBinder;
|
||||
import org.hibernate.boot.model.source.spi.MetadataSourceProcessor;
|
||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.spi.AdditionalJaxbMappingProducer;
|
||||
import org.hibernate.boot.spi.BootstrapContext;
|
||||
|
@ -42,7 +43,6 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.BasicTypeRegistry;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
|
@ -60,6 +60,11 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
import org.jboss.jandex.IndexView;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.internal.util.config.ConfigurationHelper.getPreferredSqlTypeCodeForArray;
|
||||
import static org.hibernate.internal.util.config.ConfigurationHelper.getPreferredSqlTypeCodeForDuration;
|
||||
import static org.hibernate.internal.util.config.ConfigurationHelper.getPreferredSqlTypeCodeForInstant;
|
||||
import static org.hibernate.internal.util.config.ConfigurationHelper.getPreferredSqlTypeCodeForUuid;
|
||||
|
||||
/**
|
||||
* Represents the process of of transforming a {@link MetadataSources}
|
||||
* reference into a {@link org.hibernate.boot.Metadata} reference. Allows for 2 different process paradigms:<ul>
|
||||
|
@ -379,15 +384,13 @@ public class MetadataBuildingProcess {
|
|||
final ClassLoaderService classLoaderService = options.getServiceRegistry().getService( ClassLoaderService.class );
|
||||
|
||||
final TypeConfiguration typeConfiguration = bootstrapContext.getTypeConfiguration();
|
||||
final StandardServiceRegistry serviceRegistry = bootstrapContext.getServiceRegistry();
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = typeConfiguration.getJdbcTypeRegistry();
|
||||
final TypeContributions typeContributions = () -> typeConfiguration;
|
||||
|
||||
// add Dialect contributed types
|
||||
final Dialect dialect = options.getServiceRegistry().getService( JdbcServices.class ).getDialect();
|
||||
dialect.contributeTypes( typeContributions, options.getServiceRegistry() );
|
||||
final JdbcType dialectUuidDescriptor = jdbcTypeRegistry.findDescriptor( SqlTypes.UUID );
|
||||
final JdbcType dialectArrayDescriptor = jdbcTypeRegistry.findDescriptor( SqlTypes.ARRAY );
|
||||
final JdbcType dialectIntervalDescriptor = jdbcTypeRegistry.findDescriptor( SqlTypes.INTERVAL_SECOND );
|
||||
|
||||
// add TypeContributor contributed types.
|
||||
for ( TypeContributor contributor : classLoaderService.loadJavaServices( TypeContributor.class ) ) {
|
||||
|
@ -395,51 +398,38 @@ public class MetadataBuildingProcess {
|
|||
}
|
||||
|
||||
// add fallback type descriptors
|
||||
final int preferredSqlTypeCodeForUuid = ConfigurationHelper.getPreferredSqlTypeCodeForUuid( bootstrapContext.getServiceRegistry() );
|
||||
final int preferredSqlTypeCodeForUuid = getPreferredSqlTypeCodeForUuid( serviceRegistry );
|
||||
if ( preferredSqlTypeCodeForUuid != SqlTypes.UUID ) {
|
||||
if ( jdbcTypeRegistry.findDescriptor( SqlTypes.UUID ) == dialectUuidDescriptor ) {
|
||||
jdbcTypeRegistry.addDescriptor(
|
||||
SqlTypes.UUID,
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForUuid )
|
||||
);
|
||||
}
|
||||
adaptToPreferredSqlTypeCode( jdbcTypeRegistry, SqlTypes.UUID, preferredSqlTypeCodeForUuid );
|
||||
}
|
||||
else {
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.UUID, SqlTypes.BINARY );
|
||||
}
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( JsonJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( XmlAsStringJdbcType.INSTANCE );
|
||||
|
||||
final int preferredSqlTypeCodeForArray = ConfigurationHelper.getPreferredSqlTypeCodeForArray( bootstrapContext.getServiceRegistry() );
|
||||
if ( preferredSqlTypeCodeForArray != SqlTypes.ARRAY ) {
|
||||
if ( jdbcTypeRegistry.findDescriptor( SqlTypes.ARRAY ) == dialectArrayDescriptor ) {
|
||||
jdbcTypeRegistry.addDescriptor(
|
||||
SqlTypes.ARRAY,
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForArray )
|
||||
);
|
||||
}
|
||||
final int preferredSqlTypeCodeForArray = getPreferredSqlTypeCodeForArray( serviceRegistry );
|
||||
if ( preferredSqlTypeCodeForArray == SqlTypes.ARRAY ) {
|
||||
adaptToPreferredSqlTypeCode( jdbcTypeRegistry, null, SqlTypes.ARRAY, SqlTypes.VARBINARY );
|
||||
}
|
||||
else if ( jdbcTypeRegistry.findDescriptor( SqlTypes.ARRAY ) == null ) {
|
||||
// Fallback to VARBINARY
|
||||
jdbcTypeRegistry.addDescriptor( SqlTypes.ARRAY, jdbcTypeRegistry.getDescriptor( SqlTypes.VARBINARY ) );
|
||||
else {
|
||||
adaptToPreferredSqlTypeCode( jdbcTypeRegistry, SqlTypes.ARRAY, preferredSqlTypeCodeForArray );
|
||||
}
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INET, SqlTypes.VARBINARY );
|
||||
final int preferredSqlTypeCodeForDuration = ConfigurationHelper.getPreferredSqlTypeCodeForDuration( bootstrapContext.getServiceRegistry() );
|
||||
|
||||
final int preferredSqlTypeCodeForDuration = getPreferredSqlTypeCodeForDuration( serviceRegistry );
|
||||
if ( preferredSqlTypeCodeForDuration != SqlTypes.INTERVAL_SECOND ) {
|
||||
if ( jdbcTypeRegistry.findDescriptor( SqlTypes.INTERVAL_SECOND ) == dialectIntervalDescriptor ) {
|
||||
jdbcTypeRegistry.addDescriptor(
|
||||
SqlTypes.INTERVAL_SECOND,
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForDuration )
|
||||
);
|
||||
}
|
||||
adaptToPreferredSqlTypeCode( jdbcTypeRegistry, SqlTypes.INTERVAL_SECOND, preferredSqlTypeCodeForDuration );
|
||||
}
|
||||
else {
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INTERVAL_SECOND, SqlTypes.NUMERIC );
|
||||
}
|
||||
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.INET, SqlTypes.VARBINARY );
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.GEOMETRY, SqlTypes.VARBINARY );
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.POINT, SqlTypes.VARBINARY );
|
||||
addFallbackIfNecessary( jdbcTypeRegistry, SqlTypes.GEOGRAPHY, SqlTypes.GEOMETRY );
|
||||
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( JsonJdbcType.INSTANCE );
|
||||
jdbcTypeRegistry.addDescriptorIfAbsent( XmlAsStringJdbcType.INSTANCE );
|
||||
|
||||
final DdlTypeRegistry ddlTypeRegistry = typeConfiguration.getDdlTypeRegistry();
|
||||
// Fallback to the biggest varchar DdlType when json is requested
|
||||
ddlTypeRegistry.addDescriptorIfAbsent(
|
||||
|
@ -471,61 +461,99 @@ public class MetadataBuildingProcess {
|
|||
// add explicit application registered types
|
||||
typeConfiguration.addBasicTypeRegistrationContributions( options.getBasicTypeRegistrations() );
|
||||
|
||||
final JdbcType timestampWithTimeZoneOverride;
|
||||
final JdbcType timestampWithTimeZoneOverride = getTimestampWithTimeZoneOverride( options, jdbcTypeRegistry );
|
||||
if ( timestampWithTimeZoneOverride != null ) {
|
||||
adaptToDefaultTimeZoneStorage( typeConfiguration, timestampWithTimeZoneOverride );
|
||||
}
|
||||
final int preferredSqlTypeCodeForInstant = getPreferredSqlTypeCodeForInstant(serviceRegistry);
|
||||
if ( preferredSqlTypeCodeForInstant != SqlTypes.TIMESTAMP_UTC ) {
|
||||
adaptToPreferredSqlTypeCodeForInstant( typeConfiguration, jdbcTypeRegistry, preferredSqlTypeCodeForInstant );
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptToPreferredSqlTypeCode(
|
||||
JdbcTypeRegistry jdbcTypeRegistry,
|
||||
int defaultSqlTypeCode,
|
||||
int preferredSqlTypeCode) {
|
||||
adaptToPreferredSqlTypeCode(
|
||||
jdbcTypeRegistry,
|
||||
jdbcTypeRegistry.findDescriptor( defaultSqlTypeCode ),
|
||||
defaultSqlTypeCode,
|
||||
preferredSqlTypeCode
|
||||
);
|
||||
}
|
||||
|
||||
private static void adaptToPreferredSqlTypeCode(
|
||||
JdbcTypeRegistry jdbcTypeRegistry,
|
||||
JdbcType dialectUuidDescriptor,
|
||||
int defaultSqlTypeCode,
|
||||
int preferredSqlTypeCode) {
|
||||
if ( jdbcTypeRegistry.findDescriptor( defaultSqlTypeCode ) == dialectUuidDescriptor ) {
|
||||
jdbcTypeRegistry.addDescriptor(
|
||||
defaultSqlTypeCode,
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCode )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void adaptToPreferredSqlTypeCodeForInstant(
|
||||
TypeConfiguration typeConfiguration,
|
||||
JdbcTypeRegistry jdbcTypeRegistry,
|
||||
int preferredSqlTypeCodeForInstant) {
|
||||
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
|
||||
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
|
||||
final BasicType<?> instantType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( Instant.class ),
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForInstant ),
|
||||
"instant"
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
instantType,
|
||||
"org.hibernate.type.InstantType",
|
||||
Instant.class.getSimpleName(),
|
||||
Instant.class.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private static void adaptToDefaultTimeZoneStorage(
|
||||
TypeConfiguration typeConfiguration,
|
||||
JdbcType timestampWithTimeZoneOverride) {
|
||||
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
|
||||
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
|
||||
final BasicType<?> offsetDateTimeType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( OffsetDateTime.class ),
|
||||
timestampWithTimeZoneOverride,
|
||||
"OffsetDateTime"
|
||||
);
|
||||
final BasicType<?> zonedDateTimeType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( ZonedDateTime.class ),
|
||||
timestampWithTimeZoneOverride,
|
||||
"ZonedDateTime"
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
offsetDateTimeType,
|
||||
"org.hibernate.type.OffsetDateTimeType",
|
||||
OffsetDateTime.class.getSimpleName(),
|
||||
OffsetDateTime.class.getName()
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
zonedDateTimeType,
|
||||
"org.hibernate.type.ZonedDateTimeType",
|
||||
ZonedDateTime.class.getSimpleName(),
|
||||
ZonedDateTime.class.getName()
|
||||
);
|
||||
}
|
||||
|
||||
private static JdbcType getTimestampWithTimeZoneOverride(MetadataBuildingOptions options, JdbcTypeRegistry jdbcTypeRegistry) {
|
||||
switch ( options.getDefaultTimeZoneStorage() ) {
|
||||
case NORMALIZE:
|
||||
// For NORMALIZE, we replace the standard types that use TIMESTAMP_WITH_TIMEZONE to use TIMESTAMP
|
||||
timestampWithTimeZoneOverride = jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP );
|
||||
break;
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP );
|
||||
case NORMALIZE_UTC:
|
||||
// For NORMALIZE_UTC, we replace the standard types that use TIMESTAMP_WITH_TIMEZONE to use TIMESTAMP_UTC
|
||||
timestampWithTimeZoneOverride = jdbcTypeRegistry.getDescriptor( SqlTypes.TIMESTAMP_UTC );
|
||||
break;
|
||||
return jdbcTypeRegistry.getDescriptor( SqlTypes.TIMESTAMP_UTC );
|
||||
default:
|
||||
timestampWithTimeZoneOverride = null;
|
||||
break;
|
||||
}
|
||||
if ( timestampWithTimeZoneOverride != null ) {
|
||||
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
|
||||
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
|
||||
final BasicType<?> offsetDateTimeType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( OffsetDateTime.class ),
|
||||
timestampWithTimeZoneOverride,
|
||||
"OffsetDateTime"
|
||||
);
|
||||
final BasicType<?> zonedDateTimeType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( ZonedDateTime.class ),
|
||||
timestampWithTimeZoneOverride,
|
||||
"ZonedDateTime"
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
offsetDateTimeType,
|
||||
"org.hibernate.type.OffsetDateTimeType",
|
||||
OffsetDateTime.class.getSimpleName(),
|
||||
OffsetDateTime.class.getName()
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
zonedDateTimeType,
|
||||
"org.hibernate.type.ZonedDateTimeType",
|
||||
ZonedDateTime.class.getSimpleName(),
|
||||
ZonedDateTime.class.getName()
|
||||
);
|
||||
}
|
||||
final int preferredSqlTypeCodeForInstant = ConfigurationHelper.getPreferredSqlTypeCodeForInstant( bootstrapContext.getServiceRegistry() );
|
||||
if ( preferredSqlTypeCodeForInstant != SqlTypes.TIMESTAMP_UTC ) {
|
||||
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
|
||||
final BasicTypeRegistry basicTypeRegistry = typeConfiguration.getBasicTypeRegistry();
|
||||
final BasicType<?> instantType = new NamedBasicTypeImpl<>(
|
||||
javaTypeRegistry.getDescriptor( Instant.class ),
|
||||
jdbcTypeRegistry.getDescriptor( preferredSqlTypeCodeForInstant ),
|
||||
"instant"
|
||||
);
|
||||
basicTypeRegistry.register(
|
||||
instantType,
|
||||
"org.hibernate.type.InstantType",
|
||||
Instant.class.getSimpleName(),
|
||||
Instant.class.getName()
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -179,19 +179,7 @@ public class BasicValueBinder implements JdbcTypeIndicators {
|
|||
}
|
||||
@Override
|
||||
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
|
||||
if ( timeZoneStorageType != null ) {
|
||||
switch ( timeZoneStorageType ) {
|
||||
case COLUMN:
|
||||
return TimeZoneStorageStrategy.COLUMN;
|
||||
case NATIVE:
|
||||
return TimeZoneStorageStrategy.NATIVE;
|
||||
case NORMALIZE:
|
||||
return TimeZoneStorageStrategy.NORMALIZE;
|
||||
case NORMALIZE_UTC:
|
||||
return TimeZoneStorageStrategy.NORMALIZE_UTC;
|
||||
}
|
||||
}
|
||||
return buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
|
||||
return BasicValue.timeZoneStorageStrategy( timeZoneStorageType, buildingContext );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.hibernate.sql.exec.spi.JdbcOperation;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An SQL dialect for DB2 for iSeries previously known as DB2/400.
|
||||
* An SQL dialect for DB2 for iSeries, previously known as "DB2/400".
|
||||
*
|
||||
* @author Peter DeGregorio (pdegregorio)
|
||||
* @author Christian Beikov
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.util.List;
|
|||
import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
|
||||
/**
|
||||
* An SQL dialect for DB2 for z/OS, previously known as known as Db2 UDB for z/OS and Db2 UDB for z/OS and OS/390.
|
||||
* A SQL dialect for DB2 for z/OS, previously known as "Db2 UDB for z/OS" and as "Db2 UDB for z/OS and OS/390".
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
|
|
|
@ -4152,7 +4152,7 @@ public abstract class Dialect implements ConversionContext {
|
|||
throw new IllegalArgumentException("scale has no meaning for floating point numbers");
|
||||
}
|
||||
// but if the user explicitly specifies a precision, we need to convert it:
|
||||
if (precision != null) {
|
||||
if ( precision != null ) {
|
||||
// convert from base 10 (as specified in @Column) to base 2 (as specified by SQL)
|
||||
// using the magic of high school math: log_2(10^n) = n*log_2(10) = n*ln(10)/ln(2)
|
||||
precision = (int) ceil( precision * LOG_BASE2OF10 );
|
||||
|
@ -4197,8 +4197,8 @@ public abstract class Dialect implements ConversionContext {
|
|||
* native datetime formatting function for this
|
||||
* database (often the {@code to_char()} function).
|
||||
* <p>
|
||||
* Since it's never possible to translate all of
|
||||
* the pattern letter sequences understood by
|
||||
* Since it's never possible to translate every
|
||||
* pattern letter sequences understood by
|
||||
* {@code DateTimeFormatter}, only the following
|
||||
* subset of pattern letters is accepted by
|
||||
* Hibernate:
|
||||
|
|
|
@ -9,22 +9,31 @@ package org.hibernate.dialect;
|
|||
import org.hibernate.Incubating;
|
||||
|
||||
/**
|
||||
* Describes the support for "with time zone" types.
|
||||
* Describes the extent to which a given database supports the SQL
|
||||
* {@code with time zone} types.
|
||||
* <p>
|
||||
* Really we only care about {@code timestamp with time zone} here,
|
||||
* since the type {@code time with time zone} is deeply conceptually
|
||||
* questionable, and so Hibernate eschews its use.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@Incubating
|
||||
public enum TimeZoneSupport {
|
||||
/**
|
||||
* The "with time zone" types retain the time zone information.
|
||||
* The {@code with time zone} types retain the time zone information.
|
||||
* That is, a round trip writing and reading a zoned datetime results
|
||||
* in the exact same zoned datetime with the same timezone.
|
||||
*/
|
||||
NATIVE,
|
||||
/**
|
||||
* The "with time zone" types normalize to UTC.
|
||||
* The {@code with time zone} types normalize to UTC. That is, a round
|
||||
* trip writing and reading a zoned datetime results in a datetime
|
||||
* representing the same instant, but in the timezone UTC.
|
||||
*/
|
||||
NORMALIZE,
|
||||
/**
|
||||
* No support for "with time zone" types.
|
||||
* No support for {@code with time zone} types.
|
||||
*/
|
||||
NONE;
|
||||
NONE
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ import java.util.Properties;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
import org.hibernate.annotations.TimeZoneStorageType;
|
||||
import org.hibernate.boot.model.TypeDefinition;
|
||||
import org.hibernate.boot.model.TypeDefinitionRegistry;
|
||||
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
|
||||
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
|
||||
import org.hibernate.boot.model.convert.spi.JpaAttributeConverterCreationContext;
|
||||
|
@ -700,6 +700,13 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
@Override
|
||||
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
|
||||
return timeZoneStorageStrategy( timeZoneStorageType, getBuildingContext() );
|
||||
}
|
||||
|
||||
@Internal
|
||||
public static TimeZoneStorageStrategy timeZoneStorageStrategy(
|
||||
TimeZoneStorageType timeZoneStorageType,
|
||||
MetadataBuildingContext buildingContext) {
|
||||
if ( timeZoneStorageType != null ) {
|
||||
switch ( timeZoneStorageType ) {
|
||||
case COLUMN:
|
||||
|
@ -712,7 +719,7 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return TimeZoneStorageStrategy.NORMALIZE_UTC;
|
||||
}
|
||||
}
|
||||
return getBuildingContext().getBuildingOptions().getDefaultTimeZoneStorage();
|
||||
return buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
@ -22,13 +20,13 @@ import jakarta.persistence.TemporalType;
|
|||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME;
|
||||
|
||||
/**
|
||||
* Java type descriptor for the {@link OffsetDateTime} type.
|
||||
*
|
||||
|
@ -52,44 +50,24 @@ public class OffsetDateTimeJavaType extends AbstractTemporalJavaType<OffsetDateT
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators stdIndicators) {
|
||||
final TemporalType temporalPrecision = stdIndicators.getTemporalPrecision();
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = stdIndicators.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( temporalPrecision == null || temporalPrecision == TemporalType.TIMESTAMP ) {
|
||||
switch ( stdIndicators.getDefaultTimeZoneStorageStrategy() ) {
|
||||
case NORMALIZE:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP );
|
||||
case NORMALIZE_UTC:
|
||||
return jdbcTypeRegistry.getDescriptor( SqlTypes.TIMESTAMP_UTC );
|
||||
default:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP_WITH_TIMEZONE );
|
||||
}
|
||||
}
|
||||
|
||||
switch ( temporalPrecision ) {
|
||||
case TIME:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIME );
|
||||
case DATE:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.DATE );
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unexpected jakarta.persistence.TemporalType : " + temporalPrecision );
|
||||
}
|
||||
return stdIndicators.getTypeConfiguration().getJdbcTypeRegistry()
|
||||
.getDescriptor( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <X> TemporalJavaType<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaType<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(OffsetDateTime value) {
|
||||
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format( value );
|
||||
return ISO_OFFSET_DATE_TIME.format( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public OffsetDateTime fromString(CharSequence string) {
|
||||
return OffsetDateTime.from( DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse( string ) );
|
||||
return OffsetDateTime.from( ISO_OFFSET_DATE_TIME.parse( string ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
package org.hibernate.type.descriptor.java;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
|
@ -23,13 +21,13 @@ import jakarta.persistence.TemporalType;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.ZonedDateTimeComparator;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import static java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME;
|
||||
|
||||
/**
|
||||
* Java type descriptor for the {@link ZonedDateTime} type.
|
||||
*
|
||||
|
@ -52,47 +50,24 @@ public class ZonedDateTimeJavaType extends AbstractTemporalJavaType<ZonedDateTim
|
|||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators stdIndicators) {
|
||||
final TemporalType temporalPrecision = stdIndicators.getTemporalPrecision();
|
||||
final JdbcTypeRegistry jdbcTypeRegistry = stdIndicators.getTypeConfiguration()
|
||||
.getJdbcTypeRegistry();
|
||||
if ( temporalPrecision == null || temporalPrecision == TemporalType.TIMESTAMP ) {
|
||||
switch ( stdIndicators.getDefaultTimeZoneStorageStrategy() ) {
|
||||
case NORMALIZE:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP );
|
||||
case NORMALIZE_UTC:
|
||||
return jdbcTypeRegistry.getDescriptor( SqlTypes.TIMESTAMP_UTC );
|
||||
default:
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP_WITH_TIMEZONE );
|
||||
}
|
||||
}
|
||||
|
||||
switch ( temporalPrecision ) {
|
||||
case TIME: {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.TIME );
|
||||
}
|
||||
case DATE: {
|
||||
return jdbcTypeRegistry.getDescriptor( Types.DATE );
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Unexpected jakarta.persistence.TemporalType : " + temporalPrecision );
|
||||
}
|
||||
}
|
||||
return stdIndicators.getTypeConfiguration().getJdbcTypeRegistry()
|
||||
.getDescriptor( stdIndicators.getDefaultZonedTimestampSqlType() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <X> TemporalJavaType<X> forTimestampPrecision(TypeConfiguration typeConfiguration) {
|
||||
//noinspection unchecked
|
||||
return (TemporalJavaType<X>) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(ZonedDateTime value) {
|
||||
return DateTimeFormatter.ISO_ZONED_DATE_TIME.format( value );
|
||||
return ISO_ZONED_DATE_TIME.format( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZonedDateTime fromString(CharSequence string) {
|
||||
return ZonedDateTime.from( DateTimeFormatter.ISO_ZONED_DATE_TIME.parse( string ) );
|
||||
return ZonedDateTime.from( ISO_ZONED_DATE_TIME.parse( string ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,11 +9,15 @@ package org.hibernate.type.descriptor.jdbc;
|
|||
import jakarta.persistence.EnumType;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.TimeZoneStorageStrategy;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* A parameter object that helps determine the {@link java.sql.Types SQL/JDBC type}
|
||||
* recommended by the JDBC spec (explicitly or implicitly) for a given Java type.
|
||||
|
@ -123,7 +127,7 @@ public interface JdbcTypeIndicators {
|
|||
|
||||
/**
|
||||
* Useful for resolutions based on column length.
|
||||
*
|
||||
* <p>
|
||||
* E.g. for choosing between a {@code VARCHAR} ({@code String}) and {@code CHAR(1)} ({@code Character}/{@code char}).
|
||||
*/
|
||||
default long getColumnLength() {
|
||||
|
@ -139,7 +143,7 @@ public interface JdbcTypeIndicators {
|
|||
|
||||
/**
|
||||
* Useful for resolutions based on column scale.
|
||||
*
|
||||
* <p>
|
||||
* E.g. for choosing between a {@code NUMERIC} and {@code INTERVAL SECOND}.
|
||||
*/
|
||||
default int getColumnScale() {
|
||||
|
@ -174,4 +178,50 @@ public interface JdbcTypeIndicators {
|
|||
private JdbcTypeIndicators getCurrentBaseSqlTypeIndicators() {
|
||||
return getTypeConfiguration().getCurrentBaseSqlTypeIndicators();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the SQL column type used for storing datetimes under the
|
||||
* given {@linkplain TimeZoneStorageStrategy storage strategy}
|
||||
*
|
||||
* @see SqlTypes#TIME_WITH_TIMEZONE
|
||||
* @see SqlTypes#TIMESTAMP
|
||||
* @see SqlTypes#TIMESTAMP_UTC
|
||||
*/
|
||||
static int getZonedTimestampSqlType(TimeZoneStorageStrategy storageStrategy) {
|
||||
switch ( storageStrategy ) {
|
||||
case NATIVE:
|
||||
return SqlTypes.TIMESTAMP_WITH_TIMEZONE;
|
||||
case COLUMN:
|
||||
case NORMALIZE:
|
||||
return SqlTypes.TIMESTAMP;
|
||||
case NORMALIZE_UTC:
|
||||
// sensitive to hibernate.type.preferred_instant_jdbc_type
|
||||
return SqlTypes.TIMESTAMP_UTC;
|
||||
default:
|
||||
throw new AssertionFailure( "unknown time zone storage strategy" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the SQL column type used for storing datetimes under the
|
||||
* default {@linkplain TimeZoneStorageStrategy storage strategy}
|
||||
*
|
||||
* @see SqlTypes#TIME_WITH_TIMEZONE
|
||||
* @see SqlTypes#TIMESTAMP
|
||||
* @see SqlTypes#TIMESTAMP_UTC
|
||||
*/
|
||||
default int getDefaultZonedTimestampSqlType() {
|
||||
final TemporalType temporalPrecision = getTemporalPrecision();
|
||||
switch ( temporalPrecision == null ? TemporalType.TIMESTAMP : temporalPrecision ) {
|
||||
case TIME:
|
||||
return Types.TIME;
|
||||
case DATE:
|
||||
return Types.DATE;
|
||||
case TIMESTAMP:
|
||||
// sensitive to hibernate.timezone.default_storage
|
||||
return getZonedTimestampSqlType( getDefaultTimeZoneStorageStrategy() );
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unexpected jakarta.persistence.TemporalType : " + temporalPrecision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -250,19 +250,19 @@ public class TypeConfiguration implements SessionFactoryObserver, Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* Understands the following target type names for the cast() function:
|
||||
*
|
||||
* - String
|
||||
* - Character
|
||||
* - Byte, Integer, Long
|
||||
* - Float, Double
|
||||
* - Time, Date, Timestamp
|
||||
* - LocalDate, LocalTime, LocalDateTime
|
||||
* - BigInteger
|
||||
* - BigDecimal
|
||||
* - Binary
|
||||
* - Boolean (fragile)
|
||||
*
|
||||
* Understands the following target type names for the {@code cast()} function:
|
||||
* <ul>
|
||||
* <li>String
|
||||
* <li>Character
|
||||
* <li>Byte, Integer, Long
|
||||
* <li>Float, Double
|
||||
* <li>Time, Date, Timestamp
|
||||
* <li>LocalDate, LocalTime, LocalDateTime
|
||||
* <li>BigInteger
|
||||
* <li>BigDecimal
|
||||
* <li>Binary
|
||||
* <li>Boolean (fragile)
|
||||
* </ul>
|
||||
* (The type names are not case-sensitive.)
|
||||
*/
|
||||
public BasicValuedMapping resolveCastTargetType(String name) {
|
||||
|
|
Loading…
Reference in New Issue