diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatedAssociationModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatedAssociationModelPart.java index b7cebe1a08..985d3be63c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatedAssociationModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/DiscriminatedAssociationModelPart.java @@ -26,4 +26,5 @@ public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableC BasicValuedModelPart getKeyPart(); EntityMappingType resolveDiscriminatorValue(Object discriminatorValue); + Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java index 92fc9726e6..ea23ed0ca8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java @@ -571,6 +571,9 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp for ( int i = 0; i < attributeMappings.size(); i++ ) { final AttributeMapping attributeMapping = attributeMappings.get( i ); + if ( attributeMapping instanceof PluralAttributeMapping ) { + continue; + } final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); span += attributeMapping.forEachJdbcValue( o, clause, span + offset, consumer, session ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java index ad6c10c073..e238cfc341 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityValuedModelPart.java @@ -94,7 +94,12 @@ public interface EntityValuedModelPart extends FetchableContainer { @Override default Object disassemble(Object value, SharedSessionContractImplementor session) { - return getEntityMappingType().disassemble( value, session ); + if ( value == null ) { + return null; + } + final EntityIdentifierMapping identifierMapping = getEntityMappingType().getIdentifierMapping(); + final Object identifier = identifierMapping.getIdentifier( value, session ); + return identifierMapping.disassemble( identifier, session ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java index 2d5711e57b..8066dfa7a8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java @@ -6,6 +6,8 @@ */ package org.hibernate.metamodel.mapping.internal; +import java.io.Serializable; + import org.hibernate.LockMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; @@ -123,6 +125,12 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions return navigableRole; } + @Override + public Object disassemble(Object value, SharedSessionContractImplementor session) { + final Serializable discriminator = metaType.disassemble( value, session, value ); + return discriminator; + } + @Override public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) { valueConsumer.consume( domainValue, this ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java index eca60cebcc..88445ba801 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicEntityIdentifierMappingImpl.java @@ -282,7 +282,8 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa if ( value == null ) { return null; } - return propertyAccess.getGetter().get( value ); + return value; +// return propertyAccess.getGetter().get( value ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java index b869bce8c5..ddee9a1f47 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java @@ -18,6 +18,7 @@ import org.hibernate.mapping.IndexedConsumer; import org.hibernate.mapping.Property; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.ManagedMappingType; @@ -93,9 +94,14 @@ public class DiscriminatedAssociationAttributeMapping @Override public EntityMappingType resolveDiscriminatorValue(Object discriminatorValue) { - return discriminatorMapping.resolveDiscriminatorValueToEntityName( discriminatorValue ); + return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( discriminatorValue ); } + public Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType) { + return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType ); + } + + @Override public Fetch generateFetch( FetchParent fetchParent, @@ -136,6 +142,25 @@ public class DiscriminatedAssociationAttributeMapping return getDiscriminatorPart().getJdbcTypeCount() + getKeyPart().getJdbcTypeCount(); } + @Override + public Object disassemble(Object value, SharedSessionContractImplementor session) { + final String entityName = session.bestGuessEntityName( value ); + final EntityMappingType entityMappingType = session.getFactory() + .getRuntimeMetamodels() + .getEntityMappingType( entityName ); + final Object discriminator = discriminatorMapping + .getModelPart() + .resolveDiscriminatorForEntityType( entityMappingType ); + + final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping(); + final Object identifier = identifierMapping.getIdentifier( value, session ); + + return new Object[] { + discriminatorMapping.getDiscriminatorPart().disassemble( discriminator, session ), + identifierMapping.disassemble( identifier, session ) + }; + } + @Override public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) { discriminatorMapping.getDiscriminatorPart().breakDownJdbcValues( domainValue, valueConsumer, session ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java index 89d1568409..035664905c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java @@ -165,7 +165,18 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption return keyPart; } - public EntityMappingType resolveDiscriminatorValueToEntityName(Object discriminatorValue) { + public Object resolveDiscriminatorValueToEntityMapping(EntityMappingType entityMappingType) { + for ( int i = 0; i < discriminatorValueMappings.size(); i++ ) { + final ValueMapping valueMapping = discriminatorValueMappings.get( i ); + if ( valueMapping.entityMapping.equals( entityMappingType ) ) { + return valueMapping.discriminatorValue; + } + } + + return null; + } + + public EntityMappingType resolveDiscriminatorValueToEntityMapping(Object discriminatorValue) { //noinspection ForLoopReplaceableByForEach for ( int i = 0; i < discriminatorValueMappings.size(); i++ ) { final ValueMapping valueMapping = discriminatorValueMappings.get( i ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java index 6dd7050103..4417640dfe 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java @@ -77,7 +77,12 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode @Override public EntityMappingType resolveDiscriminatorValue(Object discriminatorValue) { - return discriminatorMapping.resolveDiscriminatorValueToEntityName( discriminatorValue ); + return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( discriminatorValue ); + } + + @Override + public Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType) { + return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingSqmPathSource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingSqmPathSource.java index 7e60f32084..d31472ab8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingSqmPathSource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/AnyMappingSqmPathSource.java @@ -10,6 +10,7 @@ import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.metamodel.model.domain.AnyMappingDomainType; import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.hql.spi.SqmCreationState; +import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; /** @@ -37,6 +38,11 @@ public class AnyMappingSqmPathSource extends AbstractSqmPathSource { @Override public SqmPath createSqmPath(SqmPath lhs, SqmCreationState creationState) { - throw new NotYetImplementedFor6Exception(); + return new SqmAnyValuedSimplePath<>( + lhs.getNavigablePath().append( getPathName() ), + this, + lhs, + creationState.getCreationContext().getQueryEngine().getCriteriaBuilder() + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java index 78b5efc8cf..54bc47f428 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/EmbeddableTypeImpl.java @@ -7,34 +7,16 @@ package org.hibernate.metamodel.model.domain.internal; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import java.util.Set; -import javax.persistence.metamodel.Attribute; -import javax.persistence.metamodel.SingularAttribute; -import javax.persistence.metamodel.Type; import org.hibernate.NotYetImplementedFor6Exception; -import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.internal.SubGraphImpl; import org.hibernate.graph.spi.SubGraphImplementor; -import org.hibernate.mapping.IndexedConsumer; -import org.hibernate.metamodel.MappingMetamodel; -import org.hibernate.metamodel.mapping.Bindable; -import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.model.domain.AbstractManagedType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; -import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.JpaMetamodel; import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.ManagedTypeRepresentationStrategy; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl; -import org.hibernate.property.access.spi.PropertyAccess; -import org.hibernate.sql.ast.Clause; -import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -46,7 +28,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; */ public class EmbeddableTypeImpl extends AbstractManagedType - implements EmbeddableDomainType, Serializable, MappingModelExpressable { + implements EmbeddableDomainType, Serializable { private final boolean isDynamic; private final EmbeddableRepresentationStrategy representationStrategy; @@ -93,88 +75,4 @@ public class EmbeddableTypeImpl public SubGraphImplementor makeSubGraph(Class subType) { return new SubGraphImpl( this, true, jpaMetamodel() ); } - - @Override - public int forEachJdbcValue( - Object value, - Clause clause, - int offset, - JdbcValuesConsumer valuesConsumer, - SharedSessionContractImplementor session) { - final Object[] disassemble = (Object[]) disassemble( value, session ); - return forEachJdbcType( - (i, jdbcMapping) -> { - valuesConsumer.consume( i + offset, disassemble[i], jdbcMapping ); - } - ); - } - - @Override - public int forEachJdbcType(int offset, IndexedConsumer action) { - final MappingMetamodel metamodel = jpaMetamodel().getTypeConfiguration().getSessionFactory().getMetamodel(); - int i = 0; - for ( Attribute attribute : getAttributes() ) { - if ( attribute instanceof SingularAttribute ) { - Type type = ( (SingularAttribute) attribute ).getType(); - switch ( type.getPersistenceType() ) { - case BASIC: - BasicType basicType = jpaMetamodel().getTypeConfiguration() - .getBasicTypeForJavaType( attribute.getJavaType() ); - action.accept( i + offset, basicType.getJdbcMapping() ); - i++; - break; - case ENTITY: - final EntityPersister entityDescriptor = metamodel.getEntityDescriptor( - ( (EntityDomainType) type ).getHibernateEntityName() - ); - i += entityDescriptor.getEntityMappingType().getIdentifierMapping().forEachJdbcType( - i + offset, - action - ); - break; - case EMBEDDABLE: - i += ( (Bindable) type ).forEachJdbcType( i + offset, action ); - break; - default: - throw new IllegalArgumentException( "Unsupported type: " + type ); - } - } - } - return i; - } - - @Override - public Object disassemble(Object value, SharedSessionContractImplementor session) { - final Set> attributes = getAttributes(); - final List result = new ArrayList<>(); - for ( Attribute attribute : attributes ) { - if ( attribute instanceof SingularAttributeImpl ) { - final PropertyAccess propertyAccess = PropertyAccessStrategyMixedImpl.INSTANCE - .buildPropertyAccess( getJavaType(), attribute.getName() ); - - final Object attributeValue = propertyAccess.getGetter().get( value ); - if ( attribute.isAssociation() ) { - final EntityPersister entityDescriptor = session.getFactory().getMetamodel() - .findEntityDescriptor( attribute.getJavaType().getName() ); - final Object disassembled = entityDescriptor.getIdentifierMapping().disassemble( - attributeValue, - session - ); - if ( disassembled instanceof Object[] ) { - for ( Object o : (Object[]) disassembled ) { - result.add( o ); - } - } - else { - result.add( disassembled ); - } - } - else { - result.add( attributeValue ); - } - } - } - return result.toArray(); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheDisabledImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheDisabledImpl.java index a566bd235e..78fbbc9eff 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheDisabledImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryInterpretationCacheDisabledImpl.java @@ -6,10 +6,13 @@ */ package org.hibernate.query.internal; +import java.util.Collections; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Supplier; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.spi.HqlInterpretation; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.ParameterMetadataImplementor; @@ -18,6 +21,7 @@ import org.hibernate.query.spi.SelectQueryPlan; import org.hibernate.query.sql.spi.ParameterInterpretation; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.tree.SqmStatement; +import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.stat.spi.StatisticsImplementor; /** @@ -64,6 +68,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation final DomainParameterXref domainParameterXref; final ParameterMetadataImplementor parameterMetadata; + if ( sqmStatement.getSqmParameters().isEmpty() ) { domainParameterXref = DomainParameterXref.empty(); parameterMetadata = ParameterMetadataImpl.EMPTY; @@ -71,6 +76,7 @@ public class QueryInterpretationCacheDisabledImpl implements QueryInterpretation else { domainParameterXref = DomainParameterXref.from( sqmStatement ); parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() ); + } if ( stats ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java index b24504c3e0..fa83636bcc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/ConcreteSqmSelectQueryPlan.java @@ -6,7 +6,6 @@ */ package org.hibernate.query.sqm.internal; -import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; @@ -21,6 +20,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.EmptyScrollableResults; import org.hibernate.internal.util.streams.StingArrayCollector; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryOptions; @@ -252,6 +252,7 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { sqmInterpretation.getJdbcParamsXref(), session.getFactory().getDomainModel(), sqmInterpretation.getTableGroupAccess()::findTableGroup, + sqmInterpretation.getSqmParameterMappingModelTypes()::get, session ); sqmInterpretation.getJdbcSelect().bindFilterJdbcParameters( jdbcParameterBindings ); @@ -278,7 +279,7 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { ); // tableGroupAccess = sqmConverter.getFromClauseAccess(); - final SqmTranslation interpretation = sqmConverter.translate(); + final SqmTranslation sqmInterpretation = sqmConverter.translate(); final FromClauseAccess tableGroupAccess = sqmConverter.getFromClauseAccess(); final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); @@ -286,12 +287,12 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { final SqlAstTranslatorFactory sqlAstTranslatorFactory = jdbcEnvironment.getSqlAstTranslatorFactory(); final SqlAstTranslator selectTranslator = sqlAstTranslatorFactory.buildSelectTranslator( sessionFactory, - interpretation.getSqlAst() + sqmInterpretation.getSqlAst() ); final Map, Map>>> jdbcParamsXref = SqmUtil.generateJdbcParamsXref( domainParameterXref, - interpretation::getJdbcParamsBySqmParam + sqmInterpretation::getJdbcParamsBySqmParam ); final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings( executionContext.getQueryParameterBindings(), @@ -299,6 +300,7 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { jdbcParamsXref, session.getFactory().getDomainModel(), tableGroupAccess::findTableGroup, + sqmInterpretation.getSqmParameterMappingModelTypeResolutions()::get, session ); final JdbcSelect jdbcSelect = selectTranslator.translate( jdbcParameterBindings, executionContext.getQueryOptions() ); @@ -307,11 +309,12 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { jdbcSelect, tableGroupAccess, jdbcParamsXref, + sqmInterpretation.getSqmParameterMappingModelTypeResolutions(), jdbcParameterBindings ); } - private static interface SqmInterpreter { + private interface SqmInterpreter { T interpret( X context, ExecutionContext executionContext, @@ -323,16 +326,19 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { private final JdbcSelect jdbcSelect; private final FromClauseAccess tableGroupAccess; private final Map, Map>>> jdbcParamsXref; + private final Map sqmParameterMappingModelTypes; private transient JdbcParameterBindings firstParameterBindings; CacheableSqmInterpretation( JdbcSelect jdbcSelect, FromClauseAccess tableGroupAccess, Map, Map>>> jdbcParamsXref, + Map sqmParameterMappingModelTypes, JdbcParameterBindings firstParameterBindings) { this.jdbcSelect = jdbcSelect; this.tableGroupAccess = tableGroupAccess; this.jdbcParamsXref = jdbcParamsXref; + this.sqmParameterMappingModelTypes = sqmParameterMappingModelTypes; this.firstParameterBindings = firstParameterBindings; } @@ -348,6 +354,10 @@ public class ConcreteSqmSelectQueryPlan implements SelectQueryPlan { return jdbcParamsXref; } + public Map getSqmParameterMappingModelTypes() { + return sqmParameterMappingModelTypes; + } + JdbcParameterBindings getFirstParameterBindings() { return firstParameterBindings; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java index 31681f7f20..327f1485b8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleDeleteQueryPlan.java @@ -104,13 +104,12 @@ public class SimpleDeleteQueryPlan implements NonSelectQueryPlan { jdbcParamsXref, factory.getDomainModel(), sqmInterpretation.getFromClauseAccess()::findTableGroup, + sqmInterpretation.getSqmParameterMappingModelTypeResolutions()::get, session ); - if ( jdbcDelete != null && !jdbcDelete.isCompatibleWith( - jdbcParameterBindings, - executionContext.getQueryOptions() - ) ) { + if ( jdbcDelete != null + && ! jdbcDelete.isCompatibleWith( jdbcParameterBindings, executionContext.getQueryOptions() ) ) { deleteTranslator = createDeleteTranslator( executionContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java index 3c656322f2..6cc26c4e4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleInsertQueryPlan.java @@ -6,11 +6,14 @@ */ package org.hibernate.query.sqm.internal; +import java.util.List; +import java.util.Map; + import org.hibernate.action.internal.BulkOperationCleanupAction; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryParameterImplementor; @@ -21,7 +24,6 @@ import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.insert.InsertStatement; @@ -29,15 +31,13 @@ import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcInsert; import org.hibernate.sql.exec.spi.JdbcParameterBindings; -import java.util.List; -import java.util.Map; - /** * @author Gavin King */ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { private final SqmInsertStatement sqmInsert; private final DomainParameterXref domainParameterXref; + private Map paramTypeResolutions; private JdbcInsert jdbcInsert; private FromClauseAccess tableGroupAccess; @@ -73,6 +73,8 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { sqmInterpretation::getJdbcParamsBySqmParam ); + this.paramTypeResolutions = sqmInterpretation.getSqmParameterMappingModelTypeResolutions(); + return factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory() .buildInsertTranslator( factory, sqmInterpretation.getSqlAst() ); } @@ -94,6 +96,7 @@ public class SimpleInsertQueryPlan implements NonSelectQueryPlan { jdbcParamsXref, factory.getDomainModel(), tableGroupAccess::findTableGroup, + paramTypeResolutions::get, session ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleUpdateQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleUpdateQueryPlan.java index 548a2741b4..6013d91453 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleUpdateQueryPlan.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SimpleUpdateQueryPlan.java @@ -10,10 +10,10 @@ import java.util.List; import java.util.Map; import org.hibernate.action.internal.BulkOperationCleanupAction; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.spi.NonSelectQueryPlan; import org.hibernate.query.spi.QueryEngine; import org.hibernate.query.spi.QueryParameterImplementor; @@ -24,11 +24,10 @@ import org.hibernate.query.sqm.sql.SqmTranslatorFactory; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.sql.ast.SqlAstTranslator; -import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.FromClauseAccess; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.update.UpdateStatement; import org.hibernate.sql.exec.spi.ExecutionContext; -import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcUpdate; @@ -42,6 +41,7 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan { private JdbcUpdate jdbcUpdate; private FromClauseAccess tableGroupAccess; private Map, Map>>> jdbcParamsXref; + private Map sqmParamMappingTypeResolutions; public SimpleUpdateQueryPlan( SqmUpdateStatement sqmUpdate, @@ -67,6 +67,7 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan { jdbcParamsXref, factory.getDomainModel(), tableGroupAccess::findTableGroup, + sqmParamMappingTypeResolutions::get, session ); @@ -119,6 +120,8 @@ public class SimpleUpdateQueryPlan implements NonSelectQueryPlan { sqmInterpretation::getJdbcParamsBySqmParam ); + this.sqmParamMappingTypeResolutions = sqmInterpretation.getSqmParameterMappingModelTypeResolutions(); + return factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory() .buildUpdateTranslator( factory, sqmInterpretation.getSqlAst() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java index 56de2f389f..ae508958ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/SqmUtil.java @@ -15,27 +15,32 @@ import java.util.Locale; import java.util.Map; import java.util.function.Function; +import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.MappingMetamodel; +import org.hibernate.metamodel.mapping.Bindable; import org.hibernate.metamodel.mapping.ConvertibleModelPart; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; -import org.hibernate.metamodel.model.domain.AllowableParameterType; import org.hibernate.query.IllegalQueryOperationException; import org.hibernate.query.NavigablePath; import org.hibernate.query.spi.QueryParameterBinding; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.query.spi.QueryParameterImplementor; import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess; +import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess; import org.hibernate.query.sqm.tree.SqmDmlStatement; import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; 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; import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl; @@ -162,6 +167,7 @@ public class SqmUtil { Map, Map>>> jdbcParamXref, MappingMetamodel domainModel, Function tableGroupLocator, + SqmParameterMappingModelResolutionAccess mappingModelResolutionAccess, SharedSessionContractImplementor session) { final JdbcParameterBindings jdbcParameterBindings = new JdbcParameterBindingsImpl( domainParameterXref.getSqmParameterCount() @@ -173,14 +179,17 @@ public class SqmUtil { final List sqmParameters = entry.getValue(); final QueryParameterBinding domainParamBinding = domainParamBindings.getBinding( queryParam ); - final AllowableParameterType parameterType = determineParameterType( - domainParamBinding, - queryParam, - session.getFactory() - ); final Map>> jdbcParamMap = jdbcParamXref.get( queryParam ); sqm_params: for ( SqmParameter sqmParameter : sqmParameters ) { + final Bindable parameterType = determineParameterType( + domainParamBinding, + queryParam, + sqmParameters, + mappingModelResolutionAccess, + session.getFactory() + ); + final List> jdbcParamsBinds = jdbcParamMap.get( sqmParameter ); if ( !domainParamBinding.isBound() ) { final MappingModelExpressable mappingExpressable = SqmMappingModelHelper.resolveMappingModelExpressable( @@ -209,6 +218,7 @@ public class SqmUtil { final List jdbcParams = jdbcParamsBinds.get( i ); createValueBindings( jdbcParameterBindings, + queryParam, domainParamBinding, parameterType, jdbcParams, @@ -229,7 +239,7 @@ public class SqmUtil { List expansionJdbcParams = jdbcParamBinds.get( i ); createValueBindings( jdbcParameterBindings, - domainParamBinding, + queryParam, domainParamBinding, parameterType, expansionJdbcParams, valueItr.next(), @@ -290,6 +300,7 @@ public class SqmUtil { final List jdbcParams = jdbcParamsBinds.get( i ); createValueBindings( jdbcParameterBindings, + queryParam, domainParamBinding, parameterType, jdbcParams, @@ -307,61 +318,69 @@ public class SqmUtil { private static void createValueBindings( JdbcParameterBindings jdbcParameterBindings, - final QueryParameterBinding domainParamBinding, - AllowableParameterType parameterType, + QueryParameterImplementor domainParam, + QueryParameterBinding domainParamBinding, + Bindable parameterType, List jdbcParams, Object bindValue, Function tableGroupLocator, SharedSessionContractImplementor session) { - final MappingMetamodel domainModel = session.getFactory().getDomainModel(); - final MappingModelExpressable mappingExpressable; if ( parameterType == null ) { - if ( domainParamBinding.getType() != null ) { - final MappingModelExpressable type = domainParamBinding.getType(); - if ( type instanceof EntityIdentifierMapping ) { - mappingExpressable = type; - EntityIdentifierMapping identifierMapping = (EntityIdentifierMapping) type; - if ( !identifierMapping.getJavaTypeDescriptor().getJavaTypeClass().isInstance( bindValue ) ) { - bindValue = identifierMapping.getIdentifier( bindValue, session ); - } - } - else if ( type instanceof ToOneAttributeMapping ) { - ToOneAttributeMapping association = (ToOneAttributeMapping) type; - bindValue = association.getForeignKeyDescriptor().getAssociationKeyFromTarget( bindValue, session ); - mappingExpressable = association.getForeignKeyDescriptor(); - } - else { - mappingExpressable = type; - } - } - else { - throw new IllegalStateException( "Parameter has no type by which it can be bound: " + jdbcParameterBindings ); + throw new SqlTreeCreationException( "Unable to interpret mapping-model type for Query parameter : " + domainParam ); + } + + if ( parameterType instanceof EntityIdentifierMapping ) { + final EntityIdentifierMapping identifierMapping = (EntityIdentifierMapping) parameterType; + final EntityMappingType entityMapping = identifierMapping.findContainingEntityMapping(); + if ( entityMapping.getRepresentationStrategy().getInstantiator().isInstance( bindValue, session.getFactory() ) ) { + bindValue = identifierMapping.getIdentifier( bindValue, session ); } } - else { - mappingExpressable = domainModel.resolveMappingExpressable( parameterType, tableGroupLocator ); + else if ( parameterType instanceof ToOneAttributeMapping ) { + ToOneAttributeMapping association = (ToOneAttributeMapping) parameterType; + bindValue = association.getForeignKeyDescriptor().getAssociationKeyFromTarget( bindValue, session ); + parameterType = association.getForeignKeyDescriptor(); + } + else if ( parameterType instanceof PluralAttributeMapping ) { + // we'd expect the values to refer to the collection element + // for now, let's blow up and see where this happens and fix the specifics... + throw new NotYetImplementedFor6Exception( "Binding parameters whose inferred type comes from plural attribute not yet implemented" ); } int offset = jdbcParameterBindings.registerParametersForEachJdbcValue( bindValue, Clause.IRRELEVANT, - mappingExpressable, + parameterType, jdbcParams, session ); assert offset == jdbcParams.size(); } - public static AllowableParameterType determineParameterType( + public static Bindable determineParameterType( QueryParameterBinding binding, QueryParameterImplementor parameter, + List sqmParameters, + SqmParameterMappingModelResolutionAccess mappingModelResolutionAccess, SessionFactoryImplementor sessionFactory) { - if ( binding.getBindType() != null ) { - return binding.getBindType(); + if ( binding.getType() != null ) { + return binding.getType(); } - if ( parameter.getHibernateType() != null ) { - return parameter.getHibernateType(); + if ( binding.getBindType() != null && binding.getBindType() instanceof Bindable ) { + return (Bindable) binding.getBindType(); + } + + if ( parameter.getHibernateType() != null && parameter.getHibernateType() instanceof Bindable ) { + return (Bindable) parameter.getHibernateType(); + } + + for ( int i = 0; i < sqmParameters.size(); i++ ) { + final MappingModelExpressable mappingModelType = mappingModelResolutionAccess + .getResolvedMappingModelType( sqmParameters.get( i ) ); + if ( mappingModelType != null ) { + return mappingModelType; + } } final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java index 604d6cf8e9..ae8cd6dd9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MatchingIdSelectionHelper.java @@ -202,6 +202,7 @@ public class MatchingIdSelectionHelper { final Map> parameterResolutions; + if ( domainParameterXref.getSqmParameterCount() == 0 ) { parameterResolutions = Collections.emptyMap(); } @@ -212,7 +213,7 @@ public class MatchingIdSelectionHelper { final Predicate restriction = sqmConverter.visitWhereClause( sqmMutationStatement.getWhereClause(), columnReference -> {}, - parameterResolutions::put + (sqmParam, mappingType, jdbcParameters) -> parameterResolutions.put( sqmParam, jdbcParameters ) ); final SelectStatement matchingIdSelection = generateMatchingIdSelectStatement( @@ -235,6 +236,7 @@ public class MatchingIdSelectionHelper { SqmUtil.generateJdbcParamsXref( domainParameterXref, sqmConverter ), factory.getDomainModel(), navigablePath -> sqmConverter.getMutatingTableGroup(), + sqmConverter.getSqmParameterMappingModelExpressableResolutions()::get, executionContext.getSession() ); final JdbcSelect idSelectJdbcOperation = sqlAstSelectTranslator.translate( diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java index 926f3035c6..35a2077f6b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java @@ -15,6 +15,7 @@ import org.hibernate.LockMode; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.internal.util.collections.Stack; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.NavigablePath; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; @@ -46,17 +47,21 @@ import org.hibernate.sql.ast.tree.update.Assignment; * of an SQM mutation query tree representing into the various SQL AST trees * needed to perform that operation. * - * @see #visitSetClause(SqmSetClause, Consumer, BiConsumer) - * @see #visitWhereClause(SqmWhereClause, Consumer, BiConsumer) - * @see #visitSelectClause(SqmSelectClause, QuerySpec, Consumer, BiConsumer) + * @see #visitSetClause(SqmSetClause, Consumer, SqmParameterResolutionConsumer) + * @see #visitWhereClause(SqmWhereClause, Consumer, SqmParameterResolutionConsumer) + * @see #visitSelectClause(SqmSelectClause, QuerySpec, Consumer, SqmParameterResolutionConsumer) * * @author Steve Ebersole */ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter { + public interface SqmParameterResolutionConsumer { + void accept(SqmParameter sqmParam, MappingModelExpressable mappingType, List jdbcParameters); + } + private final EntityMappingType mutatingEntityDescriptor; private final TableGroup mutatingTableGroup; - private BiConsumer> parameterResolutionConsumer; + private SqmParameterResolutionConsumer parameterResolutionConsumer; public MultiTableSqmMutationConverter( EntityMappingType mutatingEntityDescriptor, @@ -111,7 +116,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter assignmentConsumer, - BiConsumer> parameterResolutionConsumer) { + SqmParameterResolutionConsumer parameterResolutionConsumer) { this.parameterResolutionConsumer = parameterResolutionConsumer; for ( SqmAssignment assignment : setClause.getAssignments() ) { @@ -144,7 +149,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter restrictionColumnReferenceConsumer, - BiConsumer> parameterResolutionConsumer) { + SqmParameterResolutionConsumer parameterResolutionConsumer) { this.parameterResolutionConsumer = parameterResolutionConsumer; if ( sqmWhereClause == null || sqmWhereClause.getPredicate() == null ) { @@ -198,7 +203,12 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter> jdbcParameters = getJdbcParamsBySqmParam().get( sqmParameter ); - parameterResolutionConsumer.accept( sqmParameter, jdbcParameters.get( jdbcParameters.size() - 1 ) ); + final MappingModelExpressable mappingType = getSqmParameterMappingModelExpressableResolutions().get( sqmParameter ); + parameterResolutionConsumer.accept( + sqmParameter, + mappingType, + jdbcParameters.get( jdbcParameters.size() - 1 ) + ); return expression; } @@ -209,7 +219,7 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter columnReferenceConsumer, - BiConsumer> parameterResolutionConsumer) { + SqmParameterResolutionConsumer parameterResolutionConsumer) { assert sqmSelectClause != null; this.parameterResolutionConsumer = parameterResolutionConsumer; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java index 474a566d7b..a36435ec05 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/AbstractCteMutationHandler.java @@ -9,12 +9,14 @@ package org.hibernate.query.sqm.mutation.internal.cte; import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.SqlExpressable; import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.query.spi.SqlOmittingQueryOptions; @@ -115,10 +117,12 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler parameterResolutions = new IdentityHashMap<>(); } + final Map paramTypeResolutions = new LinkedHashMap<>(); + final Predicate restriction = sqmConverter.visitWhereClause( sqmMutationStatement.getWhereClause(), columnReference -> {}, - parameterResolutions::put + (sqmParam, mappingType, jdbcParameters) -> paramTypeResolutions.put( sqmParam, mappingType ) ); final CteStatement idSelectCte = new CteStatement( @@ -172,6 +176,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler SqmUtil.generateJdbcParamsXref( domainParameterXref, sqmConverter ), factory.getDomainModel(), navigablePath -> sqmConverter.getMutatingTableGroup(), + paramTypeResolutions::get, executionContext.getSession() ); final JdbcSelect select = translator.translate( jdbcParameterBindings, executionContext.getQueryOptions() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java index 2275ad035e..5ed469262e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/cte/CteUpdateHandler.java @@ -7,6 +7,7 @@ package org.hibernate.query.sqm.mutation.internal.cte; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; @@ -14,6 +15,7 @@ import java.util.function.BiConsumer; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.query.sqm.internal.DomainParameterXref; @@ -75,11 +77,15 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda // information about the assignments final SqmSetClause setClause = updateStatement.getSetClause(); final List assignments = new ArrayList<>( setClause.getAssignments().size() ); + final Map paramTypeResolutions = new LinkedHashMap<>(); sqmConverter.visitSetClause( setClause, assignments::add, - parameterResolutions::put + (sqmParam, mappingType, jdbcParameters) -> { + parameterResolutions.put( sqmParam, jdbcParameters ); + paramTypeResolutions.put( sqmParam, mappingType ); + } ); sqmConverter.addVersionedAssignment( assignments::add, updateStatement ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/RestrictedDeleteExecutionDelegate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/RestrictedDeleteExecutionDelegate.java index 76774f48e4..cdaefca57f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/RestrictedDeleteExecutionDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/RestrictedDeleteExecutionDelegate.java @@ -9,6 +9,7 @@ package org.hibernate.query.sqm.mutation.internal.idtable; import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -21,12 +22,13 @@ import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.MutableInteger; import org.hibernate.internal.FilterHelper; -import org.hibernate.metamodel.mapping.SelectableConsumer; +import org.hibernate.internal.util.MutableInteger; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelHelper; +import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.query.spi.QueryOptions; @@ -126,11 +128,15 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle assert hierarchyRootTableReference != null; final Map>> parameterResolutions; + final Map paramTypeResolutions; + if ( domainParameterXref.getSqmParameterCount() == 0 ) { parameterResolutions = Collections.emptyMap(); + paramTypeResolutions = Collections.emptyMap(); } else { parameterResolutions = new IdentityHashMap<>(); + paramTypeResolutions = new LinkedHashMap<>(); } // Use the converter to interpret the where-clause. We do this for 2 reasons: @@ -146,10 +152,13 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle needsIdTableWrapper.set( true ); } }, - (sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent( - sqmParameter, - k -> new ArrayList<>( 1 ) - ).add( jdbcParameters ) + (sqmParameter, mappingType, jdbcParameters) -> { + parameterResolutions.computeIfAbsent( + sqmParameter, + k -> new ArrayList<>( 1 ) + ).add( jdbcParameters ); + paramTypeResolutions.put( sqmParameter, mappingType ); + } ); final FilterPredicate filterPredicate = FilterHelper.createFilterPredicate( @@ -169,6 +178,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle predicate, deletingTableGroup, parameterResolutions, + paramTypeResolutions, executionContext ); } @@ -177,6 +187,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle predicate, deletingTableGroup, parameterResolutions, + paramTypeResolutions, converter.getSqlExpressionResolver(), executionContext ); @@ -187,6 +198,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle Predicate suppliedPredicate, TableGroup tableGroup, Map>> restrictionSqmParameterResolutions, + Map paramTypeResolutions, SqlExpressionResolver sqlExpressionResolver, ExecutionContext executionContext) { final EntityPersister rootEntityPersister; @@ -221,6 +233,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle ), sessionFactory.getDomainModel(), navigablePath -> tableGroup, + paramTypeResolutions::get, executionContext.getSession() ); @@ -358,6 +371,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle Predicate predicate, TableGroup deletingTableGroup, Map>> restrictionSqmParameterResolutions, + Map paramTypeResolutions, ExecutionContext executionContext) { final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings( executionContext.getQueryParameterBindings(), @@ -368,6 +382,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle ), sessionFactory.getDomainModel(), navigablePath -> deletingTableGroup, + paramTypeResolutions::get, executionContext.getSession() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedDeleteHandler.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedDeleteHandler.java index a2de5e1755..eb6d3da59f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedDeleteHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedDeleteHandler.java @@ -44,8 +44,10 @@ public class TableBasedDeleteHandler public TableBasedDeleteHandler( SqmDeleteStatement sqmDeleteStatement, - DomainParameterXref domainParameterXref, IdTable idTable, - Function sessionUidAccess, + DomainParameterXref domainParameterXref, + IdTable idTable, + Function sessionUidAccess, Supplier exporterSupplier, BeforeUseAction beforeUseAction, AfterUseAction afterUseAction, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedUpdateHandler.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedUpdateHandler.java index dad96bf279..19ff097b5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedUpdateHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/TableBasedUpdateHandler.java @@ -9,6 +9,7 @@ package org.hibernate.query.sqm.mutation.internal.idtable; import java.util.ArrayList; import java.util.Collections; import java.util.IdentityHashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; @@ -21,6 +22,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.FilterHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.metamodel.MappingMetamodel; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.Joinable; import org.hibernate.query.sqm.internal.DomainParameterXref; @@ -147,14 +149,18 @@ public class TableBasedUpdateHandler // information about the assignments final List assignments = new ArrayList<>(); + final Map paramTypeResolutions = new LinkedHashMap<>(); converterDelegate.visitSetClause( getSqmDeleteOrUpdateStatement().getSetClause(), assignments::add, - (sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent( - sqmParameter, - k -> new ArrayList<>( 1 ) - ).add( jdbcParameters ) + (sqmParameter, mappingType, jdbcParameters) -> { + parameterResolutions.computeIfAbsent( + sqmParameter, + k -> new ArrayList<>( 1 ) + ).add( jdbcParameters ); + paramTypeResolutions.put( sqmParameter, mappingType ); + } ); converterDelegate.addVersionedAssignment( assignments::add, getSqmDeleteOrUpdateStatement() ); @@ -171,10 +177,14 @@ public class TableBasedUpdateHandler predicate = converterDelegate.visitWhereClause( whereClause, columnReference -> {}, - (sqmParameter, jdbcParameters) -> parameterResolutions.computeIfAbsent( - sqmParameter, - k -> new ArrayList<>( 1 ) - ).add( jdbcParameters ) + (sqmParameter, mappingType, jdbcParameters) -> { + parameterResolutions.computeIfAbsent( + sqmParameter, + k -> new ArrayList<>( 1 ) + ).add( jdbcParameters ); + paramTypeResolutions.put( sqmParameter, mappingType ); + } + ); assert predicate != null; } @@ -214,6 +224,7 @@ public class TableBasedUpdateHandler assignments, predicate, parameterResolutions, + paramTypeResolutions, executionContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/UpdateExecutionDelegate.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/UpdateExecutionDelegate.java index b07a46b720..dc5d94225f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/UpdateExecutionDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/idtable/UpdateExecutionDelegate.java @@ -18,9 +18,10 @@ import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.CollectionHelper; -import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.EntityMappingType; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.ModelPartContainer; +import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.query.spi.SqlOmittingQueryOptions; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.SqmUtil; @@ -28,6 +29,7 @@ import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.query.sqm.tree.update.SqmUpdateStatement; import org.hibernate.sql.ast.tree.expression.ColumnReference; +import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate; @@ -36,7 +38,6 @@ import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.update.Assignment; import org.hibernate.sql.ast.tree.update.UpdateStatement; import org.hibernate.sql.exec.spi.ExecutionContext; -import org.hibernate.sql.ast.tree.expression.JdbcParameter; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcUpdate; @@ -61,6 +62,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio private final JdbcParameterBindings jdbcParameterBindings; private final Map> assignmentsByTable; + private final Map paramTypeResolutions; private final SessionFactoryImplementor sessionFactory; public UpdateExecutionDelegate( @@ -79,6 +81,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio List assignments, Predicate suppliedPredicate, Map>> parameterResolutions, + Map paramTypeResolutions, ExecutionContext executionContext) { this.sqmUpdate = sqmUpdate; this.sqmConverter = sqmConverter; @@ -91,6 +94,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio this.domainParameterXref = domainParameterXref; this.updatingTableGroup = updatingTableGroup; this.suppliedPredicate = suppliedPredicate; + this.paramTypeResolutions = paramTypeResolutions; this.sessionFactory = executionContext.getSession().getFactory(); @@ -110,6 +114,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio ), sessionFactory.getDomainModel(), navigablePath -> updatingTableGroup, + paramTypeResolutions::get, executionContext.getSession() ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/JdbcParameterBySqmParameterAccess.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/JdbcParameterBySqmParameterAccess.java index e6a16da1d9..fc420a2868 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/JdbcParameterBySqmParameterAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/JdbcParameterBySqmParameterAccess.java @@ -17,6 +17,7 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter; * * @author Steve Ebersole */ +@FunctionalInterface public interface JdbcParameterBySqmParameterAccess { /** * The mapping between an SqmParameter and all of its JDBC parameters diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmParameterMappingModelResolutionAccess.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmParameterMappingModelResolutionAccess.java new file mode 100644 index 0000000000..9324a69ff9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/spi/SqmParameterMappingModelResolutionAccess.java @@ -0,0 +1,18 @@ +/* + * 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.query.sqm.spi; + +import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.tree.expression.SqmParameter; + +/** + * @author Steve Ebersole + */ +@FunctionalInterface +public interface SqmParameterMappingModelResolutionAccess { + MappingModelExpressable getResolvedMappingModelType(SqmParameter parameter); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index 6635905f89..53e5ee4e10 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -90,6 +90,7 @@ import org.hibernate.query.sqm.function.AbstractSqmSelfRenderingFunctionDescript import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression; import org.hibernate.query.sqm.internal.DomainParameterXref; import org.hibernate.query.sqm.internal.SqmMappingModelHelper; +import org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter; import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker; import org.hibernate.query.sqm.sql.internal.BasicValuedPathInterpretation; import org.hibernate.query.sqm.sql.internal.DomainResultProducer; @@ -325,6 +326,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base private final DomainParameterXref domainParameterXref; private final QueryParameterBindings domainParameterBindings; + private final Map sqmParameterMappingModelTypes = new LinkedHashMap<>(); private final Map, Supplier>> jpaCriteriaParamResolutions; private final List domainResults; private final EntityGraphTraversalState entityGraphTraversalState; @@ -412,6 +414,10 @@ public abstract class BaseSqmToSqlAstConverter extends Base .getJpaCriteriaParamResolutions(); } + public Map getSqmParameterMappingModelExpressableResolutions() { + return sqmParameterMappingModelTypes; + } + protected Stack getProcessingStateStack() { return processingStateStack; } @@ -538,6 +544,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base return new StandardSqmTranslation<>( statement, getJdbcParamsBySqmParam(), + sqmParameterMappingModelTypes, lastPoppedProcessingState.getSqlExpressionResolver(), getFromClauseAccess() ); @@ -2521,6 +2528,9 @@ public abstract class BaseSqmToSqlAstConverter extends Base if ( currentExpressableSupplier != null ) { final MappingModelExpressable inferredMapping = currentExpressableSupplier.get(); if ( inferredMapping != null ) { + if ( inferredMapping instanceof PluralAttributeMapping ) { + return ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor(); + } return inferredMapping; } } @@ -2569,6 +2579,8 @@ public abstract class BaseSqmToSqlAstConverter extends Base SqmParameter expression, MappingModelExpressable valueMapping, BiConsumer jdbcParameterConsumer) { + sqmParameterMappingModelTypes.put( expression, valueMapping ); + if ( valueMapping instanceof Association ) { ( (Association) valueMapping ).getForeignKeyDescriptor().forEachJdbcType( (index, jdbcMapping) -> jdbcParameterConsumer.accept( index, new JdbcParameterImpl( jdbcMapping ) ) diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslation.java index c6d98d5d99..ceb6c11193 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/SqmTranslation.java @@ -8,7 +8,10 @@ package org.hibernate.query.sqm.sql; import java.util.List; import java.util.Map; +import java.util.function.Function; +import org.hibernate.metamodel.mapping.MappingModelExpressable; +import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.SqlExpressionResolver; @@ -22,7 +25,8 @@ import org.hibernate.sql.ast.tree.expression.JdbcParameter; */ public interface SqmTranslation { T getSqlAst(); - Map>> getJdbcParamsBySqmParam(); SqlExpressionResolver getSqlExpressionResolver(); FromClauseAccess getFromClauseAccess(); + Map>> getJdbcParamsBySqmParam(); + Map getSqmParameterMappingModelTypeResolutions(); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslation.java index 0d7968a459..b71d739245 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/StandardSqmTranslation.java @@ -9,6 +9,7 @@ package org.hibernate.query.sqm.sql; import java.util.List; import java.util.Map; +import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.query.sqm.tree.expression.SqmParameter; import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.SqlExpressionResolver; @@ -22,16 +23,19 @@ public class StandardSqmTranslation implements SqmTranslati private final T sqlAst; private final Map>> jdbcParamMap; + private final Map parameterMappingModelTypeMap; private final SqlExpressionResolver sqlExpressionResolver; private final FromClauseAccess fromClauseAccess; public StandardSqmTranslation( T sqlAst, Map>> jdbcParamMap, + Map parameterMappingModelTypeMap, SqlExpressionResolver sqlExpressionResolver, FromClauseAccess fromClauseAccess) { this.sqlAst = sqlAst; this.jdbcParamMap = jdbcParamMap; + this.parameterMappingModelTypeMap = parameterMappingModelTypeMap; this.sqlExpressionResolver = sqlExpressionResolver; this.fromClauseAccess = fromClauseAccess; } @@ -46,6 +50,11 @@ public class StandardSqmTranslation implements SqmTranslati return jdbcParamMap; } + @Override + public Map getSqmParameterMappingModelTypeResolutions() { + return parameterMappingModelTypeMap; + } + @Override public SqlExpressionResolver getSqlExpressionResolver() { return sqlExpressionResolver; diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EmbeddableValuedPathInterpretation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EmbeddableValuedPathInterpretation.java index fac944925a..d9be0bb8d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EmbeddableValuedPathInterpretation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EmbeddableValuedPathInterpretation.java @@ -18,13 +18,14 @@ import org.hibernate.sql.ast.SqlAstWalker; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.SqlTuple; +import org.hibernate.sql.ast.tree.expression.SqlTupleContainer; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.update.Assignable; /** * @author Steve Ebersole */ -public class EmbeddableValuedPathInterpretation extends AbstractSqmPathInterpretation implements Assignable { +public class EmbeddableValuedPathInterpretation extends AbstractSqmPathInterpretation implements Assignable, SqlTupleContainer { /** * Static factory @@ -95,4 +96,9 @@ public class EmbeddableValuedPathInterpretation extends AbstractSqmPathInterp visitColumnReferences( results::add ); return results; } + + @Override + public SqlTuple getSqlTuple() { + return sqlExpression; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java index bb3de8320e..dcd7256721 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/EntityValuedPathInterpretation.java @@ -27,6 +27,7 @@ import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.SqlTuple; +import org.hibernate.sql.ast.tree.expression.SqlTupleContainer; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.ast.tree.from.TableReference; @@ -37,7 +38,7 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere /** * @author Koen Aers */ -public class EntityValuedPathInterpretation extends AbstractSqmPathInterpretation { +public class EntityValuedPathInterpretation extends AbstractSqmPathInterpretation implements SqlTupleContainer { public static EntityValuedPathInterpretation from( SqmEntityValuedSimplePath sqmPath, @@ -62,10 +63,10 @@ public class EntityValuedPathInterpretation extends AbstractSqmPathInterpreta ); } - private final Expression sqlExpression; + private final SqlTuple sqlExpression; private EntityValuedPathInterpretation( - Expression sqlExpression, + SqlTuple sqlExpression, SqmEntityValuedSimplePath sqmPath, TableGroup tableGroup, EntityValuedModelPart mapping) { @@ -226,4 +227,9 @@ public class EntityValuedPathInterpretation extends AbstractSqmPathInterpreta } return tableReference; } + + @Override + public SqlTuple getSqlTuple() { + return sqlExpression; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/NonAggregatedCompositeValuedPathInterpretation.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/NonAggregatedCompositeValuedPathInterpretation.java index a96e9a2b33..f8804f7237 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/NonAggregatedCompositeValuedPathInterpretation.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/NonAggregatedCompositeValuedPathInterpretation.java @@ -12,14 +12,16 @@ import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath; import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.sql.ast.SqlAstWalker; -import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.SqlTuple; +import org.hibernate.sql.ast.tree.expression.SqlTupleContainer; import org.hibernate.sql.ast.tree.from.TableGroup; /** * @author Andrea Boriero */ -public class NonAggregatedCompositeValuedPathInterpretation extends AbstractSqmPathInterpretation { +public class NonAggregatedCompositeValuedPathInterpretation + extends AbstractSqmPathInterpretation + implements SqlTupleContainer { public static NonAggregatedCompositeValuedPathInterpretation from( NonAggregatedCompositeSimplePath sqmPath, @@ -64,4 +66,8 @@ public class NonAggregatedCompositeValuedPathInterpretation extends AbstractS sqlExpression.accept( sqlTreeWalker ); } + @Override + public SqlTuple getSqlTuple() { + return sqlExpression; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java index a8b0fee63e..9627396ab1 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/spi/AbstractSqlAstTranslator.java @@ -95,6 +95,7 @@ import org.hibernate.sql.ast.tree.expression.QueryLiteral; import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; import org.hibernate.sql.ast.tree.expression.SqlSelectionExpression; import org.hibernate.sql.ast.tree.expression.SqlTuple; +import org.hibernate.sql.ast.tree.expression.SqlTupleContainer; import org.hibernate.sql.ast.tree.expression.Star; import org.hibernate.sql.ast.tree.expression.Summarization; import org.hibernate.sql.ast.tree.expression.TrimSpecification; @@ -1580,9 +1581,10 @@ public abstract class AbstractSqlAstTranslator implemen final Expression sortExpression = sortSpecification.getSortExpression(); final NullPrecedence nullPrecedence = sortSpecification.getNullPrecedence(); final SortOrder sortOrder = sortSpecification.getSortOrder(); - if ( sortExpression instanceof SqlTuple ) { + if ( sortExpression instanceof SqlTupleContainer ) { + final SqlTuple sqlTuple = ( (SqlTupleContainer) sortExpression ).getSqlTuple(); String separator = NO_SEPARATOR; - for ( Expression expression : ( (SqlTuple) sortExpression ).getExpressions() ) { + for ( Expression expression : sqlTuple.getExpressions() ) { appendSql( separator ); visitSortSpecification( expression, sortOrder, nullPrecedence ); separator = COMA_SEPARATOR; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java index 90f7271f40..1e1eb3b663 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTuple.java @@ -16,7 +16,7 @@ import org.hibernate.sql.ast.SqlAstWalker; /** * @author Steve Ebersole */ -public class SqlTuple implements Expression { +public class SqlTuple implements Expression, SqlTupleContainer { private final List expressions; private final MappingModelExpressable valueMapping; @@ -39,6 +39,11 @@ public class SqlTuple implements Expression { sqlTreeWalker.visitTuple( this ); } + @Override + public SqlTuple getSqlTuple() { + return this; + } + public static class Builder { private final MappingModelExpressable valueMapping; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTupleContainer.java b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTupleContainer.java new file mode 100644 index 0000000000..d8fc5b714e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/ast/tree/expression/SqlTupleContainer.java @@ -0,0 +1,14 @@ +/* + * 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.sql.ast.tree.expression; + +/** + * @author Steve Ebersole + */ +public interface SqlTupleContainer { + SqlTuple getSqlTuple(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java index 0fd49a94a7..68ecd51135 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CustomType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CustomType.java @@ -23,6 +23,9 @@ import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; @@ -48,7 +51,7 @@ import org.hibernate.usertype.UserVersionType; */ public class CustomType extends AbstractType - implements BasicType, IdentifierType, DiscriminatorType, VersionType, StringRepresentableType, ProcedureParameterNamedBinder, ProcedureParameterExtractionAware { + implements BasicType, IdentifierType, DiscriminatorType, VersionType, StringRepresentableType, ProcedureParameterNamedBinder, ProcedureParameterExtractionAware, ValueBinder { private final UserType userType; private final String[] registrationKeys; @@ -58,6 +61,8 @@ public class CustomType private final JavaTypeDescriptor mappedJavaTypeDescriptor; private final JdbcTypeDescriptor jdbcTypeDescriptor; + private final ValueExtractor valueExtractor; + private final Size dictatedSize; private final Size defaultSize; @@ -85,10 +90,42 @@ public class CustomType this.defaultSize = null; } + if ( userType instanceof ValueExtractor ) { + this.valueExtractor = (ValueExtractor) userType; + } + else { + this.valueExtractor = jdbcTypeDescriptor.getExtractor( mappedJavaTypeDescriptor ); + } + this.customLogging = userType instanceof LoggableUserType; this.registrationKeys = registrationKeys; } + @Override + public ValueBinder getJdbcValueBinder() { + return this; + } + + @Override + public void bind(PreparedStatement st, Object value, int index, WrapperOptions options) throws SQLException { + userType.nullSafeSet( st, value, index, options.getSession() ); + } + + @Override + public void bind(CallableStatement st, Object value, String name, WrapperOptions options) throws SQLException { + if ( userType instanceof ProcedureParameterNamedBinder ) { + final ProcedureParameterNamedBinder namedParamSupport = (ProcedureParameterNamedBinder) userType; + if ( namedParamSupport.canDoSetting() ) { + namedParamSupport.nullSafeSet( st, value, name, options.getSession() ); + } + } + } + + @Override + public ValueExtractor getJdbcValueExtractor() { + return valueExtractor; + } + public UserType getUserType() { return userType; } @@ -156,7 +193,6 @@ public class CustomType return nullSafeGet(rs, new String[] { columnName }, session, owner); } - @Override public Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) { return getUserType().assemble( cached, owner); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/filter/CriteriaQueryWithAppliedFilterTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/filter/CriteriaQueryWithAppliedFilterTest.java index d4d24fdf25..516ca94b68 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/filter/CriteriaQueryWithAppliedFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/filter/CriteriaQueryWithAppliedFilterTest.java @@ -217,7 +217,6 @@ public class CriteriaQueryWithAppliedFilterTest { } @Test - @FailureExpected(reason = "component criteria not fully implemented in v6 yet") void testRestrictionsOnComponentTypes(SessionFactoryScope scope) { scope.inTransaction( session -> { session.enableFilter( "statusFilter" ).setParameter( "status", "active" ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/OrdinalEnumTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/OrdinalEnumTypeTest.java index cc2bbe63dc..2867b28110 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/OrdinalEnumTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/enums/OrdinalEnumTypeTest.java @@ -63,7 +63,7 @@ public class OrdinalEnumTypeTest { scope.inTransaction( (session) -> { session.createQuery( "select p.id from Person p where p.id = :id", Long.class ) - .setParameter( "id", 1 ) + .setParameter( "id", 1L ) .list(); assertTrue( loggingWatcher.wasTriggered() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/OrderByTests.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/OrderByTests.java index 19c07a62e6..a6a23c9baa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingOrderByTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/OrderByTests.java @@ -1,10 +1,10 @@ /* * 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 . + * 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.hql; +package org.hibernate.orm.test.query.hql; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -22,6 +22,13 @@ import org.hibernate.query.hql.HqlTranslator; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.test.hql.Address; +import org.hibernate.test.hql.Human; +import org.hibernate.test.hql.Mammal; +import org.hibernate.test.hql.Name; +import org.hibernate.test.hql.StateProvince; +import org.hibernate.test.hql.Zoo; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -30,7 +37,7 @@ import static org.junit.Assert.assertTrue; * * @author Gail Badner */ -public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase { +public class OrderByTests extends BaseCoreFunctionalTestCase { StateProvince stateProvince; private Zoo zoo1; private Zoo zoo2; @@ -351,7 +358,6 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase { } @Test - @FailureExpected( jiraKey = "unknown" ) public void testOrderByComponentDescNoSelectAliasRef() { createData(); @@ -359,21 +365,21 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase { Transaction t = s.beginTransaction(); // ordered by address DESC, name DESC: - // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA - // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA checkTestOrderByResults( s.createQuery( "select z.name, z.address from Zoo z order by z.address DESC, z.name DESC" ).list(), - zoo1, zoo2, zoo4, zoo3, null + zoo4, zoo1, zoo2, zoo3, null ); checkTestOrderByResults( s.createQuery( "select name, address from Zoo order by address DESC, name DESC" ).list(), - zoo1, zoo2, zoo4, zoo3, null + zoo4, zoo1, zoo2, zoo3, null ); t.commit(); s.close(); @@ -541,24 +547,23 @@ public class ASTParserLoadingOrderByTest extends BaseCoreFunctionalTestCase { } @Test - @FailureExpected( jiraKey = "unknown") - public void testOrderByComponentDescSelectAliasRefFailureExpected() { + public void testOrderByComponentDescSelectAliasRef() { createData(); Session s = openSession(); Transaction t = s.beginTransaction(); // ordered by address desc, name desc: - // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA // zoo4 Duh Zoo 1312 Mockingbird Lane, Nowhere, IL USA - // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA // zoo1 Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo2 A Zoo 1313 Mockingbird Lane, Anywhere, IL USA + // zoo3 Zoo 1312 Mockingbird Lane, Anywhere, IL USA // using DESC checkTestOrderByResults( s.createQuery( "select z.name as zooName, z.address as zooAddress from Zoo z order by zooAddress DESC, zooName DESC" ).list(), - zoo1, zoo2, zoo4, zoo3, null + zoo4, zoo1, zoo2, zoo3, null ); t.commit(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/org/hibernate/orm/test/query/hql/set/SetOperationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/set/SetOperationTest.java similarity index 98% rename from hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/org/hibernate/orm/test/query/hql/set/SetOperationTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/set/SetOperationTest.java index 20c78dec93..521e6044df 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/org/hibernate/orm/test/query/hql/set/SetOperationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/hql/set/SetOperationTest.java @@ -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.orm.test.query.hql.org.hibernate.orm.test.query.hql.set; +package org.hibernate.orm.test.query.hql.set; import java.util.List; diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java index 138e3aa9c0..caebf8ea73 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java @@ -36,7 +36,6 @@ import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.hibernate.testing.transaction.TransactionUtil2.fromTransaction; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -114,7 +113,6 @@ public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase { sqlInterceptor.clear(); final Child detachedChild = fromTransaction( - sessionFactory(), (s) -> { Child child = s.get( Child.class, originalChild.getId() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java index b4e7afe56e..1bb42d9a7f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ASTParserLoadingTest.java @@ -53,6 +53,7 @@ import org.hibernate.loader.MultipleBagFetchException; import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; +import org.hibernate.metamodel.model.domain.internal.EntitySqmPathSource; import org.hibernate.orm.test.any.hbm.IntegerPropertyValue; import org.hibernate.orm.test.any.hbm.PropertySet; import org.hibernate.orm.test.any.hbm.PropertyValue; @@ -249,21 +250,18 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { @Test public void testSubSelectAsArithmeticOperand() { - Session s = openSession(); - s.beginTransaction(); + inTransaction( + (s) -> { + s.createQuery( "from Zoo z where ( select count(*) from Zoo ) = 0" ).list(); - // first a control - s.createQuery( "from Zoo z where ( select count(*) from Zoo ) = 0" ).list(); + // now as operands singly: + s.createQuery( "from Zoo z where ( select count(*) from Zoo ) + 0 = 0" ).list(); + s.createQuery( "from Zoo z where 0 + ( select count(*) from Zoo ) = 0" ).list(); - // now as operands singly: - s.createQuery( "from Zoo z where ( select count(*) from Zoo ) + 0 = 0" ).list(); - s.createQuery( "from Zoo z where 0 + ( select count(*) from Zoo ) = 0" ).list(); - - // and doubly: - s.createQuery( "from Zoo z where ( select count(*) from Zoo ) + ( select count(*) from Zoo ) = 0" ).list(); - - s.getTransaction().commit(); - s.close(); + // and doubly: + s.createQuery( "from Zoo z where ( select count(*) from Zoo ) + ( select count(*) from Zoo ) = 0" ).list(); + } + ); } @Test @@ -278,33 +276,24 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { "City 8", "City 9", "City 10", "City 11", "City 12" }; - Session session = openSession(); + inTransaction( + (session) -> { + Address address = new Address(); + Zoo zoo = new Zoo( "ZOO 1", address ); + address.setCity( "City 1" ); + session.save( zoo ); + } + ); - session.getTransaction().begin(); - Address address = new Address(); - Zoo zoo = new Zoo( "ZOO 1", address ); - address.setCity( "City 1" ); - session.save( zoo ); - session.getTransaction().commit(); - - session.clear(); - - session.getTransaction().begin(); - List result = session.createQuery( "FROM Zoo z WHERE z.name IN (?1) and z.address.city IN (?2)" ) - .setParameterList( 1, namesArray ) - .setParameterList( 2, citiesArray ) - .list(); - assertEquals( 1, result.size() ); - session.getTransaction().commit(); - - session.clear(); - - session.getTransaction().begin(); - zoo = (Zoo) session.get( Zoo.class, zoo.getId() ); - session.delete( zoo ); - session.getTransaction().commit(); - - session.close(); + inTransaction( + (session) -> { + List result = session.createQuery( "FROM Zoo z WHERE z.name IN (?1) and z.address.city IN (?2)" ) + .setParameterList( 1, namesArray ) + .setParameterList( 2, citiesArray ) + .list(); + assertEquals( 1, result.size() ); + } + ); } @Test @@ -312,34 +301,23 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { // For now, restrict to H2. Selecting w/ predicate functions cause issues for too many dialects. @RequiresDialect(value = H2Dialect.class, jiraKey = "HHH-9052") public void testBooleanPredicate() { - final Session session = openSession(); - - session.getTransaction().begin(); - final Constructor constructor = new Constructor(); - session.save( constructor ); - session.getTransaction().commit(); - - session.clear(); - Constructor.resetConstructorExecutionCount(); - - session.getTransaction().begin(); - final Constructor result = (Constructor) session.createQuery( - "select new Constructor( c.id, c.id is not null, c.id = c.id, c.id + 1, concat( c.id, 'foo' ) ) from Constructor c where c.id = :id" - ).setParameter( "id", constructor.getId() ).uniqueResult(); - session.getTransaction().commit(); - - assertEquals( 1, Constructor.getConstructorExecutionCount() ); - assertEquals( - new Constructor( - constructor.getId(), - true, - true, - constructor.getId() + 1, - constructor.getId() + "foo" - ), result + final Constructor created = fromTransaction( + (session) -> { + final Constructor constructor = new Constructor(); + session.save( constructor ); + return constructor; + } ); - session.close(); + Constructor.resetConstructorExecutionCount(); + + inTransaction( + (session) -> { + final String qry = "select new Constructor( c.id, c.id is not null, c.id = c.id, c.id + 1, concat( c.id, 'foo' ) ) from Constructor c where c.id = :id"; + final Constructor result = (Constructor) session.createQuery(qry ).setParameter( "id", created.getId() ).uniqueResult(); + assertEquals( created, result ); + } + ); } @Test @@ -382,109 +360,91 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { @Test public void testComponentJoins() { - Session s = openSession(); - s.beginTransaction(); - ComponentContainer root = new ComponentContainer( - new ComponentContainer.Address( - "123 Main", - "Anywhere", - "USA", - new ComponentContainer.Address.Zip( 12345, 6789 ) - ) + inTransaction( + (s) -> { + ComponentContainer root = new ComponentContainer( + new ComponentContainer.Address( + "123 Main", + "Anywhere", + "USA", + new ComponentContainer.Address.Zip( 12345, 6789 ) + ) + ); + s.save( root ); + } ); - s.save( root ); - s.getTransaction().commit(); - s.close(); - s = openSession(); - s.beginTransaction(); - List result = s.createQuery( "select a from ComponentContainer c join c.address a" ).list(); - assertEquals( 1, result.size() ); - assertTrue( ComponentContainer.Address.class.isInstance( result.get( 0 ) ) ); + inTransaction( + (s) -> { + List result = s.createQuery( "select a from ComponentContainer c join c.address a" ).list(); + assertEquals( 1, result.size() ); + assertTrue( ComponentContainer.Address.class.isInstance( result.get( 0 ) ) ); - result = s.createQuery( "select a.zip from ComponentContainer c join c.address a" ).list(); - assertEquals( 1, result.size() ); - assertTrue( ComponentContainer.Address.Zip.class.isInstance( result.get( 0 ) ) ); + result = s.createQuery( "select a.zip from ComponentContainer c join c.address a" ).list(); + assertEquals( 1, result.size() ); + assertTrue( ComponentContainer.Address.Zip.class.isInstance( result.get( 0 ) ) ); - result = s.createQuery( "select z from ComponentContainer c join c.address a join a.zip z" ).list(); - assertEquals( 1, result.size() ); - assertTrue( ComponentContainer.Address.Zip.class.isInstance( result.get( 0 ) ) ); + result = s.createQuery( "select z from ComponentContainer c join c.address a join a.zip z" ).list(); + assertEquals( 1, result.size() ); + assertTrue( ComponentContainer.Address.Zip.class.isInstance( result.get( 0 ) ) ); - result = s.createQuery( "select z.code from ComponentContainer c join c.address a join a.zip z" ).list(); - assertEquals( 1, result.size() ); - assertTrue( Integer.class.isInstance( result.get( 0 ) ) ); - s.delete( root ); - s.getTransaction().commit(); - s.close(); + result = s.createQuery( "select z.code from ComponentContainer c join c.address a join a.zip z" ).list(); + assertEquals( 1, result.size() ); + assertTrue( Integer.class.isInstance( result.get( 0 ) ) ); + } + ); } @Test @TestForIssue( jiraKey = "HHH-9642") public void testLazyAssociationInComponent() { - Session session = openSession(); - session.getTransaction().begin(); + inTransaction( + (session) -> { + Address address = new Address(); + Zoo zoo = new Zoo( "ZOO 1", address ); + address.setCity( "City 1" ); + StateProvince stateProvince = new StateProvince(); + stateProvince.setName( "Illinois" ); + session.save( stateProvince ); + address.setStateProvince( stateProvince ); + session.save( zoo ); + } + ); - Address address = new Address(); - Zoo zoo = new Zoo( "ZOO 1", address ); - address.setCity( "City 1" ); - StateProvince stateProvince = new StateProvince(); - stateProvince.setName( "Illinois" ); - session.save( stateProvince ); - address.setStateProvince( stateProvince ); - session.save( zoo ); - - session.getTransaction().commit(); - session.close(); - - session = openSession(); - session.getTransaction().begin(); - - zoo = (Zoo) session.createQuery( "from Zoo z" ).uniqueResult(); - assertNotNull( zoo ); - assertNotNull( zoo.getAddress() ); - assertEquals( "City 1", zoo.getAddress().getCity() ); - assertFalse( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); - assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); - assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); - - session.getTransaction().commit(); - session.close(); + inTransaction( + (session) -> { + final Zoo zoo = (Zoo) session.createQuery( "from Zoo z" ).uniqueResult(); + assertNotNull( zoo ); + assertNotNull( zoo.getAddress() ); + assertEquals( "City 1", zoo.getAddress().getCity() ); + assertFalse( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); + assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); + assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); + } + ); - session = openSession(); - session.getTransaction().begin(); + inTransaction( + (session) -> { + final Zoo zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address.stateProvince" ).uniqueResult(); + assertNotNull( zoo ); + assertNotNull( zoo.getAddress() ); + assertEquals( "City 1", zoo.getAddress().getCity() ); + assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); + assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); + } + ); - zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address.stateProvince" ).uniqueResult(); - assertNotNull( zoo ); - assertNotNull( zoo.getAddress() ); - assertEquals( "City 1", zoo.getAddress().getCity() ); - assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); - assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); - - session.getTransaction().commit(); - session.close(); - - session = openSession(); - session.getTransaction().begin(); - - zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address a join fetch a.stateProvince" ).uniqueResult(); - assertNotNull( zoo ); - assertNotNull( zoo.getAddress() ); - assertEquals( "City 1", zoo.getAddress().getCity() ); - assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); - assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); - - session.getTransaction().commit(); - session.close(); - - session = openSession(); - session.getTransaction().begin(); - - zoo.getAddress().setStateProvince( null ); - session.delete( stateProvince ); - session.delete( zoo ); - session.getTransaction().commit(); - session.close(); + inTransaction( + (session) -> { + final Zoo zoo = (Zoo) session.createQuery( "from Zoo z join fetch z.address a join fetch a.stateProvince" ).uniqueResult(); + assertNotNull( zoo ); + assertNotNull( zoo.getAddress() ); + assertEquals( "City 1", zoo.getAddress().getCity() ); + assertTrue( Hibernate.isInitialized( zoo.getAddress().getStateProvince() ) ); + assertEquals( "Illinois", zoo.getAddress().getStateProvince().getName() ); + } + ); } @Test @@ -2242,11 +2202,11 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase { final SqmSelection sqmSelection = sqmStatement.getQuerySpec().getSelectClause().getSelections().get( 0 ); assertThat( sqmSelection.getSelectableNode(), instanceOf( SqmPath.class ) ); final SqmPath selectedPath = (SqmPath) sqmSelection.getSelectableNode(); - assertThat( selectedPath.getReferencedPathSource(), instanceOf( SingularPersistentAttribute.class ) ); - final SingularPersistentAttribute selectedAttr = (SingularPersistentAttribute) selectedPath.getReferencedPathSource(); - assertThat( selectedAttr.getName(), is( "zoo" ) ); - assertThat( selectedAttr.getType(), instanceOf( EntityDomainType.class ) ); - final EntityDomainType zooType = (EntityDomainType) selectedAttr.getType(); + assertThat( selectedPath.getReferencedPathSource(), instanceOf( EntitySqmPathSource.class ) ); + final EntitySqmPathSource selectedAttr = (EntitySqmPathSource) selectedPath.getReferencedPathSource(); + assertThat( selectedAttr.getPathName(), is( "zoo" ) ); + assertThat( selectedAttr.getSqmPathType(), instanceOf( EntityDomainType.class ) ); + final EntityDomainType zooType = (EntityDomainType) selectedAttr.getSqmPathType(); assertThat( zooType.getHibernateEntityName(), is( Zoo.class.getName() ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java b/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java index e858074613..6fc15bc3b2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/ClassificationType.java @@ -7,6 +7,7 @@ package org.hibernate.test.hql; import java.io.Serializable; +import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -15,6 +16,8 @@ import java.sql.Types; import org.hibernate.HibernateException; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.type.StandardBasicTypes; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.usertype.EnhancedUserType; /** @@ -26,7 +29,7 @@ import org.hibernate.usertype.EnhancedUserType; * * @author Steve Ebersole */ -public class ClassificationType implements EnhancedUserType { +public class ClassificationType implements EnhancedUserType, ValueExtractor { @Override public int[] sqlTypes() { @@ -119,4 +122,19 @@ public class ClassificationType implements EnhancedUserType { private String extractOrdinalString(Object value) { return Integer.toString( extractOrdinal( value ) ); } + + @Override + public Classification extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return Classification.valueOf( rs.getInt( paramIndex ) ); + } + + @Override + public Classification extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException { + return Classification.valueOf( statement.getInt( paramIndex ) ); + } + + @Override + public Classification extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException { + return Classification.valueOf( statement.getInt( paramName ) ); + } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index de4dedc61e..116cb48ecf 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -535,6 +535,10 @@ public abstract class BaseCoreFunctionalTestCase extends BaseUnitTestCase { TransactionUtil2.inTransaction( sessionFactory(), action ); } + protected T fromTransaction(Function action) { + return TransactionUtil2.fromTransaction( sessionFactory(), action ); + } + protected void inTransaction(SessionImplementor session, Consumer action) { TransactionUtil2.inTransaction( session, action ); }