Skip to content

Commit 004de8a

Browse files
mbelladebeikov
authored andcommitted
HHH-18745 Avoid resolving unnecessary table references for subtypes
Also, handle type expressions in case statements like we do for comparison logic.
1 parent b0fda32 commit 004de8a

File tree

2 files changed

+40
-6
lines changed

2 files changed

+40
-6
lines changed

hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,8 +3057,6 @@ else if ( useKind == EntityNameUse.UseKind.PROJECTION ) {
30573057
for ( EntityMappingType subType : persister.getSubMappingTypes() ) {
30583058
entityNameUses.compute( subType.getEntityName(),
30593059
(s, existingUse) -> finalEntityNameUse.stronger( existingUse ) );
3060-
actualTableGroup.resolveTableReference( null,
3061-
subType.getEntityPersister().getMappedTableDetails().getTableName() );
30623060
}
30633061
}
30643062
}
@@ -7023,6 +7021,8 @@ public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple<?, ?> expres
70237021
inferrableTypeAccessStack.push( () -> fixtureType );
70247022
final Expression checkValue = (Expression) whenFragment.getCheckValue().accept( this );
70257023
inferrableTypeAccessStack.pop();
7024+
handleTypeInCaseExpression( fixture, checkValue );
7025+
70267026
final MappingModelExpressible<?> alreadyKnown = resolved;
70277027
inferrableTypeAccessStack.push(
70287028
() -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown
@@ -7058,6 +7058,40 @@ public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple<?, ?> expres
70587058
);
70597059
}
70607060

7061+
private void handleTypeInCaseExpression(Expression fixture, Expression checkValue) {
7062+
if ( fixture instanceof DiscriminatorPathInterpretation<?> typeExpression ) {
7063+
final TableGroup tableGroup = getFromClauseIndex().getTableGroup( typeExpression.getNavigablePath().getParent() );
7064+
final MappingType partMappingType = tableGroup.getModelPart().getPartMappingType();
7065+
if ( !(partMappingType instanceof EntityMappingType entityMappingType) ) {
7066+
return;
7067+
}
7068+
if ( entityMappingType.getDiscriminatorMapping().hasPhysicalColumn() ) {
7069+
// If the entity type has a physical type column we only need to register an expression
7070+
// usage for the root type to prevent pruning the table where the discriminator is found
7071+
registerEntityNameUsage(
7072+
tableGroup,
7073+
EntityNameUse.EXPRESSION,
7074+
entityMappingType.getRootEntityDescriptor().getEntityName()
7075+
);
7076+
}
7077+
else if ( checkValue instanceof EntityTypeLiteral typeLiteral ) {
7078+
// Register an expression type usage for the literal subtype to prevent pruning its table group
7079+
registerEntityNameUsage(
7080+
tableGroup,
7081+
EntityNameUse.EXPRESSION,
7082+
typeLiteral.getEntityTypeDescriptor().getEntityName()
7083+
);
7084+
}
7085+
else {
7086+
// We have to assume all types are possible and can't do optimizations
7087+
registerEntityNameUsage( tableGroup, EntityNameUse.EXPRESSION, entityMappingType.getEntityName() );
7088+
for ( EntityMappingType subMappingType : entityMappingType.getSubMappingTypes() ) {
7089+
registerEntityNameUsage( tableGroup, EntityNameUse.EXPRESSION, subMappingType.getEntityName() );
7090+
}
7091+
}
7092+
}
7093+
}
7094+
70617095
@Override
70627096
public CaseSearchedExpression visitSearchedCaseExpression(SqmCaseSearched<?> expression) {
70637097
final List<CaseSearchedExpression.WhenFragment> whenFragments = new ArrayList<>( expression.getWhenFragments().size() );

hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/discriminator/JoinedInheritanceDiscriminatorSelectionTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,28 +139,28 @@ public void testSelectInstance(SessionFactoryScope scope) {
139139
inspector.clear();
140140

141141
scope.inTransaction( session -> {
142-
// With type filters we still join all subclasses when selecting the entity instance
142+
// With type filters we still join all subclasses that have properties when selecting the entity instance
143143
// because we are not aware of the type restriction when processing the selection
144144

145145
assertThat( session.createQuery(
146146
"from ParentEntity p where type(p) = ParentEntity",
147147
ParentEntity.class
148148
).getResultList() ).hasSize( 1 );
149-
inspector.assertNumberOfJoins( 0, 3 );
149+
inspector.assertNumberOfJoins( 0, 2 );
150150
inspector.clear();
151151

152152
assertThat( session.createQuery(
153153
"from ParentEntity p where type(p) = ChildA",
154154
ParentEntity.class
155155
).getResultList() ).hasSize( 1 );
156-
inspector.assertNumberOfJoins( 0, 3 );
156+
inspector.assertNumberOfJoins( 0, 2 );
157157
inspector.clear();
158158

159159
assertThat( session.createQuery(
160160
"from ParentEntity p where type(p) = SubChildA",
161161
ParentEntity.class
162162
).getResultList() ).hasSize( 1 );
163-
inspector.assertNumberOfJoins( 0, 3 );
163+
inspector.assertNumberOfJoins( 0, 2 );
164164
inspector.clear();
165165

166166
// With treat() we only join the needed subclasses

0 commit comments

Comments
 (0)