Implement global configuration and sketch out annotations for time zone storage configuration. Move type tests and add skips for some tests running into H2 bugs. Also, fix some jdbc type assertion tests

This commit is contained in:
Christian Beikov 2021-10-07 12:19:32 +02:00
parent 597f4bdf6a
commit 548df627e6
80 changed files with 849 additions and 237 deletions

View File

@ -295,6 +295,20 @@ Assuming `hibernate.globally_quoted_identifiers` is `true`, this allows the glob
`*hibernate.auto_quote_keyword*` (e.g. `true` or `false` (default value))::
Specifies whether to automatically quote any names that are deemed keywords.
==== Time zone storage
`*hibernate.timezone.default_storage*` (e.g. `COLUMN`, `NATIVE`, `AUTO` or `NORMALIZE` (default value))::
Global setting for configuring the default storage for the time zone information for time zone based types.
+
`NORMALIZE`::: Does not store the time zone, and instead normalizes timestamps to UTC
`COLUMN`::: Stores the time zone in a separate column; works in conjunction with `@TimeZoneColumn`
`NATIVE`::: Stores the time zone by using the `with time zone` type. Error if `Dialect#getTimeZoneSupport()` is not `NATIVE`
`AUTO`::: Stores the time zone either with `NATIVE` if `Dialect#getTimeZoneSupport()` is `NATIVE`, otherwise uses the `COLUMN` strategy.
+
The default value is given by the {@link org.hibernate.annotations.TimeZoneStorageType#NORMALIZE},
meaning that time zone information is not stored by default, but timestamps are normalized instead.
+
See the discussion https://github.com/hibernate/hibernate-orm/discussions/4201[on GitHub] for additional background info.
==== Discriminator options
`*hibernate.discriminator.implicit_for_joined*` (e.g. `true` or `false` (default value))::
The legacy behavior of Hibernate is to not use discriminators for joined inheritance (Hibernate does not need the discriminator).

View File

@ -16,6 +16,7 @@ import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -41,6 +42,8 @@ public class BigDecimalMappingTests {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBigDecimals.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
@ -48,7 +51,7 @@ public class BigDecimalMappingTests {
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigDecimal.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.NUMERIC ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( Types.NUMERIC ) ) );
}

View File

@ -16,6 +16,7 @@ import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -41,6 +42,8 @@ public class BigIntegerMappingTests {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBigIntegers.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
@ -48,7 +51,7 @@ public class BigIntegerMappingTests {
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( BigInteger.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.NUMERIC ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( Types.NUMERIC ) ) );
}

View File

@ -16,6 +16,7 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -43,6 +44,8 @@ public class ByteMappingTests {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfBytes.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapper" );
@ -50,7 +53,7 @@ public class ByteMappingTests {
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.TINYINT ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( Types.TINYINT ) ) );
}
{
@ -59,7 +62,7 @@ public class ByteMappingTests {
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Byte.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), is( Types.TINYINT ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( Types.TINYINT ) ) );
}

View File

@ -19,6 +19,7 @@ import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
import org.hibernate.testing.orm.junit.DomainModel;
@ -29,6 +30,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* @see CharacterArrayMappingTests
@ -43,6 +45,8 @@ public class CharacterArrayNationalizedMappingTests {
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithCharArrays.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
@ -50,26 +54,26 @@ public class CharacterArrayNationalizedMappingTests {
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveNVarchar" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() ) ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperNVarchar" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() ) ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "primitiveNClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() ) ) );
}
{
final BasicAttributeMapping attributeMapping = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "wrapperNClob" );
final JdbcMapping jdbcMapping = attributeMapping.getJdbcMapping();
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() ) ) );
}
}

View File

@ -17,6 +17,7 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -25,6 +26,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* @author Steve Ebersole
@ -37,11 +39,13 @@ public class DurationMappingTests {
public void verifyMappings(SessionFactoryScope scope) {
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityWithDuration.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final BasicAttributeMapping duration = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "duration" );
final JdbcMapping jdbcMapping = duration.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( Duration.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( Types.NUMERIC ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( Types.NUMERIC ) ) );
scope.inTransaction(
(session) -> {

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.userguide.mapping.basic;
import java.sql.Types;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Lob;
@ -18,6 +20,7 @@ import org.hibernate.metamodel.MappingMetamodel;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
@ -27,6 +30,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
/**
* Tests for mapping `double` values
@ -42,6 +46,8 @@ public class StringNationalizedMappingTests {
// first, verify the type selections...
final MappingMetamodel domainModel = scope.getSessionFactory().getDomainModel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( EntityOfStrings.class );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final Dialect dialect = scope.getSessionFactory().getJdbcServices().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
@ -50,14 +56,14 @@ public class StringNationalizedMappingTests {
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "nstring" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getVarcharVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() ) ) );
}
{
final BasicAttributeMapping attribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "nclobString" );
final JdbcMapping jdbcMapping = attribute.getJdbcMapping();
assertThat( jdbcMapping.getJavaTypeDescriptor().getJavaTypeClass(), equalTo( String.class ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor().getJdbcTypeCode(), equalTo( nationalizationSupport.getClobVariantCode() ) );
assertThat( jdbcMapping.getJdbcTypeDescriptor(), is( jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() ) ) );
}

View File

@ -10,6 +10,7 @@ import org.hibernate.HibernateException;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.community.dialect.identity.CUBRIDIdentityColumnSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
@ -372,8 +373,8 @@ public class CUBRIDDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NATIVE;
}
@Override

View File

@ -10,6 +10,7 @@ import org.hibernate.HibernateException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.dialect.BooleanDecoder;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.query.NullOrdering;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.function.CommonFunctionFactory;
@ -57,11 +58,9 @@ import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.temporal.TemporalAccessor;
import java.util.Arrays;
@ -170,8 +169,8 @@ public class FirebirdDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return getVersion() >= 400;
public TimeZoneSupport getTimeZoneSupport() {
return getVersion() >= 400 ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;
}
@Override
@ -315,7 +314,7 @@ public class FirebirdDialect extends Dialect {
@Override
public String currentLocalTime() {
if ( supportsTimezoneTypes() ) {
if ( getTimeZoneSupport() == TimeZoneSupport.NATIVE ) {
return "localtime";
}
else {
@ -325,7 +324,7 @@ public class FirebirdDialect extends Dialect {
@Override
public String currentLocalTimestamp() {
if ( supportsTimezoneTypes() ) {
if ( getTimeZoneSupport() == TimeZoneSupport.NATIVE ) {
return "localtimestamp";
}
else {

View File

@ -9,6 +9,7 @@ package org.hibernate.community.dialect;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.function.CommonFunctionFactory;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.community.dialect.identity.Ingres10IdentityColumnSupport;
@ -318,8 +319,8 @@ public class IngresDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NATIVE;
}
@Override

View File

@ -10,6 +10,7 @@ package org.hibernate.community.dialect;
import org.hibernate.LockOptions;
import org.hibernate.dialect.RowLockStrategy;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.community.dialect.identity.SybaseAnywhereIdentityColumnSupport;
import org.hibernate.dialect.pagination.LimitHandler;
@ -80,8 +81,8 @@ public class SybaseAnywhereDialect extends SybaseDialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NATIVE;
}
@Override

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate;
/**
* Describes the storage strategies understood by Hibernate.
*
* @author Christian Beikov
* @author Steve Ebersole
* @author Andrea Boriero
*/
@Incubating
public enum TimeZoneStorageStrategy {
/**
* Stores the time zone through the "with time zone" types which retain the information.
*/
NATIVE,
/**
* Stores the time zone in a separate column.
*/
COLUMN,
/**
* Doesn't store the time zone, but instead normalizes to UTC.
*/
NORMALIZE;
}

View File

@ -0,0 +1,48 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hibernate.Incubating;
import jakarta.persistence.Column;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
/**
* Specifies the column name and type to use 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.
*
* @author Christian Beikov
* @author Steve Ebersole
* @author Andrea Boriero
* @see TimeZoneStorage
* @see TimeZoneStorageType#COLUMN
* @see TimeZoneStorageType#AUTO
*/
@Incubating
@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD })
public @interface TimeZoneColumn {
/**
* The column for the time zone information.
*/
Column column();
/**
* The storage type for the time zone information.
*/
TimeZoneType type() default TimeZoneType.OFFSET;
}

View File

@ -0,0 +1,51 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hibernate.Incubating;
import static java.lang.annotation.ElementType.FIELD;
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>.
*
* <pre>
* Example:
*
* &#064;Entity public class Person {
* public OffsetDateTime getBirthDateTimeNormalized() {...}
*
* &#064;TimeZoneStorage
* &#064;TimeZoneColumn(column = &#064;Column(...))
* public OffsetDateTime getBirthDateTimeNativeOrColumn() {...}
* ...
* }
* </pre>
*
* @author Christian Beikov
* @author Steve Ebersole
* @author Andrea Boriero
* @see TimeZoneColumn
*/
@Incubating
@Retention(RetentionPolicy.RUNTIME)
@Target({ FIELD, METHOD })
public @interface TimeZoneStorage {
/**
* The storage strategy for the time zone information.
*/
TimeZoneStorageType value() default TimeZoneStorageType.AUTO;
}

View File

@ -0,0 +1,38 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.annotations;
import org.hibernate.Incubating;
import org.hibernate.dialect.Dialect;
/**
* Describes the storage for the time zone information for time zone based types.
*
* @author Christian Beikov
* @author Steve Ebersole
* @author Andrea Boriero
*/
@Incubating
public enum TimeZoneStorageType {
/**
* Stores the time zone by using the "with time zone" type. Error if {@link Dialect#getTimeZoneSupport()} is not {@link org.hibernate.dialect.TimeZoneSupport#NATIVE}.
*/
NATIVE,
/**
* Does not store the time zone, and instead normalizes timestamps to UTC.
*/
NORMALIZE,
/**
* Stores the time zone in a separate column; works in conjunction with {@link TimeZoneColumn}.
*/
COLUMN,
/**
* Stores the time zone either with {@link #NATIVE} if {@link Dialect#getTimeZoneSupport()} is {@link org.hibernate.dialect.TimeZoneSupport#NATIVE}, otherwise uses the {@link #COLUMN} strategy.
*/
AUTO
}

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.annotations;
import org.hibernate.Incubating;
/**
* The type of storage to use for the time zone information.
*
* @author Christian Beikov
* @author Steve Ebersole
* @author Andrea Boriero
*/
@Incubating
public enum TimeZoneType {
/**
* Stores the time zone id as String.
*/
ZONE_ID,
/**
* Stores the offset seconds of a timestamp as Integer.
*/
OFFSET;
}

View File

@ -17,11 +17,6 @@ public class NoJdbcTypeDescriptor implements JdbcTypeDescriptor {
throw new UnsupportedOperationException();
}
@Override
public boolean canBeRemapped() {
throw new UnsupportedOperationException();
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
throw new UnsupportedOperationException();

View File

@ -16,7 +16,9 @@ import jakarta.persistence.SharedCacheMode;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.TimeZoneStorageType;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.MetadataBuilder;
@ -58,8 +60,10 @@ import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.dialect.TimeZoneSupport;
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.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.log.DeprecationLogger;
@ -533,6 +537,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
implements MetadataBuildingOptions, JpaOrmXmlPersistenceUnitDefaultAware {
private final StandardServiceRegistry serviceRegistry;
private final MappingDefaultsImpl mappingDefaults;
private final TimeZoneStorageStrategy defaultTimezoneStorage;
// todo (6.0) : remove bootstrapContext property along with the deprecated methods
private BootstrapContext bootstrapContext;
@ -565,6 +570,7 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
this.mappingDefaults = new MappingDefaultsImpl( serviceRegistry );
this.defaultTimezoneStorage = resolveTimeZoneStorageStrategy( serviceRegistry, configService );
this.multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configService.getSettings() );
this.xmlMappingEnabled = configService.getSetting(
@ -744,6 +750,11 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
return mappingDefaults;
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorage() {
return defaultTimezoneStorage;
}
@Override
public List<BasicTypeRegistration> getBasicTypeRegistrations() {
return basicTypeRegistrations;
@ -896,4 +907,54 @@ public class MetadataBuilderImpl implements MetadataBuilderImplementor, TypeCont
this.bootstrapContext = bootstrapContext;
}
}
private static TimeZoneStorageStrategy resolveTimeZoneStorageStrategy(
StandardServiceRegistry serviceRegistry,
ConfigurationService configService) {
final TimeZoneStorageType configuredTimeZoneStorageType = configService.getSetting(
AvailableSettings.TIMEZONE_DEFAULT_STORAGE,
TimeZoneStorageType.class,
null
);
final TimeZoneStorageStrategy resolvedTimezoneStorage;
// For now, we default to NORMALIZE as that is the Hibernate 5.x behavior
if ( configuredTimeZoneStorageType == null ) {
resolvedTimezoneStorage = TimeZoneStorageStrategy.NORMALIZE;
}
else {
final TimeZoneSupport timeZoneSupport = serviceRegistry.getService( JdbcServices.class )
.getDialect()
.getTimeZoneSupport();
switch ( configuredTimeZoneStorageType ) {
case NATIVE:
if ( timeZoneSupport != TimeZoneSupport.NATIVE ) {
throw new HibernateException( "The configured time zone storage type NATIVE is not supported with the configured dialect" );
}
resolvedTimezoneStorage = TimeZoneStorageStrategy.NATIVE;
break;
case COLUMN:
resolvedTimezoneStorage = TimeZoneStorageStrategy.COLUMN;
break;
case NORMALIZE:
resolvedTimezoneStorage = TimeZoneStorageStrategy.NORMALIZE;
break;
case AUTO:
switch ( timeZoneSupport ) {
case NATIVE:
resolvedTimezoneStorage = TimeZoneStorageStrategy.NATIVE;
break;
case NORMALIZE:
case NONE:
resolvedTimezoneStorage = TimeZoneStorageStrategy.COLUMN;
break;
default:
throw new HibernateException( "Unsupported time zone support: " + timeZoneSupport );
}
break;
default:
throw new HibernateException( "Unsupported time zone storage type: " + configuredTimeZoneStorageType );
}
}
return resolvedTimezoneStorage;
}
}

View File

@ -27,6 +27,7 @@ import org.hibernate.Interceptor;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.SessionEventListener;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.SchemaAutoTooling;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.registry.StandardServiceRegistry;
@ -219,6 +220,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
private boolean conventionalJavaConstants;
private final boolean omitJoinOfSuperclassTablesEnabled;
private final int preferredSqlTypeCodeForBoolean;
private final TimeZoneStorageStrategy defaultTimeZoneStorageStrategy;
// Caching
private boolean secondLevelCacheEnabled;
@ -422,6 +424,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
CONVENTIONAL_JAVA_CONSTANTS, BOOLEAN, true );
this.omitJoinOfSuperclassTablesEnabled = cfgService.getSetting( OMIT_JOIN_OF_SUPERCLASS_TABLES, BOOLEAN, true );
this.preferredSqlTypeCodeForBoolean = ConfigurationHelper.getPreferredSqlTypeCodeForBoolean( serviceRegistry );
this.defaultTimeZoneStorageStrategy = context.getMetadataBuildingOptions().getDefaultTimeZoneStorage();
final RegionFactory regionFactory = serviceRegistry.getService( RegionFactory.class );
if ( !NoCachingRegionFactory.class.isInstance( regionFactory ) ) {
@ -1182,6 +1185,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
public int getPreferredSqlTypeCodeForBoolean() {
return preferredSqlTypeCodeForBoolean;
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return defaultTimeZoneStorageStrategy;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// In-flight mutation access

View File

@ -9,6 +9,7 @@ package org.hibernate.boot.model.process.internal;
import java.util.function.Function;
import jakarta.persistence.TemporalType;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.mapping.BasicValue;
import org.hibernate.metamodel.mapping.JdbcMapping;
@ -57,6 +58,11 @@ public class VersionResolution<E> implements BasicValue.Resolution<E> {
// if it is a temporal version, it needs to be a TIMESTAMP
return TemporalType.TIMESTAMP;
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return context.getBuildingOptions().getDefaultTimeZoneStorage();
}
}
);

View File

@ -6,11 +6,15 @@
*/
package org.hibernate.boot.model.process.spi;
import java.sql.Types;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.internal.InFlightMetadataCollectorImpl;
import org.hibernate.boot.internal.MetadataBuildingContextRootImpl;
@ -42,9 +46,10 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeRegistry;
import org.hibernate.type.CustomType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.internal.NamedBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.UserType;
@ -420,5 +425,37 @@ public class MetadataBuildingProcess {
// add explicit application registered types
bootstrapContext.getTypeConfiguration()
.addBasicTypeRegistrationContributions( options.getBasicTypeRegistrations() );
// For NORMALIZE, we replace the standard types that use TIMESTAMP_WITH_TIMEZONE to use TIMESTAMP
if ( options.getDefaultTimeZoneStorage() == TimeZoneStorageStrategy.NORMALIZE ) {
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = bootstrapContext.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final JavaTypeDescriptorRegistry javaTypeRegistry = bootstrapContext.getTypeConfiguration()
.getJavaTypeDescriptorRegistry();
final JdbcTypeDescriptor timestampDescriptor = jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP );
final BasicTypeRegistry basicTypeRegistry = bootstrapContext.getTypeConfiguration().getBasicTypeRegistry();
final BasicType<?> offsetDateTimeType = new NamedBasicTypeImpl<>(
javaTypeRegistry.getDescriptor( OffsetDateTime.class ),
timestampDescriptor,
"OffsetDateTime"
);
final BasicType<?> zonedDateTimeType = new NamedBasicTypeImpl<>(
javaTypeRegistry.getDescriptor( ZonedDateTime.class ),
timestampDescriptor,
"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()
);
}
}
}

View File

@ -11,6 +11,7 @@ import jakarta.persistence.SharedCacheMode;
import org.hibernate.HibernateException;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
@ -55,6 +56,11 @@ public abstract class AbstractDelegatingMetadataBuildingOptions implements Metad
return delegate.getMappingDefaults();
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorage() {
return delegate.getDefaultTimeZoneStorage();
}
@Override
public List<BasicTypeRegistration> getBasicTypeRegistrations() {
return delegate.getBasicTypeRegistrations();

View File

@ -17,6 +17,7 @@ import org.hibernate.EntityNameResolver;
import org.hibernate.Interceptor;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.SchemaAutoTooling;
import org.hibernate.boot.TempTableDdlTransactionHandling;
import org.hibernate.boot.registry.StandardServiceRegistry;
@ -468,4 +469,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
public int getPreferredSqlTypeCodeForBoolean() {
return delegate.getPreferredSqlTypeCodeForBoolean();
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return delegate.getDefaultTimeZoneStorageStrategy();
}
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import jakarta.persistence.SharedCacheMode;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.boot.CacheRegionDefinition;
import org.hibernate.boot.archive.scan.spi.ScanEnvironment;
@ -52,6 +53,8 @@ public interface MetadataBuildingOptions {
*/
MappingDefaults getMappingDefaults();
TimeZoneStorageStrategy getDefaultTimeZoneStorage();
default ManagedTypeRepresentationResolver getManagedTypeRepresentationResolver() {
// for now always return the standard one
return ManagedTypeRepresentationResolverStandard.INSTANCE;

View File

@ -17,6 +17,7 @@ import org.hibernate.EntityNameResolver;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.MultiTenancyStrategy;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.query.NullPrecedence;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.SchemaAutoTooling;
@ -348,4 +349,6 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
boolean isOmitJoinOfSuperclassTablesEnabled();
int getPreferredSqlTypeCodeForBoolean();
TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy();
}

View File

@ -2383,7 +2383,6 @@ public interface AvailableSettings {
*/
String OMIT_JOIN_OF_SUPERCLASS_TABLES = "hibernate.query.omit_join_of_superclass_tables";
/**
* Global setting identifying the preferred JDBC type code for storing
* boolean values. The fallback is to ask the Dialect
@ -2392,6 +2391,21 @@ public interface AvailableSettings {
*/
String PREFERRED_BOOLEAN_JDBC_TYPE_CODE = "hibernate.type.perferred_boolean_jdbc_type_code";
/**
* Global setting for configuring the default storage for the time zone information for time zone based types.
* </p>
* Possible values are {@link org.hibernate.annotations.TimeZoneStorageType#NORMALIZE},
* {@link org.hibernate.annotations.TimeZoneStorageType#COLUMN},
* {@link org.hibernate.annotations.TimeZoneStorageType#NATIVE}
* and {@link org.hibernate.annotations.TimeZoneStorageType#AUTO}.
* </p>
* The default value is given by the {@link org.hibernate.annotations.TimeZoneStorageType#NORMALIZE},
* meaning that time zone information is not stored by default, but timestamps are normalized instead.
*
* @since 6.0
*/
String TIMEZONE_DEFAULT_STORAGE = "hibernate.timezone.default_storage";
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Java (javax) Persistence defined settings
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -17,6 +17,7 @@ import java.util.function.Function;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.MappingException;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.AnyDiscriminator;
import org.hibernate.annotations.AnyKeyJavaClass;
import org.hibernate.annotations.AnyKeyJavaType;
@ -190,6 +191,10 @@ public class BasicValueBinder<T> implements JdbcTypeDescriptorIndicators {
public TypeConfiguration getTypeConfiguration() {
return buildingContext.getBootstrapContext().getTypeConfiguration();
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -141,8 +141,8 @@ public class CockroachDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NORMALIZE;
}
@Override

View File

@ -54,8 +54,8 @@ public class DB2zDialect extends DB2Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return getZVersion() > 1000;
public TimeZoneSupport getTimeZoneSupport() {
return getZVersion() > 1000 ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;
}
int getZVersion() {

View File

@ -3726,10 +3726,10 @@ public abstract class Dialect implements ConversionContext {
}
/**
* Whether the Dialect supports timezone types like {@link Types#TIMESTAMP_WITH_TIMEZONE}.
* How the Dialect supports time zone types like {@link Types#TIMESTAMP_WITH_TIMEZONE}.
*/
public boolean supportsTimezoneTypes() {
return false;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NONE;
}
/**

View File

@ -52,6 +52,7 @@ import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorH2
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl;
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
import org.jboss.logging.Logger;
import static org.hibernate.query.TemporalUnit.SECOND;
@ -147,6 +148,11 @@ public class H2Dialect extends Dialect {
);
}
public boolean hasDstBug() {
// H2 1.4.200 has a bug: https://github.com/h2database/h2database/issues/3184
return getVersion() == 104200;
}
@Override
public int getVersion() {
return version;
@ -265,8 +271,8 @@ public class H2Dialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NATIVE;
}
@Override

View File

@ -567,8 +567,8 @@ public class OracleDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return getVersion() >= 900;
public TimeZoneSupport getTimeZoneSupport() {
return getVersion() >= 900 ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;
}
protected void registerBinaryTypeMappings() {

View File

@ -69,7 +69,6 @@ import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.BlobJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ClobJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsBinaryTypeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
@ -287,8 +286,8 @@ public class PostgreSQLDialect extends Dialect {
}
@Override
public boolean supportsTimezoneTypes() {
return true;
public TimeZoneSupport getTimeZoneSupport() {
return TimeZoneSupport.NORMALIZE;
}
@Override

View File

@ -149,8 +149,8 @@ public class SQLServerDialect extends AbstractTransactSQLDialect {
}
@Override
public boolean supportsTimezoneTypes() {
return getVersion() >= 10;
public TimeZoneSupport getTimeZoneSupport() {
return getVersion() >= 10 ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE;
}
@Override

View File

@ -45,7 +45,6 @@ import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.ObjectNullAsNullTypeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.SmallIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import java.sql.DatabaseMetaData;
@ -172,9 +171,10 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
// The jTDS driver doesn't support the JDBC4 signatures using 'long length' for stream bindings
jdbcTypeRegistry.addDescriptor( Types.CLOB, ClobJdbcTypeDescriptor.CLOB_BINDING );
jdbcTypeRegistry.addDescriptor( Types.NCLOB, NClobJdbcTypeDescriptor.NCLOB_BINDING );
// The jTDS driver doesn't support the JDBC4 setNString method
jdbcTypeRegistry.addDescriptor( Types.NVARCHAR, NClobJdbcTypeDescriptor.NCLOB_BINDING );
// The jTDS driver doesn't support nationalized types
jdbcTypeRegistry.addDescriptor( Types.NCLOB, ClobJdbcTypeDescriptor.CLOB_BINDING );
jdbcTypeRegistry.addDescriptor( Types.NVARCHAR, ClobJdbcTypeDescriptor.CLOB_BINDING );
}
else {
// Some Sybase drivers cannot support getClob. See HHH-7889

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.Incubating;
/**
* Describes the support for "with time zone" types.
*
* @author Christian Beikov
*/
@Incubating
public enum TimeZoneSupport {
/**
* The "with time zone" types retain the time zone information.
*/
NATIVE,
/**
* The "with time zone" types normalize to UTC.
*/
NORMALIZE,
/**
* No support for "with time zone" types.
*/
NONE;
}

View File

@ -17,6 +17,7 @@ import jakarta.persistence.PessimisticLockScope;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockOptions;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
@ -66,7 +67,6 @@ import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.LockOptionsHelper;
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JAKARTA_LOCK_TIMEOUT;
@ -147,6 +147,7 @@ public final class FastSessionServices {
final boolean disallowOutOfTransactionUpdateOperations;
final boolean useStreamForLobBinding;
final int preferredSqlTypeCodeForBoolean;
final TimeZoneStorageStrategy defaultTimeZoneStorageStrategy;
final boolean requiresMultiTenantConnectionProvider;
final ConnectionProvider connectionProvider;
final MultiTenantConnectionProvider multiTenantConnectionProvider;
@ -216,6 +217,7 @@ public final class FastSessionServices {
this.disallowOutOfTransactionUpdateOperations = !sessionFactoryOptions.isAllowOutOfTransactionUpdateOperations();
this.useStreamForLobBinding = Environment.useStreamsForBinary() || dialect.useInputStreamToInsertBlob();
this.preferredSqlTypeCodeForBoolean = sessionFactoryOptions.getPreferredSqlTypeCodeForBoolean();
this.defaultTimeZoneStorageStrategy = sessionFactoryOptions.getDefaultTimeZoneStorageStrategy();
this.requiresMultiTenantConnectionProvider = sf.getSettings().getMultiTenancyStrategy().requiresMultiTenantConnectionProvider();
//Some "hot" services:
@ -361,4 +363,8 @@ public final class FastSessionServices {
public int getPreferredSqlTypeCodeForBoolean() {
return preferredSqlTypeCodeForBoolean;
}
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return defaultTimeZoneStorageStrategy;
}
}

View File

@ -12,6 +12,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import org.hibernate.MappingException;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.boot.model.TypeDefinition;
import org.hibernate.boot.model.TypeDefinitionRegistry;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
@ -68,7 +69,6 @@ public class BasicValue extends SimpleValue implements JdbcTypeDescriptorIndicat
private static final CoreMessageLogger log = CoreLogging.messageLogger( BasicValue.class );
private final TypeConfiguration typeConfiguration;
private final int preferredJdbcTypeCodeForBoolean;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// incoming "configuration" values
@ -102,7 +102,6 @@ public class BasicValue extends SimpleValue implements JdbcTypeDescriptorIndicat
super( buildingContext, table );
this.typeConfiguration = buildingContext.getBootstrapContext().getTypeConfiguration();
this.preferredJdbcTypeCodeForBoolean = buildingContext.getPreferredSqlTypeCodeForBoolean();
buildingContext.getMetadataCollector().registerValueMappingResolver( this::resolve );
}
@ -600,7 +599,12 @@ public class BasicValue extends SimpleValue implements JdbcTypeDescriptorIndicat
@Override
public int getPreferredSqlTypeCodeForBoolean() {
return preferredJdbcTypeCodeForBoolean;
return getBuildingContext().getPreferredSqlTypeCodeForBoolean();
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return getBuildingContext().getBuildingOptions().getDefaultTimeZoneStorage();
}
@Override

View File

@ -20,6 +20,7 @@ import jakarta.persistence.AttributeConverter;
import org.hibernate.FetchMode;
import org.hibernate.MappingException;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor;
import org.hibernate.boot.model.convert.spi.ConverterDescriptor;
@ -33,7 +34,6 @@ import org.hibernate.cfg.AvailableSettings;
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.engine.spi.Mapping;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.IdentityGenerator;
@ -53,6 +53,7 @@ import org.hibernate.type.descriptor.converter.AttributeConverterJdbcTypeDescrip
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter;
import org.hibernate.type.descriptor.java.BasicJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.LobTypeMappings;
import org.hibernate.type.descriptor.jdbc.NationalizedTypeMappings;
import org.hibernate.type.spi.TypeConfiguration;
@ -668,7 +669,17 @@ public abstract class SimpleValue implements KeyValue {
// VARCHAR/CHAR
final JdbcTypeDescriptor recommendedJdbcType = jpaAttributeConverter.getRelationalJavaTypeDescriptor().getRecommendedJdbcType(
// todo (6.0) : handle the other JdbcRecommendedSqlTypeMappingContext methods
metadata::getTypeConfiguration
new JdbcTypeDescriptorIndicators() {
@Override
public TypeConfiguration getTypeConfiguration() {
return metadata.getTypeConfiguration();
}
@Override
public TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return buildingContext.getBuildingOptions().getDefaultTimeZoneStorage();
}
}
);
int jdbcTypeCode = recommendedJdbcType.getJdbcTypeCode();
if ( isLob() ) {

View File

@ -388,7 +388,8 @@ public final class StandardBasicTypes {
);
/**
* The standard Hibernate type for mapping {@link OffsetDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}.
* The standard Hibernate type for mapping {@link OffsetDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}
* or {@link java.sql.Types#TIMESTAMP TIMESTAMP} depending on the {@link org.hibernate.cfg.AvailableSettings#TIMEZONE_DEFAULT_STORAGE} setting.
*/
public static final BasicTypeReference<OffsetDateTime> OFFSET_DATE_TIME = new BasicTypeReference<>(
"OffsetDateTime",
@ -396,18 +397,36 @@ public final class StandardBasicTypes {
Types.TIMESTAMP_WITH_TIMEZONE
);
/**
* The standard Hibernate type for mapping {@link OffsetDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}.
*/
public static final BasicTypeReference<OffsetDateTime> OFFSET_DATE_TIME_WITH_TIMEZONE = new BasicTypeReference<>(
"OffsetDateTimeWithTimezone",
OffsetDateTime.class,
Types.TIMESTAMP_WITH_TIMEZONE
);
/**
* The standard Hibernate type for mapping {@link OffsetDateTime} to JDBC {@link java.sql.Types#TIMESTAMP TIMESTAMP}.
*/
public static final BasicTypeReference<OffsetDateTime> OFFSET_DATE_TIME_WITHOUT_TIMEZONE = new BasicTypeReference<>(
"OffsetDateTimeWithoutTimezone",
OffsetDateTime.class,
Types.TIMESTAMP
);
/**
* The standard Hibernate type for mapping {@link OffsetTime} to JDBC {@link java.sql.Types#TIME TIME}.
*/
public static final BasicTypeReference<OffsetTime> OFFSET_TIME = new BasicTypeReference<>(
"ZonedDateTime",
"OffsetTime",
OffsetTime.class,
// todo (6.0): why not TIME_WITH_TIMEZONE ?
Types.TIME
);
/**
* The standard Hibernate type for mapping {@link ZonedDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}.
* The standard Hibernate type for mapping {@link ZonedDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}
* or {@link java.sql.Types#TIMESTAMP TIMESTAMP} depending on the {@link org.hibernate.cfg.AvailableSettings#TIMEZONE_DEFAULT_STORAGE} setting.
*/
public static final BasicTypeReference<ZonedDateTime> ZONED_DATE_TIME = new BasicTypeReference<>(
"ZonedDateTime",
@ -415,6 +434,24 @@ public final class StandardBasicTypes {
Types.TIMESTAMP_WITH_TIMEZONE
);
/**
* The standard Hibernate type for mapping {@link ZonedDateTime} to JDBC {@link java.sql.Types#TIMESTAMP_WITH_TIMEZONE TIMESTAMP_WITH_TIMEZONE}.
*/
public static final BasicTypeReference<ZonedDateTime> ZONED_DATE_TIME_WITH_TIMEZONE = new BasicTypeReference<>(
"ZonedDateTimeWithTimezone",
ZonedDateTime.class,
Types.TIMESTAMP_WITH_TIMEZONE
);
/**
* The standard Hibernate type for mapping {@link ZonedDateTime} to JDBC {@link java.sql.Types#TIMESTAMP TIMESTAMP}.
*/
public static final BasicTypeReference<ZonedDateTime> ZONED_DATE_TIME_WITHOUT_TIMEZONE = new BasicTypeReference<>(
"ZonedDateTimeWithoutTimezone",
ZonedDateTime.class,
Types.TIMESTAMP
);
/**
* The standard Hibernate type for mapping {@link Instant} to JDBC
* {@link java.sql.Types#TIMESTAMP TIMESTAMP}.

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.type.descriptor.java;
import java.sql.Types;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
@ -40,7 +41,7 @@ public class CalendarDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDesc
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return DateJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.DATE );
}
@Override

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.type.descriptor.java;
import java.sql.Types;
import java.util.Calendar;
import java.util.Comparator;
import java.util.GregorianCalendar;
@ -49,7 +50,7 @@ public class CalendarJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimestampJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
}
@Override

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.type.descriptor.java;
import java.sql.Types;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
@ -40,7 +41,7 @@ public class CalendarTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDesc
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimeJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.java;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@ -57,7 +58,7 @@ public class DateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescriptor<D
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimestampJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.java;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
@ -23,7 +24,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -69,7 +69,7 @@ public class InstantJavaTypeDescriptor extends AbstractTemporalJavaTypeDescripto
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimestampJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
}
@Override
@ -94,8 +94,7 @@ public class InstantJavaTypeDescriptor extends AbstractTemporalJavaTypeDescripto
}
if ( Calendar.class.isAssignableFrom( type ) ) {
final ZoneId zoneId = ZoneId.ofOffset( "UTC", ZoneOffset.UTC );
return (X) GregorianCalendar.from( instant.atZone( zoneId ) );
return (X) GregorianCalendar.from( instant.atZone( ZoneOffset.UTC ) );
}
if ( Timestamp.class.isAssignableFrom( type ) ) {

View File

@ -6,8 +6,10 @@
*/
package org.hibernate.type.descriptor.java;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
@ -73,7 +75,7 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return DateJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.DATE );
}
@Override
@ -166,6 +168,11 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
if ( Long.class.isAssignableFrom( type ) ) {
return (X) Long.valueOf( value.getTime() );
}
if ( LocalDate.class.isAssignableFrom( type ) ) {
if ( value instanceof java.sql.Date ) {
return (X) ( (java.sql.Date) value ).toLocalDate();
}
}
throw unknownUnwrap( type );
}
@ -190,6 +197,10 @@ public class JdbcDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
return new java.sql.Date( ( (Date) value ).getTime() );
}
if ( value instanceof LocalDate ) {
return java.sql.Date.valueOf( (LocalDate) value );
}
throw unknownWrap( value.getClass() );
}
}

View File

@ -7,8 +7,10 @@
package org.hibernate.type.descriptor.java;
import java.sql.Time;
import java.sql.Types;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Date;
@ -69,7 +71,7 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimeJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
}
@Override
@ -164,6 +166,11 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
if ( Long.class.isAssignableFrom( type ) ) {
return (X) Long.valueOf( value.getTime() );
}
if ( LocalTime.class.isAssignableFrom( type ) ) {
if ( value instanceof Time ) {
return (X) ( (Time) value ).toLocalTime();
}
}
throw unknownUnwrap( type );
}
@Override
@ -187,6 +194,10 @@ public class JdbcTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescript
return new Time( ( (Date) value ).getTime() );
}
if ( value instanceof LocalTime ) {
return Time.valueOf( (LocalTime) value );
}
throw unknownWrap( value.getClass() );
}

View File

@ -7,6 +7,8 @@
package org.hibernate.type.descriptor.java;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
@ -76,7 +78,7 @@ public class JdbcTimestampJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimestampJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.java;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -48,7 +49,7 @@ public class LocalDateJavaTypeDescriptor extends AbstractTemporalJavaTypeDescrip
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return DateJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.DATE );
}
@Override

View File

@ -7,6 +7,7 @@
package org.hibernate.type.descriptor.java;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@ -49,7 +50,7 @@ public class LocalDateTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimestampJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIMESTAMP );
}
@Override

View File

@ -8,6 +8,7 @@ package org.hibernate.type.descriptor.java;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
@ -52,7 +53,7 @@ public class LocalTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescrip
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimeJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
}
@Override

View File

@ -7,26 +7,25 @@
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.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import jakarta.persistence.TemporalType;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.jdbc.DateJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.TimeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TimestampWithTimeZoneJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -54,17 +53,20 @@ public class OffsetDateTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDe
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators stdIndicators) {
final TemporalType temporalPrecision = stdIndicators.getTemporalPrecision();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = stdIndicators.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
if ( temporalPrecision == null || temporalPrecision == TemporalType.TIMESTAMP ) {
return TimestampWithTimeZoneJdbcTypeDescriptor.INSTANCE;
return stdIndicators.getDefaultTimeZoneStorageStrategy() == TimeZoneStorageStrategy.NORMALIZE
? jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP )
: jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP_WITH_TIMEZONE );
}
switch ( temporalPrecision ) {
case TIME: {
return TimeJdbcTypeDescriptor.INSTANCE;
return jdbcTypeRegistry.getDescriptor( Types.TIME );
}
case DATE: {
return DateJdbcTypeDescriptor.INSTANCE;
return jdbcTypeRegistry.getDescriptor( Types.DATE );
}
default: {
throw new IllegalArgumentException( "Unexpected jakarta.persistence.TemporalType : " + temporalPrecision );

View File

@ -8,8 +8,11 @@ package org.hibernate.type.descriptor.java;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.OffsetTime;
import java.time.ZoneOffset;
@ -51,7 +54,7 @@ public class OffsetTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDescri
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return TimeJdbcTypeDescriptor.INSTANCE;
return context.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor( Types.TIME );
}
@Override

View File

@ -7,27 +7,26 @@
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.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import jakarta.persistence.TemporalType;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.ZonedDateTimeComparator;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.jdbc.DateJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.hibernate.type.descriptor.jdbc.TimeJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TimestampWithTimeZoneJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -54,16 +53,20 @@ public class ZonedDateTimeJavaTypeDescriptor extends AbstractTemporalJavaTypeDes
@Override
public JdbcTypeDescriptor getRecommendedJdbcType(JdbcTypeDescriptorIndicators stdIndicators) {
final TemporalType temporalPrecision = stdIndicators.getTemporalPrecision();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = stdIndicators.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
if ( temporalPrecision == null || temporalPrecision == TemporalType.TIMESTAMP ) {
return TimestampWithTimeZoneJdbcTypeDescriptor.INSTANCE;
return stdIndicators.getDefaultTimeZoneStorageStrategy() == TimeZoneStorageStrategy.NORMALIZE
? jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP )
: jdbcTypeRegistry.getDescriptor( Types.TIMESTAMP_WITH_TIMEZONE );
}
switch ( temporalPrecision ) {
case TIME: {
return TimeJdbcTypeDescriptor.INSTANCE;
return jdbcTypeRegistry.getDescriptor( Types.TIME );
}
case DATE: {
return DateJdbcTypeDescriptor.INSTANCE;
return jdbcTypeRegistry.getDescriptor( Types.DATE );
}
default: {
throw new IllegalArgumentException( "Unexpected jakarta.persistence.TemporalType : " + temporalPrecision );

View File

@ -10,6 +10,7 @@ import java.sql.Types;
import jakarta.persistence.EnumType;
import jakarta.persistence.TemporalType;
import org.hibernate.TimeZoneStorageStrategy;
import org.hibernate.type.descriptor.java.BasicJavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
@ -76,6 +77,10 @@ public interface JdbcTypeDescriptorIndicators {
return NO_COLUMN_LENGTH;
}
default TimeZoneStorageStrategy getDefaultTimeZoneStorageStrategy() {
return getTypeConfiguration().getSessionFactory().getFastSessionServices().getDefaultTimeZoneStorageStrategy();
}
/**
* Provides access to the TypeConfiguration for access to various type-system registries.
*/

View File

@ -14,7 +14,7 @@ import java.util.Currency;
/**
* @author Emmanuel Bernard
*/
public class MonetaryAmount implements Serializable {
public class MonetaryAmount {
private BigDecimal amount;
private Currency currency;

View File

@ -19,6 +19,7 @@ import org.hibernate.annotations.Nationalized;
import org.hibernate.annotations.JdbcType;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.JdbcTypeRegistration;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.mapping.BasicValue;
@ -30,6 +31,7 @@ import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
@ -50,20 +52,42 @@ public class JdbcTypeTests {
@Test
public void verifyResolutions(DomainModelScope scope) {
final Dialect dialect = scope.getDomainModel()
.getDatabase()
.getDialect();
final MetadataImplementor domainModel = scope.getDomainModel();
final Dialect dialect = domainModel.getDatabase().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final PersistentClass entityBinding = domainModel.getEntityBinding( SimpleEntity.class.getName() );
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding( SimpleEntity.class.getName() );
verifyJdbcTypeCode(
entityBinding.getProperty( "materializedClob" ),
jdbcTypeRegistry.getDescriptor( Types.CLOB ).getJdbcTypeCode()
);
verifyJdbcTypeCode(
entityBinding.getProperty( "materializedNClob" ),
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() )
.getJdbcTypeCode()
);
verifyJdbcTypeCode(
entityBinding.getProperty( "jpaMaterializedClob" ),
jdbcTypeRegistry.getDescriptor( Types.CLOB ).getJdbcTypeCode()
);
verifyJdbcTypeCode(
entityBinding.getProperty( "jpaMaterializedNClob" ),
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() )
.getJdbcTypeCode()
);
verifyJdbcTypeCode( entityBinding.getProperty( "materializedClob" ), Types.CLOB );
verifyJdbcTypeCode( entityBinding.getProperty( "materializedNClob" ), nationalizationSupport.getClobVariantCode() );
verifyJdbcTypeCode( entityBinding.getProperty( "jpaMaterializedClob" ), Types.CLOB );
verifyJdbcTypeCode( entityBinding.getProperty( "jpaMaterializedNClob" ), nationalizationSupport.getClobVariantCode() );
verifyJdbcTypeCode( entityBinding.getProperty( "nationalizedString" ), nationalizationSupport.getVarcharVariantCode() );
verifyJdbcTypeCode( entityBinding.getProperty( "nationalizedClob" ), nationalizationSupport.getClobVariantCode() );
verifyJdbcTypeCode(
entityBinding.getProperty( "nationalizedString" ),
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() )
.getJdbcTypeCode()
);
verifyJdbcTypeCode(
entityBinding.getProperty( "nationalizedClob" ),
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getClobVariantCode() )
.getJdbcTypeCode()
);
verifyResolution( entityBinding.getProperty( "customType" ), CustomJdbcTypeDescriptor.class );
verifyResolution( entityBinding.getProperty( "customTypeRegistration" ), RegisteredCustomJdbcTypeDescriptor.class );

View File

@ -12,11 +12,13 @@ import java.util.function.Consumer;
import org.hibernate.annotations.ListIndexJdbcType;
import org.hibernate.annotations.ListIndexJdbcTypeCode;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.mapping.BasicValue;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
@ -42,11 +44,17 @@ public class ListIndexJdbcTypeTests {
@Test
public void verifyResolutions(DomainModelScope scope) {
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding( TheEntity.class.getName() );
final MetadataImplementor domainModel = scope.getDomainModel();
final PersistentClass entityBinding = domainModel.getEntityBinding( TheEntity.class.getName() );
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
verifyJdbcTypeCodes( entityBinding.getProperty( "listOfStrings" ), Types.TINYINT );
verifyJdbcTypeCodes( entityBinding.getProperty( "anotherListOfStrings" ), Types.TINYINT );
verifyJdbcTypeCodes(
entityBinding.getProperty( "anotherListOfStrings" ),
jdbcTypeRegistry.getDescriptor( Types.TINYINT ).getJdbcTypeCode()
);
}
private void verifyJdbcTypeCodes(Property property, int expectedCode) {
verifyJdbcTypeResolution(

View File

@ -13,6 +13,7 @@ import java.util.function.Consumer;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.annotations.MapKeyJdbcType;
import org.hibernate.annotations.MapKeyJdbcTypeCode;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.dialect.SybaseDialect;
@ -21,6 +22,7 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TinyIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.DomainModelScope;
@ -45,27 +47,30 @@ public class MapKeyJdbcTypeTests {
@Test
public void verifyResolutions(DomainModelScope scope) {
final Dialect dialect = scope.getDomainModel().getDatabase().getDialect();
final MetadataImplementor domainModel = scope.getDomainModel();
final Dialect dialect = domainModel.getDatabase().getDialect();
final NationalizationSupport nationalizationSupport = dialect.getNationalizationSupport();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = domainModel.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final PersistentClass entityBinding = scope.getDomainModel().getEntityBinding( MyEntity.class.getName() );
final PersistentClass entityBinding = domainModel.getEntityBinding( MyEntity.class.getName() );
verifyJdbcTypeCodes(
entityBinding.getProperty( "baseMap" ),
Types.INTEGER,
Types.VARCHAR
jdbcTypeRegistry.getDescriptor( Types.INTEGER ).getJdbcTypeCode(),
jdbcTypeRegistry.getDescriptor( Types.VARCHAR ).getJdbcTypeCode()
);
verifyJdbcTypeCodes(
entityBinding.getProperty( "sqlTypeCodeMap" ),
Types.TINYINT,
nationalizationSupport.getVarcharVariantCode()
jdbcTypeRegistry.getDescriptor( Types.TINYINT ).getJdbcTypeCode(),
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() ).getJdbcTypeCode()
);
verifyJdbcTypeCodes(
entityBinding.getProperty( "sqlTypeMap" ),
Types.TINYINT,
nationalizationSupport.getVarcharVariantCode()
jdbcTypeRegistry.getDescriptor( nationalizationSupport.getVarcharVariantCode() ).getJdbcTypeCode()
);
}

View File

@ -37,6 +37,8 @@ import org.hibernate.type.descriptor.jdbc.NCharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NClobJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.testing.orm.junit.BaseUnitTest;
import org.junit.jupiter.api.Test;
@ -88,6 +90,9 @@ public class SimpleNationalizedTest {
ms.addAnnotatedClass( NationalizedEntity.class );
final Metadata metadata = ms.buildMetadata();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = metadata.getDatabase()
.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
PersistentClass pc = metadata.getEntityBinding( NationalizedEntity.class.getName() );
assertNotNull( pc );
@ -96,77 +101,58 @@ public class SimpleNationalizedTest {
final Dialect dialect = metadata.getDatabase().getDialect();
assertSame( StringJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
assertSame( VarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.VARCHAR ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( NVarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NVARCHAR ), type.getJdbcTypeDescriptor() );
}
prop = pc.getProperty( "materializedNclobAtt" );
type = (BasicType<?>) prop.getType();
assertSame( StringJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
if ( dialect instanceof SybaseDialect ) {
assertSame( ClobJdbcTypeDescriptor.CLOB_BINDING, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.CLOB ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( ClobJdbcTypeDescriptor.DEFAULT, type.getJdbcTypeDescriptor() );
}
}
else {
assertSame( NClobJdbcTypeDescriptor.DEFAULT, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NCLOB ), type.getJdbcTypeDescriptor() );
}
prop = pc.getProperty( "nclobAtt" );
type = (BasicType<?>) prop.getType();
assertSame( NClobJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
if ( dialect instanceof SybaseDialect ) {
assertSame( ClobJdbcTypeDescriptor.CLOB_BINDING, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.CLOB ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( ClobJdbcTypeDescriptor.DEFAULT, type.getJdbcTypeDescriptor() );
}
}
else {
assertSame( NClobJdbcTypeDescriptor.DEFAULT, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NCLOB ), type.getJdbcTypeDescriptor() );
}
prop = pc.getProperty( "nlongvarcharcharAtt" );
{
final BasicValue.Resolution<?> resolution = ( (BasicValue) prop.getValue() ).resolve();
final int jdbcTypeExpected;
type = (BasicType<?>) prop.getType();
assertSame( StringJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
jdbcTypeExpected = Types.CLOB;
assertSame( jdbcTypeRegistry.getDescriptor( Types.CLOB ), type.getJdbcTypeDescriptor() );
}
else {
jdbcTypeExpected = Types.NCLOB;
}
Assertions.assertThat( resolution.getJdbcTypeDescriptor().getJdbcTypeCode() ).isEqualTo( jdbcTypeExpected );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NCLOB ), type.getJdbcTypeDescriptor() );
}
prop = pc.getProperty( "ncharArrAtt" );
type = (BasicType<?>) prop.getType();
assertSame( CharacterArrayJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
assertSame( VarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.VARCHAR ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( NVarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NVARCHAR ), type.getJdbcTypeDescriptor() );
}
prop = pc.getProperty( "ncharacterAtt" );
type = (BasicType<?>) prop.getType();
assertSame( CharacterJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
assertSame( CharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.CHAR ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( NCharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
assertSame( jdbcTypeRegistry.getDescriptor( Types.NCHAR ), type.getJdbcTypeDescriptor() );
}
}
finally {

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.orm.test.nationalized;
import java.sql.Types;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
@ -27,10 +29,12 @@ import org.hibernate.type.descriptor.jdbc.CharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NCharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.VarcharJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeDescriptorRegistry;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;
import static org.junit.Assert.assertSame;
@ -53,18 +57,19 @@ public class UseNationalizedCharDataSettingTest extends BaseUnitTestCase {
ms.addAnnotatedClass( NationalizedBySettingEntity.class );
final Metadata metadata = ms.buildMetadata();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = metadata.getDatabase()
.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final PersistentClass pc = metadata.getEntityBinding( NationalizedBySettingEntity.class.getName() );
final Property nameAttribute = pc.getProperty( "name" );
final BasicType<?> type = (BasicType<?>) nameAttribute.getType();
final Dialect dialect = metadata.getDatabase().getDialect();
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
// See issue HHH-10693
assertSame( StringJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
assertSame( VarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
Assertions.assertSame( jdbcTypeRegistry.getDescriptor( Types.VARCHAR ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( StringJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
assertSame( NVarcharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
Assertions.assertSame( jdbcTypeRegistry.getDescriptor( Types.NVARCHAR ), type.getJdbcTypeDescriptor() );
}
}
@ -85,17 +90,19 @@ public class UseNationalizedCharDataSettingTest extends BaseUnitTestCase {
ms.addAnnotatedClass( NationalizedBySettingEntity.class );
final Metadata metadata = ms.buildMetadata();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = metadata.getDatabase()
.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
final PersistentClass pc = metadata.getEntityBinding( NationalizedBySettingEntity.class.getName() );
final Property nameAttribute = pc.getProperty( "flag" );
final BasicType<?> type = (BasicType<?>) nameAttribute.getType();
final Dialect dialect = metadata.getDatabase().getDialect();
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
assertSame( CharacterJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
assertSame( CharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
if ( dialect.getNationalizationSupport() != NationalizationSupport.EXPLICIT ) {
Assertions.assertSame( jdbcTypeRegistry.getDescriptor( Types.CHAR ), type.getJdbcTypeDescriptor() );
}
else {
assertSame( CharacterJavaTypeDescriptor.INSTANCE, type.getJavaTypeDescriptor() );
assertSame( NCharJdbcTypeDescriptor.INSTANCE, type.getJdbcTypeDescriptor() );
Assertions.assertSame( jdbcTypeRegistry.getDescriptor( Types.NCHAR ), type.getJdbcTypeDescriptor() );
}
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -20,6 +20,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.cfg.AvailableSettings;
@ -27,7 +28,6 @@ import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
@ -47,7 +47,7 @@ import static org.junit.Assert.assertEquals;
* @param <E> The entity type used in tests.
*/
@RunWith(CustomParameterized.class)
abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase {
public abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase {
private static Dialect determineDialect() {
try {
@ -287,6 +287,13 @@ abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase
return thisAsS();
}
public S skippedForDialects(Predicate<Dialect> skipPredicate, Consumer<S> skippedIfDialectMatchesClasses) {
if ( !skipPredicate.test( dialect ) ) {
skippedIfDialectMatchesClasses.accept( thisAsS() );
}
return thisAsS();
}
public S withForcedJdbcTimezone(String zoneIdString, Consumer<S> contributor) {
ZoneId zoneId = ZoneId.of( zoneIdString );
this.forcedJdbcTimeZone = zoneId;
@ -301,7 +308,7 @@ abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase
@SafeVarargs
public final S alsoTestRemappingsWithH2(Class<? extends AbstractRemappingH2Dialect> ... dialectClasses) {
if ( dialect instanceof H2Dialect ) {
if ( dialect instanceof H2Dialect && !( (H2Dialect) dialect ).hasDstBug() ) {
// Only test remappings with H2
Collections.addAll( remappingDialectClasses, dialectClasses );
}
@ -395,11 +402,12 @@ abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase
protected static class AbstractRemappingH2Dialect extends H2Dialect {
private final int overriddenSqlTypeCode;
private final JdbcTypeDescriptor overriddenJdbcTypeDescriptor;
private final int overridingSqlTypeCode;
public AbstractRemappingH2Dialect(int overriddenSqlTypeCode, JdbcTypeDescriptor overriddenJdbcTypeDescriptor) {
public AbstractRemappingH2Dialect(int overriddenSqlTypeCode, int overridingSqlTypeCode) {
super( getDialect().getVersion() );
this.overriddenSqlTypeCode = overriddenSqlTypeCode;
this.overriddenJdbcTypeDescriptor = overriddenJdbcTypeDescriptor;
this.overridingSqlTypeCode = overridingSqlTypeCode;
}
@Override
@ -408,7 +416,9 @@ abstract class AbstractJavaTimeTypeTest<T, E> extends BaseCoreFunctionalTestCase
typeContributions.getTypeConfiguration().getJdbcTypeDescriptorRegistry().addDescriptor(
overriddenSqlTypeCode,
overriddenJdbcTypeDescriptor
typeContributions.getTypeConfiguration().getJdbcTypeDescriptorRegistry().getDescriptor(
overridingSqlTypeCode
)
);
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import org.hibernate.Session;
import org.hibernate.query.Query;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -22,8 +22,10 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.SybaseASEDialect;
import org.hibernate.dialect.SybaseDialect;
import org.junit.runners.Parameterized;
@ -61,21 +63,26 @@ public class InstantTest extends AbstractJavaTimeTypeTest<Instant, InstantTest.E
.add( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS )
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
.add( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_PARIS )
.add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_AMSTERDAM )
)
.skippedForDialects(
// MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp.
Arrays.asList( MySQLDialect.class, MariaDBDialect.class, SybaseDialect.class ),
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect
|| dialect instanceof SybaseDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
)
// HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621)
// => This used to work correctly in 5.4.1.Final and earlier
.add( 2018, 10, 28, 1, 0, 0, 0, ZONE_PARIS )
.skippedForDialects(
dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b.add( 2018, 10, 28, 1, 0, 0, 0, ZONE_PARIS )
.add( 2018, 3, 31, 14, 0, 0, 0, ZONE_AUCKLAND )
)
// => This has never worked correctly, unless the JDBC timezone was set to UTC
.withForcedJdbcTimezone( "UTC", b -> b
.add( 2018, 10, 28, 0, 0, 0, 0, ZONE_PARIS )
@ -83,8 +90,12 @@ public class InstantTest extends AbstractJavaTimeTypeTest<Instant, InstantTest.E
)
// => Also test DST start, just in case
.add( 2018, 3, 25, 1, 0, 0, 0, ZONE_PARIS )
.add( 2018, 3, 25, 2, 0, 0, 0, ZONE_PARIS )
.skippedForDialects(
// No idea what Sybase is doing here exactly
dialect -> dialect instanceof SybaseASEDialect,
b -> b.add( 2018, 3, 25, 2, 0, 0, 0, ZONE_PARIS )
.add( 2018, 9, 30, 2, 0, 0, 0, ZONE_AUCKLAND )
)
.add( 2018, 9, 30, 3, 0, 0, 0, ZONE_AUCKLAND )
// => Also test dates around 1905-01-01, because the code behaves differently before and after 1905
.add( 1904, 12, 31, 22, 59, 59, 999_999_999, ZONE_PARIS )

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.time.Duration;
import java.time.Instant;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
import static org.junit.Assert.assertFalse;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.Date;
import java.sql.PreparedStatement;
@ -22,10 +22,11 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcTypeDescriptor;
import org.hibernate.dialect.SybaseASEDialect;
import org.hibernate.testing.SkipForDialect;
import org.hibernate.testing.TestForIssue;
@ -37,11 +38,13 @@ import org.junit.runners.Parameterized;
@TestForIssue(jiraKey = "HHH-10371")
@SkipForDialect(value = AbstractHANADialect.class,
comment = "HANA systematically returns the wrong date when the JVM default timezone is not UTC")
@SkipForDialect(value = MySQL5Dialect.class,
@SkipForDialect(value = MySQLDialect.class,
comment = "HHH-13582: MySQL ConnectorJ 8.x returns the wrong date"
+ " when the JVM default timezone is different from the server timezone:"
+ " https://bugs.mysql.com/bug.php?id=91112"
)
@SkipForDialect(value = H2Dialect.class, comment = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug")
@SkipForDialect(value = HSQLDialect.class, comment = "HSQL has problems with DST edges")
public class LocalDateTest extends AbstractJavaTimeTypeTest<LocalDate, LocalDateTest.EntityWithLocalDate> {
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
@ -70,7 +73,11 @@ public class LocalDateTest extends AbstractJavaTimeTypeTest<LocalDate, LocalDate
.add( 1892, 1, 1, ZONE_OSLO )
.add( 1900, 1, 1, ZONE_PARIS )
.add( 1900, 1, 1, ZONE_AMSTERDAM )
.add( 1600, 1, 1, ZONE_AMSTERDAM )
)
.skippedForDialects(
// No idea what Sybase is doing here exactly
dialect -> dialect instanceof SybaseASEDialect,
b -> b.add( 1600, 1, 1, ZONE_AMSTERDAM )
)
// HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621)
// It doesn't seem that any date at midnight can be affected by HHH-13379, but we add some tests just in case
@ -167,7 +174,7 @@ public class LocalDateTest extends AbstractJavaTimeTypeTest<LocalDate, LocalDate
public static class DateAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect {
public DateAsTimestampRemappingH2Dialect() {
super( Types.DATE, TimestampJdbcTypeDescriptor.INSTANCE );
super( Types.DATE, Types.TIMESTAMP );
}
}
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -19,6 +19,7 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.SybaseDialect;
@ -56,25 +57,40 @@ public class LocalDateTimeTest extends AbstractJavaTimeTypeTest<LocalDateTime, L
.add( 1900, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS )
.add( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, ZONE_AMSTERDAM )
)
.skippedForDialects(
// MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp.
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO )
)
.skippedForDialects(
// MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp.
Arrays.asList( MySQLDialect.class, MariaDBDialect.class, SybaseDialect.class ),
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect || dialect instanceof SybaseDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM )
)
// HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621)
// It doesn't seem that any LocalDateTime can be affected by HHH-13379, but we add some tests just in case
.add( 2018, 10, 28, 1, 0, 0, 0, ZONE_PARIS )
.skippedForDialects(
dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 2018, 10, 28, 2, 0, 0, 0, ZONE_PARIS )
)
.add( 2018, 10, 28, 3, 0, 0, 0, ZONE_PARIS )
.add( 2018, 10, 28, 4, 0, 0, 0, ZONE_PARIS )
.add( 2018, 4, 1, 1, 0, 0, 0, ZONE_AUCKLAND )
.skippedForDialects(
dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 2018, 4, 1, 2, 0, 0, 0, ZONE_AUCKLAND )
)
.add( 2018, 4, 1, 3, 0, 0, 0, ZONE_AUCKLAND )
.add( 2018, 4, 1, 4, 0, 0, 0, ZONE_AUCKLAND )
// => Also test DST start

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -23,10 +23,10 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcTypeDescriptor;
import org.hibernate.testing.SkipForDialect;
import org.junit.Test;
@ -35,6 +35,7 @@ import org.junit.runners.Parameterized;
/**
* Tests for storage of LocalTime properties.
*/
@SkipForDialect(value = H2Dialect.class, comment = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug")
public class LocalTimeTest extends AbstractJavaTimeTypeTest<LocalTime, LocalTimeTest.EntityWithLocalTime> {
private static class ParametersBuilder extends AbstractParametersBuilder<ParametersBuilder> {
@ -200,12 +201,13 @@ public class LocalTimeTest extends AbstractJavaTimeTypeTest<LocalTime, LocalTime
@Override
@Test
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time")
@SkipForDialect(value = MySQL5Dialect.class,
@SkipForDialect(value = MySQLDialect.class,
comment = "HHH-13580 MySQL seems to store the whole timestamp, not just the time,"
+ " which for some timezones results in a date other than 1970-01-01 being returned"
+ " (typically 1969-12-31), even though the time is always right."
+ " Since java.sql.Time holds the whole timestamp, not just the time,"
+ " its equals() method ends up returning false in this test.")
@SkipForDialect(value = HSQLDialect.class, comment = "Timezone issue?")
public void writeThenNativeRead() {
super.writeThenNativeRead();
}
@ -231,7 +233,7 @@ public class LocalTimeTest extends AbstractJavaTimeTypeTest<LocalTime, LocalTime
public static class TimeAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect {
public TimeAsTimestampRemappingH2Dialect() {
super( Types.TIME, TimestampJdbcTypeDescriptor.INSTANCE );
super( Types.TIME, Types.TIMESTAMP );
}
}
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -22,11 +22,11 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.query.Query;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.OffsetDateTimeType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.testing.TestForIssue;
@ -88,22 +88,32 @@ public class OffsetDateTimeTest extends AbstractJavaTimeTypeTest<OffsetDateTime,
.add( 1900, 1, 1, 0, 9, 21, 0, "+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "+00:19:32", ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, "+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "+00:19:32", ZONE_AMSTERDAM )
)
.skippedForDialects(
// MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp.
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, "+00:00", ZONE_OSLO )
)
.skippedForDialects(
// MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp.
Arrays.asList( MySQLDialect.class, MariaDBDialect.class, SybaseDialect.class ),
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect || dialect instanceof SybaseDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 1600, 1, 1, 0, 0, 0, 0, "+00:19:32", ZONE_AMSTERDAM )
)
// HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621)
// => This used to work correctly in 5.4.1.Final and earlier
.add( 2018, 10, 28, 2, 0, 0, 0, "+01:00", ZONE_PARIS )
.skippedForDialects(
dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b.add( 2018, 10, 28, 2, 0, 0, 0, "+01:00", ZONE_PARIS )
.add( 2018, 4, 1, 2, 0, 0, 0, "+12:00", ZONE_AUCKLAND )
)
// => This has never worked correctly, unless the JDBC timezone was set to UTC
.withForcedJdbcTimezone( "UTC", b -> b
.add( 2018, 10, 28, 2, 0, 0, 0, "+02:00", ZONE_PARIS )

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -25,11 +25,9 @@ import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.AbstractHANADialect;
import org.hibernate.dialect.HSQLDialect;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQL5Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.type.descriptor.jdbc.BigIntJdbcTypeDescriptor;
import org.hibernate.type.descriptor.jdbc.TimestampJdbcTypeDescriptor;
import org.hibernate.testing.SkipForDialect;
import org.junit.Test;
@ -229,12 +227,13 @@ public class OffsetTimeTest extends AbstractJavaTimeTypeTest<OffsetTime, OffsetT
@Override
@Test
@SkipForDialect(value = AbstractHANADialect.class, comment = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time")
@SkipForDialect(value = MySQL5Dialect.class,
@SkipForDialect(value = MySQLDialect.class,
comment = "HHH-13580 MySQL seems to store the whole timestamp, not just the time,"
+ " which for some timezones results in a date other than 1970-01-01 being returned"
+ " (typically 1969-12-31), even though the time is always right."
+ " Since java.sql.Time holds the whole timestamp, not just the time,"
+ " its equals() method ends up returning false in this test.")
@SkipForDialect(value = HSQLDialect.class, comment = "Timezone issue?")
public void writeThenNativeRead() {
super.writeThenNativeRead();
}
@ -260,13 +259,13 @@ public class OffsetTimeTest extends AbstractJavaTimeTypeTest<OffsetTime, OffsetT
public static class TimeAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect {
public TimeAsTimestampRemappingH2Dialect() {
super( Types.TIME, TimestampJdbcTypeDescriptor.INSTANCE );
super( Types.TIME, Types.TIMESTAMP );
}
}
public static class TimeAsBigIntRemappingH2Dialect extends AbstractRemappingH2Dialect {
public TimeAsBigIntRemappingH2Dialect() {
super( Types.TIME, BigIntJdbcTypeDescriptor.INSTANCE );
super( Types.TIME, Types.BIGINT );
}
}
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
@ -17,35 +17,34 @@ import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.SQLServer2008Dialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.hibernate.testing.RequiresDialect;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/**
* @author Andrea Boriero
*/
@TestForIssue(jiraKey = "HHH-10529")
@RequiresDialect(value = SQLServer2008Dialect.class)
public class SQLServer2008NVarCharTypeTest extends BaseUnitTestCase {
@RequiresDialect(value = SQLServerDialect.class, version = 10)
public class SQLServer2008NVarCharTypeTest {
private StandardServiceRegistry ssr;
private MetadataImplementor metadata;
private SchemaExport schemaExport;
@Before
@BeforeEach
public void setUp() {
ssr = new StandardServiceRegistryBuilder().build();
schemaExport = createSchemaExport( new Class[] {MyEntity.class} );
}
@After
@AfterEach
public void tearDown() {
schemaExport.drop( EnumSet.of( TargetType.DATABASE ), metadata );
StandardServiceRegistryBuilder.destroy( ssr );

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Column;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.net.URL;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.Time;
import java.sql.Timestamp;
@ -50,14 +50,14 @@ public class TimeAndTimestampTest extends BaseNonConfigCoreFunctionalTestCase {
Event event = new Event();
event.id = 1L;
event.timeValue = new Time( 1000 );
event.timestampValue = new Timestamp( 45678 );
event.timestampValue = new Timestamp( 45677 );
session.persist( event );
} );
doInHibernate( this::sessionFactory, session -> {
Event event = session.find( Event.class, 1L );
assertEquals(1000, event.timeValue.getTime() % TimeUnit.DAYS.toMillis( 1 ));
assertEquals(45678, event.timestampValue.getTime() % TimeUnit.DAYS.toMillis( 1 ));
assertEquals(45677, event.timestampValue.getTime() % TimeUnit.DAYS.toMillis( 1 ));
} );
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.type;
package org.hibernate.orm.test.type;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -22,12 +22,12 @@ import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.query.Query;
import org.hibernate.dialect.MariaDBDialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.SybaseDialect;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.ZonedDateTimeType;
import org.hibernate.testing.TestForIssue;
import org.junit.Test;
@ -96,26 +96,36 @@ public class ZonedDateTimeTest extends AbstractJavaTimeTypeTest<ZonedDateTime, Z
.add( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 32, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1900, 1, 1, 0, 19, 32, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_OSLO )
.add( 1892, 1, 1, 0, 0, 0, 0, "Europe/Oslo", ZONE_OSLO )
.add( 1900, 1, 1, 0, 9, 20, 0, "GMT+00:09:21", ZONE_PARIS )
.add( 1900, 1, 1, 0, 9, 20, 0, "Europe/Paris", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZONE_PARIS )
.add( 1900, 1, 1, 0, 19, 31, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1900, 1, 1, 0, 19, 31, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
)
.skippedForDialects(
// MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp.
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
// Affected by HHH-13266 (JDK-8061577)
.add( 1892, 1, 1, 0, 0, 0, 0, "GMT+00:00", ZONE_OSLO )
.add( 1892, 1, 1, 0, 0, 0, 0, "Europe/Oslo", ZONE_OSLO )
)
.skippedForDialects(
// MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp.
Arrays.asList( MySQLDialect.class, MariaDBDialect.class, SybaseDialect.class ),
dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect || dialect instanceof SybaseDialect
|| dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b
.add( 1600, 1, 1, 0, 0, 0, 0, "GMT+00:19:32", ZONE_AMSTERDAM )
.add( 1600, 1, 1, 0, 0, 0, 0, "Europe/Amsterdam", ZONE_AMSTERDAM )
)
// HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621)
// => This used to work correctly in 5.4.1.Final and earlier
.add( 2018, 10, 28, 2, 0, 0, 0, "+01:00", ZONE_PARIS )
.skippedForDialects(
dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasDstBug(),
b -> b.add( 2018, 10, 28, 2, 0, 0, 0, "+01:00", ZONE_PARIS )
.add( 2018, 4, 1, 2, 0, 0, 0, "+12:00", ZONE_AUCKLAND )
)
// => This has never worked correctly, unless the JDBC timezone was set to UTC
.withForcedJdbcTimezone( "UTC", b -> b
.add( 2018, 10, 28, 2, 0, 0, 0, "+02:00", ZONE_PARIS )

View File

@ -50,33 +50,34 @@ public class TypeOverrideTest extends BaseSessionFactoryFunctionalTest {
@Test
public void testStandardBasicSqlTypeDescriptor() {
final Dialect dialect = getMetadata().getDatabase().getDialect();
final JdbcTypeDescriptorRegistry jdbcTypeRegistry = getMetadata().getTypeConfiguration()
.getJdbcTypeDescriptorRegistry();
// no override
assertSame( IntegerJdbcTypeDescriptor.INSTANCE, jdbcTypeRegistry.getDescriptor( Types.INTEGER ) );
// A few dialects explicitly override BlobTypeDescriptor.DEFAULT
if ( CockroachDialect.class.isInstance( getDialect() ) ) {
if ( CockroachDialect.class.isInstance( dialect ) ) {
assertSame(
VarbinaryJdbcTypeDescriptor.INSTANCE,
jdbcTypeRegistry.getDescriptor( Types.BLOB )
);
}
else if ( PostgreSQLDialect.class.isInstance( getDialect() ) ) {
else if ( PostgreSQLDialect.class.isInstance( dialect ) ) {
assertSame(
BlobJdbcTypeDescriptor.BLOB_BINDING,
jdbcTypeRegistry.getDescriptor( Types.BLOB )
);
}
else if ( SybaseDialect.class.isInstance( getDialect() ) ) {
else if ( SybaseDialect.class.isInstance( dialect ) ) {
assertSame(
BlobJdbcTypeDescriptor.PRIMITIVE_ARRAY_BINDING,
jdbcTypeRegistry.getDescriptor( Types.BLOB )
);
}
else if ( AbstractHANADialect.class.isInstance( getDialect() ) ) {
else if ( AbstractHANADialect.class.isInstance( dialect ) ) {
assertSame(
( (AbstractHANADialect) getDialect() ).getBlobTypeDescriptor(),
( (AbstractHANADialect) dialect ).getBlobTypeDescriptor(),
jdbcTypeRegistry.getDescriptor( Types.BLOB )
);
}

View File

@ -17,6 +17,7 @@ import org.hibernate.dialect.NationalizationSupport;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.PostgreSQLDialect;
import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.dialect.TimeZoneSupport;
import org.hibernate.query.FetchClauseType;
/**
@ -269,7 +270,7 @@ abstract public class DialectFeatureChecks {
public static class SupportsTimezoneTypes implements DialectFeatureCheck {
public boolean apply(Dialect dialect) {
return dialect.supportsTimezoneTypes();
return dialect.getTimeZoneSupport() == TimeZoneSupport.NATIVE;
}
}