HHH-17806 Avoid joined + discriminator inheritance joins in more cases

This commit is contained in:
Marco Belladelli 2024-03-05 12:19:05 +01:00
parent ab01984807
commit d475b59715
2 changed files with 98 additions and 26 deletions

View File

@ -7593,41 +7593,45 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> 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<String> 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<String> 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() );
}
}
}
}

View File

@ -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();
} );
}