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