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 98380e1d2b..10d00e7eab 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 @@ -7593,41 +7593,45 @@ public abstract class BaseSqmToSqlAstConverter extends Base final TableGroup tableGroup = getFromClauseIndex().getTableGroup( typeExpression.getNavigablePath().getParent() ); final EntityMappingType entityMappingType = (EntityMappingType) tableGroup.getModelPart().getPartMappingType(); if ( entityMappingType.getDiscriminatorMapping().hasPhysicalColumn() ) { - // Prevent pruning of the root type's table reference containing the physical discriminator column + // If the entity has a physical discriminator column we don't need to register any FILTER usages. + // Register only an EXPRESSION usage to prevent pruning of the root type's table reference which + // contains the physical discriminator column registerEntityNameUsage( tableGroup, EntityNameUse.EXPRESSION, entityMappingType.getRootEntityDescriptor().getEntityName() ); } - if ( literalExpressions == null ) { - // We have to assume all types are possible and can't do optimizations - registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, entityMappingType.getEntityName() ); - for ( EntityMappingType subMappingType : entityMappingType.getSubMappingTypes() ) { - registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, subMappingType.getEntityName() ); - } - } else { - if ( inclusive ) { - for ( EntityTypeLiteral literalExpr : literalExpressions ) { - registerEntityNameUsage( - tableGroup, - EntityNameUse.FILTER, - literalExpr.getEntityTypeDescriptor().getEntityName() - ); + if ( literalExpressions == null ) { + // We have to assume all types are possible and can't do optimizations + registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, entityMappingType.getEntityName() ); + for ( EntityMappingType subMappingType : entityMappingType.getSubMappingTypes() ) { + registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, subMappingType.getEntityName() ); } } else { - final Set excludedEntityNames = new HashSet<>( entityMappingType.getSubMappingTypes().size() ); - for ( EntityTypeLiteral literalExpr : literalExpressions ) { - excludedEntityNames.add( literalExpr.getEntityTypeDescriptor().getEntityName() ); + if ( inclusive ) { + for ( EntityTypeLiteral literalExpr : literalExpressions ) { + registerEntityNameUsage( + tableGroup, + EntityNameUse.FILTER, + literalExpr.getEntityTypeDescriptor().getEntityName() + ); + } } - if ( !excludedEntityNames.contains( entityMappingType.getEntityName() ) ) { - registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, entityMappingType.getEntityName() ); - } - for ( EntityMappingType subMappingType : entityMappingType.getSubMappingTypes() ) { - if ( !excludedEntityNames.contains( subMappingType.getEntityName() ) ) { - registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, subMappingType.getEntityName() ); + else { + final Set excludedEntityNames = new HashSet<>( entityMappingType.getSubMappingTypes().size() ); + for ( EntityTypeLiteral literalExpr : literalExpressions ) { + excludedEntityNames.add( literalExpr.getEntityTypeDescriptor().getEntityName() ); + } + if ( !excludedEntityNames.contains( entityMappingType.getEntityName() ) ) { + registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, entityMappingType.getEntityName() ); + } + for ( EntityMappingType subMappingType : entityMappingType.getSubMappingTypes() ) { + if ( !excludedEntityNames.contains( subMappingType.getEntityName() ) ) { + registerEntityNameUsage( tableGroup, EntityNameUse.FILTER, subMappingType.getEntityName() ); + } } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/JoinedInheritanceDiscriminatorSelectionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/JoinedInheritanceDiscriminatorSelectionTest.java index 458006f1bd..932c6ae6ff 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/JoinedInheritanceDiscriminatorSelectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/JoinedInheritanceDiscriminatorSelectionTest.java @@ -6,6 +6,8 @@ */ package org.hibernate.orm.test.inheritance.discriminator; +import java.util.List; + import org.hibernate.testing.jdbc.SQLStatementInspector; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.Jira; @@ -35,6 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat; } ) @SessionFactory( useCollectingStatementInspector = true ) @Jira( "https://hibernate.atlassian.net/browse/HHH-17727" ) +@Jira( "https://hibernate.atlassian.net/browse/HHH-17806" ) public class JoinedInheritanceDiscriminatorSelectionTest { @BeforeAll public void setUp(SessionFactoryScope scope) { @@ -71,12 +74,25 @@ public class JoinedInheritanceDiscriminatorSelectionTest { inspector.assertNumberOfJoins( 0, 0 ); inspector.clear(); + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) in (ParentEntity)", + String.class + ).getSingleResult() ).isEqualTo( "parent" ); + inspector.assertNumberOfJoins( 0, 0 ); + inspector.clear(); + assertThat( session.createQuery( "select p.name from ParentEntity p where type(p) = ChildA", String.class ).getSingleResult() ).isEqualTo( "child_a" ); - // We still inner-join the subtype table, this could be avoided since we have a discriminator condition - inspector.assertNumberOfJoins( 0, 1 ); + inspector.assertNumberOfJoins( 0, 0 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) in (ParentEntity, ChildA)", + String.class + ).getResultList() ).containsOnly( "parent", "child_a" ); + inspector.assertNumberOfJoins( 0, 0 ); } ); } @@ -128,6 +144,58 @@ public class JoinedInheritanceDiscriminatorSelectionTest { ParentEntity.class ).getResultList() ).hasSize( 1 ); inspector.assertNumberOfJoins( 0, 3 ); + } ); + } + + @Test + public void testTypeFilterParameter(SessionFactoryScope scope) { + final SQLStatementInspector inspector = scope.getCollectingStatementInspector(); + inspector.clear(); + + scope.inTransaction( session -> { + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) = :type", + String.class + ).setParameter( "type", ParentEntity.class ).getSingleResult() ).isEqualTo( "parent" ); + inspector.assertNumberOfJoins( 0, 0 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.propertyA from ParentEntity p where type(p) = :type", + Integer.class + ).setParameter( "type", ChildA.class ).getSingleResult() ).isEqualTo( 2 ); + inspector.assertNumberOfJoins( 0, 1 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) = :type", + String.class + ).setParameter( "type", ChildA.class ).getSingleResult() ).isEqualTo( "child_a" ); + inspector.assertNumberOfJoins( 0, 0 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) in :types", + String.class + ).setParameter( "types", List.of( ParentEntity.class ) ).getSingleResult() ).isEqualTo( "parent" ); + inspector.assertNumberOfJoins( 0, 0 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.subPropertyA from ParentEntity p where type(p) in :types", + Integer.class + ).setParameter( "types", List.of( SubChildA.class ) ).getSingleResult() ).isEqualTo( 3 ); + inspector.assertNumberOfJoins( 0, 1 ); + inspector.clear(); + + assertThat( session.createQuery( + "select p.name from ParentEntity p where type(p) in :types", + String.class + ).setParameter( "types", List.of( ParentEntity.class, ChildA.class ) ).getResultList() ).containsOnly( + "parent", + "child_a" + ); + inspector.assertNumberOfJoins( 0, 0 ); inspector.clear(); } ); }