mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-01 15:29:11 +00:00
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:
parent
b176814b44
commit
4f2b0778d3
@ -93,12 +93,6 @@ public Properties getParameters() {
|
|||||||
return parameters;
|
return parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Properties getParametersAsProperties() {
|
|
||||||
Properties properties = new Properties();
|
|
||||||
properties.putAll( parameters );
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BasicValue.Resolution<?> resolve(
|
public BasicValue.Resolution<?> resolve(
|
||||||
Map localConfigParameters,
|
Map localConfigParameters,
|
||||||
MutabilityPlan explicitMutabilityPlan,
|
MutabilityPlan explicitMutabilityPlan,
|
||||||
@ -255,7 +249,7 @@ public BasicType getLegacyResolvedBasicType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JavaTypeDescriptor<Object> getDomainJavaDescriptor() {
|
public JavaTypeDescriptor<Object> getDomainJavaDescriptor() {
|
||||||
return resolved.getMappedJavaTypeDescriptor();
|
return (JavaTypeDescriptor) resolved.getMappedJavaTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||||
import org.hibernate.usertype.UserType;
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
@ -33,13 +34,13 @@ public T deepCopy(T value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(T value) {
|
public Serializable disassemble(T value, SharedSessionContract session) {
|
||||||
return userType.disassemble( value );
|
return userType.disassemble( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public T assemble(Serializable cached) {
|
public T assemble(Serializable cached, SharedSessionContract session) {
|
||||||
return (T) userType.assemble( cached, null );
|
return (T) userType.assemble( cached, null );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ public static QueryKey from(
|
|||||||
|
|
||||||
return new QueryKey(
|
return new QueryKey(
|
||||||
sqlQueryString,
|
sqlQueryString,
|
||||||
parameterBindings.generateQueryKeyMemento(),
|
parameterBindings.generateQueryKeyMemento( persistenceContext ),
|
||||||
limitToUse.getFirstRow(),
|
limitToUse.getFirstRow(),
|
||||||
limitToUse.getMaxRows(),
|
limitToUse.getMaxRows(),
|
||||||
persistenceContext.getTenantIdentifier(),
|
persistenceContext.getTenantIdentifier(),
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.Internal;
|
||||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.dialect.Database;
|
import org.hibernate.dialect.Database;
|
||||||
@ -287,6 +288,11 @@ public boolean isValid(Connection connection) throws SQLException {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public void releasePooledConnections() {
|
||||||
|
state.pool.releasePooledConnections();
|
||||||
|
}
|
||||||
|
|
||||||
public static class PooledConnections {
|
public static class PooledConnections {
|
||||||
|
|
||||||
private final ConcurrentLinkedQueue<Connection> allConnections = new ConcurrentLinkedQueue<>();
|
private final ConcurrentLinkedQueue<Connection> allConnections = new ConcurrentLinkedQueue<>();
|
||||||
@ -455,6 +461,13 @@ public String getUrl() {
|
|||||||
return connectionCreator.getUrl();
|
return connectionCreator.getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
public void releasePooledConnections() {
|
||||||
|
for ( Connection connection : allConnections ) {
|
||||||
|
closeConnection( connection, null );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
private final ConnectionCreator connectionCreator;
|
private final ConnectionCreator connectionCreator;
|
||||||
private ConnectionValidator connectionValidator;
|
private ConnectionValidator connectionValidator;
|
||||||
|
@ -392,8 +392,15 @@ public void sessionFactoryClosed(SessionFactory factory) {
|
|||||||
for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
|
for ( Integrator integrator : serviceRegistry.getService( IntegratorService.class ).getIntegrators() ) {
|
||||||
integrator.disintegrate( this, serviceRegistry );
|
integrator.disintegrate( this, serviceRegistry );
|
||||||
integratorObserver.integrators.remove( integrator );
|
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;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
import org.hibernate.property.access.internal.PropertyAccessMapImpl;
|
import org.hibernate.property.access.internal.PropertyAccessMapImpl;
|
||||||
import org.hibernate.property.access.spi.Getter;
|
import org.hibernate.property.access.spi.Getter;
|
||||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
|
import org.hibernate.type.AnyType;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
import org.hibernate.type.EmbeddedComponentType;
|
import org.hibernate.type.EmbeddedComponentType;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
@ -220,13 +221,12 @@ public static <Y> SimpleDomainType<Y> determineSimpleType(ValueContext typeConte
|
|||||||
return context.locateEntityType( entityType.getAssociatedEntityName() );
|
return context.locateEntityType( entityType.getAssociatedEntityName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
assert type instanceof CompositeType;
|
assert type instanceof AnyType;
|
||||||
final JavaTypeDescriptor<Y> objectJtd = (JavaTypeDescriptor<Y>) context
|
final AnyType anyType = (AnyType) type;
|
||||||
.getTypeConfiguration()
|
final JavaTypeDescriptor<Object> baseJtd = context.getTypeConfiguration()
|
||||||
.getJavaTypeDescriptorRegistry()
|
.getJavaTypeDescriptorRegistry()
|
||||||
.getDescriptor( Object.class );
|
.resolveDescriptor( anyType.getReturnedClass() );
|
||||||
|
return new AnyMappingDomainTypeImpl<>( anyType, baseJtd );
|
||||||
return new AnyMappingDomainTypeImpl<>( objectJtd );
|
|
||||||
}
|
}
|
||||||
case EMBEDDABLE: {
|
case EMBEDDABLE: {
|
||||||
final Component component = (Component) typeContext.getHibernateValue();
|
final Component component = (Component) typeContext.getHibernateValue();
|
||||||
|
@ -8,13 +8,15 @@
|
|||||||
|
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
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.
|
* Describes an attribute at the mapping model level.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface AttributeMapping extends ModelPart, ValueMapping, Fetchable, PropertyBasedMapping {
|
public interface AttributeMapping extends ModelPart, ValueMapping, Fetchable, PropertyBasedMapping, MutabilityPlanExposer {
|
||||||
String getAttributeName();
|
String getAttributeName();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -32,4 +34,9 @@ default String getPartName() {
|
|||||||
default EntityMappingType findContainingEntityMapping() {
|
default EntityMappingType findContainingEntityMapping() {
|
||||||
return getDeclaringType().findContainingEntityMapping();
|
return getDeclaringType().findContainingEntityMapping();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default MutabilityPlan<?> getExposedMutabilityPlan() {
|
||||||
|
return getAttributeMetadataAccess().resolveAttributeMetadata( null ).getMutabilityPlan();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,13 +8,12 @@
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.mapping.IndexedConsumer;
|
import org.hibernate.mapping.IndexedConsumer;
|
||||||
import org.hibernate.sql.ast.Clause;
|
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
|
* Contract for things at the domain/mapping level that can be bound into a JDBC
|
||||||
@ -24,6 +23,7 @@
|
|||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@Incubating
|
||||||
public interface Bindable {
|
public interface Bindable {
|
||||||
/*
|
/*
|
||||||
* todo (6.0) : much of this contract uses Clause which (1) kludgy and (2) not always necessary
|
* 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() {
|
default int getJdbcTypeCount() {
|
||||||
return forEachJdbcType( (index, jdbcMapping) -> {} );
|
return forEachJdbcType( (index, jdbcMapping) -> {} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of JDBC mappings
|
||||||
|
*/
|
||||||
default List<JdbcMapping> getJdbcMappings() {
|
default List<JdbcMapping> getJdbcMappings() {
|
||||||
final List<JdbcMapping> results = new ArrayList<>();
|
final List<JdbcMapping> results = new ArrayList<>();
|
||||||
forEachJdbcType( (index, jdbcMapping) -> results.add( jdbcMapping ) );
|
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?
|
// 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.
|
* Visit each of JdbcMapping
|
||||||
* <p>
|
*
|
||||||
* Used during cacheable SQL AST creation.
|
* @apiNote Same as {@link #forEachJdbcType(int, IndexedConsumer)} starting from `0`
|
||||||
*/
|
*/
|
||||||
|
|
||||||
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
|
default int forEachJdbcType(IndexedConsumer<JdbcMapping> action) {
|
||||||
return forEachJdbcType( 0, action );
|
return forEachJdbcType( 0, action );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visit each JdbcMapping starting from the given offset
|
||||||
|
*/
|
||||||
default int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
|
default int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
* Commonality between {@link org.hibernate.annotations.Any} and
|
* Commonality between {@link org.hibernate.annotations.Any} and
|
||||||
* {@link org.hibernate.annotations.ManyToAny} mappings.
|
* {@link org.hibernate.annotations.ManyToAny} mappings.
|
||||||
*
|
*
|
||||||
* todo (6.0) : atm `@ManyToAny` is not implemented
|
|
||||||
*
|
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {
|
public interface DiscriminatedAssociationModelPart extends Fetchable, FetchableContainer {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.cfg.Environment;
|
import org.hibernate.cfg.Environment;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
@ -263,12 +264,12 @@ public Object deepCopy(Object value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(Object value) {
|
public Serializable disassemble(Object value, SharedSessionContract session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object assemble(Serializable cached) {
|
public Object assemble(Serializable cached, SharedSessionContract session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
|
||||||
@ -17,7 +18,7 @@
|
|||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface EntityAssociationMapping extends ModelPart, Association {
|
public interface EntityAssociationMapping extends ModelPart, Association, TableGroupJoinProducer {
|
||||||
@Override
|
@Override
|
||||||
default String getFetchableName() {
|
default String getFetchableName() {
|
||||||
return getPartName();
|
return getPartName();
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes an attribute with a property access.
|
* Describes an attribute with a property access.
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
|
|
||||||
import java.util.Locale;
|
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.
|
* Describes a mapping related to any part of the app's domain model - e.g.
|
||||||
* an attribute, an entity identifier, collection elements, etc
|
* an attribute, an entity identifier, collection elements, etc
|
||||||
@ -18,13 +21,18 @@
|
|||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface ValueMapping extends MappingModelExpressable {
|
public interface ValueMapping extends MappingModelExpressable, JavaTypedExpressable {
|
||||||
/**
|
/**
|
||||||
* Descriptor for the type of this mapping
|
* Descriptor for the type of this mapping
|
||||||
*/
|
*/
|
||||||
MappingType getMappedType();
|
MappingType getMappedType();
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
|
default JavaTypeDescriptor<?> getExpressableJavaTypeDescriptor() {
|
||||||
|
return getMappedType().getMappedJavaTypeDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**return null;
|
||||||
* Treat operation. Asks the ValueMapping to treat itself as the
|
* Treat operation. Asks the ValueMapping to treat itself as the
|
||||||
* given `targetType`, if it can.
|
* given `targetType`, if it can.
|
||||||
*
|
*
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
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.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||||
@ -45,7 +47,7 @@
|
|||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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;
|
public static final String ROLE_NAME = EntityDiscriminatorMapping.ROLE_NAME;
|
||||||
|
|
||||||
private final NavigableRole navigableRole;
|
private final NavigableRole navigableRole;
|
||||||
@ -162,6 +164,17 @@ public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
|
|||||||
return getJdbcTypeCount();
|
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
|
@Override
|
||||||
public Fetch generateFetch(
|
public Fetch generateFetch(
|
||||||
FetchParent fetchParent,
|
FetchParent fetchParent,
|
||||||
|
@ -219,10 +219,10 @@ public DomainResult<?> createDomainResult(
|
|||||||
);
|
);
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return new BasicResult<Object>(
|
return new BasicResult<>(
|
||||||
sqlSelection.getValuesArrayPosition(),
|
sqlSelection.getValuesArrayPosition(),
|
||||||
null,
|
null,
|
||||||
type.getJavaTypeDescriptor(),
|
(JavaTypeDescriptor<Object>) type.getJavaTypeDescriptor(),
|
||||||
collectionPath
|
collectionPath
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.metamodel.mapping.internal;
|
package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
|
import org.hibernate.engine.internal.ForeignKeys;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.mapping.Any;
|
import org.hibernate.mapping.Any;
|
||||||
import org.hibernate.mapping.IndexedConsumer;
|
import org.hibernate.mapping.IndexedConsumer;
|
||||||
@ -24,16 +29,22 @@
|
|||||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.query.NavigablePath;
|
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.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
import org.hibernate.sql.results.graph.FetchParent;
|
import org.hibernate.sql.results.graph.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
import org.hibernate.sql.results.graph.Fetchable;
|
||||||
import org.hibernate.type.AnyType;
|
import org.hibernate.type.AnyType;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Singular, any-valued attribute
|
* Singular, any-valued attribute
|
||||||
@ -101,7 +112,6 @@ public Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingT
|
|||||||
return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType );
|
return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Fetch generateFetch(
|
public Fetch generateFetch(
|
||||||
FetchParent fetchParent,
|
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
|
@Override
|
||||||
public NavigableRole getNavigableRole() {
|
public NavigableRole getNavigableRole() {
|
||||||
return navigableRole;
|
return navigableRole;
|
||||||
@ -144,15 +173,16 @@ public int getJdbcTypeCount() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||||
final String entityName = session.bestGuessEntityName( value );
|
if ( value == null ) {
|
||||||
final EntityMappingType entityMappingType = session.getFactory()
|
return null;
|
||||||
.getRuntimeMetamodels()
|
}
|
||||||
.getEntityMappingType( entityName );
|
|
||||||
|
final EntityMappingType concreteMappingType = determineConcreteType( value, session );
|
||||||
|
final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping();
|
||||||
|
|
||||||
final Object discriminator = discriminatorMapping
|
final Object discriminator = discriminatorMapping
|
||||||
.getModelPart()
|
.getModelPart()
|
||||||
.resolveDiscriminatorForEntityType( entityMappingType );
|
.resolveDiscriminatorForEntityType( concreteMappingType );
|
||||||
|
|
||||||
final EntityIdentifierMapping identifierMapping = entityMappingType.getIdentifierMapping();
|
|
||||||
final Object identifier = identifierMapping.getIdentifier( value, session );
|
final Object identifier = identifierMapping.getIdentifier( value, session );
|
||||||
|
|
||||||
return new Object[] {
|
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
|
@Override
|
||||||
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
|
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
|
@Override
|
||||||
@ -180,15 +291,7 @@ public void visitFetchables(Consumer<Fetchable> fetchableConsumer, EntityMapping
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||||
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
|
return discriminatorMapping.findSubPart( name, treatTargetType );
|
||||||
return getDiscriminatorPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
|
|
||||||
return getKeyPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -196,4 +299,57 @@ public void visitSubParts(Consumer<ModelPart> consumer, EntityMappingType treatT
|
|||||||
consumer.accept( getDiscriminatorPart() );
|
consumer.accept( getDiscriminatorPart() );
|
||||||
consumer.accept( getKeyPart() );
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,10 @@
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.FetchStyle;
|
import org.hibernate.engine.FetchStyle;
|
||||||
@ -23,8 +26,10 @@
|
|||||||
import org.hibernate.metamodel.RuntimeMetamodels;
|
import org.hibernate.metamodel.RuntimeMetamodels;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingType;
|
import org.hibernate.metamodel.mapping.MappingType;
|
||||||
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.FetchParent;
|
||||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||||
import org.hibernate.sql.results.graph.Fetchable;
|
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.JdbcValuesSourceProcessingOptions;
|
||||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||||
import org.hibernate.type.AnyType;
|
import org.hibernate.type.AnyType;
|
||||||
@ -188,6 +194,99 @@ public EntityMappingType resolveDiscriminatorValueToEntityMapping(Object discrim
|
|||||||
return null;
|
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() {
|
public MappingType getPartMappingType() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -151,15 +151,7 @@ public EntityMappingType findContainingEntityMapping() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||||
if ( AnyDiscriminatorPart.ROLE_NAME.equals( name ) ) {
|
return discriminatorMapping.findSubPart( name, treatTargetType );
|
||||||
return getDiscriminatorPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( AnyKeyPart.ROLE_NAME.equals( name ) ) {
|
|
||||||
return getKeyPart();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,9 +25,14 @@
|
|||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
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.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
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.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.Fetch;
|
import org.hibernate.sql.results.graph.Fetch;
|
||||||
@ -335,4 +340,36 @@ public FetchStyle getStyle() {
|
|||||||
public FetchTiming getTiming() {
|
public FetchTiming getTiming() {
|
||||||
return FetchTiming.IMMEDIATE;
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.collection.internal.StandardArraySemantics;
|
import org.hibernate.collection.internal.StandardArraySemantics;
|
||||||
import org.hibernate.collection.internal.StandardBagSemantics;
|
import org.hibernate.collection.internal.StandardBagSemantics;
|
||||||
import org.hibernate.collection.internal.StandardIdentifierBagSemantics;
|
import org.hibernate.collection.internal.StandardIdentifierBagSemantics;
|
||||||
@ -488,12 +489,12 @@ public Object deepCopy(Object value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(Object value) {
|
public Serializable disassemble(Object value, SharedSessionContract session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object assemble(Serializable cached) {
|
public Object assemble(Serializable cached, SharedSessionContract session) {
|
||||||
throw new NotYetImplementedFor6Exception( getClass() );
|
throw new NotYetImplementedFor6Exception( getClass() );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -960,19 +960,27 @@ public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
|||||||
if ( nature == CollectionPart.Nature.ELEMENT ) {
|
if ( nature == CollectionPart.Nature.ELEMENT ) {
|
||||||
return elementDescriptor;
|
return elementDescriptor;
|
||||||
}
|
}
|
||||||
else if ( nature == CollectionPart.Nature.INDEX ) {
|
|
||||||
|
if ( nature == CollectionPart.Nature.INDEX ) {
|
||||||
return indexDescriptor;
|
return indexDescriptor;
|
||||||
}
|
}
|
||||||
else if ( nature == CollectionPart.Nature.ID ) {
|
|
||||||
|
if ( nature == CollectionPart.Nature.ID ) {
|
||||||
return identifierDescriptor;
|
return identifierDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
||||||
return ( (EntityCollectionPart) elementDescriptor ).findSubPart( name );
|
return ( (EntityCollectionPart) elementDescriptor ).findSubPart( name );
|
||||||
}
|
}
|
||||||
else if ( elementDescriptor instanceof EmbeddedCollectionPart ) {
|
|
||||||
|
if ( elementDescriptor instanceof EmbeddedCollectionPart ) {
|
||||||
return ( (EmbeddedCollectionPart) elementDescriptor ).findSubPart( name, treatTargetType );
|
return ( (EmbeddedCollectionPart) elementDescriptor ).findSubPart( name, treatTargetType );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( elementDescriptor instanceof DiscriminatedCollectionPart ) {
|
||||||
|
return ( (DiscriminatedCollectionPart) elementDescriptor ).findSubPart( name, treatTargetType );
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,4 +14,6 @@
|
|||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface AnyMappingDomainType<J> extends SimpleDomainType<J> {
|
public interface AnyMappingDomainType<J> extends SimpleDomainType<J> {
|
||||||
|
SimpleDomainType getDiscriminatorType();
|
||||||
|
SimpleDomainType getKeyType();
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,20 @@
|
|||||||
package org.hibernate.metamodel.model.domain.internal;
|
package org.hibernate.metamodel.model.domain.internal;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
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;
|
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
|
public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
|
||||||
|
private final AnyType anyType;
|
||||||
private final JavaTypeDescriptor<T> baseJtd;
|
private final JavaTypeDescriptor<T> baseJtd;
|
||||||
|
|
||||||
public AnyMappingDomainTypeImpl(JavaTypeDescriptor<T> baseJtd) {
|
public AnyMappingDomainTypeImpl(AnyType anyType, JavaTypeDescriptor baseJtd) {
|
||||||
|
this.anyType = anyType;
|
||||||
this.baseJtd = baseJtd;
|
this.baseJtd = baseJtd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,11 +31,23 @@ public PersistenceType getPersistenceType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Class<T> getJavaType() {
|
public Class<T> getJavaType() {
|
||||||
return baseJtd.getJavaTypeClass();
|
return anyType.getReturnedClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
|
public JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
|
||||||
return baseJtd;
|
return baseJtd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public SimpleDomainType<?> getDiscriminatorType() {
|
||||||
|
return (BasicType) anyType.getDiscriminatorType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public SimpleDomainType<?> getKeyType() {
|
||||||
|
return (BasicType) anyType.getIdentifierType();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,21 +8,27 @@
|
|||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
||||||
|
import org.hibernate.metamodel.model.domain.BasicDomainType;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmAnyValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
|
|
||||||
|
import static javax.persistence.metamodel.Bindable.BindableType.SINGULAR_ATTRIBUTE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
|
public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
|
||||||
|
private SqmPathSource<?> keyPathSource;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public AnyMappingSqmPathSource(
|
public AnyMappingSqmPathSource(
|
||||||
String localPathName,
|
String localPathName,
|
||||||
AnyMappingDomainType<J> domainType,
|
AnyMappingDomainType<J> domainType,
|
||||||
BindableType jpaBindableType) {
|
BindableType jpaBindableType) {
|
||||||
super( localPathName, domainType, jpaBindableType );
|
super( localPathName, domainType, jpaBindableType );
|
||||||
|
keyPathSource = new BasicSqmPathSource( "id", (BasicDomainType) domainType.getKeyType(), SINGULAR_ATTRIBUTE );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -33,7 +39,11 @@ public AnyMappingDomainType<J> getSqmPathType() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPathSource<?> findSubPathSource(String name) {
|
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
|
@Override
|
||||||
@ -45,4 +55,5 @@ public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmCreationState creationState)
|
|||||||
creationState.getCreationContext().getQueryEngine().getCriteriaBuilder()
|
creationState.getCreationContext().getQueryEngine().getCriteriaBuilder()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6516,12 +6516,13 @@ private AttributeMapping generateNonIdAttributeMapping(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if ( attrType instanceof AnyType ) {
|
else if ( attrType instanceof AnyType ) {
|
||||||
// todo (6.0) : determine a "base JTD"?
|
|
||||||
final JavaTypeDescriptor<Object> baseAssociationJtd = sessionFactory
|
final JavaTypeDescriptor<Object> baseAssociationJtd = sessionFactory
|
||||||
.getTypeConfiguration()
|
.getTypeConfiguration()
|
||||||
.getJavaTypeDescriptorRegistry()
|
.getJavaTypeDescriptorRegistry()
|
||||||
.getDescriptor( Object.class );
|
.getDescriptor( Object.class );
|
||||||
|
|
||||||
|
final AnyType anyType = (AnyType) attrType;
|
||||||
|
|
||||||
return new DiscriminatedAssociationAttributeMapping(
|
return new DiscriminatedAssociationAttributeMapping(
|
||||||
navigableRole.append( bootProperty.getName() ),
|
navigableRole.append( bootProperty.getName() ),
|
||||||
baseAssociationJtd,
|
baseAssociationJtd,
|
||||||
@ -6529,7 +6530,7 @@ else if ( attrType instanceof AnyType ) {
|
|||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
entityMappingType -> new StateArrayContributorMetadata() {
|
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 nullable = bootProperty.isOptional();
|
||||||
private final boolean insertable = bootProperty.isInsertable();
|
private final boolean insertable = bootProperty.isInsertable();
|
||||||
|
@ -6,23 +6,32 @@
|
|||||||
*/
|
*/
|
||||||
package org.hibernate.query.internal;
|
package org.hibernate.query.internal;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.IdentityHashMap;
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.QueryException;
|
import org.hibernate.QueryException;
|
||||||
import org.hibernate.QueryParameterException;
|
import org.hibernate.QueryParameterException;
|
||||||
import org.hibernate.cache.spi.QueryKey;
|
import org.hibernate.cache.spi.QueryKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
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.QueryParameter;
|
||||||
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
import org.hibernate.query.spi.ParameterMetadataImplementor;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
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.
|
* Manages the group of QueryParameterBinding for a particular query.
|
||||||
@ -36,7 +45,7 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||||||
private final ParameterMetadataImplementor parameterMetadata;
|
private final ParameterMetadataImplementor parameterMetadata;
|
||||||
private final boolean queryParametersValidationEnabled;
|
private final boolean queryParametersValidationEnabled;
|
||||||
|
|
||||||
private Map<QueryParameter, QueryParameterBinding> parameterBindingMap;
|
private Map<QueryParameter<?>, QueryParameterBinding<?>> parameterBindingMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a QueryParameterBindings based on the passed information
|
* Constructs a QueryParameterBindings based on the passed information
|
||||||
@ -84,8 +93,8 @@ private QueryParameterBindingsImpl(
|
|||||||
this.parameterBindingMap = new ConcurrentHashMap<>( parameterMetadata.getParameterCount() );
|
this.parameterBindingMap = new ConcurrentHashMap<>( parameterMetadata.getParameterCount() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"WeakerAccess", "unchecked"})
|
@SuppressWarnings({"WeakerAccess" })
|
||||||
protected QueryParameterBinding makeBinding(QueryParameterImplementor queryParameter) {
|
protected QueryParameterBinding<?> makeBinding(QueryParameterImplementor<?> queryParameter) {
|
||||||
if ( parameterBindingMap == null ) {
|
if ( parameterBindingMap == null ) {
|
||||||
parameterBindingMap = new IdentityHashMap<>();
|
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 );
|
parameterBindingMap.put( queryParameter, binding );
|
||||||
|
|
||||||
return binding;
|
return binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBound(QueryParameterImplementor parameter) {
|
public boolean isBound(QueryParameterImplementor<?> parameter) {
|
||||||
//noinspection unchecked
|
|
||||||
return getBinding( parameter ).isBound();
|
return getBinding( parameter ).isBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,17 +123,17 @@ public boolean isBound(QueryParameterImplementor parameter) {
|
|||||||
public <P> QueryParameterBinding<P> getBinding(QueryParameterImplementor<P> parameter) {
|
public <P> QueryParameterBinding<P> getBinding(QueryParameterImplementor<P> parameter) {
|
||||||
if ( parameterBindingMap == null ) {
|
if ( parameterBindingMap == null ) {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return makeBinding( parameter );
|
return (QueryParameterBinding<P>) makeBinding( parameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryParameterBinding binding = parameterBindingMap.get( parameter );
|
QueryParameterBinding<?> binding = parameterBindingMap.get( parameter );
|
||||||
|
|
||||||
if ( binding == null ) {
|
if ( binding == null ) {
|
||||||
binding = makeBinding( parameter );
|
binding = makeBinding( parameter );
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return binding;
|
return (QueryParameterBinding<P>) binding;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,7 +171,7 @@ public void validate() {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAnyMultiValuedBindings() {
|
public boolean hasAnyMultiValuedBindings() {
|
||||||
for ( QueryParameterBinding binding : parameterBindingMap.values() ) {
|
for ( QueryParameterBinding<?> binding : parameterBindingMap.values() ) {
|
||||||
if ( binding.isMultiValued() ) {
|
if ( binding.isMultiValued() ) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -173,7 +181,7 @@ public boolean hasAnyMultiValuedBindings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBindings(BiConsumer action) {
|
public void visitBindings(@SuppressWarnings("rawtypes") BiConsumer action) {
|
||||||
parameterMetadata.visitRegistrations(
|
parameterMetadata.visitRegistrations(
|
||||||
queryParameterImplementor -> {
|
queryParameterImplementor -> {
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
@ -183,21 +191,77 @@ public void visitBindings(BiConsumer action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
|
public QueryKey.ParameterBindingsMemento generateQueryKeyMemento(SharedSessionContractImplementor persistenceContext) {
|
||||||
final int size = parameterBindingMap.size();
|
final int size = parameterBindingMap.size();
|
||||||
final Object[] values = new Object[size];
|
final List<Object> allBindValues = new ArrayList<>( size );
|
||||||
int i = 0;
|
|
||||||
int hashCode = 0;
|
int hashCode = 0;
|
||||||
for ( QueryParameterBinding binding : parameterBindingMap.values() ) {
|
|
||||||
JavaTypeDescriptor javaTypeDescriptor = binding.getBindType().getExpressableJavaTypeDescriptor();
|
for ( QueryParameterBinding<?> binding : parameterBindingMap.values() ) {
|
||||||
final Object value = javaTypeDescriptor.getMutabilityPlan().deepCopy( binding.getBindValue() );
|
final MappingModelExpressable<?> mappingType = determineMappingType( binding, persistenceContext );
|
||||||
hashCode = 31 * hashCode + javaTypeDescriptor.extractHashCode( value );
|
assert mappingType instanceof JavaTypedExpressable;
|
||||||
values[i] = value;
|
|
||||||
|
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 static class ParameterBindingsMementoImpl implements QueryKey.ParameterBindingsMemento {
|
||||||
private final Object[] values;
|
private final Object[] values;
|
||||||
private final int hashCode;
|
private final int hashCode;
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
import org.hibernate.Incubating;
|
import org.hibernate.Incubating;
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.cache.spi.QueryKey;
|
import org.hibernate.cache.spi.QueryKey;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.query.QueryParameter;
|
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
|
* Generate a "memento" for these parameter bindings that can be used
|
||||||
* in creating a {@link org.hibernate.cache.spi.QueryKey}
|
* in creating a {@link org.hibernate.cache.spi.QueryKey}
|
||||||
|
* @param persistenceContext
|
||||||
*/
|
*/
|
||||||
default QueryKey.ParameterBindingsMemento generateQueryKeyMemento() {
|
default QueryKey.ParameterBindingsMemento generateQueryKeyMemento(SharedSessionContractImplementor persistenceContext) {
|
||||||
throw new NotYetImplementedFor6Exception( );
|
throw new NotYetImplementedFor6Exception( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||||
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
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.SqmBasicValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
@ -138,6 +139,8 @@ public interface SemanticQueryWalker<T> {
|
|||||||
|
|
||||||
T visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath<?> path);
|
T visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath<?> path);
|
||||||
|
|
||||||
|
T visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path);
|
||||||
|
|
||||||
T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path);
|
T visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path);
|
||||||
|
|
||||||
T visitEntityValuedPath(SqmEntityValuedSimplePath<?> path);
|
T visitEntityValuedPath(SqmEntityValuedSimplePath<?> path);
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||||
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
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.SqmBasicValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
@ -570,6 +571,13 @@ public Object visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath path) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
|
||||||
|
logWithIndentation( "-> [any-path] - `%s`", path.getNavigablePath().getFullPath() );
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
|
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
|
||||||
logWithIndentation( "-> [non-aggregated-composite-path] - `%s`", path.getNavigablePath().getFullPath() );
|
logWithIndentation( "-> [non-aggregated-composite-path] - `%s`", path.getNavigablePath().getFullPath() );
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||||
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
|
||||||
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
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.SqmBasicValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
import org.hibernate.query.sqm.tree.domain.SqmCorrelation;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
@ -268,6 +269,11 @@ public Object visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath<?> path) {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
|
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath path) {
|
||||||
return path;
|
return path;
|
||||||
|
@ -90,8 +90,8 @@
|
|||||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||||
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
import org.hibernate.query.sqm.internal.DomainParameterXref;
|
||||||
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
|
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.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.BasicValuedPathInterpretation;
|
||||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||||
import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
|
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.delete.SqmDeleteStatement;
|
||||||
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
|
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
|
||||||
import org.hibernate.query.sqm.tree.domain.NonAggregatedCompositeSimplePath;
|
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.SqmBasicValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||||
@ -2080,20 +2081,24 @@ private void consumeImplicitJoins(
|
|||||||
: null
|
: null
|
||||||
);
|
);
|
||||||
|
|
||||||
assert subPart instanceof TableGroupJoinProducer;
|
if ( subPart instanceof TableGroupJoinProducer ) {
|
||||||
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
|
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
|
||||||
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
|
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(
|
||||||
joinedPath.getNavigablePath(),
|
joinedPath.getNavigablePath(),
|
||||||
tableGroup,
|
tableGroup,
|
||||||
null,
|
null,
|
||||||
tableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT,
|
tableGroup.isInnerJoinPossible() ? SqlAstJoinType.INNER : SqlAstJoinType.LEFT,
|
||||||
null,
|
null,
|
||||||
this
|
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 );
|
return EmbeddableValuedPathInterpretation.from( sqmPath, this, this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPathInterpretation visitAnyValuedValuedPath(SqmAnyValuedSimplePath<?> path) {
|
||||||
|
return DiscriminatedAssociationPathInterpretation.from( path, this );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath sqmPath) {
|
public Object visitNonAggregatedCompositeValuedPath(NonAggregatedCompositeSimplePath sqmPath) {
|
||||||
return NonAggregatedCompositeValuedPathInterpretation.from( sqmPath, this, this );
|
return NonAggregatedCompositeValuedPathInterpretation.from( sqmPath, this, this );
|
||||||
|
@ -45,6 +45,10 @@ public ModelPart getExpressionType() {
|
|||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TableGroup getTableGroup() {
|
||||||
|
return tableGroup;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DomainResult<T> createDomainResult(
|
public DomainResult<T> createDomainResult(
|
||||||
String resultVariable,
|
String resultVariable,
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -10,18 +10,21 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
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.EntityValuedModelPart;
|
||||||
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
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.SqlAstJoinType;
|
||||||
import org.hibernate.sql.ast.SqlAstWalker;
|
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.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
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.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
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;
|
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(
|
public static <T> EntityValuedPathInterpretation<T> from(
|
||||||
SqmEntityValuedSimplePath<T> sqmPath,
|
SqmEntityValuedSimplePath<T> sqmPath,
|
||||||
SqmToSqlAstConverter sqlAstCreationState) {
|
SqmToSqlAstConverter sqlAstCreationState) {
|
||||||
|
final SqlExpressionResolver sqlExprResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||||
|
final SessionFactoryImplementor sessionFactory = sqlAstCreationState.getCreationContext().getSessionFactory();
|
||||||
|
|
||||||
final TableGroup tableGroup = sqlAstCreationState
|
final TableGroup tableGroup = sqlAstCreationState
|
||||||
.getFromClauseAccess()
|
.getFromClauseAccess()
|
||||||
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||||
|
|
||||||
final EntityValuedModelPart mapping = (EntityValuedModelPart) tableGroup.getModelPart()
|
final EntityValuedModelPart mapping = (EntityValuedModelPart) tableGroup.getModelPart()
|
||||||
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
.findSubPart( sqmPath.getReferencedPathSource().getPathName(), null );
|
||||||
|
|
||||||
SqlTuple sqlExpression = resolveSqlExpression(
|
final Expression sqlExpression;
|
||||||
sqmPath,
|
|
||||||
sqlAstCreationState,
|
if ( mapping instanceof EntityAssociationMapping ) {
|
||||||
tableGroup,
|
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mapping;
|
||||||
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<>(
|
return new EntityValuedPathInterpretation<>(
|
||||||
sqlExpression,
|
sqlExpression,
|
||||||
sqmPath,
|
sqmPath,
|
||||||
@ -63,10 +130,11 @@ public static <T> EntityValuedPathInterpretation<T> from(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final SqlTuple sqlExpression;
|
private final Expression sqlExpression;
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
private EntityValuedPathInterpretation(
|
private EntityValuedPathInterpretation(
|
||||||
SqlTuple sqlExpression,
|
Expression sqlExpression,
|
||||||
SqmEntityValuedSimplePath sqmPath,
|
SqmEntityValuedSimplePath sqmPath,
|
||||||
TableGroup tableGroup,
|
TableGroup tableGroup,
|
||||||
EntityValuedModelPart mapping) {
|
EntityValuedModelPart mapping) {
|
||||||
@ -79,64 +147,39 @@ public void accept(SqlAstWalker sqlTreeWalker) {
|
|||||||
sqlExpression.accept( sqlTreeWalker );
|
sqlExpression.accept( sqlTreeWalker );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> SqlTuple resolveSqlExpression(
|
@Override
|
||||||
SqmEntityValuedSimplePath<T> sqmPath,
|
public SqlTuple getSqlTuple() {
|
||||||
SqmToSqlAstConverter sqlAstCreationState,
|
return sqlExpression instanceof SqlTuple
|
||||||
TableGroup tableGroup,
|
? (SqlTuple) sqlExpression
|
||||||
EntityValuedModelPart mapping) {
|
: null;
|
||||||
final List<ColumnReference> columnReferences = new ArrayList<>();
|
}
|
||||||
|
|
||||||
// todo (6.0) : "polymorphize" this
|
@Override
|
||||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
public EntityValuedModelPart getExpressionType() {
|
||||||
if ( mapping instanceof ToOneAttributeMapping ) {
|
return (EntityValuedModelPart) super.getExpressionType();
|
||||||
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) mapping;
|
}
|
||||||
final ModelPart modelPart = getModelPart( sqlAstCreationState, toOne );
|
|
||||||
|
|
||||||
modelPart.forEachSelectable(
|
@Override
|
||||||
(columnIndex, selection) -> {
|
public DomainResult<T> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
|
||||||
final TableReference tableReference = getTableReference(
|
final EntityValuedModelPart mappingType = getExpressionType();
|
||||||
sqmPath,
|
if ( mappingType instanceof EntityAssociationMapping ) {
|
||||||
sqlAstCreationState,
|
final NavigablePath navigablePath = getNavigablePath();
|
||||||
tableGroup,
|
|
||||||
toOne,
|
|
||||||
selection.getContainingTableExpression()
|
|
||||||
);
|
|
||||||
final Expression columnReference = sqlExpressionResolver.resolveSqlExpression(
|
|
||||||
createColumnReferenceKey(
|
|
||||||
tableReference,
|
|
||||||
selection.getSelectionExpression()
|
|
||||||
),
|
|
||||||
sqlAstProcessingState -> new ColumnReference(
|
|
||||||
tableReference.getIdentificationVariable(),
|
|
||||||
selection,
|
|
||||||
sqlAstCreationState.getCreationContext().getSessionFactory()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
columnReferences.add( columnReference.unwrap( ColumnReference.class ) );
|
// 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
|
||||||
}
|
|
||||||
else {
|
|
||||||
final EntityCollectionPart entityCollectionPart = (EntityCollectionPart) mapping;
|
|
||||||
final NavigablePath mapNavigablePath = sqmPath.getNavigablePath().getParent();
|
|
||||||
|
|
||||||
final TableGroup mapTableGroup = sqlAstCreationState.getFromClauseAccess().resolveTableGroup(
|
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||||
mapNavigablePath,
|
final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();
|
||||||
(navigablePath) -> {
|
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mappingType;
|
||||||
final TableGroup mapParentTableGroup = sqlAstCreationState
|
final TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
|
||||||
.getFromClauseAccess()
|
navigablePath,
|
||||||
.getTableGroup( mapNavigablePath.getParent() );
|
np -> {
|
||||||
|
final TableGroup parentTableGroup = getTableGroup();
|
||||||
|
|
||||||
final ModelPartContainer mapParent = mapParentTableGroup.getModelPart();
|
final TableGroupJoin tableGroupJoin = associationMapping.createTableGroupJoin(
|
||||||
final PluralAttributeMapping mapDescriptor = (PluralAttributeMapping) mapParent.findSubPart(
|
|
||||||
mapNavigablePath.getLocalName(),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
final TableGroupJoin tableGroupJoin = mapDescriptor.createTableGroupJoin(
|
|
||||||
navigablePath,
|
navigablePath,
|
||||||
mapParentTableGroup,
|
parentTableGroup,
|
||||||
null,
|
null,
|
||||||
SqlAstJoinType.INNER,
|
SqlAstJoinType.INNER,
|
||||||
LockMode.READ,
|
LockMode.READ,
|
||||||
@ -147,89 +190,9 @@ private static <T> SqlTuple resolveSqlExpression(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
entityCollectionPart.forEachSelectable(
|
return associationMapping.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
|
||||||
(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()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SqlTuple sqlExpression = new SqlTuple( columnReferences, mapping );
|
return super.createDomainResult( resultVariable, creationState );
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
|
||||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.metamodel.model.domain.AllowableParameterType;
|
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.Expression;
|
||||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
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.basic.BasicResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
|
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmParameterInterpretation implements Expression, DomainResultProducer {
|
public class SqmParameterInterpretation implements Expression, DomainResultProducer, SqlTupleContainer {
|
||||||
private final SqmParameter sqmParameter;
|
private final SqmParameter sqmParameter;
|
||||||
private final QueryParameterImplementor<?> queryParameter;
|
private final QueryParameterImplementor<?> queryParameter;
|
||||||
private final MappingModelExpressable valueMapping;
|
private final MappingModelExpressable valueMapping;
|
||||||
@ -44,15 +47,29 @@ public SqmParameterInterpretation(
|
|||||||
Function<QueryParameterImplementor, QueryParameterBinding> queryParameterBindingResolver) {
|
Function<QueryParameterImplementor, QueryParameterBinding> queryParameterBindingResolver) {
|
||||||
this.sqmParameter = sqmParameter;
|
this.sqmParameter = sqmParameter;
|
||||||
this.queryParameter = queryParameter;
|
this.queryParameter = queryParameter;
|
||||||
this.valueMapping = valueMapping;
|
|
||||||
this.queryParameterBindingResolver = queryParameterBindingResolver;
|
this.queryParameterBindingResolver = queryParameterBindingResolver;
|
||||||
|
|
||||||
|
if ( valueMapping instanceof EntityValuedFetchable ) {
|
||||||
|
this.valueMapping = ( (EntityValuedFetchable) valueMapping ).getEntityMappingType().getIdentifierMapping();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.valueMapping = valueMapping;
|
||||||
|
}
|
||||||
|
|
||||||
assert jdbcParameters != null;
|
assert jdbcParameters != null;
|
||||||
assert jdbcParameters.size() > 0;
|
assert jdbcParameters.size() > 0;
|
||||||
|
|
||||||
this.resolvedExpression = valueMapping instanceof EmbeddableValuedModelPart
|
this.resolvedExpression = determineResolvedExpression( jdbcParameters, this.valueMapping );
|
||||||
? new SqlTuple( jdbcParameters, valueMapping )
|
}
|
||||||
: jdbcParameters.get( 0 );
|
|
||||||
|
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() {
|
public Expression getResolvedExpression() {
|
||||||
@ -99,4 +116,11 @@ public DomainResult createDomainResult(
|
|||||||
nodeType.getExpressableJavaTypeDescriptor()
|
nodeType.getExpressableJavaTypeDescriptor()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqlTuple getSqlTuple() {
|
||||||
|
return resolvedExpression instanceof SqlTuple
|
||||||
|
? (SqlTuple) resolvedExpression
|
||||||
|
: null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||||
import org.hibernate.query.hql.spi.SemanticPathPart;
|
import org.hibernate.query.hql.spi.SemanticPathPart;
|
||||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||||
|
import org.hibernate.query.sqm.UnknownPathException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
@ -58,11 +59,20 @@ public SemanticPathPart resolvePathPart(
|
|||||||
String name,
|
String name,
|
||||||
boolean isTerminal,
|
boolean isTerminal,
|
||||||
SqmCreationState creationState) {
|
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
|
@Override
|
||||||
public <X> X accept(SemanticQueryWalker<X> walker) {
|
public <X> X accept(SemanticQueryWalker<X> walker) {
|
||||||
return null;
|
return walker.visitAnyValuedValuedPath( this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1583,11 +1583,16 @@ public void visitSortSpecification(SortSpecification sortSpecification) {
|
|||||||
final SortOrder sortOrder = sortSpecification.getSortOrder();
|
final SortOrder sortOrder = sortSpecification.getSortOrder();
|
||||||
if ( sortExpression instanceof SqlTupleContainer ) {
|
if ( sortExpression instanceof SqlTupleContainer ) {
|
||||||
final SqlTuple sqlTuple = ( (SqlTupleContainer) sortExpression ).getSqlTuple();
|
final SqlTuple sqlTuple = ( (SqlTupleContainer) sortExpression ).getSqlTuple();
|
||||||
String separator = NO_SEPARATOR;
|
if ( sqlTuple != null ){
|
||||||
for ( Expression expression : sqlTuple.getExpressions() ) {
|
String separator = NO_SEPARATOR;
|
||||||
appendSql( separator );
|
for ( Expression expression : sqlTuple.getExpressions() ) {
|
||||||
visitSortSpecification( expression, sortOrder, nullPrecedence );
|
appendSql( separator );
|
||||||
separator = COMA_SEPARATOR;
|
visitSortSpecification( expression, sortOrder, nullPrecedence );
|
||||||
|
separator = COMA_SEPARATOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
visitSortSpecification( sortExpression, sortOrder, nullPrecedence );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -3508,21 +3513,10 @@ else if ( !supportsRowValueConstructorSyntaxInInList() ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected final SqlTuple getTuple(Expression expression) {
|
protected final SqlTuple getTuple(Expression expression) {
|
||||||
if ( expression instanceof SqlTuple ) {
|
if ( expression instanceof SqlTupleContainer ) {
|
||||||
return (SqlTuple) expression;
|
return ( (SqlTupleContainer) expression ).getSqlTuple();
|
||||||
}
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
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
|
// If we decide to support that ^^ we should validate that *both* sides of the
|
||||||
// predicate are multi-valued parameters. because...
|
// predicate are multi-valued parameters. because...
|
||||||
// well... its stupid :)
|
// well... its stupid :)
|
||||||
// if ( relationalPredicate.getLeftHandExpression() instanceof GenericParameter ) {
|
|
||||||
// final GenericParameter lhs =
|
|
||||||
// // transform this into a
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
final SqlTuple lhsTuple;
|
final SqlTuple lhsTuple;
|
||||||
final SqlTuple rhsTuple;
|
final SqlTuple rhsTuple;
|
||||||
if ( ( lhsTuple = getTuple( comparisonPredicate.getLeftHandExpression() ) ) != null ) {
|
if ( ( lhsTuple = getTuple( comparisonPredicate.getLeftHandExpression() ) ) != null ) {
|
||||||
|
@ -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()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,6 +26,8 @@
|
|||||||
import org.hibernate.sql.results.graph.DomainResult;
|
import org.hibernate.sql.results.graph.DomainResult;
|
||||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
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
|
* Represents a literal in the SQL AST. This form accepts a {@link JdbcMapping} and acts
|
||||||
@ -35,7 +37,7 @@
|
|||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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 T literalValue;
|
||||||
private final JdbcMapping jdbcMapping;
|
private final JdbcMapping jdbcMapping;
|
||||||
|
|
||||||
@ -157,4 +159,8 @@ public void applySqlSelections(DomainResultCreationState creationState) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
|
||||||
|
return jdbcMapping.getJavaTypeDescriptor();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.sql.ast.SqlAstWalker;
|
import org.hibernate.sql.ast.SqlAstWalker;
|
||||||
|
import org.hibernate.sql.ast.SqlTreeCreationLogger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
@ -23,6 +24,13 @@ public class SqlTuple implements Expression, SqlTupleContainer {
|
|||||||
public SqlTuple(List<? extends Expression> expressions, MappingModelExpressable valueMapping) {
|
public SqlTuple(List<? extends Expression> expressions, MappingModelExpressable valueMapping) {
|
||||||
this.expressions = expressions;
|
this.expressions = expressions;
|
||||||
this.valueMapping = valueMapping;
|
this.valueMapping = valueMapping;
|
||||||
|
|
||||||
|
if ( expressions.size() < 2 ) {
|
||||||
|
SqlTreeCreationLogger.LOGGER.debugf(
|
||||||
|
"SqlTuple created with `%s` expression(s)",
|
||||||
|
expressions.size()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -345,12 +345,12 @@ protected final T deepCopy(T value) {
|
|||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public final Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
|
public final Serializable disassemble(Object value, SharedSessionContractImplementor session, Object owner) throws HibernateException {
|
||||||
return getMutabilityPlan().disassemble( (T) value );
|
return getMutabilityPlan().disassemble( (T) value, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException {
|
public final Object assemble(Serializable cached, SharedSessionContractImplementor session, Object owner) throws HibernateException {
|
||||||
return getMutabilityPlan().assemble( cached );
|
return getMutabilityPlan().assemble( cached, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -36,29 +36,32 @@ default MappingType getMappedType() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default JavaTypeDescriptor getJavaTypeDescriptor() {
|
default JavaTypeDescriptor<T> getJavaTypeDescriptor() {
|
||||||
return getMappedJavaTypeDescriptor();
|
return getMappedJavaTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default JavaTypeDescriptor<T> getExpressableJavaTypeDescriptor() {
|
||||||
|
return getJavaTypeDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default JdbcMapping getJdbcMapping() {
|
default JdbcMapping getJdbcMapping() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default JavaTypeDescriptor getMappedJavaTypeDescriptor() {
|
default JavaTypeDescriptor<T> getMappedJavaTypeDescriptor() {
|
||||||
return getJavaTypeDescriptor();
|
return getJavaTypeDescriptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default ValueExtractor getJdbcValueExtractor() {
|
default ValueExtractor<T> getJdbcValueExtractor() {
|
||||||
//noinspection unchecked
|
|
||||||
return getJdbcTypeDescriptor().getExtractor( getMappedJavaTypeDescriptor() );
|
return getJdbcTypeDescriptor().getExtractor( getMappedJavaTypeDescriptor() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default ValueBinder getJdbcValueBinder() {
|
default ValueBinder<T> getJdbcValueBinder() {
|
||||||
//noinspection unchecked
|
|
||||||
return getJdbcTypeDescriptor().getBinder( getMappedJavaTypeDescriptor() );
|
return getJdbcTypeDescriptor().getBinder( getMappedJavaTypeDescriptor() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
|
||||||
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
|
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ protected T deepCopyNotNull(T value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(T value) {
|
public Serializable disassemble(T value, SharedSessionContract session) {
|
||||||
if ( mutable ) {
|
if ( mutable ) {
|
||||||
return (Serializable) converter.toRelationalValue( value );
|
return (Serializable) converter.toRelationalValue( value );
|
||||||
}
|
}
|
||||||
@ -51,7 +52,7 @@ public Serializable disassemble(T value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T assemble(Serializable cached) {
|
public T assemble(Serializable cached, SharedSessionContract session) {
|
||||||
if ( mutable ) {
|
if ( mutable ) {
|
||||||
return (T) converter.toDomainValue( cached );
|
return (T) converter.toDomainValue( cached );
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.BinaryStream;
|
import org.hibernate.engine.jdbc.BinaryStream;
|
||||||
import org.hibernate.engine.jdbc.BlobImplementer;
|
import org.hibernate.engine.jdbc.BlobImplementer;
|
||||||
@ -48,12 +49,12 @@ public Blob deepCopy(Blob value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(Blob value) {
|
public Serializable disassemble(Blob value, SharedSessionContract session) {
|
||||||
throw new UnsupportedOperationException( "Blobs are not cacheable" );
|
throw new UnsupportedOperationException( "Blobs are not cacheable" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Blob assemble(Serializable cached) {
|
public Blob assemble(Serializable cached, SharedSessionContract session) {
|
||||||
throw new UnsupportedOperationException( "Blobs are not cacheable" );
|
throw new UnsupportedOperationException( "Blobs are not cacheable" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.engine.jdbc.CharacterStream;
|
import org.hibernate.engine.jdbc.CharacterStream;
|
||||||
import org.hibernate.engine.jdbc.ClobImplementer;
|
import org.hibernate.engine.jdbc.ClobImplementer;
|
||||||
@ -173,11 +174,11 @@ public Clob deepCopy(Clob value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable disassemble(Clob value) {
|
public Serializable disassemble(Clob value, SharedSessionContract session) {
|
||||||
throw new UnsupportedOperationException( "Clobs are not cacheable" );
|
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" );
|
throw new UnsupportedOperationException( "Clobs are not cacheable" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutability plan for immutable objects
|
* Mutability plan for immutable objects
|
||||||
*
|
*
|
||||||
@ -32,13 +34,13 @@ public T deepCopy(T value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(T value) {
|
public Serializable disassemble(T value, SharedSessionContract session) {
|
||||||
return (Serializable) value;
|
return (Serializable) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public T assemble(Serializable cached) {
|
public T assemble(Serializable cached, SharedSessionContract session) {
|
||||||
return (T) cached;
|
return (T) cached;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
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
|
* 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.
|
* 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.
|
* @return True if the internal state can be changed; false otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isMutable();
|
boolean isMutable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a deep copy of the value.
|
* Return a deep copy of the value.
|
||||||
@ -29,29 +31,21 @@ public interface MutabilityPlan<T> extends Serializable {
|
|||||||
*
|
*
|
||||||
* @return The deep copy.
|
* @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}
|
* second level cache. Compliment to {@link #assemble}
|
||||||
*
|
*
|
||||||
* @param value The value to disassemble
|
|
||||||
*
|
|
||||||
* @return The disassembled value.
|
|
||||||
*
|
|
||||||
* @see #assemble
|
* @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
|
* Assemble a previously {@linkplain #disassemble disassembled} value. This is used when pulling values from the
|
||||||
* second level cache. Compliment to {@link #disassemble}
|
* second level cache. Compliment to {@link #disassemble}
|
||||||
*
|
*
|
||||||
* @param cached The disassembled state
|
|
||||||
*
|
|
||||||
* @return The re-assembled value.
|
|
||||||
*
|
|
||||||
* @see #disassemble
|
* @see #disassemble
|
||||||
*/
|
*/
|
||||||
public T assemble(Serializable cached);
|
T assemble(Serializable cached, SharedSessionContract session);
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
}
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutability plan for mutable objects
|
* Mutability plan for mutable objects
|
||||||
*
|
*
|
||||||
@ -20,13 +22,13 @@ public boolean isMutable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Serializable disassemble(T value) {
|
public Serializable disassemble(T value, SharedSessionContract session) {
|
||||||
return (Serializable) deepCopy( value );
|
return (Serializable) deepCopy( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked" })
|
@SuppressWarnings({ "unchecked" })
|
||||||
public T assemble(Serializable cached) {
|
public T assemble(Serializable cached, SharedSessionContract session) {
|
||||||
return deepCopy( (T) cached );
|
return deepCopy( (T) cached );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.engine.jdbc.CharacterStream;
|
import org.hibernate.engine.jdbc.CharacterStream;
|
||||||
import org.hibernate.engine.jdbc.NClobImplementer;
|
import org.hibernate.engine.jdbc.NClobImplementer;
|
||||||
import org.hibernate.engine.jdbc.NClobProxy;
|
import org.hibernate.engine.jdbc.NClobProxy;
|
||||||
@ -42,11 +43,11 @@ public NClob deepCopy(NClob value) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Serializable disassemble(NClob value) {
|
public Serializable disassemble(NClob value, SharedSessionContract session) {
|
||||||
throw new UnsupportedOperationException( "Clobs are not cacheable" );
|
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" );
|
throw new UnsupportedOperationException( "Clobs are not cacheable" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,8 @@ public void testExternalization() {
|
|||||||
public void testMutabilityPlan() {
|
public void testMutabilityPlan() {
|
||||||
assertTrue( shouldBeMutable() == typeDescriptor.getMutabilityPlan().isMutable() );
|
assertTrue( shouldBeMutable() == typeDescriptor.getMutabilityPlan().isMutable() );
|
||||||
|
|
||||||
if ( Clob.class.isInstance( testData.copyOfOriginalValue )
|
if ( testData.copyOfOriginalValue instanceof Clob
|
||||||
|| Blob.class.isInstance( testData.copyOfOriginalValue ) ) {
|
|| testData.copyOfOriginalValue instanceof Blob ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,11 +84,13 @@ public void testMutabilityPlan() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ensure the symmetry of assemble/disassebly
|
// 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() ) {
|
if ( ! shouldBeMutable() ) {
|
||||||
assertTrue( cached == testData.copyOfOriginalValue );
|
assertTrue( cached == testData.copyOfOriginalValue );
|
||||||
}
|
}
|
||||||
T reassembled = typeDescriptor.getMutabilityPlan().assemble( cached );
|
T reassembled = typeDescriptor.getMutabilityPlan().assemble( cached, null );
|
||||||
assertTrue( typeDescriptor.areEqual( testData.originalValue, reassembled ) );
|
assertTrue( typeDescriptor.areEqual( testData.originalValue, reassembled ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.Entity;
|
||||||
import javax.persistence.GeneratedValue;
|
import javax.persistence.GeneratedValue;
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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 java.util.Set;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Hibernate, Relational Persistence for Idiomatic Java
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
*
|
*
|
||||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
* 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>.
|
* 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.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
Loading…
x
Reference in New Issue
Block a user