diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AssociationKey.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AssociationKey.java index d0c5c1485b..bca5354c12 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AssociationKey.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AssociationKey.java @@ -20,6 +20,10 @@ public class AssociationKey { this.columns = columns; } + public String getTable() { + return table; + } + @Override public boolean equals(Object o) { if ( this == o ) { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java index 7307ae78d3..20b4bff5b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityCollectionPart.java @@ -166,10 +166,9 @@ public class EntityCollectionPart TableGroup tableGroup, String resultVariable, DomainResultCreationState creationState) { - throw new NotYetImplementedFor6Exception( getClass() ); + return fkTargetModelPart.createDomainResult( navigablePath, tableGroup, resultVariable, creationState ); } - @Override public void visitColumns(ColumnConsumer consumer) { entityMappingType.visitColumns( consumer ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java index 851bc790f0..6c1f6b48ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java @@ -29,6 +29,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor; import org.hibernate.metamodel.mapping.CollectionMappingType; import org.hibernate.metamodel.mapping.CollectionPart; +import org.hibernate.metamodel.mapping.ColumnConsumer; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 8f28e956d2..273b492454 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -83,6 +83,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping private ForeignKeyDescriptor foreignKeyDescriptor; private ForeignKeyDirection foreignKeyDirection; private String identifyingColumnsTableExpression; + private boolean isKeyReferringSide; public ToOneAttributeMapping( String name, @@ -184,6 +185,8 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) { this.foreignKeyDescriptor = foreignKeyDescriptor; + assert identifyingColumnsTableExpression != null; + isKeyReferringSide = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression ); } public void setIdentifyingColumnsTableExpression(String tableExpression) { @@ -310,7 +313,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping We have a cirularity but it is not bidirectional */ - if ( referringPrimaryKey ) { + if ( isKeyReferringSide ) { final TableGroup parentTableGroup = creationState .getSqlAstCreationState() .getFromClauseAccess() @@ -462,13 +465,13 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping */ boolean selectByUniqueKey; - if ( referringPrimaryKey ) { + if ( isKeyReferringSide ) { // case 1.2 keyResult = foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, creationState ); selectByUniqueKey = false; } else { - keyResult = ((EntityPersister) getDeclaringType()).getIdentifierMapping() + keyResult = ( (EntityPersister) getDeclaringType() ).getIdentifierMapping() .createDomainResult( fetchablePath, parentTableGroup, null, creationState ); // case 1.1 selectByUniqueKey = true; @@ -616,7 +619,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping @Override public void visitColumns(ColumnConsumer consumer) { - if ( foreignKeyDirection == ForeignKeyDirection.FROM_PARENT ) { + if ( isKeyReferringSide ) { foreignKeyDescriptor.visitReferringColumns( consumer ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java index fd39ff5a3c..e138e113bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/mutation/internal/MultiTableSqmMutationConverter.java @@ -6,7 +6,6 @@ */ package org.hibernate.query.sqm.mutation.internal; -import java.util.Collections; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; @@ -30,7 +29,6 @@ import org.hibernate.query.sqm.tree.select.SqmSelectClause; import org.hibernate.query.sqm.tree.update.SqmAssignment; import org.hibernate.query.sqm.tree.update.SqmSetClause; import org.hibernate.sql.ast.spi.SqlAstCreationContext; -import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstProcessingState; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.expression.ColumnReference; @@ -41,9 +39,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.update.Assignable; import org.hibernate.sql.ast.tree.update.Assignment; -import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchParent; /** * Specialized BaseSqmToSqlAstConverter implementation used during conversion @@ -56,7 +51,7 @@ import org.hibernate.sql.results.graph.FetchParent; * * @author Steve Ebersole */ -public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter implements DomainResultCreationState { +public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter { private final EntityMappingType mutatingEntityDescriptor; private final TableGroup mutatingTableGroup; @@ -212,16 +207,6 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter imp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - @Override - public SqlAstCreationState getSqlAstCreationState() { - return this; - } - - @Override - public List visitFetches(FetchParent fetchParent) { - return Collections.emptyList(); - } - public void visitSelectClause( SqmSelectClause sqmSelectClause, QuerySpec sqlQuerySpec, diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index cadcbd6cd3..2694d18ece 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -7,6 +7,7 @@ package org.hibernate.query.sqm.sql; import java.util.ArrayList; +import java.util.Collections; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; @@ -21,12 +22,10 @@ import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.dialect.function.TimestampaddFunction; import org.hibernate.dialect.function.TimestampdiffFunction; import org.hibernate.engine.spi.LoadQueryInfluencers; -import org.hibernate.internal.util.MutableInteger; import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.CollectionPart; -import org.hibernate.metamodel.mapping.ColumnConsumer; import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.PluralAttributeMapping; @@ -137,6 +136,7 @@ import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator; import org.hibernate.sql.ast.spi.SqlAliasBaseManager; import org.hibernate.sql.ast.spi.SqlAstCreationContext; +import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlAstProcessingState; import org.hibernate.sql.ast.spi.SqlAstQuerySpecProcessingState; import org.hibernate.sql.ast.spi.SqlAstTreeHelper; @@ -150,7 +150,6 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.CastTarget; -import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.DurationUnit; @@ -185,7 +184,9 @@ import org.hibernate.sql.ast.tree.select.SortSpecification; import org.hibernate.sql.exec.internal.JdbcParameterImpl; import org.hibernate.sql.exec.internal.JdbcParametersImpl; import org.hibernate.sql.exec.spi.JdbcParameters; -import org.hibernate.sql.results.internal.SqlSelectionImpl; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.type.spi.TypeConfiguration; import org.jboss.logging.Logger; @@ -204,7 +205,7 @@ import static org.hibernate.type.spi.TypeConfiguration.isDuration; */ public abstract class BaseSqmToSqlAstConverter extends BaseSemanticQueryWalker - implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, FromClauseAccess { + implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, FromClauseAccess, DomainResultCreationState { private static final Logger log = Logger.getLogger( BaseSqmToSqlAstConverter.class ); @@ -2213,6 +2214,15 @@ public abstract class BaseSqmToSqlAstConverter private QuerySpec createMemberOfSubQuery(SqmPath pluralPath, PluralAttributeMapping mappingModelExpressable) { final QuerySpec querySpec = new QuerySpec( true ); + processingStateStack.push( + new SqlAstQuerySpecProcessingStateImpl( + querySpec, + processingStateStack.getCurrent(), + this, + currentClauseStack::getCurrent + ) + ); + final TableGroup rootTableGroup = mappingModelExpressable.createRootTableGroup( pluralPath.getNavigablePath(), null, @@ -2223,22 +2233,17 @@ public abstract class BaseSqmToSqlAstConverter () -> querySpec::applyPredicate, creationContext ); + querySpec.getFromClause().addRoot( rootTableGroup ); final CollectionPart elementDescriptor = mappingModelExpressable.getElementDescriptor(); - final ColumnConsumer columnConsumer = createMemberOfColumnConsumer( querySpec, rootTableGroup ); - if ( elementDescriptor instanceof EntityCollectionPart ) { - ( (EntityCollectionPart) elementDescriptor ).getEntityMappingType() - .getIdentifierMapping().visitColumns( columnConsumer ); - } - else if ( elementDescriptor instanceof BasicValuedCollectionPart ) { - elementDescriptor.visitColumns( columnConsumer ); - } - else { - throw new NotYetImplementedFor6Exception( - "Member of with Collection of Embeddable has not yet been implemented" ); - } + elementDescriptor.createDomainResult( + pluralPath.getNavigablePath(), + rootTableGroup, + null, + this + ); final Predicate predicate = mappingModelExpressable.getKeyDescriptor().generateJoinPredicate( getFromClauseAccess().findTableGroup( pluralPath.getNavigablePath().getParent() ), @@ -2249,28 +2254,10 @@ public abstract class BaseSqmToSqlAstConverter ); querySpec.applyPredicate( predicate ); + processingStateStack.pop(); return querySpec; } - private ColumnConsumer createMemberOfColumnConsumer(QuerySpec querySpec, TableGroup rootTableGroup) { - final MutableInteger count = new MutableInteger(); - return (containingTableExpression, columnExpression, isColumnExpressionFormula, jdbcMapping) -> { - ColumnReference columnReference = new ColumnReference( - rootTableGroup.getPrimaryTableReference(), - columnExpression, - isColumnExpressionFormula, - jdbcMapping, - creationContext.getSessionFactory() - ); - - final int valuesPosition = count.getAndIncrement(); - - querySpec.getSelectClause().addSqlSelection( - new SqlSelectionImpl( valuesPosition + 1, valuesPosition, columnReference ) - ); - }; - } - @Override public NegatedPredicate visitNegatedPredicate(SqmNegatedPredicate predicate) { return new NegatedPredicate( @@ -2453,4 +2440,14 @@ public abstract class BaseSqmToSqlAstConverter public Object visitExistsPredicate(SqmExistsPredicate predicate) { return new ExistsPredicate( (QuerySpec) predicate.getExpression().accept( this ) ); } + + @Override + public SqlAstCreationState getSqlAstCreationState() { + return this; + } + + @Override + public List visitFetches(FetchParent fetchParent) { + return Collections.emptyList(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java index 5f56f2e29d..e411b298fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmInsertTranslator.java @@ -6,6 +6,8 @@ */ package org.hibernate.query.sqm.sql.internal; +import java.util.List; + import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.internal.util.collections.CollectionHelper; @@ -27,7 +29,6 @@ import org.hibernate.query.sqm.tree.insert.SqmValues; import org.hibernate.query.sqm.tree.select.SqmSelectStatement; import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.sql.ast.spi.SqlAstCreationContext; -import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.tree.cte.CteStatement; import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.from.TableGroup; @@ -37,19 +38,13 @@ import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.update.Assignable; 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 java.util.Collections; -import java.util.List; /** * @author Steve Ebersole */ public class StandardSqmInsertTranslator extends BaseSqmToSqlAstConverter - implements SqmInsertTranslator, DomainResultCreationState { + implements SqmInsertTranslator { private final List domainResults = CollectionHelper.arrayList( 10 ); @@ -229,13 +224,4 @@ public class StandardSqmInsertTranslator return new SelectStatement( querySpec, domainResults ); } - @Override - public SqlAstCreationState getSqlAstCreationState() { - return this; - } - - @Override - public List visitFetches(FetchParent fetchParent) { - return Collections.emptyList(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmSelectTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmSelectTranslator.java index 5c4c44d4f1..50171f083a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmSelectTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmSelectTranslator.java @@ -73,7 +73,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.results.graph.DomainResult; -import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.EntityGraphTraversalState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; @@ -93,7 +92,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @SuppressWarnings("unchecked") public class StandardSqmSelectTranslator extends BaseSqmToSqlAstConverter - implements DomainResultCreationState, SqmSelectTranslator { + implements SqmSelectTranslator { // prepare for 10 root selections to avoid list growth in most cases private final List domainResults = CollectionHelper.arrayList( 10 ); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmUpdateTranslator.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmUpdateTranslator.java index 9328d9c571..dd64555114 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmUpdateTranslator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/internal/StandardSqmUpdateTranslator.java @@ -56,7 +56,6 @@ public class StandardSqmUpdateTranslator extends BaseSqmToSqlAstConverter implements SimpleSqmUpdateTranslator { - public StandardSqmUpdateTranslator( SqlAstCreationContext creationContext, QueryOptions queryOptions, @@ -292,4 +291,5 @@ public class StandardSqmUpdateTranslator return assignments; } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/ManyToManyHqlMemberOfQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/ManyToManyHqlMemberOfQueryTest.java index 7861653ce2..62e39b3f0a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/ManyToManyHqlMemberOfQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/manytomany/ManyToManyHqlMemberOfQueryTest.java @@ -31,6 +31,7 @@ import javax.persistence.TemporalType; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -104,6 +105,17 @@ public class ManyToManyHqlMemberOfQueryTest { ); } + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.createQuery( "delete from Call" ).executeUpdate(); + session.createQuery( "delete from Person" ).executeUpdate(); + session.createQuery( "delete from Phone" ).executeUpdate(); + } + ); + } + @Test public void testMemberOf(SessionFactoryScope scope) { scope.inTransaction( @@ -155,7 +167,7 @@ public class ManyToManyHqlMemberOfQueryTest { @Temporal(TemporalType.TIMESTAMP) private Date createdOn; - @ManyToMany( cascade = CascadeType.ALL) + @ManyToMany(cascade = CascadeType.ALL) private List phones = new ArrayList<>(); @ElementCollection