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