re-enable tests

re-organize some tests
continuing with o.h.test.hql
improve parameter handling by tracking mapping-model types resolved for them in SQM->SQL translation
improve support for ANY mapping use in queries
improve support for comparisons involving SqlTuple
improve support for binding composite Query param values
improve support for plural-attribute refs in SQM
improve support for to-one attribute refs in SQM (including lazily generating the TableGroupJoin when used as selection)
This commit is contained in:
Steve Ebersole 2021-04-09 16:02:42 -05:00
parent b176814b44
commit 4f2b0778d3
55 changed files with 923 additions and 425 deletions

View File

@ -93,12 +93,6 @@ public Properties getParameters() {
return parameters;
}
public Properties getParametersAsProperties() {
Properties properties = new Properties();
properties.putAll( parameters );
return properties;
}
public BasicValue.Resolution<?> resolve(
Map localConfigParameters,
MutabilityPlan explicitMutabilityPlan,
@ -255,7 +249,7 @@ public BasicType getLegacyResolvedBasicType() {
@Override
public JavaTypeDescriptor<Object> getDomainJavaDescriptor() {
return resolved.getMappedJavaTypeDescriptor();
return (JavaTypeDescriptor) resolved.getMappedJavaTypeDescriptor();
}
@Override

View File

@ -8,6 +8,7 @@
import java.io.Serializable;
import org.hibernate.SharedSessionContract;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.usertype.UserType;
@ -33,13 +34,13 @@ public T deepCopy(T value) {
}
@Override
public Serializable disassemble(T value) {
public Serializable disassemble(T value, SharedSessionContract session) {
return userType.disassemble( value );
}
@Override
@SuppressWarnings("unchecked")
public T assemble(Serializable cached) {
public T assemble(Serializable cached, SharedSessionContract session) {
return (T) userType.assemble( cached, null );
}
}

View File

@ -44,7 +44,7 @@ public static QueryKey from(
return new QueryKey(
sqlQueryString,
parameterBindings.generateQueryKeyMemento(),
parameterBindings.generateQueryKeyMemento( persistenceContext ),
limitToUse.getFirstRow(),
limitToUse.getMaxRows(),
persistenceContext.getTenantIdentifier(),

View File

@ -22,6 +22,7 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.dialect.Database;
@ -287,6 +288,11 @@ public boolean isValid(Connection connection) throws SQLException {
return true;
}
@Internal
public void releasePooledConnections() {
state.pool.releasePooledConnections();
}
public static class PooledConnections {
private final ConcurrentLinkedQueue<Connection> allConnections = new ConcurrentLinkedQueue<>();
@ -455,6 +461,13 @@ public String getUrl() {
return connectionCreator.getUrl();
}
@Internal
public void releasePooledConnections() {
for ( Connection connection : allConnections ) {
closeConnection( connection, null );
}
}
public static class Builder {
private final ConnectionCreator connectionCreator;
private ConnectionValidator connectionValidator;

View File

@ -392,8 +392,15 @@ public void sessionFactoryClosed(SessionFactory factory) {
for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
integrator.disintegrate( this, serviceRegistry );
integratorObserver.integrators.remove( integrator );
serviceRegistry.close();
}
try {
close();
}
catch (Exception closeException) {
LOG.debugf( "Eating error closing SF on failed attempt to start it" );
}
close();
throw e;
}
}

View File

@ -47,6 +47,7 @@
import org.hibernate.property.access.internal.PropertyAccessMapImpl;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.AnyType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.EntityType;
@ -220,13 +221,12 @@ public static <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeConte
return context.locateEntityType( entityType.getAssociatedEntityName() );
}
assert type instanceof CompositeType;
final JavaTypeDescriptor<Y> objectJtd = (JavaTypeDescriptor<Y>) context
.getTypeConfiguration()
assert type instanceof AnyType;
final AnyType anyType = (AnyType) type;
final JavaTypeDescriptor<Object> baseJtd = context.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class );
return new AnyMappingDomainTypeImpl<>( objectJtd );
.resolveDescriptor( anyType.getReturnedClass() );
return new AnyMappingDomainTypeImpl<>( anyType, baseJtd );
}
case EMBEDDABLE: {
final Component component = (Component) typeContext.getHibernateValue();

View File

@ -8,13 +8,15 @@
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.MutabilityPlanExposer;
/**
* Describes an attribute at the mapping model level.
*
* @author Steve Ebersole
*/
public interface AttributeMapping extends ModelPart, ValueMapping, Fetchable, PropertyBasedMapping {
public interface AttributeMapping extends ModelPart, ValueMapping, Fetchable, PropertyBasedMapping, MutabilityPlanExposer {
String getAttributeName();
@Override
@ -32,4 +34,9 @@ default String getPartName() {
default EntityMappingType findContainingEntityMapping() {
return getDeclaringType().findContainingEntityMapping();
}
@Override
default MutabilityPlan<?> getExposedMutabilityPlan() {
return getAttributeMetadataAccess().resolveAttributeMetadata( null ).getMutabilityPlan();
}
}

View File

@ -8,13 +8,12 @@
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.sql.ast.Clause;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Contract for things at the domain/mapping level that can be bound into a JDBC
@ -24,6 +23,7 @@
*
* @author Steve Ebersole
*/
@Incubating
public interface Bindable {
/*
* todo (6.0) : much of this contract uses Clause which (1) kludgy and (2) not always necessary
@ -43,10 +43,16 @@ public interface Bindable {
* }
*/
/**
* The number of JDBC mappings
*/
default int getJdbcTypeCount() {
return forEachJdbcType( (index, jdbcMapping) -> {} );
}
/**
* The list of JDBC mappings
*/
default List<JdbcMapping> getJdbcMappings() {
final List<JdbcMapping> results = new ArrayList<>();
forEachJdbcType( (index, jdbcMapping) -> results.add( jdbcMapping ) );
@ -56,15 +62,17 @@ default List<JdbcMapping> getJdbcMappings() {
// todo (6.0) : why did I do 2 forms of JDBC-type visiting? in-flight change?
/**
* Visit all of the SqlExpressableTypes associated with this this Bindable.
* <p>
* Used during cacheable SQL AST creation.
* Visit each of JdbcMapping
*
* @apiNote Same as {@link #forEachJdbcType(int, IndexedConsumer)} starting from `0`
*/
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
return forEachJdbcType( 0, action );
}
/**
* Visit each JdbcMapping starting from the given offset
*/
default int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
throw new NotYetImplementedFor6Exception( getClass() );
}

View File

@ -17,8 +17,6 @@
* Commonality between {@link org.hibernate.annotations.Any} and
* {@link org.hibernate.annotations.ManyToAny} mappings.
*
* todo (6.0) : atm `@ManyToAny` is not implemented
*
* @author Steve Ebersole
*/
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {

View File

@ -16,6 +16,7 @@
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.SharedSessionContract;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.FetchTiming;
@ -263,12 +264,12 @@ public Object deepCopy(Object value) {
}
@Override
public Serializable disassemble(Object value) {
public Serializable disassemble(Object value, SharedSessionContract session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public Object assemble(Serializable cached) {
public Object assemble(Serializable cached, SharedSessionContract session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
};

View File

@ -9,6 +9,7 @@
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
@ -17,7 +18,7 @@
*
* @author Steve Ebersole
*/
public interface EntityAssociationMapping extends ModelPart, Association {
public interface EntityAssociationMapping extends ModelPart, Association, TableGroupJoinProducer {
@Override
default String getFetchableName() {
return getPartName();

View File

@ -7,7 +7,6 @@
package org.hibernate.metamodel.mapping;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.Fetchable;
/**
* Describes an attribute with a property access.

View File

@ -8,6 +8,9 @@
import java.util.Locale;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
/**
* Describes a mapping related to any part of the app's domain model - e.g.
* an attribute, an entity identifier, collection elements, etc
@ -18,13 +21,18 @@
*
* @author Steve Ebersole
*/
public interface ValueMapping extends MappingModelExpressable {
public interface ValueMapping extends MappingModelExpressable, JavaTypedExpressable {
/**
* Descriptor for the type of this mapping
*/
MappingType getMappedType();
/**
@Override
default JavaTypeDescriptor<?> getExpressableJavaTypeDescriptor() {
return getMappedType().getMappedJavaTypeDescriptor();
}
/**return null;
* Treat operation. Asks the ValueMapping to treat itself as the
* given `targetType`, if it can.
*

View File

@ -20,6 +20,8 @@
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.FromClauseAccess;
@ -45,7 +47,7 @@
*
* @author Steve Ebersole
*/
public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions {
public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, SelectableMapping {
public static final String ROLE_NAME = EntityDiscriminatorMapping.ROLE_NAME;
private final NavigableRole navigableRole;
@ -162,6 +164,17 @@ public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
return getJdbcTypeCount();
}
@Override
public int forEachSelectable(SelectableConsumer consumer) {
return forEachSelectable( 0, consumer );
}
@Override
public int forEachSelectable(int offset, SelectableConsumer consumer) {
consumer.accept( offset, this );
return 1;
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,

View File

@ -219,10 +219,10 @@ public DomainResult<?> createDomainResult(
);
//noinspection unchecked
return new BasicResult<Object>(
return new BasicResult<>(
sqlSelection.getValuesArrayPosition(),
null,
type.getJavaTypeDescriptor(),
(JavaTypeDescriptor<Object>) type.getJavaTypeDescriptor(),
collectionPath
);
}

View File

@ -6,12 +6,17 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.io.Serializable;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.SharedSessionContract;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.internal.ForeignKeys;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.Any;
import org.hibernate.mapping.IndexedConsumer;
@ -24,16 +29,22 @@
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.type.AnyType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.MutabilityPlan;
/**
* Singular, any-valued attribute
@ -101,7 +112,6 @@ public Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingT
return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType );
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
@ -122,6 +132,25 @@ public Fetch generateFetch(
);
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void applySqlSelections(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void applySqlSelections(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState, BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public NavigableRole getNavigableRole() {
return navigableRole;
@ -144,15 +173,16 @@ public int getJdbcTypeCount() {
@Override
public Object disassemble(Object value, SharedSessionContractImplementor session) {
final String entityName = session.bestGuessEntityName( value );
final EntityMappingType entityMappingType = session.getFactory()
.getRuntimeMetamodels()
.getEntityMappingType( entityName );
if ( value == null ) {
return null;
}
final EntityMappingType concreteMappingType = determineConcreteType( value, session );
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
final Object discriminator = discriminatorMapping
.getModelPart()
.resolveDiscriminatorForEntityType( entityMappingType );
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
.resolveDiscriminatorForEntityType( concreteMappingType );
final Object identifier = identifierMapping.getIdentifier( value, session );
return new Object[] {
@ -161,9 +191,90 @@ public Object disassemble(Object value, SharedSessionContractImplementor session
};
}
private EntityMappingType determineConcreteType(Object entity, SharedSessionContractImplementor session) {
final String entityName = session.bestGuessEntityName( entity );
return session.getFactory()
.getRuntimeMetamodels()
.getEntityMappingType( entityName );
}
@Override
public int forEachSelectable(int offset, SelectableConsumer consumer) {
discriminatorMapping.getDiscriminatorPart().forEachSelectable( offset, consumer );
discriminatorMapping.getKeyPart().forEachSelectable( offset + 1, consumer );
return 2;
}
@Override
public int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
action.accept( 0, discriminatorMapping.getDiscriminatorPart().getJdbcMapping() );
action.accept( 1, discriminatorMapping.getKeyPart().getJdbcMapping() );
return 2;
}
@Override
public int forEachDisassembledJdbcValue(
Object value,
Clause clause,
int offset,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
if ( value != null ) {
if ( value.getClass().isArray() ) {
final Object[] values = (Object[]) value;
valuesConsumer.consume(
offset,
values[0],
discriminatorMapping.getDiscriminatorPart().getJdbcMapping()
);
valuesConsumer.consume(
offset + 1,
values[1],
discriminatorMapping.getKeyPart().getJdbcMapping()
);
}
else {
final EntityMappingType concreteMappingType = determineConcreteType( value, session );
final Object discriminator = discriminatorMapping
.getModelPart()
.resolveDiscriminatorForEntityType( concreteMappingType );
final Object disassembledDiscriminator = discriminatorMapping.getDiscriminatorPart().disassemble( discriminator, session );
valuesConsumer.consume(
offset,
disassembledDiscriminator,
discriminatorMapping.getDiscriminatorPart().getJdbcMapping()
);
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
final Object identifier = identifierMapping.getIdentifier( value, session );
final Object disassembledKey = discriminatorMapping.getKeyPart().disassemble( identifier, session );
valuesConsumer.consume(
offset + 1,
disassembledKey,
discriminatorMapping.getKeyPart().getJdbcMapping()
);
}
}
return 2;
}
@Override
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
discriminatorMapping.getDiscriminatorPart().breakDownJdbcValues( domainValue, valueConsumer, session );
final EntityMappingType concreteMappingType = determineConcreteType( domainValue, session );
final Object discriminator = discriminatorMapping
.getModelPart()
.resolveDiscriminatorForEntityType( concreteMappingType );
final Object disassembledDiscriminator = discriminatorMapping.getDiscriminatorPart().disassemble( discriminator, session );
valueConsumer.consume( disassembledDiscriminator, discriminatorMapping.getDiscriminatorPart() );
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
final Object identifier = identifierMapping.getIdentifier( domainValue, session );
final Object disassembledKey = discriminatorMapping.getKeyPart().disassemble( identifier, session );
valueConsumer.consume( disassembledKey, discriminatorMapping.getKeyPart() );
}
@Override
@ -180,15 +291,7 @@ public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMapping
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
return getDiscriminatorPart();
}
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
return getKeyPart();
}
return null;
return discriminatorMapping.findSubPart( name, treatTargetType );
}
@Override
@ -196,4 +299,57 @@ public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatT
consumer.accept( getDiscriminatorPart() );
consumer.accept( getKeyPart() );
}
public static class MutabilityPlanImpl implements MutabilityPlan {
// for now use the AnyType for consistency with write-operations
private final AnyType anyType;
public MutabilityPlanImpl(AnyType anyType) {
this.anyType = anyType;
}
@Override
public boolean isMutable() {
return anyType.isMutable();
}
@Override
public Object deepCopy(Object value) {
return value;
}
@Override
public Serializable disassemble(Object value, SharedSessionContract session) {
// if ( value == null ) {
// return null;
// }
// else {
// return new AnyType.ObjectTypeCacheEntry(
// persistenceContext.bestGuessEntityName( value ),
// ForeignKeys.getEntityIdentifierIfNotUnsaved(
// persistenceContext.bestGuessEntityName( value ),
// value,
// persistenceContext
// )
// );
// }
// this ^^ is what we want eventually, but for the time-being to ensure compatibility with
// writing just reuse the AnyType
final SharedSessionContractImplementor persistenceContext = (SharedSessionContractImplementor) session;
return anyType.disassemble( value, persistenceContext, null );
}
@Override
public Object assemble(Serializable cached, SharedSessionContract session) {
// final AnyType.ObjectTypeCacheEntry e = (AnyType.ObjectTypeCacheEntry) cached;
// return e == null ? null : session.internalLoad( e.entityName, e.id, eager, false );
// again, what we want eventually ^^ versus what we should do now vv
final SharedSessionContractImplementor persistenceContext = (SharedSessionContractImplementor) session;
return anyType.assemble( cached, persistenceContext, null );
}
}
}

View File

@ -10,7 +10,10 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStyle;
@ -23,8 +26,10 @@
import org.hibernate.metamodel.RuntimeMetamodels;
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.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -38,6 +43,7 @@
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.AnyType;
@ -188,6 +194,99 @@ public EntityMappingType resolveDiscriminatorValueToEntityMapping(Object discrim
return null;
}
public void forEachConcreteType(Consumer<EntityMappingType> consumer) {
discriminatorValueMappings.forEach( valueMapping -> consumer.accept( valueMapping.entityMapping ) );
}
public EntityMappingType findConcrete(Function<EntityMappingType, EntityMappingType> matcher) {
for ( ValueMapping discriminatorValueMapping : discriminatorValueMappings ) {
final EntityMappingType matched = matcher.apply( discriminatorValueMapping.entityMapping );
if ( matched != null ) {
return matched;
}
}
return null;
}
public <T> T fromConcrete(Function<EntityMappingType,T> matcher) {
for ( ValueMapping discriminatorValueMapping : discriminatorValueMappings ) {
final T matched = matcher.apply( discriminatorValueMapping.entityMapping );
if ( matched != null ) {
return matched;
}
}
return null;
}
public ModelPart findSubPart(String name, EntityMappingType treatTarget) {
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
return getDiscriminatorPart();
}
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
return getKeyPart();
}
if ( treatTarget != null ) {
// make sure the treat-target is one of the mapped entities
ensureMapped( treatTarget );
return resolveAssociatedSubPart( name, treatTarget );
}
for ( ValueMapping discriminatorValueMapping : discriminatorValueMappings ) {
try {
final ModelPart subPart = resolveAssociatedSubPart( name, discriminatorValueMapping.entityMapping );
if ( subPart != null ) {
return subPart;
}
}
catch (Exception e) {
//noinspection UnnecessaryContinue
continue;
}
}
return null;
}
private ModelPart resolveAssociatedSubPart(String name, EntityMappingType entityMapping) {
final EntityIdentifierMapping identifierMapping = entityMapping.getIdentifierMapping();
if ( identifierMapping.getPartName().equals( name ) ) {
return getKeyPart();
}
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
final String idAttrName = ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName();
if ( idAttrName.equals( name ) ) {
return getKeyPart();
}
}
return entityMapping.findSubPart( name );
}
private void ensureMapped(EntityMappingType treatTarget) {
assert treatTarget != null;
for ( ValueMapping mapping : discriminatorValueMappings ) {
if ( mapping.entityMapping.equals( treatTarget ) ) {
return;
}
}
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Treat-target [`%s`] is not not an entity mapped by ANY value : %s",
treatTarget.getEntityName(),
modelPart.getNavigableRole()
)
);
}
public MappingType getPartMappingType() {
return this;
}

View File

@ -151,15 +151,7 @@ public EntityMappingType findContainingEntityMapping() {
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
return getDiscriminatorPart();
}
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
return getKeyPart();
}
return null;
return discriminatorMapping.findSubPart( name, treatTargetType );
}
@Override

View File

@ -25,9 +25,14 @@
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -335,4 +340,36 @@ public FetchStyle getStyle() {
public FetchTiming getTiming() {
return FetchTiming.IMMEDIATE;
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
SqlAstJoinType sqlAstJoinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return collectionDescriptor.getAttributeMapping().createTableGroupJoin(
navigablePath,
lhs,
explicitSourceAlias,
sqlAstJoinType,
lockMode,
aliasBaseGenerator,
sqlExpressionResolver,
creationContext
);
}
@Override
public String getSqlAliasStem() {
return collectionDescriptor.getAttributeMapping().getSqlAliasStem();
}
@Override
public boolean containsTableReference(String tableExpression) {
return collectionDescriptor.getAttributeMapping().containsTableReference( tableExpression );
}
}

View File

@ -18,6 +18,7 @@
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.SharedSessionContract;
import org.hibernate.collection.internal.StandardArraySemantics;
import org.hibernate.collection.internal.StandardBagSemantics;
import org.hibernate.collection.internal.StandardIdentifierBagSemantics;
@ -488,12 +489,12 @@ public Object deepCopy(Object value) {
}
@Override
public Serializable disassemble(Object value) {
public Serializable disassemble(Object value, SharedSessionContract session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public Object assemble(Serializable cached) {
public Object assemble(Serializable cached, SharedSessionContract session) {
throw new NotYetImplementedFor6Exception( getClass() );
}
};

View File

@ -960,19 +960,27 @@ public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( nature == CollectionPart.Nature.ELEMENT ) {
return elementDescriptor;
}
else if ( nature == CollectionPart.Nature.INDEX ) {
if ( nature == CollectionPart.Nature.INDEX ) {
return indexDescriptor;
}
else if ( nature == CollectionPart.Nature.ID ) {
if ( nature == CollectionPart.Nature.ID ) {
return identifierDescriptor;
}
if ( elementDescriptor instanceof EntityCollectionPart ) {
return ( (EntityCollectionPart) elementDescriptor ).findSubPart( name );
}
else if ( elementDescriptor instanceof EmbeddedCollectionPart ) {
if ( elementDescriptor instanceof EmbeddedCollectionPart ) {
return ( (EmbeddedCollectionPart) elementDescriptor ).findSubPart( name, treatTargetType );
}
if ( elementDescriptor instanceof DiscriminatedCollectionPart ) {
return ( (DiscriminatedCollectionPart) elementDescriptor ).findSubPart( name, treatTargetType );
}
return null;
}

View File

@ -14,4 +14,6 @@
* @author Steve Ebersole
*/
public interface AnyMappingDomainType<J> extends SimpleDomainType<J> {
SimpleDomainType getDiscriminatorType();
SimpleDomainType getKeyType();
}

View File

@ -7,15 +7,20 @@
package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.type.AnyType;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
private final AnyType anyType;
private final JavaTypeDescriptor<T> baseJtd;
public AnyMappingDomainTypeImpl(JavaTypeDescriptor<T> baseJtd) {
public AnyMappingDomainTypeImpl(AnyType anyType, JavaTypeDescriptor baseJtd) {
this.anyType = anyType;
this.baseJtd = baseJtd;
}
@ -26,11 +31,23 @@ public PersistenceType getPersistenceType() {
@Override
public Class<T> getJavaType() {
return baseJtd.getJavaTypeClass();
return anyType.getReturnedClass();
}
@Override
public JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
return baseJtd;
}
@Override
@SuppressWarnings("rawtypes")
public SimpleDomainType<?> getDiscriminatorType() {
return (BasicType) anyType.getDiscriminatorType();
}
@Override
@SuppressWarnings("rawtypes")
public SimpleDomainType<?> getKeyType() {
return (BasicType) anyType.getIdentifierType();
}
}

View File

@ -8,21 +8,27 @@
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
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;
import static javax.persistence.metamodel.Bindable.BindableType.SINGULAR_ATTRIBUTE;
/**
* @author Steve Ebersole
*/
public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
private SqmPathSource<?> keyPathSource;
@SuppressWarnings("WeakerAccess")
public AnyMappingSqmPathSource(
String localPathName,
AnyMappingDomainType<J> domainType,
BindableType jpaBindableType) {
super( localPathName, domainType, jpaBindableType );
keyPathSource = new BasicSqmPathSource( "id", (BasicDomainType) domainType.getKeyType(), SINGULAR_ATTRIBUTE );
}
@Override
@ -33,7 +39,11 @@ public AnyMappingDomainType<J> getSqmPathType() {
@Override
public SqmPathSource<?> findSubPathSource(String name) {
throw new NotYetImplementedFor6Exception();
if ( "id".equals( name ) ) {
return keyPathSource;
}
throw new UnsupportedOperationException( "De-referencing parts of an ANY mapping, other than the key, is not supported" );
}
@Override
@ -45,4 +55,5 @@ public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmCreationState creationState)
creationState.getCreationContext().getQueryEngine().getCriteriaBuilder()
);
}
}

View File

@ -6516,12 +6516,13 @@ private AttributeMapping generateNonIdAttributeMapping(
);
}
else if ( attrType instanceof AnyType ) {
// todo (6.0) : determine a "base JTD"?
final JavaTypeDescriptor<Object> baseAssociationJtd = sessionFactory
.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( Object.class );
final AnyType anyType = (AnyType) attrType;
return new DiscriminatedAssociationAttributeMapping(
navigableRole.append( bootProperty.getName() ),
baseAssociationJtd,
@ -6529,7 +6530,7 @@ else if ( attrType instanceof AnyType ) {
stateArrayPosition,
entityMappingType -> new StateArrayContributorMetadata() {
private final MutabilityPlan<?> mutabilityPlan = baseAssociationJtd.getMutabilityPlan();
private final MutabilityPlan<?> mutabilityPlan = new DiscriminatedAssociationAttributeMapping.MutabilityPlanImpl( anyType );
private final boolean nullable = bootProperty.isOptional();
private final boolean insertable = bootProperty.isInsertable();

View File

@ -6,23 +6,32 @@
*/
package org.hibernate.query.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import org.hibernate.Incubating;
import org.hibernate.QueryException;
import org.hibernate.QueryParameterException;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.MutabilityPlanExposer;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Manages the group of QueryParameterBinding for a particular query.
@ -36,7 +45,7 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
private final ParameterMetadataImplementor parameterMetadata;
private final boolean queryParametersValidationEnabled;
private Map<QueryParameter, QueryParameterBinding> parameterBindingMap;
private Map<QueryParameter<?>, QueryParameterBinding<?>> parameterBindingMap;
/**
* Constructs a QueryParameterBindings based on the passed information
@ -84,8 +93,8 @@ private QueryParameterBindingsImpl(
this.parameterBindingMap = new ConcurrentHashMap<>( parameterMetadata.getParameterCount() );
}
@SuppressWarnings({"WeakerAccess", "unchecked"})
protected QueryParameterBinding makeBinding(QueryParameterImplementor queryParameter) {
@SuppressWarnings({"WeakerAccess" })
protected QueryParameterBinding<?> makeBinding(QueryParameterImplementor<?> queryParameter) {
if ( parameterBindingMap == null ) {
parameterBindingMap = new IdentityHashMap<>();
}
@ -99,15 +108,14 @@ protected QueryParameterBinding makeBinding(QueryParameterImplementor queryParam
);
}
final QueryParameterBinding binding = new QueryParameterBindingImpl( queryParameter, sessionFactory, null, queryParametersValidationEnabled );
final QueryParameterBinding<?> binding = new QueryParameterBindingImpl<>( queryParameter, sessionFactory, null, queryParametersValidationEnabled );
parameterBindingMap.put( queryParameter, binding );
return binding;
}
@Override
public boolean isBound(QueryParameterImplementor parameter) {
//noinspection unchecked
public boolean isBound(QueryParameterImplementor<?> parameter) {
return getBinding( parameter ).isBound();
}
@ -115,17 +123,17 @@ public boolean isBound(QueryParameterImplementor parameter) {
public <P> QueryParameterBinding<P> getBinding(QueryParameterImplementor<P> parameter) {
if ( parameterBindingMap == null ) {
//noinspection unchecked
return makeBinding( parameter );
return (QueryParameterBinding<P>) makeBinding( parameter );
}
QueryParameterBinding binding = parameterBindingMap.get( parameter );
QueryParameterBinding<?> binding = parameterBindingMap.get( parameter );
if ( binding == null ) {
binding = makeBinding( parameter );
}
//noinspection unchecked
return binding;
return (QueryParameterBinding<P>) binding;
}
@Override
@ -163,7 +171,7 @@ public void validate() {
@Override
public boolean hasAnyMultiValuedBindings() {
for ( QueryParameterBinding binding : parameterBindingMap.values() ) {
for ( QueryParameterBinding<?> binding : parameterBindingMap.values() ) {
if ( binding.isMultiValued() ) {
return true;
}
@ -173,7 +181,7 @@ public boolean hasAnyMultiValuedBindings() {
}
@Override
public void visitBindings(BiConsumer action) {
public void visitBindings(@SuppressWarnings("rawtypes") BiConsumer action) {
parameterMetadata.visitRegistrations(
queryParameterImplementor -> {
//noinspection unchecked
@ -183,21 +191,77 @@ public void visitBindings(BiConsumer action) {
}
@Override
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento(SharedSessionContractImplementor persistenceContext) {
final int size = parameterBindingMap.size();
final Object[] values = new Object[size];
int i = 0;
final List<Object> allBindValues = new ArrayList<>( size );
int hashCode = 0;
for ( QueryParameterBinding binding : parameterBindingMap.values() ) {
JavaTypeDescriptor javaTypeDescriptor = binding.getBindType().getExpressableJavaTypeDescriptor();
final Object value = javaTypeDescriptor.getMutabilityPlan().deepCopy( binding.getBindValue() );
hashCode = 31 * hashCode + javaTypeDescriptor.extractHashCode( value );
values[i] = value;
for ( QueryParameterBinding<?> binding : parameterBindingMap.values() ) {
final MappingModelExpressable<?> mappingType = determineMappingType( binding, persistenceContext );
assert mappingType instanceof JavaTypedExpressable;
if ( binding.isMultiValued() ) {
for ( Object bindValue : binding.getBindValues() ) {
assert bindValue != null;
final Object disassembled = mappingType.disassemble( bindValue, persistenceContext );
allBindValues.add( disassembled );
//noinspection unchecked
final int valueHashCode = ( (JavaTypedExpressable<Object>) mappingType ).getExpressableJavaTypeDescriptor().extractHashCode( bindValue );
hashCode = 31 * hashCode + valueHashCode;
}
}
else {
final Object bindValue = binding.getBindValue();
final Object disassembled = mappingType.disassemble( bindValue, persistenceContext );
allBindValues.add( disassembled );
//noinspection unchecked
final int valueHashCode = ( (JavaTypedExpressable<Object>) mappingType ).getExpressableJavaTypeDescriptor().extractHashCode( bindValue );
hashCode = 31 * hashCode + valueHashCode;
}
}
return new ParameterBindingsMementoImpl( values, hashCode);
return new ParameterBindingsMementoImpl( allBindValues.toArray( new Object[0] ), hashCode );
}
private MappingModelExpressable<?> determineMappingType(QueryParameterBinding<?> binding, SharedSessionContractImplementor session) {
if ( binding.getBindType() != null ) {
if ( binding.getBindType() instanceof MappingModelExpressable ) {
//noinspection unchecked
return (MappingModelExpressable<Object>) binding.getBindType();
}
}
if ( binding.getType() != null ) {
return binding.getType();
}
final TypeConfiguration typeConfiguration = session.getFactory().getTypeConfiguration();
if ( binding.getBindType() instanceof JavaTypedExpressable ) {
final JavaTypedExpressable javaTypedExpressable = (JavaTypedExpressable) binding.getBindType();
final JavaTypeDescriptor jtd = javaTypedExpressable.getExpressableJavaTypeDescriptor();
if ( jtd.getJavaTypeClass() != null ) {
// avoid dynamic models
return typeConfiguration.getBasicTypeForJavaType( jtd.getJavaTypeClass() );
}
}
if ( binding.isMultiValued() ) {
final Object firstBindValue = binding.getBindValues().iterator().next();
return typeConfiguration.getBasicTypeForJavaType( firstBindValue.getClass() );
}
else {
return typeConfiguration.getBasicTypeForJavaType( binding.getBindValue().getClass() );
}
}
private static class ParameterBindingsMementoImpl implements QueryKey.ParameterBindingsMemento {
private final Object[] values;
private final int hashCode;

View File

@ -11,6 +11,7 @@
import org.hibernate.Incubating;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.cache.spi.QueryKey;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.query.QueryParameter;
/**
@ -80,8 +81,9 @@ default <P> QueryParameterBinding<P> getBinding(QueryParameter<P> parameter) {
/**
* Generate a "memento" for these parameter bindings that can be used
* in creating a {@link org.hibernate.cache.spi.QueryKey}
* @param persistenceContext
*/
default QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
default QueryKey.ParameterBindingsMemento generateQueryKeyMemento(SharedSessionContractImplementor persistenceContext) {
throw new NotYetImplementedFor6Exception( );
}

View File

@ -13,6 +13,7 @@
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
@ -138,6 +139,8 @@ public interface SemanticQueryWalker<T> {
T visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath<?> path);
T visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path);
T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path);
T visitEntityValuedPath(SqmEntityValuedSimplePath<?> path);

View File

@ -17,6 +17,7 @@
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
@ -570,6 +571,13 @@ public Object visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath path) {
return null;
}
@Override
public Object visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
logWithIndentation( "-> [any-path] - `%s`", path.getNavigablePath().getFullPath() );
return null;
}
@Override
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
logWithIndentation( "-> [non-aggregated-composite-path] - `%s`", path.getNavigablePath().getFullPath() );

View File

@ -15,6 +15,7 @@
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
@ -268,6 +269,11 @@ public Object visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath<?> path) {
return path;
}
@Override
public Object visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
return path;
}
@Override
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
return path;

View File

@ -90,8 +90,8 @@
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.DiscriminatedAssociationPathInterpretation;
import org.hibernate.query.sqm.sql.internal.BasicValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
@ -112,6 +112,7 @@
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
@ -2080,20 +2081,24 @@ private void consumeImplicitJoins(
: null
);
assert subPart instanceof TableGroupJoinProducer;
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
joinedPath.getNavigablePath(),
tableGroup,
null,
tableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT,
null,
this
);
if ( subPart instanceof TableGroupJoinProducer ) {
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
joinedPath.getNavigablePath(),
tableGroup,
null,
tableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT,
null,
this
);
fromClauseIndex.register( joinedPath, tableGroupJoin.getJoinedGroup() );
fromClauseIndex.register( joinedPath, tableGroupJoin.getJoinedGroup() );
consumeImplicitJoins( joinedPath, tableGroupJoin.getJoinedGroup(), implicitJoinChecker );
consumeImplicitJoins( joinedPath, tableGroupJoin.getJoinedGroup(), implicitJoinChecker );
}
else {
fromClauseIndex.register( joinedPath, tableGroup );
}
}
);
}
@ -2242,6 +2247,11 @@ public SqmPathInterpretation<?> visitEmbeddableValuedPath(SqmEmbeddedValuedSimpl
return EmbeddableValuedPathInterpretation.from( sqmPath, this, this );
}
@Override
public SqmPathInterpretation visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
return DiscriminatedAssociationPathInterpretation.from( path, this );
}
@Override
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath sqmPath) {
return NonAggregatedCompositeValuedPathInterpretation.from( sqmPath, this, this );

View File

@ -45,6 +45,10 @@ public ModelPart getExpressionType() {
return mapping;
}
protected TableGroup getTableGroup() {
return tableGroup;
}
@Override
public DomainResult<T> createDomainResult(
String resultVariable,

View File

@ -0,0 +1,84 @@
/*
* 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.sql.internal;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.SqlAstWalker;
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.TableReference;
/**
* SqmPathInterpretation for discriminated association (ANY) mappings
*/
public class DiscriminatedAssociationPathInterpretation<T> extends AbstractSqmPathInterpretation<T> implements SqlTupleContainer {
public static <T> DiscriminatedAssociationPathInterpretation<T> from(
SqmAnyValuedSimplePath<T> sqmPath,
SqmToSqlAstConverter converter) {
final TableGroup tableGroup = converter.getFromClauseAccess()
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
final DiscriminatedAssociationModelPart mapping = (DiscriminatedAssociationModelPart ) tableGroup.getModelPart().findSubPart(
sqmPath.getReferencedPathSource().getPathName(),
null
);
final List<Expression> tupleExpressions = new ArrayList<>();
mapping.forEachSelectable(
(selectionIndex, selectableMapping) -> {
final TableReference tableReference = tableGroup.resolveTableReference( selectableMapping.getContainingTableExpression() );
final Expression expression = converter.getSqlExpressionResolver().resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableReference, selectableMapping.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
selectableMapping,
converter.getCreationContext().getSessionFactory()
)
);
tupleExpressions.add( expression );
}
);
return new DiscriminatedAssociationPathInterpretation<T>(
sqmPath,
mapping,
tableGroup,
new SqlTuple( tupleExpressions, mapping )
);
}
private final SqlTuple sqlTuple;
public DiscriminatedAssociationPathInterpretation(SqmPath<T> sqmPath, ModelPart mapping, TableGroup tableGroup, SqlTuple sqlTuple) {
super( sqmPath, mapping, tableGroup );
this.sqlTuple = sqlTuple;
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTuple.accept( sqlTreeWalker );
}
@Override
public SqlTuple getSqlTuple() {
return sqlTuple;
}
}

View File

@ -10,18 +10,21 @@
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
@ -31,7 +34,8 @@
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
@ -43,18 +47,81 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
public static <T> EntityValuedPathInterpretation<T> from(
SqmEntityValuedSimplePath<T> sqmPath,
SqmToSqlAstConverter sqlAstCreationState) {
final SqlExpressionResolver sqlExprResolver = sqlAstCreationState.getSqlExpressionResolver();
final SessionFactoryImplementor sessionFactory = sqlAstCreationState.getCreationContext().getSessionFactory();
final TableGroup tableGroup = sqlAstCreationState
.getFromClauseAccess()
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
final EntityValuedModelPart mapping = (EntityValuedModelPart) tableGroup.getModelPart()
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
SqlTuple sqlExpression = resolveSqlExpression(
sqmPath,
sqlAstCreationState,
tableGroup,
mapping
);
final Expression sqlExpression;
if ( mapping instanceof EntityAssociationMapping ) {
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mapping;
final ForeignKeyDescriptor keyDescriptor = associationMapping.getForeignKeyDescriptor();
final TableReference tableReference = tableGroup.resolveTableReference( keyDescriptor.getKeyTable() );
if ( keyDescriptor instanceof SimpleForeignKeyDescriptor ) {
final SimpleForeignKeyDescriptor simpleKeyDescriptor = (SimpleForeignKeyDescriptor) keyDescriptor;
sqlExpression = sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, simpleKeyDescriptor.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
simpleKeyDescriptor,
sessionFactory
)
);
}
else {
final List<Expression> expressions = new ArrayList<>();
keyDescriptor.forEachSelectable(
(selectionIndex, selectableMapping) -> sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, selectableMapping.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
selectableMapping,
sessionFactory
)
)
);
sqlExpression = new SqlTuple( expressions, keyDescriptor );
}
}
else {
assert mapping instanceof EntityMappingType;
final EntityMappingType entityMappingType = (EntityMappingType) mapping;
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
if ( identifierMapping instanceof BasicEntityIdentifierMapping ) {
final BasicEntityIdentifierMapping simpleIdMapping = (BasicEntityIdentifierMapping) identifierMapping;
final TableReference tableReference = tableGroup.resolveTableReference( simpleIdMapping.getContainingTableExpression() );
assert tableReference != null : "Could not resolve table-group : " + simpleIdMapping.getContainingTableExpression();
sqlExpression = sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, simpleIdMapping.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
simpleIdMapping,
sessionFactory
)
);
}
else {
final List<Expression> expressions = new ArrayList<>();
identifierMapping.forEachSelectable(
(selectionIndex, selectableMapping) -> {
}
);
sqlExpression = new SqlTuple( expressions, identifierMapping );
}
}
return new EntityValuedPathInterpretation<>(
sqlExpression,
sqmPath,
@ -63,10 +130,11 @@ public static <T> EntityValuedPathInterpretation<T> from(
);
}
private final SqlTuple sqlExpression;
private final Expression sqlExpression;
@SuppressWarnings({ "rawtypes", "unchecked" })
private EntityValuedPathInterpretation(
SqlTuple sqlExpression,
Expression sqlExpression,
SqmEntityValuedSimplePath sqmPath,
TableGroup tableGroup,
EntityValuedModelPart mapping) {
@ -79,64 +147,39 @@ public void accept(SqlAstWalker sqlTreeWalker) {
sqlExpression.accept( sqlTreeWalker );
}
private static <T> SqlTuple resolveSqlExpression(
SqmEntityValuedSimplePath<T> sqmPath,
SqmToSqlAstConverter sqlAstCreationState,
TableGroup tableGroup,
EntityValuedModelPart mapping) {
final List<ColumnReference> columnReferences = new ArrayList<>();
@Override
public SqlTuple getSqlTuple() {
return sqlExpression instanceof SqlTuple
? (SqlTuple) sqlExpression
: null;
}
// todo (6.0) : "polymorphize" this
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
if ( mapping instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) mapping;
final ModelPart modelPart = getModelPart( sqlAstCreationState, toOne );
@Override
public EntityValuedModelPart getExpressionType() {
return (EntityValuedModelPart) super.getExpressionType();
}
modelPart.forEachSelectable(
(columnIndex, selection) -> {
final TableReference tableReference = getTableReference(
sqmPath,
sqlAstCreationState,
tableGroup,
toOne,
selection.getContainingTableExpression()
);
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey(
tableReference,
selection.getSelectionExpression()
),
sqlAstProcessingState -> new ColumnReference(
tableReference.getIdentificationVariable(),
selection,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
);
@Override
public DomainResult<T> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
final EntityValuedModelPart mappingType = getExpressionType();
if ( mappingType instanceof EntityAssociationMapping ) {
final NavigablePath navigablePath = getNavigablePath();
columnReferences.add( columnReference.unwrap( ColumnReference.class ) );
}
);
}
else {
final EntityCollectionPart entityCollectionPart = (EntityCollectionPart) mapping;
final NavigablePath mapNavigablePath = sqmPath.getNavigablePath().getParent();
// for a to-one or to-many we may not have yet joined to the association table,
// but we need to because the association is a root return and needs to select
// all of the entity columns
final TableGroup mapTableGroup = sqlAstCreationState.getFromClauseAccess().resolveTableGroup(
mapNavigablePath,
(navigablePath) -> {
final TableGroup mapParentTableGroup = sqlAstCreationState
.getFromClauseAccess()
.getTableGroup( mapNavigablePath.getParent() );
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mappingType;
final TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
navigablePath,
np -> {
final TableGroup parentTableGroup = getTableGroup();
final ModelPartContainer mapParent = mapParentTableGroup.getModelPart();
final PluralAttributeMapping mapDescriptor = (PluralAttributeMapping) mapParent.findSubPart(
mapNavigablePath.getLocalName(),
null
);
final TableGroupJoin tableGroupJoin = mapDescriptor.createTableGroupJoin(
final TableGroupJoin tableGroupJoin = associationMapping.createTableGroupJoin(
navigablePath,
mapParentTableGroup,
parentTableGroup,
null,
SqlAstJoinType.INNER,
LockMode.READ,
@ -147,89 +190,9 @@ private static <T> SqlTuple resolveSqlExpression(
}
);
entityCollectionPart.forEachSelectable(
(index, selectable) -> {
final TableReference tableReference = mapTableGroup.resolveTableReference( selectable.getContainingTableExpression() );
final SqlExpressionResolver expressionResolver = sqlExpressionResolver;
columnReferences.add(
(ColumnReference) expressionResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, selectable.getSelectionExpression() ),
(processingState) -> new ColumnReference(
tableReference.getIdentificationVariable(),
selectable,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
)
);
}
);
return associationMapping.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
}
SqlTuple sqlExpression = new SqlTuple( columnReferences, mapping );
return sqlExpression;
}
private static ModelPart getModelPart(
SqmToSqlAstConverter sqlAstCreationState,
EntityValuedFetchable fetchable) {
if ( fetchable instanceof ToOneAttributeMapping ) {
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable;
final Clause current = sqlAstCreationState.getCurrentClauseStack().getCurrent();
if ( current == Clause.SELECT ) {
return toOne.getAssociatedEntityMappingType().getIdentifierMapping();
}
else {
return toOne.getForeignKeyDescriptor();
}
}
return fetchable;
}
private static ModelPart getModelPart(
SqmToSqlAstConverter sqlAstCreationState,
ToOneAttributeMapping toOneAttributeMapping) {
final Clause current = sqlAstCreationState.getCurrentClauseStack()
.getCurrent();
final ModelPart modelPart;
if ( current == Clause.SELECT ) {
modelPart = toOneAttributeMapping.getAssociatedEntityMappingType().getIdentifierMapping();
}
else {
modelPart = toOneAttributeMapping.getForeignKeyDescriptor();
}
return modelPart;
}
private static <T> TableReference getTableReference(
SqmEntityValuedSimplePath<T> sqmPath,
SqlAstCreationState sqlAstCreationState,
TableGroup tableGroup,
ToOneAttributeMapping toOneAttributeMapping,
String containingTableExpression) {
TableReference tableReference = tableGroup.getTableReference( containingTableExpression );
if ( tableReference == null ) {
final TableGroupJoin tableGroupJoin = toOneAttributeMapping.createTableGroupJoin(
sqmPath.getNavigablePath(),
tableGroup,
null,
toOneAttributeMapping.isNullable() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT,
LockMode.NONE,
sqlAstCreationState
);
sqlAstCreationState.getFromClauseAccess().registerTableGroup(
sqmPath.getNavigablePath(),
tableGroupJoin.getJoinedGroup()
);
return tableGroupJoin.getJoinedGroup().getTableReference( containingTableExpression );
}
return tableReference;
}
@Override
public SqlTuple getSqlTuple() {
return sqlExpression;
return super.createDomainResult( resultVariable, creationState );
}
}

View File

@ -9,6 +9,7 @@
import java.util.List;
import java.util.function.Function;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
@ -21,14 +22,16 @@
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
/**
* @author Steve Ebersole
*/
public class SqmParameterInterpretation implements Expression, DomainResultProducer {
public class SqmParameterInterpretation implements Expression, DomainResultProducer, SqlTupleContainer {
private final SqmParameter sqmParameter;
private final QueryParameterImplementor<?> queryParameter;
private final MappingModelExpressable valueMapping;
@ -44,15 +47,29 @@ public SqmParameterInterpretation(
Function<QueryParameterImplementor, QueryParameterBinding> queryParameterBindingResolver) {
this.sqmParameter = sqmParameter;
this.queryParameter = queryParameter;
this.valueMapping = valueMapping;
this.queryParameterBindingResolver = queryParameterBindingResolver;
if ( valueMapping instanceof EntityValuedFetchable ) {
this.valueMapping = ( (EntityValuedFetchable) valueMapping ).getEntityMappingType().getIdentifierMapping();
}
else {
this.valueMapping = valueMapping;
}
assert jdbcParameters != null;
assert jdbcParameters.size() > 0;
this.resolvedExpression = valueMapping instanceof EmbeddableValuedModelPart
? new SqlTuple( jdbcParameters, valueMapping )
: jdbcParameters.get( 0 );
this.resolvedExpression = determineResolvedExpression( jdbcParameters, this.valueMapping );
}
private Expression determineResolvedExpression(List<JdbcParameter> jdbcParameters, MappingModelExpressable valueMapping) {
if ( valueMapping instanceof EmbeddableValuedModelPart
|| valueMapping instanceof DiscriminatedAssociationModelPart ) {
return new SqlTuple( jdbcParameters, valueMapping );
}
assert jdbcParameters.size() == 1;
return jdbcParameters.get( 0 );
}
public Expression getResolvedExpression() {
@ -99,4 +116,11 @@ public DomainResult createDomainResult(
nodeType.getExpressableJavaTypeDescriptor()
);
}
@Override
public SqlTuple getSqlTuple() {
return resolvedExpression instanceof SqlTuple
? (SqlTuple) resolvedExpression
: null;
}
}

View File

@ -16,6 +16,7 @@
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.UnknownPathException;
/**
* @author Steve Ebersole
@ -58,11 +59,20 @@ public SemanticPathPart resolvePathPart(
String name,
boolean isTerminal,
SqmCreationState creationState) {
return null;
final SqmPathSource<?> subPathSource = getReferencedPathSource().findSubPathSource( name );
if ( subPathSource == null ) {
throw UnknownPathException.unknownSubPath( this, name );
}
return subPathSource.createSqmPath( this, creationState );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Visitation
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return null;
return walker.visitAnyValuedValuedPath( this );
}
}

View File

@ -1583,11 +1583,16 @@ public void visitSortSpecification(SortSpecification sortSpecification) {
final SortOrder sortOrder = sortSpecification.getSortOrder();
if ( sortExpression instanceof SqlTupleContainer ) {
final SqlTuple sqlTuple = ( (SqlTupleContainer) sortExpression ).getSqlTuple();
String separator = NO_SEPARATOR;
for ( Expression expression : sqlTuple.getExpressions() ) {
appendSql( separator );
visitSortSpecification( expression, sortOrder, nullPrecedence );
separator = COMA_SEPARATOR;
if ( sqlTuple != null ){
String separator = NO_SEPARATOR;
for ( Expression expression : sqlTuple.getExpressions() ) {
appendSql( separator );
visitSortSpecification( expression, sortOrder, nullPrecedence );
separator = COMA_SEPARATOR;
}
}
else {
visitSortSpecification( sortExpression, sortOrder, nullPrecedence );
}
}
else {
@ -3508,21 +3513,10 @@ else if ( !supportsRowValueConstructorSyntaxInInList() ) {
}
protected final SqlTuple getTuple(Expression expression) {
if ( expression instanceof SqlTuple ) {
return (SqlTuple) expression;
}
else if ( expression instanceof SqmParameterInterpretation ) {
final Expression resolvedExpression = ( (SqmParameterInterpretation) expression ).getResolvedExpression();
if ( resolvedExpression instanceof SqlTuple ) {
return (SqlTuple) resolvedExpression;
}
}
else if ( expression instanceof EmbeddableValuedPathInterpretation<?> ) {
return ( (EmbeddableValuedPathInterpretation<?>) expression ).getSqlExpression();
}
else if ( expression instanceof NonAggregatedCompositeValuedPathInterpretation<?> ) {
return ( (NonAggregatedCompositeValuedPathInterpretation<?>) expression ).getSqlExpression();
if ( expression instanceof SqlTupleContainer ) {
return ( (SqlTupleContainer) expression ).getSqlTuple();
}
return null;
}
@ -3799,11 +3793,7 @@ public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) {
// If we decide to support that ^^ we should validate that *both* sides of the
// predicate are multi-valued parameters. because...
// well... its stupid :)
// if ( relationalPredicate.getLeftHandExpression() instanceof GenericParameter ) {
// final GenericParameter lhs =
// // transform this into a
// }
//
final SqlTuple lhsTuple;
final SqlTuple rhsTuple;
if ( ( lhsTuple = getTuple( comparisonPredicate.getLeftHandExpression() ) ) != null ) {

View File

@ -1,93 +0,0 @@
/*
* 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;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
/**
* We classify literals different based on their source so that we can handle then differently
* when rendering SQL. This class offers convenience for those implementations
* <p/>
* Can function as a ParameterBinder for cases where we want to treat literals using bind parameters.
*
* @author Steve Ebersole
*/
public abstract class AbstractLiteral<T>
implements JdbcParameterBinder, Expression, DomainResultProducer<T> {
private final Object value;
private final BasicValuedMapping type;
private final Clause clause;
public AbstractLiteral(Object value, BasicValuedMapping type, Clause clause) {
this.value = value;
this.type = type;
this.clause = clause;
}
public Object getValue() {
return value;
}
public boolean isInSelect() {
return clause == Clause.SELECT;
}
@Override
public BasicValuedMapping getExpressionType() {
return type;
}
@Override
public DomainResult<T> createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
this,
type.getMappedType().getMappedJavaTypeDescriptor(),
creationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory()
.getTypeConfiguration()
);
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
resultVariable,
type.getMappedType().getMappedJavaTypeDescriptor()
);
}
@Override
public void bindParameterValue(
PreparedStatement statement,
int startPosition,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext) throws SQLException {
//noinspection unchecked
( ( BasicType<?> ) getExpressionType() ).getJdbcValueBinder().bind(
statement,
getValue(),
startPosition,
executionContext.getSession()
);
}
}

View File

@ -26,6 +26,8 @@
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypedExpressable;
/**
* Represents a literal in the SQL AST. This form accepts a {@link JdbcMapping} and acts
@ -35,7 +37,7 @@
*
* @author Steve Ebersole
*/
public class JdbcLiteral<T> implements Literal, MappingModelExpressable<T>, DomainResultProducer<T> {
public class JdbcLiteral<T> implements Literal, MappingModelExpressable<T>, DomainResultProducer<T>, JavaTypedExpressable<T> {
private final T literalValue;
private final JdbcMapping jdbcMapping;
@ -157,4 +159,8 @@ public void applySqlSelections(DomainResultCreationState creationState) {
);
}
@Override
public JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
return jdbcMapping.getJavaTypeDescriptor();
}
}

View File

@ -12,6 +12,7 @@
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.SqlTreeCreationLogger;
/**
* @author Steve Ebersole
@ -23,6 +24,13 @@ public class SqlTuple implements Expression, SqlTupleContainer {
public SqlTuple(List<? extends Expression> expressions, MappingModelExpressable valueMapping) {
this.expressions = expressions;
this.valueMapping = valueMapping;
if ( expressions.size() < 2 ) {
SqlTreeCreationLogger.LOGGER.debugf(
"SqlTuple created with `%s` expression(s)",
expressions.size()
);
}
}
@Override

View File

@ -345,12 +345,12 @@ protected final T deepCopy(T value) {
@Override
@SuppressWarnings({ "unchecked" })
public final Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
return getMutabilityPlan().disassemble( (T) value );
return getMutabilityPlan().disassemble( (T) value, session );
}
@Override
public final Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException {
return getMutabilityPlan().assemble( cached );
return getMutabilityPlan().assemble( cached, session );
}
@Override

View File

@ -36,29 +36,32 @@ default MappingType getMappedType() {
}
@Override
default JavaTypeDescriptor getJavaTypeDescriptor() {
default JavaTypeDescriptor<T> getJavaTypeDescriptor() {
return getMappedJavaTypeDescriptor();
}
@Override
default JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
return getJavaTypeDescriptor();
}
@Override
default JdbcMapping getJdbcMapping() {
return this;
}
@Override
default JavaTypeDescriptor getMappedJavaTypeDescriptor() {
default JavaTypeDescriptor<T> getMappedJavaTypeDescriptor() {
return getJavaTypeDescriptor();
}
@Override
default ValueExtractor getJdbcValueExtractor() {
//noinspection unchecked
default ValueExtractor<T> getJdbcValueExtractor() {
return getJdbcTypeDescriptor().getExtractor( getMappedJavaTypeDescriptor() );
}
@Override
default ValueBinder getJdbcValueBinder() {
//noinspection unchecked
default ValueBinder<T> getJdbcValueBinder() {
return getJdbcTypeDescriptor().getBinder( getMappedJavaTypeDescriptor() );
}

View File

@ -8,6 +8,7 @@
import java.io.Serializable;
import org.hibernate.SharedSessionContract;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
@ -43,7 +44,7 @@ protected T deepCopyNotNull(T value) {
}
@Override
public Serializable disassemble(T value) {
public Serializable disassemble(T value, SharedSessionContract session) {
if ( mutable ) {
return (Serializable) converter.toRelationalValue( value );
}
@ -51,7 +52,7 @@ public Serializable disassemble(T value) {
}
@Override
public T assemble(Serializable cached) {
public T assemble(Serializable cached, SharedSessionContract session) {
if ( mutable ) {
return (T) converter.toDomainValue( cached );
}

View File

@ -14,6 +14,7 @@
import java.util.Comparator;
import org.hibernate.HibernateException;
import org.hibernate.SharedSessionContract;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.BinaryStream;
import org.hibernate.engine.jdbc.BlobImplementer;
@ -48,12 +49,12 @@ public Blob deepCopy(Blob value) {
}
@Override
public Serializable disassemble(Blob value) {
public Serializable disassemble(Blob value, SharedSessionContract session) {
throw new UnsupportedOperationException( "Blobs are not cacheable" );
}
@Override
public Blob assemble(Serializable cached) {
public Blob assemble(Serializable cached, SharedSessionContract session) {
throw new UnsupportedOperationException( "Blobs are not cacheable" );
}
}

View File

@ -14,6 +14,7 @@
import java.util.Comparator;
import org.hibernate.HibernateException;
import org.hibernate.SharedSessionContract;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.CharacterStream;
import org.hibernate.engine.jdbc.ClobImplementer;
@ -173,11 +174,11 @@ public Clob deepCopy(Clob value) {
return value;
}
public Serializable disassemble(Clob value) {
public Serializable disassemble(Clob value, SharedSessionContract session) {
throw new UnsupportedOperationException( "Clobs are not cacheable" );
}
public Clob assemble(Serializable cached) {
public Clob assemble(Serializable cached, SharedSessionContract session) {
throw new UnsupportedOperationException( "Clobs are not cacheable" );
}
}

View File

@ -8,6 +8,8 @@
import java.io.Serializable;
import org.hibernate.SharedSessionContract;
/**
* Mutability plan for immutable objects
*
@ -32,13 +34,13 @@ public T deepCopy(T value) {
}
@Override
public Serializable disassemble(T value) {
public Serializable disassemble(T value, SharedSessionContract session) {
return (Serializable) value;
}
@Override
@SuppressWarnings({ "unchecked" })
public T assemble(Serializable cached) {
public T assemble(Serializable cached, SharedSessionContract session) {
return (T) cached;
}
}

View File

@ -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.type.descriptor.java;
/**
* Contract for something that has an associated JavaTypeDescriptor
*/
public interface JavaTypedExpressable<T> {
JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor();
}

View File

@ -8,6 +8,8 @@
import java.io.Serializable;
import org.hibernate.SharedSessionContract;
/**
* Describes the mutability aspects of a Java type. The term mutability refers to the fact that generally speaking
* the aspects described by this contract are defined by whether the Java type's internal state is mutable or not.
@ -20,7 +22,7 @@ public interface MutabilityPlan<T> extends Serializable {
*
* @return True if the internal state can be changed; false otherwise.
*/
public boolean isMutable();
boolean isMutable();
/**
* Return a deep copy of the value.
@ -29,29 +31,21 @@ public interface MutabilityPlan<T> extends Serializable {
*
* @return The deep copy.
*/
public T deepCopy(T value);
T deepCopy(T value);
/**
* Return a "disassembled" representation of the value. This is used to push values onto the
* Return a disassembled representation of the value. This is used to push values onto the
* second level cache. Compliment to {@link #assemble}
*
* @param value The value to disassemble
*
* @return The disassembled value.
*
* @see #assemble
*/
public Serializable disassemble(T value);
Serializable disassemble(T value, SharedSessionContract session);
/**
* Assemble a previously {@linkplain #disassemble disassembled} value. This is used when pulling values from the
* second level cache. Compliment to {@link #disassemble}
*
* @param cached The disassembled state
*
* @return The re-assembled value.
*
* @see #disassemble
*/
public T assemble(Serializable cached);
T assemble(Serializable cached, SharedSessionContract session);
}

View File

@ -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.type.descriptor.java;
/**
* Something that exposes a MutabilityPlan
*/
public interface MutabilityPlanExposer<T> {
MutabilityPlan<T> getExposedMutabilityPlan();
}

View File

@ -8,6 +8,8 @@
import java.io.Serializable;
import org.hibernate.SharedSessionContract;
/**
* Mutability plan for mutable objects
*
@ -20,13 +22,13 @@ public boolean isMutable() {
}
@Override
public Serializable disassemble(T value) {
public Serializable disassemble(T value, SharedSessionContract session) {
return (Serializable) deepCopy( value );
}
@Override
@SuppressWarnings({ "unchecked" })
public T assemble(Serializable cached) {
public T assemble(Serializable cached, SharedSessionContract session) {
return deepCopy( (T) cached );
}

View File

@ -13,6 +13,7 @@
import java.util.Comparator;
import org.hibernate.HibernateException;
import org.hibernate.SharedSessionContract;
import org.hibernate.engine.jdbc.CharacterStream;
import org.hibernate.engine.jdbc.NClobImplementer;
import org.hibernate.engine.jdbc.NClobProxy;
@ -42,11 +43,11 @@ public NClob deepCopy(NClob value) {
return value;
}
public Serializable disassemble(NClob value) {
public Serializable disassemble(NClob value, SharedSessionContract session) {
throw new UnsupportedOperationException( "Clobs are not cacheable" );
}
public NClob assemble(Serializable cached) {
public NClob assemble(Serializable cached, SharedSessionContract session) {
throw new UnsupportedOperationException( "Clobs are not cacheable" );
}
}

View File

@ -72,8 +72,8 @@ public void testExternalization() {
public void testMutabilityPlan() {
assertTrue( shouldBeMutable() == typeDescriptor.getMutabilityPlan().isMutable() );
if ( Clob.class.isInstance( testData.copyOfOriginalValue )
|| Blob.class.isInstance( testData.copyOfOriginalValue ) ) {
if ( testData.copyOfOriginalValue instanceof Clob
|| testData.copyOfOriginalValue instanceof Blob ) {
return;
}
@ -84,11 +84,13 @@ public void testMutabilityPlan() {
}
// ensure the symmetry of assemble/disassebly
Serializable cached = typeDescriptor.getMutabilityPlan().disassemble( testData.copyOfOriginalValue );
// NOTE: these should not use Session, so we just pass null
Serializable cached = typeDescriptor.getMutabilityPlan().disassemble( testData.copyOfOriginalValue, null );
if ( ! shouldBeMutable() ) {
assertTrue( cached == testData.copyOfOriginalValue );
}
T reassembled = typeDescriptor.getMutabilityPlan().assemble( cached );
T reassembled = typeDescriptor.getMutabilityPlan().assemble( cached, null );
assertTrue( typeDescriptor.areEqual( testData.originalValue, reassembled ) );
}
}

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
* 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 javax.persistence.Entity;
import javax.persistence.GeneratedValue;

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
* 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.Set;
import javax.persistence.Column;

View File

@ -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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
* 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 org.hibernate.Session;
import org.hibernate.Transaction;