HHH-15135 Respect precision in temporal version types when generating timestamps
This commit is contained in:
parent
8470d6db5b
commit
75a8ad1851
|
@ -80,6 +80,9 @@ public class UnsavedValueFactory {
|
||||||
public static <T> VersionValue getUnsavedVersionValue(
|
public static <T> VersionValue getUnsavedVersionValue(
|
||||||
KeyValue bootVersionMapping,
|
KeyValue bootVersionMapping,
|
||||||
VersionJavaType<T> jtd,
|
VersionJavaType<T> jtd,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
Getter getter,
|
Getter getter,
|
||||||
Supplier<?> templateInstanceAccess) {
|
Supplier<?> templateInstanceAccess) {
|
||||||
final String unsavedValue = bootVersionMapping.getNullValue();
|
final String unsavedValue = bootVersionMapping.getNullValue();
|
||||||
|
@ -91,7 +94,7 @@ public class UnsavedValueFactory {
|
||||||
|
|
||||||
// if the version of a newly instantiated object is not the same
|
// if the version of a newly instantiated object is not the same
|
||||||
// as the version seed value, use that as the unsaved-value
|
// as the version seed value, use that as the unsaved-value
|
||||||
final T seedValue = jtd.seed( null );
|
final T seedValue = jtd.seed( length, precision, scale, null );
|
||||||
return jtd.areEqual( seedValue, defaultValue )
|
return jtd.areEqual( seedValue, defaultValue )
|
||||||
? VersionValue.UNDEFINED
|
? VersionValue.UNDEFINED
|
||||||
: new VersionValue( defaultValue );
|
: new VersionValue( defaultValue );
|
||||||
|
@ -116,72 +119,6 @@ public class UnsavedValueFactory {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiate a class using the provided Constructor
|
|
||||||
*
|
|
||||||
* @param constructor The constructor
|
|
||||||
*
|
|
||||||
* @return The instantiated object
|
|
||||||
*
|
|
||||||
* @throws InstantiationException if something went wrong
|
|
||||||
*/
|
|
||||||
private static Object instantiate(Constructor<?> constructor) {
|
|
||||||
try {
|
|
||||||
return constructor.newInstance();
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new InstantiationException( "could not instantiate test object", constructor.getDeclaringClass(), e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return an IdentifierValue for the specified unsaved-value. If none is specified,
|
|
||||||
* guess the unsaved value by instantiating a test instance of the class and
|
|
||||||
* reading it's version property value, or if that is not possible, using the java default
|
|
||||||
* value for the type
|
|
||||||
*
|
|
||||||
* @param versionUnsavedValue The mapping defined unsaved value
|
|
||||||
* @param versionGetter The version attribute getter
|
|
||||||
* @param versionType The mapping type for the version
|
|
||||||
* @param constructor The constructor for the entity
|
|
||||||
*
|
|
||||||
* @return The appropriate VersionValue
|
|
||||||
*/
|
|
||||||
public static <X> VersionValue getUnsavedVersionValue(
|
|
||||||
String versionUnsavedValue,
|
|
||||||
Getter versionGetter,
|
|
||||||
VersionJavaType<X> versionType,
|
|
||||||
Constructor<?> constructor) {
|
|
||||||
|
|
||||||
if ( versionUnsavedValue == null ) {
|
|
||||||
if ( constructor!=null ) {
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
final X defaultValue = (X) versionGetter.get( instantiate( constructor ) );
|
|
||||||
// if the version of a newly instantiated object is not the same
|
|
||||||
// as the version seed value, use that as the unsaved-value
|
|
||||||
return versionType.areEqual( versionType.seed( null ), defaultValue )
|
|
||||||
? VersionValue.UNDEFINED
|
|
||||||
: new VersionValue( defaultValue );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return VersionValue.UNDEFINED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switch (versionUnsavedValue) {
|
|
||||||
case "undefined":
|
|
||||||
return VersionValue.UNDEFINED;
|
|
||||||
case "null":
|
|
||||||
return VersionValue.NULL;
|
|
||||||
case "negative":
|
|
||||||
return VersionValue.NEGATIVE;
|
|
||||||
default:
|
|
||||||
// this should not happen since the DTD prevents it
|
|
||||||
throw new MappingException("Could not parse version unsaved-value: " + versionUnsavedValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnsavedValueFactory() {
|
private UnsavedValueFactory() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.engine.internal;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.type.descriptor.java.VersionJavaType;
|
import org.hibernate.type.descriptor.java.VersionJavaType;
|
||||||
|
|
||||||
|
@ -31,15 +32,20 @@ public final class Versioning {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an initial optimistic locking value according the {@link VersionJavaType}
|
* Create an initial optimistic locking value according the {@link EntityVersionMapping}
|
||||||
* contract for the version property.
|
* contract for the version property.
|
||||||
*
|
*
|
||||||
* @param versionType The version type.
|
* @param versionMapping The version mapping
|
||||||
* @param session The originating session
|
* @param session The originating session
|
||||||
* @return The initial optimistic locking value
|
* @return The initial optimistic locking value
|
||||||
*/
|
*/
|
||||||
private static Object seed(VersionJavaType<Object> versionType, SharedSessionContractImplementor session) {
|
private static Object seed(EntityVersionMapping versionMapping, SharedSessionContractImplementor session) {
|
||||||
final Object seed = versionType.seed( session );
|
final Object seed = versionMapping.getJavaType().seed(
|
||||||
|
versionMapping.getLength(),
|
||||||
|
versionMapping.getPrecision(),
|
||||||
|
versionMapping.getScale(),
|
||||||
|
session
|
||||||
|
);
|
||||||
LOG.tracef( "Seeding: %s", seed );
|
LOG.tracef( "Seeding: %s", seed );
|
||||||
return seed;
|
return seed;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +57,7 @@ public final class Versioning {
|
||||||
*
|
*
|
||||||
* @param fields The current snapshot state
|
* @param fields The current snapshot state
|
||||||
* @param versionProperty The index of the version property
|
* @param versionProperty The index of the version property
|
||||||
* @param versionType The version type
|
* @param versionMapping The version mapping
|
||||||
* @param session The originating session
|
* @param session The originating session
|
||||||
* @return True if we injected a new version value into the fields array; false
|
* @return True if we injected a new version value into the fields array; false
|
||||||
* otherwise.
|
* otherwise.
|
||||||
|
@ -59,7 +65,7 @@ public final class Versioning {
|
||||||
public static boolean seedVersion(
|
public static boolean seedVersion(
|
||||||
Object[] fields,
|
Object[] fields,
|
||||||
int versionProperty,
|
int versionProperty,
|
||||||
VersionJavaType<Object> versionType,
|
EntityVersionMapping versionMapping,
|
||||||
SharedSessionContractImplementor session) {
|
SharedSessionContractImplementor session) {
|
||||||
final Object initialVersion = fields[versionProperty];
|
final Object initialVersion = fields[versionProperty];
|
||||||
if (
|
if (
|
||||||
|
@ -70,7 +76,7 @@ public final class Versioning {
|
||||||
// TODO: shift it into unsaved-value strategy
|
// TODO: shift it into unsaved-value strategy
|
||||||
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
|
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
|
||||||
) {
|
) {
|
||||||
fields[versionProperty] = seed( versionType, session );
|
fields[versionProperty] = seed( versionMapping, session );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
LOG.tracev( "Using initial version: {0}", initialVersion );
|
LOG.tracev( "Using initial version: {0}", initialVersion );
|
||||||
|
@ -83,12 +89,20 @@ public final class Versioning {
|
||||||
* the {@link VersionJavaType} contract for the version property.
|
* the {@link VersionJavaType} contract for the version property.
|
||||||
*
|
*
|
||||||
* @param version The current version
|
* @param version The current version
|
||||||
* @param versionType The version type
|
* @param versionMapping The version mapping
|
||||||
* @param session The originating session
|
* @param session The originating session
|
||||||
* @return The incremented optimistic locking value.
|
* @return The incremented optimistic locking value.
|
||||||
*/
|
*/
|
||||||
public static Object increment(Object version, VersionJavaType<Object> versionType, SharedSessionContractImplementor session) {
|
public static Object increment(Object version, EntityVersionMapping versionMapping, SharedSessionContractImplementor session) {
|
||||||
final Object next = versionType.next( version, session );
|
@SuppressWarnings("unchecked")
|
||||||
|
final VersionJavaType<Object> versionType = (VersionJavaType<Object>) versionMapping.getJavaType();
|
||||||
|
final Object next = versionType.next(
|
||||||
|
version,
|
||||||
|
versionMapping.getLength(),
|
||||||
|
versionMapping.getPrecision(),
|
||||||
|
versionMapping.getScale(),
|
||||||
|
session
|
||||||
|
);
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.tracef(
|
LOG.tracef(
|
||||||
"Incrementing: %s to %s",
|
"Incrementing: %s to %s",
|
||||||
|
|
|
@ -414,7 +414,7 @@ public abstract class AbstractSaveEventListener<C>
|
||||||
substitute = Versioning.seedVersion(
|
substitute = Versioning.seedVersion(
|
||||||
values,
|
values,
|
||||||
persister.getVersionProperty(),
|
persister.getVersionProperty(),
|
||||||
persister.getVersionJavaType(),
|
persister.getVersionMapping(),
|
||||||
source
|
source
|
||||||
) || substitute;
|
) || substitute;
|
||||||
}
|
}
|
||||||
|
|
|
@ -397,7 +397,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
||||||
);
|
);
|
||||||
|
|
||||||
final Object nextVersion = isVersionIncrementRequired
|
final Object nextVersion = isVersionIncrementRequired
|
||||||
? Versioning.increment( entry.getVersion(), persister.getVersionJavaType(), event.getSession() )
|
? Versioning.increment( entry.getVersion(), persister.getVersionMapping(), event.getSession() )
|
||||||
: entry.getVersion(); //use the current version
|
: entry.getVersion(); //use the current version
|
||||||
|
|
||||||
Versioning.setVersion( values, nextVersion, persister );
|
Versioning.setVersion( values, nextVersion, persister );
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
boolean substitute = Versioning.seedVersion(
|
boolean substitute = Versioning.seedVersion(
|
||||||
state,
|
state,
|
||||||
persister.getVersionProperty(),
|
persister.getVersionProperty(),
|
||||||
persister.getVersionJavaType(),
|
persister.getVersionMapping(),
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
if ( substitute ) {
|
if ( substitute ) {
|
||||||
|
@ -141,7 +141,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
Object oldVersion;
|
Object oldVersion;
|
||||||
if ( persister.isVersioned() ) {
|
if ( persister.isVersioned() ) {
|
||||||
oldVersion = persister.getVersion( entity );
|
oldVersion = persister.getVersion( entity );
|
||||||
Object newVersion = Versioning.increment( oldVersion, persister.getVersionJavaType(), this );
|
Object newVersion = Versioning.increment( oldVersion, persister.getVersionMapping(), this );
|
||||||
Versioning.setVersion( state, newVersion, persister );
|
Versioning.setVersion( state, newVersion, persister );
|
||||||
persister.setValues( entity, state );
|
persister.setValues( entity, state );
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.VersionValue;
|
import org.hibernate.engine.spi.VersionValue;
|
||||||
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
|
||||||
|
import org.hibernate.type.descriptor.java.JavaType;
|
||||||
|
import org.hibernate.type.descriptor.java.VersionJavaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes the mapping of an entity's version
|
* Describes the mapping of an entity's version
|
||||||
|
@ -25,4 +27,12 @@ public interface EntityVersionMapping extends BasicValuedModelPart {
|
||||||
* state based on the version mapping
|
* state based on the version mapping
|
||||||
*/
|
*/
|
||||||
VersionValue getUnsavedStrategy();
|
VersionValue getUnsavedStrategy();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
VersionJavaType<?> getJavaType();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default VersionJavaType<?> getExpressibleJavaType() {
|
||||||
|
return (VersionJavaType<?>) getMappedType().getMappedJavaType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,9 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
unsavedValueStrategy = UnsavedValueFactory.getUnsavedVersionValue(
|
unsavedValueStrategy = UnsavedValueFactory.getUnsavedVersionValue(
|
||||||
(KeyValue) bootEntityDescriptor.getVersion().getValue(),
|
(KeyValue) bootEntityDescriptor.getVersion().getValue(),
|
||||||
(VersionJavaType<?>) versionBasicType.getJavaTypeDescriptor(),
|
(VersionJavaType<?>) versionBasicType.getJavaTypeDescriptor(),
|
||||||
|
length,
|
||||||
|
precision,
|
||||||
|
scale,
|
||||||
declaringType
|
declaringType
|
||||||
.getRepresentationStrategy()
|
.getRepresentationStrategy()
|
||||||
.resolvePropertyAccess( bootEntityDescriptor.getVersion() )
|
.resolvePropertyAccess( bootEntityDescriptor.getVersion() )
|
||||||
|
@ -168,8 +171,8 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JavaType<?> getJavaType() {
|
public VersionJavaType<?> getJavaType() {
|
||||||
return versionBasicType.getJavaTypeDescriptor();
|
return (VersionJavaType<?>) versionBasicType.getJavaTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -2093,9 +2093,16 @@ public abstract class AbstractEntityPersister
|
||||||
// the difficulty here is exactly what we update in order to
|
// the difficulty here is exactly what we update in order to
|
||||||
// force the version to be incremented in the db...
|
// force the version to be incremented in the db...
|
||||||
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
|
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
|
||||||
}
|
|
||||||
|
|
||||||
Object nextVersion = getVersionJavaType().next( currentVersion, session );
|
}
|
||||||
|
final EntityVersionMapping versionMapping = getVersionMapping();
|
||||||
|
final Object nextVersion = getVersionJavaType().next(
|
||||||
|
currentVersion,
|
||||||
|
versionMapping.getLength(),
|
||||||
|
versionMapping.getPrecision(),
|
||||||
|
versionMapping.getScale(),
|
||||||
|
session
|
||||||
|
);
|
||||||
if ( LOG.isTraceEnabled() ) {
|
if ( LOG.isTraceEnabled() ) {
|
||||||
LOG.trace(
|
LOG.trace(
|
||||||
"Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) + "; "
|
"Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) + "; "
|
||||||
|
|
|
@ -806,7 +806,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
final ColumnReference versionColumn = targetColumnReferences.get( 0 );
|
final ColumnReference versionColumn = targetColumnReferences.get( 0 );
|
||||||
final Expression value;
|
final Expression value;
|
||||||
if ( versionMapping.getJdbcMapping().getJdbcType().isTemporal() ) {
|
if ( versionMapping.getJdbcMapping().getJdbcType().isTemporal() ) {
|
||||||
value = new VersionTypeSeedParameterSpecification( versionType, persister.getVersionJavaType() );
|
value = new VersionTypeSeedParameterSpecification( versionMapping );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value = new BinaryArithmeticExpression(
|
value = new BinaryArithmeticExpression(
|
||||||
|
@ -1201,10 +1201,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
assert targetColumnReferences.size() == 1;
|
assert targetColumnReferences.size() == 1;
|
||||||
|
|
||||||
targetColumnReferenceConsumer.accept( versionPath, targetColumnReferences );
|
targetColumnReferenceConsumer.accept( versionPath, targetColumnReferences );
|
||||||
versionExpression = new VersionTypeSeedParameterSpecification(
|
versionExpression = new VersionTypeSeedParameterSpecification( entityDescriptor.getVersionMapping() );
|
||||||
entityDescriptor.getVersionMapping().getJdbcMapping(),
|
|
||||||
entityDescriptor.getVersionJavaType()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ( discriminatorMapping != null && discriminatorMapping.isPhysical() ) {
|
if ( discriminatorMapping != null && discriminatorMapping.isPhysical() ) {
|
||||||
final BasicValuedPathInterpretation<?> discriminatorPath = new BasicValuedPathInterpretation<>(
|
final BasicValuedPathInterpretation<?> discriminatorPath = new BasicValuedPathInterpretation<>(
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.sql.exec.internal;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||||
|
@ -20,16 +21,16 @@ import org.hibernate.type.descriptor.java.VersionJavaType;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class VersionTypeSeedParameterSpecification extends AbstractJdbcParameter {
|
public class VersionTypeSeedParameterSpecification extends AbstractJdbcParameter {
|
||||||
private final VersionJavaType<?> type;
|
private final EntityVersionMapping versionMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a version seed parameter bind specification.
|
* Constructs a version seed parameter bind specification.
|
||||||
*
|
*
|
||||||
* @param type The version type.
|
* @param versionMapping The version mapping.
|
||||||
*/
|
*/
|
||||||
public VersionTypeSeedParameterSpecification(JdbcMapping jdbcMapping, VersionJavaType<?> type) {
|
public VersionTypeSeedParameterSpecification(EntityVersionMapping versionMapping) {
|
||||||
super( jdbcMapping );
|
super( versionMapping.getJdbcMapping() );
|
||||||
this.type = type;
|
this.versionMapping = versionMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,7 +42,12 @@ public class VersionTypeSeedParameterSpecification extends AbstractJdbcParameter
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
getJdbcMapping().getJdbcValueBinder().bind(
|
getJdbcMapping().getJdbcValueBinder().bind(
|
||||||
statement,
|
statement,
|
||||||
type.seed( executionContext.getSession() ),
|
versionMapping.getJavaType().seed(
|
||||||
|
versionMapping.getLength(),
|
||||||
|
versionMapping.getPrecision(),
|
||||||
|
versionMapping.getScale(),
|
||||||
|
executionContext.getSession()
|
||||||
|
),
|
||||||
startPosition,
|
startPosition,
|
||||||
executionContext.getSession()
|
executionContext.getSession()
|
||||||
);
|
);
|
||||||
|
|
|
@ -176,12 +176,19 @@ public class ByteJavaType extends AbstractClassJavaType<Byte>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Byte next(Byte current, SharedSessionContractImplementor session) {
|
public Byte next(
|
||||||
|
Byte current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
return (byte) ( current + 1 );
|
return (byte) ( current + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Byte seed(SharedSessionContractImplementor session) {
|
public Byte seed(
|
||||||
|
Long length,
|
||||||
|
Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,9 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.type.descriptor.java;
|
package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
|
import java.sql.Timestamp;
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
|
||||||
|
@ -155,12 +157,17 @@ public class CalendarJavaType extends AbstractTemporalJavaType<Calendar> impleme
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Calendar next(Calendar current, SharedSessionContractImplementor session) {
|
public Calendar next(
|
||||||
return seed( session );
|
Calendar current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return seed( length, precision, scale, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Calendar seed(SharedSessionContractImplementor session) {
|
public Calendar seed(Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return Calendar.getInstance();
|
return GregorianCalendar.from( ZonedDateTime.now( ClockHelper.forPrecision( precision, session ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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.type.descriptor.java;
|
||||||
|
|
||||||
|
import java.time.Clock;
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for determining the correct clock for precision
|
||||||
|
*/
|
||||||
|
public class ClockHelper {
|
||||||
|
|
||||||
|
private static final Duration TICK_8 = Duration.ofNanos( 10L );
|
||||||
|
private static final Duration TICK_7 = Duration.ofNanos( 100L );
|
||||||
|
private static final Duration TICK_6 = Duration.ofNanos( 1000L );
|
||||||
|
private static final Duration TICK_5 = Duration.ofNanos( 10000L );
|
||||||
|
private static final Duration TICK_4 = Duration.ofNanos( 100000L );
|
||||||
|
private static final Duration TICK_3 = Duration.ofNanos( 1000000L );
|
||||||
|
private static final Duration TICK_2 = Duration.ofNanos( 10000000L );
|
||||||
|
private static final Duration TICK_1 = Duration.ofNanos( 100000000L );
|
||||||
|
private static final Duration TICK_0 = Duration.ofNanos( 1000000000L );
|
||||||
|
|
||||||
|
public static Clock forPrecision(Integer precision, SharedSessionContractImplementor session) {
|
||||||
|
final int resolvedPrecision;
|
||||||
|
if ( precision == null ) {
|
||||||
|
resolvedPrecision = session.getJdbcServices().getDialect().getDefaultTimestampPrecision();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolvedPrecision = precision;
|
||||||
|
}
|
||||||
|
final Clock clock = Clock.systemDefaultZone();
|
||||||
|
switch ( resolvedPrecision ) {
|
||||||
|
case 0:
|
||||||
|
return Clock.tick( clock, TICK_0 );
|
||||||
|
case 1:
|
||||||
|
return Clock.tick( clock, TICK_1 );
|
||||||
|
case 2:
|
||||||
|
return Clock.tick( clock, TICK_2 );
|
||||||
|
case 3:
|
||||||
|
return Clock.tick( clock, TICK_3 );
|
||||||
|
case 4:
|
||||||
|
return Clock.tick( clock, TICK_4 );
|
||||||
|
case 5:
|
||||||
|
return Clock.tick( clock, TICK_5 );
|
||||||
|
case 6:
|
||||||
|
return Clock.tick( clock, TICK_6 );
|
||||||
|
case 7:
|
||||||
|
return Clock.tick( clock, TICK_7 );
|
||||||
|
case 8:
|
||||||
|
return Clock.tick( clock, TICK_8 );
|
||||||
|
case 9:
|
||||||
|
return clock;
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException( "Illegal precision: " + resolvedPrecision );
|
||||||
|
}
|
||||||
|
}
|
|
@ -166,12 +166,19 @@ public class DateJavaType extends AbstractTemporalJavaType<Date> implements Vers
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date next(Date current, SharedSessionContractImplementor session) {
|
public Date next(
|
||||||
return seed( session );
|
Date current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return seed( length, precision, scale, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date seed(SharedSessionContractImplementor session) {
|
public Date seed(
|
||||||
return new Timestamp( System.currentTimeMillis() );
|
Long length,
|
||||||
|
Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
|
return Timestamp.from( ClockHelper.forPrecision( precision, session ).instant() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,20 +47,29 @@ public class DbTimestampJavaType<T> implements VersionJavaType<T>, TemporalJavaT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T next(T current, SharedSessionContractImplementor session) {
|
public T next(
|
||||||
return seed( session );
|
T current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return seed( length, precision, scale, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T seed(SharedSessionContractImplementor session) {
|
public T seed(
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
if ( session == null ) {
|
if ( session == null ) {
|
||||||
LOG.trace( "Incoming session was null; using current jvm time" );
|
LOG.trace( "Incoming session was null; using current jvm time" );
|
||||||
return ((VersionJavaType<T>) delegate).seed( null );
|
return ((VersionJavaType<T>) delegate).seed( length, precision, scale, null );
|
||||||
}
|
}
|
||||||
else if ( !session.getJdbcServices().getJdbcEnvironment().getDialect().supportsCurrentTimestampSelection() ) {
|
else if ( !session.getJdbcServices().getJdbcEnvironment().getDialect().supportsCurrentTimestampSelection() ) {
|
||||||
LOG.debug( "Falling back to vm-based timestamp, as dialect does not support current timestamp selection" );
|
LOG.debug( "Falling back to vm-based timestamp, as dialect does not support current timestamp selection" );
|
||||||
return ((VersionJavaType<T>) delegate).seed( session );
|
return ((VersionJavaType<T>) delegate).seed( length, precision, scale, session );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return getCurrentTimestamp( session );
|
return getCurrentTimestamp( session );
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
package org.hibernate.type.descriptor.java;
|
package org.hibernate.type.descriptor.java;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.sql.Types;
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
|
@ -196,13 +195,18 @@ public class InstantJavaType extends AbstractTemporalJavaType<Instant>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instant seed(SharedSessionContractImplementor session) {
|
public Instant seed(Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return Instant.now();
|
return Instant.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Instant next(Instant current, SharedSessionContractImplementor session) {
|
public Instant next(
|
||||||
return Instant.now();
|
Instant current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return Instant.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,12 +195,17 @@ public class IntegerJavaType extends AbstractClassJavaType<Integer>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer seed(SharedSessionContractImplementor session) {
|
public Integer seed(
|
||||||
|
Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer next(Integer current, SharedSessionContractImplementor session) {
|
public Integer next(
|
||||||
|
Integer current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale, SharedSessionContractImplementor session) {
|
||||||
return current + 1;
|
return current + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -216,13 +216,22 @@ public class JdbcTimestampJavaType extends AbstractTemporalJavaType<Date> implem
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date next(Date current, SharedSessionContractImplementor session) {
|
public Date next(
|
||||||
return seed( session );
|
Date current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return seed( length, precision, scale, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date seed(SharedSessionContractImplementor session) {
|
public Date seed(
|
||||||
return new Timestamp( System.currentTimeMillis() );
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return Timestamp.from( ClockHelper.forPrecision( precision, session ).instant() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -163,12 +163,17 @@ public class LocalDateTimeJavaType extends AbstractTemporalJavaType<LocalDateTim
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime seed(SharedSessionContractImplementor session) {
|
public LocalDateTime seed(Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return LocalDateTime.now();
|
return LocalDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LocalDateTime next(LocalDateTime current, SharedSessionContractImplementor session) {
|
public LocalDateTime next(
|
||||||
return LocalDateTime.now();
|
LocalDateTime current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return LocalDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,12 +197,19 @@ public class LongJavaType extends AbstractClassJavaType<Long>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long next(Long current, SharedSessionContractImplementor session) {
|
public Long next(
|
||||||
|
Long current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
return current + 1L;
|
return current + 1L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long seed(SharedSessionContractImplementor session) {
|
public Long seed(
|
||||||
|
Long length,
|
||||||
|
Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,12 +206,21 @@ public class OffsetDateTimeJavaType extends AbstractTemporalJavaType<OffsetDateT
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OffsetDateTime seed(SharedSessionContractImplementor session) {
|
public OffsetDateTime seed(
|
||||||
return OffsetDateTime.now();
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return OffsetDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OffsetDateTime next(OffsetDateTime current, SharedSessionContractImplementor session) {
|
public OffsetDateTime next(
|
||||||
return OffsetDateTime.now();
|
OffsetDateTime current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return OffsetDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,7 +130,8 @@ public class PrimitiveByteArrayJavaType extends AbstractClassJavaType<byte[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] seed(SharedSessionContractImplementor session) {
|
public byte[] seed(
|
||||||
|
Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
// Note : simply returns null for seed() and next() as the only known
|
// Note : simply returns null for seed() and next() as the only known
|
||||||
// application of binary types for versioning is for use with the
|
// application of binary types for versioning is for use with the
|
||||||
// TIMESTAMP datatype supported by Sybase and SQL Server, which
|
// TIMESTAMP datatype supported by Sybase and SQL Server, which
|
||||||
|
@ -139,7 +140,11 @@ public class PrimitiveByteArrayJavaType extends AbstractClassJavaType<byte[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] next(byte[] current, SharedSessionContractImplementor session) {
|
public byte[] next(
|
||||||
|
byte[] current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale, SharedSessionContractImplementor session) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,8 @@ public class RowVersionJavaType extends AbstractClassJavaType<byte[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] seed(SharedSessionContractImplementor session) {
|
public byte[] seed(
|
||||||
|
Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
// Note : simply returns null for seed() and next() as the only known
|
// Note : simply returns null for seed() and next() as the only known
|
||||||
// application of binary types for versioning is for use with the
|
// application of binary types for versioning is for use with the
|
||||||
// TIMESTAMP datatype supported by Sybase and SQL Server, which
|
// TIMESTAMP datatype supported by Sybase and SQL Server, which
|
||||||
|
@ -134,7 +135,11 @@ public class RowVersionJavaType extends AbstractClassJavaType<byte[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] next(byte[] current, SharedSessionContractImplementor session) {
|
public byte[] next(
|
||||||
|
byte[] current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale, SharedSessionContractImplementor session) {
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,12 +184,19 @@ public class ShortJavaType extends AbstractClassJavaType<Short>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Short seed(SharedSessionContractImplementor session) {
|
public Short seed(
|
||||||
|
Long length,
|
||||||
|
Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ZERO;
|
return ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Short next(Short current, SharedSessionContractImplementor session) {
|
public Short next(
|
||||||
|
Short current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
return (short) ( current + 1 );
|
return (short) ( current + 1 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,18 +17,24 @@ public interface VersionJavaType<T> extends JavaType<T> {
|
||||||
/**
|
/**
|
||||||
* Generate an initial version.
|
* Generate an initial version.
|
||||||
*
|
*
|
||||||
|
* @param length The length of the type
|
||||||
|
* @param precision The precision of the type
|
||||||
|
* @param scale The scale of the type
|
||||||
* @param session The session from which this request originates.
|
* @param session The session from which this request originates.
|
||||||
* @return an instance of the type
|
* @return an instance of the type
|
||||||
*/
|
*/
|
||||||
T seed(SharedSessionContractImplementor session);
|
T seed(Long length, Integer precision, Integer scale, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Increment the version.
|
* Increment the version.
|
||||||
*
|
*
|
||||||
* @param session The session from which this request originates.
|
|
||||||
* @param current the current version
|
* @param current the current version
|
||||||
|
* @param length The length of the type
|
||||||
|
* @param precision The precision of the type
|
||||||
|
* @param scale The scale of the type
|
||||||
|
* @param session The session from which this request originates.
|
||||||
* @return an instance of the type
|
* @return an instance of the type
|
||||||
*/
|
*/
|
||||||
T next(T current, SharedSessionContractImplementor session);
|
T next(T current, Long length, Integer precision, Integer scale, SharedSessionContractImplementor session);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,12 +206,17 @@ public class ZonedDateTimeJavaType extends AbstractTemporalJavaType<ZonedDateTim
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ZonedDateTime seed(SharedSessionContractImplementor session) {
|
public ZonedDateTime seed(Long length, Integer precision, Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ZonedDateTime.now();
|
return ZonedDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ZonedDateTime next(ZonedDateTime current, SharedSessionContractImplementor session) {
|
public ZonedDateTime next(
|
||||||
return ZonedDateTime.now();
|
ZonedDateTime current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
|
return ZonedDateTime.now( ClockHelper.forPrecision( precision, session ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,12 +21,20 @@ public class UserTypeVersionJavaTypeWrapper<J> extends UserTypeJavaTypeWrapper<J
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public J seed(SharedSessionContractImplementor session) {
|
public J seed(
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale, SharedSessionContractImplementor session) {
|
||||||
return ( (UserVersionType<J>) userType ).seed( session );
|
return ( (UserVersionType<J>) userType ).seed( session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public J next(J current, SharedSessionContractImplementor session) {
|
public J next(
|
||||||
|
J current,
|
||||||
|
Long length,
|
||||||
|
Integer precision,
|
||||||
|
Integer scale,
|
||||||
|
SharedSessionContractImplementor session) {
|
||||||
return ( (UserVersionType<J>) userType ).next( current, session );
|
return ( (UserVersionType<J>) userType ).next( current, session );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue