HHH-17687 AttributeConverter, query does not use converter to convert 'null' fields

This commit is contained in:
Andrea Boriero 2024-01-30 17:49:30 +01:00 committed by Christian Beikov
parent f29cf88748
commit 6b78d0cf43
7 changed files with 63 additions and 120 deletions

View File

@ -6,8 +6,6 @@
*/
package org.hibernate.engine.internal;
import java.io.Serializable;
import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.cache.spi.access.CachedDomainDataAccess;
import org.hibernate.engine.spi.SessionEventListenerManager;
@ -90,31 +88,29 @@ public final class CacheHelper {
}
return cachedValue;
}
public static void addBasicValueToCacheKey(
MutableCacheKeyBuilder cacheKey,
Object value,
JdbcMapping jdbcMapping,
SharedSessionContractImplementor session) {
if ( value == null ) {
cacheKey.addValue( null );
cacheKey.addHashCode( 0 );
return;
}
final BasicValueConverter converter = jdbcMapping.getValueConverter();
final Serializable disassemble;
final int hashCode;
final Object convertedValue;
final JavaType javaType;
if ( converter == null ) {
disassemble = jdbcMapping.getJavaTypeDescriptor().getMutabilityPlan().disassemble( value, session );
hashCode = ( (JavaType) jdbcMapping.getMappedJavaType() ).extractHashCode( value );
javaType = jdbcMapping.getJavaTypeDescriptor();
convertedValue = value;
}
else {
final Object relationalValue = converter.toRelationalValue( value );
final JavaType relationalJavaType = converter.getRelationalJavaType();
disassemble = relationalJavaType.getMutabilityPlan().disassemble( relationalValue, session );
hashCode = relationalJavaType.extractHashCode( relationalValue );
javaType = converter.getRelationalJavaType();
convertedValue = converter.toRelationalValue( value );
}
if ( convertedValue == null ) {
cacheKey.addValue( null );
cacheKey.addHashCode( 0 );
}
else {
cacheKey.addValue( javaType.getMutabilityPlan().disassemble( convertedValue, session ) );
cacheKey.addHashCode( javaType.extractHashCode( convertedValue ) );
}
cacheKey.addValue( disassemble );
cacheKey.addHashCode( hashCode );
}
}

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@ -16,6 +15,7 @@ import java.util.function.IntFunction;
import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.IndexedConsumer;
import org.hibernate.metamodel.mapping.AssociationKey;
@ -57,7 +57,6 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -468,27 +467,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
@Override
public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) {
if ( value == null ) {
return;
}
final JdbcMapping jdbcMapping = getJdbcMapping();
final BasicValueConverter converter = jdbcMapping.getValueConverter();
final Serializable disassemble;
final int hashCode;
if ( converter == null ) {
final JavaType javaTypeDescriptor = jdbcMapping.getJavaTypeDescriptor();
disassemble = javaTypeDescriptor.getMutabilityPlan().disassemble( value, session );
hashCode = javaTypeDescriptor.extractHashCode( disassemble );
}
else {
final Object relationalValue = converter.toRelationalValue( value );
final JavaType relationalJavaType = converter.getRelationalJavaType();
disassemble = relationalJavaType.getMutabilityPlan().disassemble( relationalValue, session );
hashCode = relationalJavaType.extractHashCode( relationalValue );
}
cacheKey.addValue( disassemble );
cacheKey.addHashCode( hashCode );
CacheHelper.addBasicValueToCacheKey( cacheKey, value, getJdbcMapping(), session );
}
@Override

View File

@ -44,7 +44,6 @@ import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmQuerySource;
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.SqmDmlStatement;
import org.hibernate.query.sqm.tree.SqmJoinType;
import org.hibernate.query.sqm.tree.SqmStatement;
@ -57,12 +56,10 @@ import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmQueryPart;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlTreeCreationException;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -350,18 +347,6 @@ public class SqmUtil {
expansionPosition++;
}
}
else if ( domainParamBinding.getBindValue() == null ) {
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
final JdbcParametersList jdbcParams = jdbcParamsBinds.get( i );
for ( int j = 0; j < jdbcParams.size(); j++ ) {
final JdbcParameter jdbcParameter = jdbcParams.get( j );
jdbcParameterBindings.addBinding(
jdbcParameter,
new JdbcParameterBindingImpl( null, null )
);
}
}
}
else {
final JdbcMapping jdbcMapping;
if ( domainParamBinding.getType() instanceof JdbcMapping ) {
@ -377,7 +362,6 @@ public class SqmUtil {
final BasicValueConverter valueConverter = jdbcMapping == null ? null : jdbcMapping.getValueConverter();
if ( valueConverter != null ) {
final Object convertedValue = valueConverter.toRelationalValue( domainParamBinding.getBindValue() );
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
final JdbcParametersList jdbcParams = jdbcParamsBinds.get( i );
assert jdbcParams.size() == 1;
@ -387,23 +371,37 @@ public class SqmUtil {
new JdbcParameterBindingImpl( jdbcMapping, convertedValue )
);
}
continue;
}
else {
final Object bindValue = domainParamBinding.getBindValue();
if ( bindValue == null ) {
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
final JdbcParametersList jdbcParams = jdbcParamsBinds.get( i );
for ( int j = 0; j < jdbcParams.size(); j++ ) {
final JdbcParameter jdbcParameter = jdbcParams.get( j );
jdbcParameterBindings.addBinding(
jdbcParameter,
new JdbcParameterBindingImpl( jdbcMapping, bindValue )
);
}
}
}
else {
final Object bindValue = domainParamBinding.getBindValue();
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
final JdbcParametersList jdbcParams = jdbcParamsBinds.get( i );
createValueBindings(
jdbcParameterBindings,
queryParam,
domainParamBinding,
parameterType,
jdbcParams,
bindValue,
tableGroupLocator,
session
);
for ( int i = 0; i < jdbcParamsBinds.size(); i++ ) {
final JdbcParametersList jdbcParams = jdbcParamsBinds.get( i );
createValueBindings(
jdbcParameterBindings,
queryParam,
domainParamBinding,
parameterType,
jdbcParams,
bindValue,
tableGroupLocator,
session
);
}
}
}
}
}

View File

@ -6,11 +6,11 @@
*/
package org.hibernate.sql.exec.internal;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.IndexedConsumer;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
@ -29,7 +29,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.EnumJavaType;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -188,27 +187,7 @@ public abstract class AbstractJdbcParameter
@Override
public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) {
if ( value == null ) {
return;
}
final JdbcMapping jdbcMapping = getJdbcMapping();
final BasicValueConverter converter = jdbcMapping.getValueConverter();
final Serializable disassemble;
final int hashCode;
if ( converter == null ) {
final JavaType javaTypeDescriptor = jdbcMapping.getJavaTypeDescriptor();
disassemble = javaTypeDescriptor.getMutabilityPlan().disassemble( value, session );
hashCode = javaTypeDescriptor.extractHashCode( value );
}
else {
final Object relationalValue = converter.toRelationalValue( value );
final JavaType relationalJavaType = converter.getRelationalJavaType();
disassemble = relationalJavaType.getMutabilityPlan().disassemble( relationalValue, session );
hashCode = relationalJavaType.extractHashCode( relationalValue );
}
cacheKey.addValue( disassemble );
cacheKey.addHashCode( hashCode );
CacheHelper.addBasicValueToCacheKey( cacheKey, value, getJdbcMapping(), session );
}
@Override

View File

@ -16,7 +16,6 @@ import java.util.function.BiConsumer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.BindableType;
import org.hibernate.query.spi.QueryParameterBinding;
@ -94,7 +93,7 @@ public class JdbcParameterBindingsImpl implements JdbcParameterBindings {
for ( Object bindValue : bindValues ) {
final JdbcParameterImpl jdbcParameter = new JdbcParameterImpl( jdbcMapping );
jdbcParameterBinders.add( jdbcParameter );
lastBindValue = bindValue == null ? null : valueConverter.toRelationalValue( bindValue );
lastBindValue = valueConverter.toRelationalValue( bindValue );
addBinding( jdbcParameter, new JdbcParameterBindingImpl( jdbcMapping, lastBindValue ) );
}
if ( bindValueMaxCount != bindValueCount ) {

View File

@ -16,6 +16,7 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.engine.internal.CacheHelper;
import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -205,7 +206,7 @@ public class CustomType<J>
// we have to handle the fact that it could produce a null value,
// in which case we will try to use a converter for disassembling,
// or if that doesn't exist, simply use the domain value as is
if ( disassembled == null && value != null ) {
if ( disassembled == null ){
final BasicValueConverter<J, Object> valueConverter = getUserType().getValueConverter();
if ( valueConverter == null ) {
return disassembled;
@ -220,7 +221,6 @@ public class CustomType<J>
@Override
public Object disassemble(Object value, SharedSessionContractImplementor session) {
// Use the value converter if available for conversion to the jdbc representation
if ( value != null ) {
final BasicValueConverter<J, Object> valueConverter = getUserType().getValueConverter();
if ( valueConverter == null ) {
return value;
@ -228,38 +228,28 @@ public class CustomType<J>
else {
return valueConverter.toRelationalValue( (J) value );
}
}
return value;
}
@Override
public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) {
if ( value == null ) {
return;
}
final Serializable disassembled = getUserType().disassemble( (J) value );
// Since UserType#disassemble is an optional operation,
// we have to handle the fact that it could produce a null value,
// in which case we will try to use a converter for disassembling,
// or if that doesn't exist, simply use the domain value as is
if ( disassembled == null && value != null ) {
final BasicValueConverter<J, Object> valueConverter = getUserType().getValueConverter();
if ( valueConverter == null ) {
cacheKey.addValue( value );
}
else {
cacheKey.addValue(
valueConverter.getRelationalJavaType().getMutabilityPlan().disassemble(
valueConverter.toRelationalValue( (J) value ),
session
)
);
}
if ( disassembled == null) {
CacheHelper.addBasicValueToCacheKey( cacheKey, value, this, session );
}
else {
cacheKey.addValue( disassembled );
if ( value == null ) {
cacheKey.addHashCode( 0 );
}
else {
cacheKey.addHashCode( getUserType().hashCode( (J) value ) );
}
}
cacheKey.addHashCode( getUserType().hashCode( (J) value ) );
}
@Override

View File

@ -11,6 +11,8 @@ import org.hibernate.dialect.Dialect;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
* Support for {@linkplain org.hibernate.type basic-typed} value conversions.
* <p>
@ -30,13 +32,13 @@ public interface BasicValueConverter<D,R> {
* Convert the relational form just retrieved from JDBC ResultSet into
* the domain form.
*/
D toDomainValue(R relationalForm);
@Nullable D toDomainValue(@Nullable R relationalForm);
/**
* Convert the domain form into the relational form in preparation for
* storage into JDBC
*/
R toRelationalValue(D domainForm);
@Nullable R toRelationalValue(@Nullable D domainForm);
/**
* Descriptor for the Java type for the domain portion of this converter